11529f529SScott Davenport /*
21529f529SScott Davenport * CDDL HEADER START
31529f529SScott Davenport *
41529f529SScott Davenport * The contents of this file are subject to the terms of the
51529f529SScott Davenport * Common Development and Distribution License (the "License").
61529f529SScott Davenport * You may not use this file except in compliance with the License.
71529f529SScott Davenport *
81529f529SScott Davenport * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91529f529SScott Davenport * or http://www.opensolaris.org/os/licensing.
101529f529SScott Davenport * See the License for the specific language governing permissions
111529f529SScott Davenport * and limitations under the License.
121529f529SScott Davenport *
131529f529SScott Davenport * When distributing Covered Code, include this CDDL HEADER in each
141529f529SScott Davenport * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151529f529SScott Davenport * If applicable, add the following below this CDDL HEADER, with the
161529f529SScott Davenport * fields enclosed by brackets "[]" replaced with your own identifying
171529f529SScott Davenport * information: Portions Copyright [yyyy] [name of copyright owner]
181529f529SScott Davenport *
191529f529SScott Davenport * CDDL HEADER END
201529f529SScott Davenport */
211529f529SScott Davenport /*
22d4ac42a1STrang Do * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
231529f529SScott Davenport */
241529f529SScott Davenport
251529f529SScott Davenport
261529f529SScott Davenport /*
271529f529SScott Davenport * Support routines for DIMMs.
281529f529SScott Davenport */
291529f529SScott Davenport
301529f529SScott Davenport #include <gmem_mem.h>
311529f529SScott Davenport #include <gmem_dimm.h>
321529f529SScott Davenport #include <gmem.h>
331529f529SScott Davenport #include <errno.h>
34d4ac42a1STrang Do #include <limits.h>
351529f529SScott Davenport #include <string.h>
361529f529SScott Davenport #include <strings.h>
371529f529SScott Davenport #include <fcntl.h>
381529f529SScott Davenport #include <unistd.h>
391529f529SScott Davenport #include <fm/fmd_api.h>
401529f529SScott Davenport #include <fm/libtopo.h>
411529f529SScott Davenport #include <sys/fm/protocol.h>
421529f529SScott Davenport #include <sys/mem.h>
431529f529SScott Davenport #include <sys/nvpair.h>
441529f529SScott Davenport
451529f529SScott Davenport nvlist_t *dimm_nvl;
461529f529SScott Davenport
471529f529SScott Davenport typedef struct dimmid {
481529f529SScott Davenport char serial[100];
491529f529SScott Davenport int type;
501529f529SScott Davenport } dimmid_t;
511529f529SScott Davenport
528f665889STrang Do static int gmem_find_dimm_chip(nvlist_t *, uint32_t *);
538f665889STrang Do
541529f529SScott Davenport nvlist_t *
gmem_dimm_fru(gmem_dimm_t * dimm)551529f529SScott Davenport gmem_dimm_fru(gmem_dimm_t *dimm)
561529f529SScott Davenport {
571529f529SScott Davenport return (dimm->dimm_asru_nvl);
581529f529SScott Davenport }
591529f529SScott Davenport
601529f529SScott Davenport static void
gmem_dimm_free(fmd_hdl_t * hdl,gmem_dimm_t * dimm,int destroy)611529f529SScott Davenport gmem_dimm_free(fmd_hdl_t *hdl, gmem_dimm_t *dimm, int destroy)
621529f529SScott Davenport {
631529f529SScott Davenport gmem_case_t *cc = &dimm->dimm_case;
641529f529SScott Davenport int i;
651529f529SScott Davenport gmem_mq_t *q;
66d4ac42a1STrang Do tstamp_t *tsp, *next;
671529f529SScott Davenport
681529f529SScott Davenport if (cc->cc_cp != NULL) {
691529f529SScott Davenport gmem_case_fini(hdl, cc->cc_cp, destroy);
701529f529SScott Davenport if (cc->cc_serdnm != NULL) {
711529f529SScott Davenport if (fmd_serd_exists(hdl, cc->cc_serdnm) &&
721529f529SScott Davenport destroy)
731529f529SScott Davenport fmd_serd_destroy(hdl, cc->cc_serdnm);
741529f529SScott Davenport fmd_hdl_strfree(hdl, cc->cc_serdnm);
751529f529SScott Davenport }
761529f529SScott Davenport }
771529f529SScott Davenport
781529f529SScott Davenport gmem_fmri_fini(hdl, &dimm->dimm_asru, destroy);
791529f529SScott Davenport
801529f529SScott Davenport for (i = 0; i < GMEM_MAX_CKWDS; i++) {
811529f529SScott Davenport while ((q = gmem_list_next(&dimm->mq_root[i])) != NULL) {
821529f529SScott Davenport if (q->mq_serdnm != NULL) {
831529f529SScott Davenport if (fmd_serd_exists(hdl, q->mq_serdnm))
841529f529SScott Davenport fmd_serd_destroy(hdl, q->mq_serdnm);
851529f529SScott Davenport fmd_hdl_strfree(hdl, q->mq_serdnm);
861529f529SScott Davenport q->mq_serdnm = NULL;
871529f529SScott Davenport }
88d4ac42a1STrang Do
89d4ac42a1STrang Do for (tsp = gmem_list_next(&q->mq_dupce_tstamp);
90d4ac42a1STrang Do tsp != NULL; tsp = next) {
91d4ac42a1STrang Do next = gmem_list_next(tsp);
92d4ac42a1STrang Do gmem_list_delete(&q->mq_dupce_tstamp,
93d4ac42a1STrang Do &tsp->ts_l);
94d4ac42a1STrang Do fmd_hdl_free(hdl, tsp, sizeof (tstamp_t));
95d4ac42a1STrang Do }
96d4ac42a1STrang Do
971529f529SScott Davenport gmem_list_delete(&dimm->mq_root[i], q);
981529f529SScott Davenport fmd_hdl_free(hdl, q, sizeof (gmem_mq_t));
991529f529SScott Davenport }
1001529f529SScott Davenport }
1011529f529SScott Davenport
1021529f529SScott Davenport if (destroy)
1031529f529SScott Davenport fmd_buf_destroy(hdl, NULL, dimm->dimm_bufname);
1041529f529SScott Davenport
1051529f529SScott Davenport gmem_list_delete(&gmem.gm_dimms, dimm);
1061529f529SScott Davenport fmd_hdl_free(hdl, dimm, sizeof (gmem_dimm_t));
1071529f529SScott Davenport }
1081529f529SScott Davenport
1091529f529SScott Davenport void
gmem_dimm_destroy(fmd_hdl_t * hdl,gmem_dimm_t * dimm)1101529f529SScott Davenport gmem_dimm_destroy(fmd_hdl_t *hdl, gmem_dimm_t *dimm)
1111529f529SScott Davenport {
1121529f529SScott Davenport fmd_stat_destroy(hdl, 1, &(dimm->dimm_retstat));
1131529f529SScott Davenport gmem_dimm_free(hdl, dimm, FMD_B_TRUE);
1141529f529SScott Davenport }
1151529f529SScott Davenport
1161529f529SScott Davenport static gmem_dimm_t *
dimm_lookup_by_serial(const char * serial)1171529f529SScott Davenport dimm_lookup_by_serial(const char *serial)
1181529f529SScott Davenport {
1191529f529SScott Davenport gmem_dimm_t *dimm;
1201529f529SScott Davenport
1211529f529SScott Davenport for (dimm = gmem_list_next(&gmem.gm_dimms); dimm != NULL;
1221529f529SScott Davenport dimm = gmem_list_next(dimm)) {
1231529f529SScott Davenport if (strcmp(dimm->dimm_serial, serial) == 0)
1241529f529SScott Davenport return (dimm);
1251529f529SScott Davenport }
1261529f529SScott Davenport
1271529f529SScott Davenport return (NULL);
1281529f529SScott Davenport }
1291529f529SScott Davenport
1301529f529SScott Davenport gmem_dimm_t *
gmem_dimm_create(fmd_hdl_t * hdl,nvlist_t * asru,nvlist_t * det)1318f665889STrang Do gmem_dimm_create(fmd_hdl_t *hdl, nvlist_t *asru, nvlist_t *det)
1321529f529SScott Davenport {
1331529f529SScott Davenport gmem_dimm_t *dimm;
1341529f529SScott Davenport nvlist_t *fmri;
1351529f529SScott Davenport char *serial;
1368f665889STrang Do uint32_t chip_id;
1371529f529SScott Davenport
1381529f529SScott Davenport if (nvlist_lookup_string(asru, FM_FMRI_HC_SERIAL_ID, &serial) != 0) {
1391529f529SScott Davenport fmd_hdl_debug(hdl, "Unable to get dimm serial\n");
1401529f529SScott Davenport return (NULL);
1411529f529SScott Davenport }
1421529f529SScott Davenport
1431529f529SScott Davenport if (nvlist_dup(asru, &fmri, 0) != 0) {
1441529f529SScott Davenport fmd_hdl_debug(hdl, "dimm create nvlist dup failed");
1451529f529SScott Davenport return (NULL);
1461529f529SScott Davenport }
1471529f529SScott Davenport
1488f665889STrang Do (void) gmem_find_dimm_chip(det, &chip_id);
1498f665889STrang Do
1501529f529SScott Davenport fmd_hdl_debug(hdl, "dimm_create: creating new DIMM serial=%s\n",
1511529f529SScott Davenport serial);
1521529f529SScott Davenport GMEM_STAT_BUMP(dimm_creat);
1531529f529SScott Davenport
1541529f529SScott Davenport dimm = fmd_hdl_zalloc(hdl, sizeof (gmem_dimm_t), FMD_SLEEP);
1551529f529SScott Davenport dimm->dimm_nodetype = GMEM_NT_DIMM;
1561529f529SScott Davenport dimm->dimm_version = GMEM_DIMM_VERSION;
157d4ac42a1STrang Do dimm->dimm_phys_addr_low = ULLONG_MAX;
158d4ac42a1STrang Do dimm->dimm_phys_addr_hi = 0;
159d4ac42a1STrang Do dimm->dimm_syl_error = USHRT_MAX;
1608f665889STrang Do dimm->dimm_chipid = chip_id;
1611529f529SScott Davenport
1621529f529SScott Davenport gmem_bufname(dimm->dimm_bufname, sizeof (dimm->dimm_bufname), "dimm_%s",
1631529f529SScott Davenport serial);
1641529f529SScott Davenport gmem_fmri_init(hdl, &dimm->dimm_asru, fmri, "dimm_asru_%s", serial);
1651529f529SScott Davenport
1661529f529SScott Davenport nvlist_free(fmri);
1671529f529SScott Davenport
1681529f529SScott Davenport (void) nvlist_lookup_string(dimm->dimm_asru_nvl, FM_FMRI_HC_SERIAL_ID,
1691529f529SScott Davenport (char **)&dimm->dimm_serial);
1701529f529SScott Davenport
1711529f529SScott Davenport gmem_mem_retirestat_create(hdl, &dimm->dimm_retstat, dimm->dimm_serial,
1721529f529SScott Davenport 0, GMEM_DIMM_STAT_PREFIX);
1731529f529SScott Davenport
1741529f529SScott Davenport gmem_list_append(&gmem.gm_dimms, dimm);
1751529f529SScott Davenport gmem_dimm_dirty(hdl, dimm);
1761529f529SScott Davenport
1771529f529SScott Davenport return (dimm);
1781529f529SScott Davenport }
1791529f529SScott Davenport
1801529f529SScott Davenport gmem_dimm_t *
gmem_dimm_lookup(fmd_hdl_t * hdl,nvlist_t * asru)1811529f529SScott Davenport gmem_dimm_lookup(fmd_hdl_t *hdl, nvlist_t *asru)
1821529f529SScott Davenport {
1831529f529SScott Davenport gmem_dimm_t *dimm;
1841529f529SScott Davenport char *serial;
1851529f529SScott Davenport int err;
1861529f529SScott Davenport
1871529f529SScott Davenport err = nvlist_lookup_string(asru, FM_FMRI_HC_SERIAL_ID, &serial);
1881529f529SScott Davenport
1891529f529SScott Davenport if (err != 0) {
1901529f529SScott Davenport fmd_hdl_debug(hdl, "Can't get dimm serial number\n");
1911529f529SScott Davenport GMEM_STAT_BUMP(bad_mem_resource);
1921529f529SScott Davenport return (NULL);
1931529f529SScott Davenport }
1941529f529SScott Davenport
1951529f529SScott Davenport dimm = dimm_lookup_by_serial(serial);
1961529f529SScott Davenport return (dimm);
1971529f529SScott Davenport }
1981529f529SScott Davenport
199d4ac42a1STrang Do
2001529f529SScott Davenport static gmem_dimm_t *
gmem_dimm_v0tov1(fmd_hdl_t * hdl,gmem_dimm_0_t * old,size_t oldsz)201d4ac42a1STrang Do gmem_dimm_v0tov1(fmd_hdl_t *hdl, gmem_dimm_0_t *old, size_t oldsz)
202d4ac42a1STrang Do {
203d4ac42a1STrang Do gmem_dimm_t *new;
204d4ac42a1STrang Do if (oldsz != sizeof (gmem_dimm_0_t)) {
205d4ac42a1STrang Do fmd_hdl_abort(hdl, "size of state doesn't match size of "
206d4ac42a1STrang Do "version 0 state (%u bytes).\n", sizeof (gmem_dimm_0_t));
207d4ac42a1STrang Do }
208d4ac42a1STrang Do
209d4ac42a1STrang Do new = fmd_hdl_zalloc(hdl, sizeof (gmem_dimm_t), FMD_SLEEP);
210d4ac42a1STrang Do new->dimm_header = old->dimm0_header;
211d4ac42a1STrang Do new->dimm_version = GMEM_DIMM_VERSION;
212d4ac42a1STrang Do new->dimm_asru = old->dimm0_asru;
213d4ac42a1STrang Do new->dimm_nretired = old->dimm0_nretired;
214d4ac42a1STrang Do new->dimm_phys_addr_hi = 0;
215d4ac42a1STrang Do new->dimm_phys_addr_low = ULLONG_MAX;
216d4ac42a1STrang Do
217d4ac42a1STrang Do fmd_hdl_free(hdl, old, oldsz);
218d4ac42a1STrang Do return (new);
219d4ac42a1STrang Do }
220d4ac42a1STrang Do
221d4ac42a1STrang Do static gmem_dimm_t *
gmem_dimm_wrapv1(fmd_hdl_t * hdl,gmem_dimm_pers_t * pers,size_t psz)222d4ac42a1STrang Do gmem_dimm_wrapv1(fmd_hdl_t *hdl, gmem_dimm_pers_t *pers, size_t psz)
2231529f529SScott Davenport {
2241529f529SScott Davenport gmem_dimm_t *dimm;
2251529f529SScott Davenport
2261529f529SScott Davenport if (psz != sizeof (gmem_dimm_pers_t)) {
2271529f529SScott Davenport fmd_hdl_abort(hdl, "size of state doesn't match size of "
2281529f529SScott Davenport "version 0 state (%u bytes).\n", sizeof (gmem_dimm_pers_t));
2291529f529SScott Davenport }
2301529f529SScott Davenport
2311529f529SScott Davenport dimm = fmd_hdl_zalloc(hdl, sizeof (gmem_dimm_t), FMD_SLEEP);
2321529f529SScott Davenport bcopy(pers, dimm, sizeof (gmem_dimm_pers_t));
2331529f529SScott Davenport fmd_hdl_free(hdl, pers, psz);
2341529f529SScott Davenport return (dimm);
2351529f529SScott Davenport }
2361529f529SScott Davenport
2371529f529SScott Davenport void *
gmem_dimm_restore(fmd_hdl_t * hdl,fmd_case_t * cp,gmem_case_ptr_t * ptr)2381529f529SScott Davenport gmem_dimm_restore(fmd_hdl_t *hdl, fmd_case_t *cp, gmem_case_ptr_t *ptr)
2391529f529SScott Davenport {
2401529f529SScott Davenport gmem_dimm_t *dimm;
2411529f529SScott Davenport
2421529f529SScott Davenport for (dimm = gmem_list_next(&gmem.gm_dimms); dimm != NULL;
2431529f529SScott Davenport dimm = gmem_list_next(dimm)) {
2441529f529SScott Davenport if (strcmp(dimm->dimm_bufname, ptr->ptr_name) == 0)
2451529f529SScott Davenport break;
2461529f529SScott Davenport }
2471529f529SScott Davenport
2481529f529SScott Davenport if (dimm == NULL) {
249d4ac42a1STrang Do int migrated = 0;
2501529f529SScott Davenport size_t dimmsz;
2511529f529SScott Davenport
2521529f529SScott Davenport fmd_hdl_debug(hdl, "restoring dimm from %s\n", ptr->ptr_name);
2531529f529SScott Davenport
2541529f529SScott Davenport if ((dimmsz = fmd_buf_size(hdl, NULL, ptr->ptr_name)) == 0) {
2551529f529SScott Davenport fmd_hdl_abort(hdl, "dimm referenced by case %s does "
2561529f529SScott Davenport "not exist in saved state\n",
2571529f529SScott Davenport fmd_case_uuid(hdl, cp));
2581529f529SScott Davenport } else if (dimmsz > GMEM_DIMM_MAXSIZE ||
2591529f529SScott Davenport dimmsz < GMEM_DIMM_MINSIZE) {
2601529f529SScott Davenport fmd_hdl_abort(hdl, "dimm buffer referenced by case %s "
2611529f529SScott Davenport "is out of bounds (is %u bytes, max %u, min %u)\n",
2621529f529SScott Davenport fmd_case_uuid(hdl, cp), dimmsz,
2631529f529SScott Davenport GMEM_DIMM_MAXSIZE, GMEM_DIMM_MINSIZE);
2641529f529SScott Davenport }
2651529f529SScott Davenport
2661529f529SScott Davenport if ((dimm = gmem_buf_read(hdl, NULL, ptr->ptr_name,
2671529f529SScott Davenport dimmsz)) == NULL) {
2681529f529SScott Davenport fmd_hdl_abort(hdl, "failed to read dimm buf %s",
2691529f529SScott Davenport ptr->ptr_name);
2701529f529SScott Davenport }
2711529f529SScott Davenport
2721529f529SScott Davenport fmd_hdl_debug(hdl, "found %d in version field\n",
2731529f529SScott Davenport dimm->dimm_version);
2741529f529SScott Davenport
275d4ac42a1STrang Do if (GMEM_DIMM_VERSIONED(dimm)) {
276d4ac42a1STrang Do
277d4ac42a1STrang Do switch (dimm->dimm_version) {
278d4ac42a1STrang Do case GMEM_DIMM_VERSION_1:
279d4ac42a1STrang Do dimm = gmem_dimm_wrapv1(hdl,
280d4ac42a1STrang Do (gmem_dimm_pers_t *)dimm, dimmsz);
281d4ac42a1STrang Do break;
282d4ac42a1STrang Do default:
283d4ac42a1STrang Do fmd_hdl_abort(hdl, "unknown version (found %d) "
284d4ac42a1STrang Do "for dimm state referenced by case %s.\n",
285d4ac42a1STrang Do dimm->dimm_version, fmd_case_uuid(hdl, cp));
286d4ac42a1STrang Do break;
287d4ac42a1STrang Do }
288d4ac42a1STrang Do } else {
289d4ac42a1STrang Do dimm = gmem_dimm_v0tov1(hdl, (gmem_dimm_0_t *)dimm,
2901529f529SScott Davenport dimmsz);
291d4ac42a1STrang Do migrated = 1;
292d4ac42a1STrang Do }
293d4ac42a1STrang Do
294d4ac42a1STrang Do if (migrated) {
295d4ac42a1STrang Do GMEM_STAT_BUMP(dimm_migrat);
296d4ac42a1STrang Do gmem_dimm_dirty(hdl, dimm);
2971529f529SScott Davenport }
2981529f529SScott Davenport
2991529f529SScott Davenport gmem_fmri_restore(hdl, &dimm->dimm_asru);
3001529f529SScott Davenport
3011529f529SScott Davenport if ((errno = nvlist_lookup_string(dimm->dimm_asru_nvl,
3021529f529SScott Davenport FM_FMRI_HC_SERIAL_ID, (char **)&dimm->dimm_serial)) != 0)
3031529f529SScott Davenport fmd_hdl_abort(hdl,
3041529f529SScott Davenport "failed to retrieve serial from asru");
3051529f529SScott Davenport
3061529f529SScott Davenport
3071529f529SScott Davenport gmem_mem_retirestat_create(hdl, &dimm->dimm_retstat,
3081529f529SScott Davenport dimm->dimm_serial, dimm->dimm_nretired,
3091529f529SScott Davenport GMEM_DIMM_STAT_PREFIX);
3101529f529SScott Davenport
3111529f529SScott Davenport gmem_list_append(&gmem.gm_dimms, dimm);
3121529f529SScott Davenport }
3131529f529SScott Davenport
3141529f529SScott Davenport switch (ptr->ptr_subtype) {
3151529f529SScott Davenport case GMEM_PTR_DIMM_CASE:
3161529f529SScott Davenport gmem_mem_case_restore(hdl, &dimm->dimm_case, cp, "dimm",
3171529f529SScott Davenport dimm->dimm_serial);
3181529f529SScott Davenport break;
3191529f529SScott Davenport default:
3201529f529SScott Davenport fmd_hdl_abort(hdl, "invalid %s subtype %d\n",
3211529f529SScott Davenport ptr->ptr_name, ptr->ptr_subtype);
3221529f529SScott Davenport }
3231529f529SScott Davenport
3241529f529SScott Davenport return (dimm);
3251529f529SScott Davenport }
3261529f529SScott Davenport
3271529f529SScott Davenport void
gmem_dimm_validate(fmd_hdl_t * hdl)3281529f529SScott Davenport gmem_dimm_validate(fmd_hdl_t *hdl)
3291529f529SScott Davenport {
3301529f529SScott Davenport gmem_dimm_t *dimm, *next;
3311529f529SScott Davenport
3321529f529SScott Davenport for (dimm = gmem_list_next(&gmem.gm_dimms); dimm != NULL; dimm = next) {
3331529f529SScott Davenport next = gmem_list_next(dimm);
3341529f529SScott Davenport
3351529f529SScott Davenport if (!gmem_dimm_present(hdl, dimm->dimm_asru_nvl))
3361529f529SScott Davenport gmem_dimm_destroy(hdl, dimm);
3371529f529SScott Davenport }
3381529f529SScott Davenport }
3391529f529SScott Davenport
3401529f529SScott Davenport void
gmem_dimm_dirty(fmd_hdl_t * hdl,gmem_dimm_t * dimm)3411529f529SScott Davenport gmem_dimm_dirty(fmd_hdl_t *hdl, gmem_dimm_t *dimm)
3421529f529SScott Davenport {
3431529f529SScott Davenport if (fmd_buf_size(hdl, NULL, dimm->dimm_bufname) !=
3441529f529SScott Davenport sizeof (gmem_dimm_pers_t))
3451529f529SScott Davenport fmd_buf_destroy(hdl, NULL, dimm->dimm_bufname);
3461529f529SScott Davenport
3471529f529SScott Davenport /* No need to rewrite the FMRIs in the dimm - they don't change */
3481529f529SScott Davenport fmd_buf_write(hdl, NULL, dimm->dimm_bufname, &dimm->dimm_pers,
3491529f529SScott Davenport sizeof (gmem_dimm_pers_t));
3501529f529SScott Davenport }
3511529f529SScott Davenport
3521529f529SScott Davenport void
gmem_dimm_gc(fmd_hdl_t * hdl)3531529f529SScott Davenport gmem_dimm_gc(fmd_hdl_t *hdl)
3541529f529SScott Davenport {
3551529f529SScott Davenport gmem_dimm_validate(hdl);
3561529f529SScott Davenport }
3571529f529SScott Davenport
3581529f529SScott Davenport void
gmem_dimm_fini(fmd_hdl_t * hdl)3591529f529SScott Davenport gmem_dimm_fini(fmd_hdl_t *hdl)
3601529f529SScott Davenport {
3611529f529SScott Davenport gmem_dimm_t *dimm;
3621529f529SScott Davenport
3631529f529SScott Davenport while ((dimm = gmem_list_next(&gmem.gm_dimms)) != NULL)
3641529f529SScott Davenport gmem_dimm_free(hdl, dimm, FMD_B_FALSE);
3651529f529SScott Davenport }
3661529f529SScott Davenport
3671529f529SScott Davenport
3681529f529SScott Davenport /*ARGSUSED*/
3691529f529SScott Davenport static int
find_dimm_hc_fmri(topo_hdl_t * thp,tnode_t * node,void * arg)3701529f529SScott Davenport find_dimm_hc_fmri(topo_hdl_t *thp, tnode_t *node, void *arg)
3711529f529SScott Davenport {
3721529f529SScott Davenport
3731529f529SScott Davenport char *topo_sn;
3741529f529SScott Davenport dimmid_t *dimmid = (dimmid_t *)arg;
3751529f529SScott Davenport nvlist_t *fru = NULL;
3761529f529SScott Davenport nvlist_t *rsc = NULL;
3771529f529SScott Davenport nvlist_t *asru = NULL;
3781529f529SScott Davenport int err;
3791529f529SScott Davenport
3801529f529SScott Davenport if (topo_node_fru(node, &fru, NULL, &err) < 0)
3811529f529SScott Davenport return (TOPO_WALK_NEXT);
3821529f529SScott Davenport
3831529f529SScott Davenport err = nvlist_lookup_string(fru, FM_FMRI_HC_SERIAL_ID, &topo_sn);
3841529f529SScott Davenport if (err != 0) {
3851529f529SScott Davenport nvlist_free(fru);
3861529f529SScott Davenport return (TOPO_WALK_NEXT);
3871529f529SScott Davenport }
3881529f529SScott Davenport
3891529f529SScott Davenport if (strcmp(dimmid->serial, topo_sn) != 0) {
3901529f529SScott Davenport nvlist_free(fru);
3911529f529SScott Davenport return (TOPO_WALK_NEXT);
3921529f529SScott Davenport }
3931529f529SScott Davenport
3941529f529SScott Davenport switch (dimmid->type) {
3951529f529SScott Davenport case FINDFRU:
3961529f529SScott Davenport (void) nvlist_dup(fru, &dimm_nvl, NV_UNIQUE_NAME);
3971529f529SScott Davenport break;
3981529f529SScott Davenport case FINDRSC:
3991529f529SScott Davenport (void) topo_node_resource(node, &rsc, &err);
4001529f529SScott Davenport if (rsc != NULL) {
4011529f529SScott Davenport (void) nvlist_dup(rsc, &dimm_nvl,
4021529f529SScott Davenport NV_UNIQUE_NAME);
4031529f529SScott Davenport nvlist_free(rsc);
4041529f529SScott Davenport }
4051529f529SScott Davenport break;
4061529f529SScott Davenport case FINDASRU:
4071529f529SScott Davenport (void) topo_node_asru(node, &asru, NULL, &err);
4081529f529SScott Davenport if (asru != NULL) {
4091529f529SScott Davenport (void) nvlist_dup(asru, &dimm_nvl,
4101529f529SScott Davenport NV_UNIQUE_NAME);
4111529f529SScott Davenport nvlist_free(asru);
4121529f529SScott Davenport }
4131529f529SScott Davenport break;
4141529f529SScott Davenport default:
4151529f529SScott Davenport break;
4161529f529SScott Davenport }
4171529f529SScott Davenport nvlist_free(fru);
4181529f529SScott Davenport return (TOPO_WALK_TERMINATE);
4191529f529SScott Davenport }
4201529f529SScott Davenport
4211529f529SScott Davenport nvlist_t *
gmem_find_dimm_by_sn(fmd_hdl_t * hdl,dimmid_t * dimmid)4221529f529SScott Davenport gmem_find_dimm_by_sn(fmd_hdl_t *hdl, dimmid_t *dimmid) {
4231529f529SScott Davenport topo_hdl_t *thp;
4241529f529SScott Davenport topo_walk_t *twp;
4251529f529SScott Davenport int err;
4261529f529SScott Davenport dimm_nvl = NULL;
4271529f529SScott Davenport
4281529f529SScott Davenport if ((thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) == NULL)
4291529f529SScott Davenport return (NULL);
4301529f529SScott Davenport
4311529f529SScott Davenport if ((twp = topo_walk_init(thp, FM_FMRI_SCHEME_HC,
4321529f529SScott Davenport find_dimm_hc_fmri, dimmid, &err)) == NULL) {
4331529f529SScott Davenport fmd_hdl_topo_rele(hdl, thp);
4341529f529SScott Davenport return (NULL);
4351529f529SScott Davenport }
4361529f529SScott Davenport
4371529f529SScott Davenport (void) topo_walk_step(twp, TOPO_WALK_CHILD);
4381529f529SScott Davenport topo_walk_fini(twp);
4391529f529SScott Davenport fmd_hdl_topo_rele(hdl, thp);
4401529f529SScott Davenport return (dimm_nvl);
4411529f529SScott Davenport }
4421529f529SScott Davenport
4431529f529SScott Davenport nvlist_t *
gmem_find_dimm_fru(fmd_hdl_t * hdl,char * sn)4441529f529SScott Davenport gmem_find_dimm_fru(fmd_hdl_t *hdl, char *sn)
4451529f529SScott Davenport {
4461529f529SScott Davenport dimmid_t fru;
4471529f529SScott Davenport (void) strcpy(fru.serial, sn);
4481529f529SScott Davenport fru.type = FINDFRU;
4491529f529SScott Davenport return (gmem_find_dimm_by_sn(hdl, &fru));
4501529f529SScott Davenport }
4511529f529SScott Davenport
4521529f529SScott Davenport nvlist_t *
gmem_find_dimm_rsc(fmd_hdl_t * hdl,char * sn)4531529f529SScott Davenport gmem_find_dimm_rsc(fmd_hdl_t *hdl, char *sn)
4541529f529SScott Davenport {
4551529f529SScott Davenport dimmid_t rsc;
4561529f529SScott Davenport (void) strcpy(rsc.serial, sn);
4571529f529SScott Davenport rsc.type = FINDRSC;
4581529f529SScott Davenport return (gmem_find_dimm_by_sn(hdl, &rsc));
4591529f529SScott Davenport }
4601529f529SScott Davenport
4611529f529SScott Davenport nvlist_t *
gmem_find_dimm_asru(fmd_hdl_t * hdl,char * sn)4621529f529SScott Davenport gmem_find_dimm_asru(fmd_hdl_t *hdl, char *sn)
4631529f529SScott Davenport {
4641529f529SScott Davenport dimmid_t asru;
4651529f529SScott Davenport (void) strcpy(asru.serial, sn);
4661529f529SScott Davenport asru.type = FINDASRU;
4671529f529SScott Davenport return (gmem_find_dimm_by_sn(hdl, &asru));
4681529f529SScott Davenport }
4691529f529SScott Davenport
4701529f529SScott Davenport int
gmem_dimm_present(fmd_hdl_t * hdl,nvlist_t * asru)4711529f529SScott Davenport gmem_dimm_present(fmd_hdl_t *hdl, nvlist_t *asru)
4721529f529SScott Davenport {
4731529f529SScott Davenport char *sn;
4741529f529SScott Davenport nvlist_t *dimm = NULL;
4751529f529SScott Davenport
4761529f529SScott Davenport if (nvlist_lookup_string(asru, FM_FMRI_HC_SERIAL_ID, &sn) != 0) {
4771529f529SScott Davenport fmd_hdl_debug(hdl, "Unable to get dimm serial\n");
4781529f529SScott Davenport return (0);
4791529f529SScott Davenport }
4801529f529SScott Davenport dimm = gmem_find_dimm_fru(hdl, sn);
4811529f529SScott Davenport if (dimm == NULL) {
4821529f529SScott Davenport fmd_hdl_debug(hdl, "Dimm sn=%s is not present\n", sn);
4831529f529SScott Davenport return (0);
4841529f529SScott Davenport }
485*aab83bb8SJosef 'Jeff' Sipek nvlist_free(dimm);
4861529f529SScott Davenport return (1);
4871529f529SScott Davenport }
488d4ac42a1STrang Do
489d4ac42a1STrang Do static int
gmem_find_dimm_chip(nvlist_t * nvl,uint32_t * chip)490d4ac42a1STrang Do gmem_find_dimm_chip(nvlist_t *nvl, uint32_t *chip)
491d4ac42a1STrang Do {
492d4ac42a1STrang Do
493d4ac42a1STrang Do char *name, *id, *end;
494d4ac42a1STrang Do nvlist_t **hcl;
495d4ac42a1STrang Do uint_t n;
496d4ac42a1STrang Do int i;
497d4ac42a1STrang Do int rc = 0;
4988f665889STrang Do *chip = ULONG_MAX;
499d4ac42a1STrang Do
500d4ac42a1STrang Do if (nvlist_lookup_nvlist_array(nvl, FM_FMRI_HC_LIST, &hcl, &n) < 0)
501d4ac42a1STrang Do return (0);
502d4ac42a1STrang Do for (i = 0; i < n; i++) {
503d4ac42a1STrang Do (void) nvlist_lookup_string(hcl[i], FM_FMRI_HC_NAME, &name);
504d4ac42a1STrang Do (void) nvlist_lookup_string(hcl[i], FM_FMRI_HC_ID, &id);
505d4ac42a1STrang Do
506d4ac42a1STrang Do if (strcmp(name, "chip") == 0) {
507d4ac42a1STrang Do *chip = (uint32_t)strtoul(id, &end, 10);
508d4ac42a1STrang Do rc = 1;
509d4ac42a1STrang Do break;
510d4ac42a1STrang Do }
511d4ac42a1STrang Do }
512d4ac42a1STrang Do return (rc);
513d4ac42a1STrang Do }
514d4ac42a1STrang Do
5158f665889STrang Do /*ARGSUSED*/
516d4ac42a1STrang Do int
gmem_same_datapath_dimms(fmd_hdl_t * hdl,gmem_dimm_t * d1,gmem_dimm_t * d2)517d4ac42a1STrang Do gmem_same_datapath_dimms(fmd_hdl_t *hdl, gmem_dimm_t *d1, gmem_dimm_t *d2)
518d4ac42a1STrang Do {
519d4ac42a1STrang Do
5208f665889STrang Do if (d1->dimm_chipid == ULONG_MAX || d2->dimm_chipid == ULONG_MAX)
521d4ac42a1STrang Do return (0);
522d4ac42a1STrang Do
5238f665889STrang Do if (d1->dimm_chipid == d2->dimm_chipid)
5248f665889STrang Do return (1);
525d4ac42a1STrang Do
526d4ac42a1STrang Do return (0);
527d4ac42a1STrang Do }
528d4ac42a1STrang Do
529d4ac42a1STrang Do int
gmem_check_symbol_error(fmd_hdl_t * hdl,gmem_dimm_t * d,uint16_t upos)530d4ac42a1STrang Do gmem_check_symbol_error(fmd_hdl_t *hdl, gmem_dimm_t *d, uint16_t upos)
531d4ac42a1STrang Do {
532d4ac42a1STrang Do gmem_dimm_t *dimm = NULL, *next = NULL;
533d4ac42a1STrang Do
534d4ac42a1STrang Do for (dimm = gmem_list_next(&gmem.gm_dimms); dimm != NULL;
535d4ac42a1STrang Do dimm = next) {
536d4ac42a1STrang Do next = gmem_list_next(dimm);
537d4ac42a1STrang Do if (gmem_same_datapath_dimms(hdl, dimm, d) &&
538d4ac42a1STrang Do dimm->dimm_syl_error == upos)
539d4ac42a1STrang Do return (1);
540d4ac42a1STrang Do }
541d4ac42a1STrang Do return (0);
542d4ac42a1STrang Do }
543d4ac42a1STrang Do
544d4ac42a1STrang Do void
gmem_save_symbol_error(fmd_hdl_t * hdl,gmem_dimm_t * d,uint16_t upos)545d4ac42a1STrang Do gmem_save_symbol_error(fmd_hdl_t *hdl, gmem_dimm_t *d, uint16_t upos)
546d4ac42a1STrang Do {
547d4ac42a1STrang Do gmem_dimm_t *dimm = NULL, *next = NULL;
548d4ac42a1STrang Do
549d4ac42a1STrang Do for (dimm = gmem_list_next(&gmem.gm_dimms); dimm != NULL;
550d4ac42a1STrang Do dimm = next) {
551d4ac42a1STrang Do next = gmem_list_next(dimm);
552d4ac42a1STrang Do if (gmem_same_datapath_dimms(hdl, dimm, d))
553d4ac42a1STrang Do dimm->dimm_syl_error = upos;
554d4ac42a1STrang Do }
555d4ac42a1STrang Do }
556