4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
27 * Support routines for DIMMs.
31 #include <gmem_dimm.h>
39 #include <fm/fmd_api.h>
40 #include <fm/libtopo.h>
41 #include <sys/fm/protocol.h>
43 #include <sys/nvpair.h>
47 typedef struct dimmid
{
52 static int gmem_find_dimm_chip(nvlist_t
*, uint32_t *);
55 gmem_dimm_fru(gmem_dimm_t
*dimm
)
57 return (dimm
->dimm_asru_nvl
);
61 gmem_dimm_free(fmd_hdl_t
*hdl
, gmem_dimm_t
*dimm
, int destroy
)
63 gmem_case_t
*cc
= &dimm
->dimm_case
;
68 if (cc
->cc_cp
!= NULL
) {
69 gmem_case_fini(hdl
, cc
->cc_cp
, destroy
);
70 if (cc
->cc_serdnm
!= NULL
) {
71 if (fmd_serd_exists(hdl
, cc
->cc_serdnm
) &&
73 fmd_serd_destroy(hdl
, cc
->cc_serdnm
);
74 fmd_hdl_strfree(hdl
, cc
->cc_serdnm
);
78 gmem_fmri_fini(hdl
, &dimm
->dimm_asru
, destroy
);
80 for (i
= 0; i
< GMEM_MAX_CKWDS
; i
++) {
81 while ((q
= gmem_list_next(&dimm
->mq_root
[i
])) != NULL
) {
82 if (q
->mq_serdnm
!= NULL
) {
83 if (fmd_serd_exists(hdl
, q
->mq_serdnm
))
84 fmd_serd_destroy(hdl
, q
->mq_serdnm
);
85 fmd_hdl_strfree(hdl
, q
->mq_serdnm
);
89 for (tsp
= gmem_list_next(&q
->mq_dupce_tstamp
);
90 tsp
!= NULL
; tsp
= next
) {
91 next
= gmem_list_next(tsp
);
92 gmem_list_delete(&q
->mq_dupce_tstamp
,
94 fmd_hdl_free(hdl
, tsp
, sizeof (tstamp_t
));
97 gmem_list_delete(&dimm
->mq_root
[i
], q
);
98 fmd_hdl_free(hdl
, q
, sizeof (gmem_mq_t
));
103 fmd_buf_destroy(hdl
, NULL
, dimm
->dimm_bufname
);
105 gmem_list_delete(&gmem
.gm_dimms
, dimm
);
106 fmd_hdl_free(hdl
, dimm
, sizeof (gmem_dimm_t
));
110 gmem_dimm_destroy(fmd_hdl_t
*hdl
, gmem_dimm_t
*dimm
)
112 fmd_stat_destroy(hdl
, 1, &(dimm
->dimm_retstat
));
113 gmem_dimm_free(hdl
, dimm
, FMD_B_TRUE
);
117 dimm_lookup_by_serial(const char *serial
)
121 for (dimm
= gmem_list_next(&gmem
.gm_dimms
); dimm
!= NULL
;
122 dimm
= gmem_list_next(dimm
)) {
123 if (strcmp(dimm
->dimm_serial
, serial
) == 0)
131 gmem_dimm_create(fmd_hdl_t
*hdl
, nvlist_t
*asru
, nvlist_t
*det
)
138 if (nvlist_lookup_string(asru
, FM_FMRI_HC_SERIAL_ID
, &serial
) != 0) {
139 fmd_hdl_debug(hdl
, "Unable to get dimm serial\n");
143 if (nvlist_dup(asru
, &fmri
, 0) != 0) {
144 fmd_hdl_debug(hdl
, "dimm create nvlist dup failed");
148 (void) gmem_find_dimm_chip(det
, &chip_id
);
150 fmd_hdl_debug(hdl
, "dimm_create: creating new DIMM serial=%s\n",
152 GMEM_STAT_BUMP(dimm_creat
);
154 dimm
= fmd_hdl_zalloc(hdl
, sizeof (gmem_dimm_t
), FMD_SLEEP
);
155 dimm
->dimm_nodetype
= GMEM_NT_DIMM
;
156 dimm
->dimm_version
= GMEM_DIMM_VERSION
;
157 dimm
->dimm_phys_addr_low
= ULLONG_MAX
;
158 dimm
->dimm_phys_addr_hi
= 0;
159 dimm
->dimm_syl_error
= USHRT_MAX
;
160 dimm
->dimm_chipid
= chip_id
;
162 gmem_bufname(dimm
->dimm_bufname
, sizeof (dimm
->dimm_bufname
), "dimm_%s",
164 gmem_fmri_init(hdl
, &dimm
->dimm_asru
, fmri
, "dimm_asru_%s", serial
);
168 (void) nvlist_lookup_string(dimm
->dimm_asru_nvl
, FM_FMRI_HC_SERIAL_ID
,
169 (char **)&dimm
->dimm_serial
);
171 gmem_mem_retirestat_create(hdl
, &dimm
->dimm_retstat
, dimm
->dimm_serial
,
172 0, GMEM_DIMM_STAT_PREFIX
);
174 gmem_list_append(&gmem
.gm_dimms
, dimm
);
175 gmem_dimm_dirty(hdl
, dimm
);
181 gmem_dimm_lookup(fmd_hdl_t
*hdl
, nvlist_t
*asru
)
187 err
= nvlist_lookup_string(asru
, FM_FMRI_HC_SERIAL_ID
, &serial
);
190 fmd_hdl_debug(hdl
, "Can't get dimm serial number\n");
191 GMEM_STAT_BUMP(bad_mem_resource
);
195 dimm
= dimm_lookup_by_serial(serial
);
201 gmem_dimm_v0tov1(fmd_hdl_t
*hdl
, gmem_dimm_0_t
*old
, size_t oldsz
)
204 if (oldsz
!= sizeof (gmem_dimm_0_t
)) {
205 fmd_hdl_abort(hdl
, "size of state doesn't match size of "
206 "version 0 state (%u bytes).\n", sizeof (gmem_dimm_0_t
));
209 new = fmd_hdl_zalloc(hdl
, sizeof (gmem_dimm_t
), FMD_SLEEP
);
210 new->dimm_header
= old
->dimm0_header
;
211 new->dimm_version
= GMEM_DIMM_VERSION
;
212 new->dimm_asru
= old
->dimm0_asru
;
213 new->dimm_nretired
= old
->dimm0_nretired
;
214 new->dimm_phys_addr_hi
= 0;
215 new->dimm_phys_addr_low
= ULLONG_MAX
;
217 fmd_hdl_free(hdl
, old
, oldsz
);
222 gmem_dimm_wrapv1(fmd_hdl_t
*hdl
, gmem_dimm_pers_t
*pers
, size_t psz
)
226 if (psz
!= sizeof (gmem_dimm_pers_t
)) {
227 fmd_hdl_abort(hdl
, "size of state doesn't match size of "
228 "version 0 state (%u bytes).\n", sizeof (gmem_dimm_pers_t
));
231 dimm
= fmd_hdl_zalloc(hdl
, sizeof (gmem_dimm_t
), FMD_SLEEP
);
232 bcopy(pers
, dimm
, sizeof (gmem_dimm_pers_t
));
233 fmd_hdl_free(hdl
, pers
, psz
);
238 gmem_dimm_restore(fmd_hdl_t
*hdl
, fmd_case_t
*cp
, gmem_case_ptr_t
*ptr
)
242 for (dimm
= gmem_list_next(&gmem
.gm_dimms
); dimm
!= NULL
;
243 dimm
= gmem_list_next(dimm
)) {
244 if (strcmp(dimm
->dimm_bufname
, ptr
->ptr_name
) == 0)
252 fmd_hdl_debug(hdl
, "restoring dimm from %s\n", ptr
->ptr_name
);
254 if ((dimmsz
= fmd_buf_size(hdl
, NULL
, ptr
->ptr_name
)) == 0) {
255 fmd_hdl_abort(hdl
, "dimm referenced by case %s does "
256 "not exist in saved state\n",
257 fmd_case_uuid(hdl
, cp
));
258 } else if (dimmsz
> GMEM_DIMM_MAXSIZE
||
259 dimmsz
< GMEM_DIMM_MINSIZE
) {
260 fmd_hdl_abort(hdl
, "dimm buffer referenced by case %s "
261 "is out of bounds (is %u bytes, max %u, min %u)\n",
262 fmd_case_uuid(hdl
, cp
), dimmsz
,
263 GMEM_DIMM_MAXSIZE
, GMEM_DIMM_MINSIZE
);
266 if ((dimm
= gmem_buf_read(hdl
, NULL
, ptr
->ptr_name
,
268 fmd_hdl_abort(hdl
, "failed to read dimm buf %s",
272 fmd_hdl_debug(hdl
, "found %d in version field\n",
275 if (GMEM_DIMM_VERSIONED(dimm
)) {
277 switch (dimm
->dimm_version
) {
278 case GMEM_DIMM_VERSION_1
:
279 dimm
= gmem_dimm_wrapv1(hdl
,
280 (gmem_dimm_pers_t
*)dimm
, dimmsz
);
283 fmd_hdl_abort(hdl
, "unknown version (found %d) "
284 "for dimm state referenced by case %s.\n",
285 dimm
->dimm_version
, fmd_case_uuid(hdl
, cp
));
289 dimm
= gmem_dimm_v0tov1(hdl
, (gmem_dimm_0_t
*)dimm
,
295 GMEM_STAT_BUMP(dimm_migrat
);
296 gmem_dimm_dirty(hdl
, dimm
);
299 gmem_fmri_restore(hdl
, &dimm
->dimm_asru
);
301 if ((errno
= nvlist_lookup_string(dimm
->dimm_asru_nvl
,
302 FM_FMRI_HC_SERIAL_ID
, (char **)&dimm
->dimm_serial
)) != 0)
304 "failed to retrieve serial from asru");
307 gmem_mem_retirestat_create(hdl
, &dimm
->dimm_retstat
,
308 dimm
->dimm_serial
, dimm
->dimm_nretired
,
309 GMEM_DIMM_STAT_PREFIX
);
311 gmem_list_append(&gmem
.gm_dimms
, dimm
);
314 switch (ptr
->ptr_subtype
) {
315 case GMEM_PTR_DIMM_CASE
:
316 gmem_mem_case_restore(hdl
, &dimm
->dimm_case
, cp
, "dimm",
320 fmd_hdl_abort(hdl
, "invalid %s subtype %d\n",
321 ptr
->ptr_name
, ptr
->ptr_subtype
);
328 gmem_dimm_validate(fmd_hdl_t
*hdl
)
330 gmem_dimm_t
*dimm
, *next
;
332 for (dimm
= gmem_list_next(&gmem
.gm_dimms
); dimm
!= NULL
; dimm
= next
) {
333 next
= gmem_list_next(dimm
);
335 if (!gmem_dimm_present(hdl
, dimm
->dimm_asru_nvl
))
336 gmem_dimm_destroy(hdl
, dimm
);
341 gmem_dimm_dirty(fmd_hdl_t
*hdl
, gmem_dimm_t
*dimm
)
343 if (fmd_buf_size(hdl
, NULL
, dimm
->dimm_bufname
) !=
344 sizeof (gmem_dimm_pers_t
))
345 fmd_buf_destroy(hdl
, NULL
, dimm
->dimm_bufname
);
347 /* No need to rewrite the FMRIs in the dimm - they don't change */
348 fmd_buf_write(hdl
, NULL
, dimm
->dimm_bufname
, &dimm
->dimm_pers
,
349 sizeof (gmem_dimm_pers_t
));
353 gmem_dimm_gc(fmd_hdl_t
*hdl
)
355 gmem_dimm_validate(hdl
);
359 gmem_dimm_fini(fmd_hdl_t
*hdl
)
363 while ((dimm
= gmem_list_next(&gmem
.gm_dimms
)) != NULL
)
364 gmem_dimm_free(hdl
, dimm
, FMD_B_FALSE
);
370 find_dimm_hc_fmri(topo_hdl_t
*thp
, tnode_t
*node
, void *arg
)
374 dimmid_t
*dimmid
= (dimmid_t
*)arg
;
375 nvlist_t
*fru
= NULL
;
376 nvlist_t
*rsc
= NULL
;
377 nvlist_t
*asru
= NULL
;
380 if (topo_node_fru(node
, &fru
, NULL
, &err
) < 0)
381 return (TOPO_WALK_NEXT
);
383 err
= nvlist_lookup_string(fru
, FM_FMRI_HC_SERIAL_ID
, &topo_sn
);
386 return (TOPO_WALK_NEXT
);
389 if (strcmp(dimmid
->serial
, topo_sn
) != 0) {
391 return (TOPO_WALK_NEXT
);
394 switch (dimmid
->type
) {
396 (void) nvlist_dup(fru
, &dimm_nvl
, NV_UNIQUE_NAME
);
399 (void) topo_node_resource(node
, &rsc
, &err
);
401 (void) nvlist_dup(rsc
, &dimm_nvl
,
407 (void) topo_node_asru(node
, &asru
, NULL
, &err
);
409 (void) nvlist_dup(asru
, &dimm_nvl
,
418 return (TOPO_WALK_TERMINATE
);
422 gmem_find_dimm_by_sn(fmd_hdl_t
*hdl
, dimmid_t
*dimmid
) {
428 if ((thp
= fmd_hdl_topo_hold(hdl
, TOPO_VERSION
)) == NULL
)
431 if ((twp
= topo_walk_init(thp
, FM_FMRI_SCHEME_HC
,
432 find_dimm_hc_fmri
, dimmid
, &err
)) == NULL
) {
433 fmd_hdl_topo_rele(hdl
, thp
);
437 (void) topo_walk_step(twp
, TOPO_WALK_CHILD
);
439 fmd_hdl_topo_rele(hdl
, thp
);
444 gmem_find_dimm_fru(fmd_hdl_t
*hdl
, char *sn
)
447 (void) strcpy(fru
.serial
, sn
);
449 return (gmem_find_dimm_by_sn(hdl
, &fru
));
453 gmem_find_dimm_rsc(fmd_hdl_t
*hdl
, char *sn
)
456 (void) strcpy(rsc
.serial
, sn
);
458 return (gmem_find_dimm_by_sn(hdl
, &rsc
));
462 gmem_find_dimm_asru(fmd_hdl_t
*hdl
, char *sn
)
465 (void) strcpy(asru
.serial
, sn
);
466 asru
.type
= FINDASRU
;
467 return (gmem_find_dimm_by_sn(hdl
, &asru
));
471 gmem_dimm_present(fmd_hdl_t
*hdl
, nvlist_t
*asru
)
474 nvlist_t
*dimm
= NULL
;
476 if (nvlist_lookup_string(asru
, FM_FMRI_HC_SERIAL_ID
, &sn
) != 0) {
477 fmd_hdl_debug(hdl
, "Unable to get dimm serial\n");
480 dimm
= gmem_find_dimm_fru(hdl
, sn
);
482 fmd_hdl_debug(hdl
, "Dimm sn=%s is not present\n", sn
);
490 gmem_find_dimm_chip(nvlist_t
*nvl
, uint32_t *chip
)
493 char *name
, *id
, *end
;
500 if (nvlist_lookup_nvlist_array(nvl
, FM_FMRI_HC_LIST
, &hcl
, &n
) < 0)
502 for (i
= 0; i
< n
; i
++) {
503 (void) nvlist_lookup_string(hcl
[i
], FM_FMRI_HC_NAME
, &name
);
504 (void) nvlist_lookup_string(hcl
[i
], FM_FMRI_HC_ID
, &id
);
506 if (strcmp(name
, "chip") == 0) {
507 *chip
= (uint32_t)strtoul(id
, &end
, 10);
517 gmem_same_datapath_dimms(fmd_hdl_t
*hdl
, gmem_dimm_t
*d1
, gmem_dimm_t
*d2
)
520 if (d1
->dimm_chipid
== ULONG_MAX
|| d2
->dimm_chipid
== ULONG_MAX
)
523 if (d1
->dimm_chipid
== d2
->dimm_chipid
)
530 gmem_check_symbol_error(fmd_hdl_t
*hdl
, gmem_dimm_t
*d
, uint16_t upos
)
532 gmem_dimm_t
*dimm
= NULL
, *next
= NULL
;
534 for (dimm
= gmem_list_next(&gmem
.gm_dimms
); dimm
!= NULL
;
536 next
= gmem_list_next(dimm
);
537 if (gmem_same_datapath_dimms(hdl
, dimm
, d
) &&
538 dimm
->dimm_syl_error
== upos
)
545 gmem_save_symbol_error(fmd_hdl_t
*hdl
, gmem_dimm_t
*d
, uint16_t upos
)
547 gmem_dimm_t
*dimm
= NULL
, *next
= NULL
;
549 for (dimm
= gmem_list_next(&gmem
.gm_dimms
); dimm
!= NULL
;
551 next
= gmem_list_next(dimm
);
552 if (gmem_same_datapath_dimms(hdl
, dimm
, d
))
553 dimm
->dimm_syl_error
= upos
;