Print this page
patch tsoome-feedback
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/fm/modules/sun4v/generic-mem/gmem_dimm.c
+++ new/usr/src/cmd/fm/modules/sun4v/generic-mem/gmem_dimm.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
23 23 */
24 24
25 25
26 26 /*
27 27 * Support routines for DIMMs.
28 28 */
29 29
30 30 #include <gmem_mem.h>
31 31 #include <gmem_dimm.h>
32 32 #include <gmem.h>
33 33 #include <errno.h>
34 34 #include <limits.h>
35 35 #include <string.h>
36 36 #include <strings.h>
37 37 #include <fcntl.h>
38 38 #include <unistd.h>
39 39 #include <fm/fmd_api.h>
40 40 #include <fm/libtopo.h>
41 41 #include <sys/fm/protocol.h>
42 42 #include <sys/mem.h>
43 43 #include <sys/nvpair.h>
44 44
45 45 nvlist_t *dimm_nvl;
46 46
47 47 typedef struct dimmid {
48 48 char serial[100];
49 49 int type;
50 50 } dimmid_t;
51 51
52 52 static int gmem_find_dimm_chip(nvlist_t *, uint32_t *);
53 53
54 54 nvlist_t *
55 55 gmem_dimm_fru(gmem_dimm_t *dimm)
56 56 {
57 57 return (dimm->dimm_asru_nvl);
58 58 }
59 59
60 60 static void
61 61 gmem_dimm_free(fmd_hdl_t *hdl, gmem_dimm_t *dimm, int destroy)
62 62 {
63 63 gmem_case_t *cc = &dimm->dimm_case;
64 64 int i;
65 65 gmem_mq_t *q;
66 66 tstamp_t *tsp, *next;
67 67
68 68 if (cc->cc_cp != NULL) {
69 69 gmem_case_fini(hdl, cc->cc_cp, destroy);
70 70 if (cc->cc_serdnm != NULL) {
71 71 if (fmd_serd_exists(hdl, cc->cc_serdnm) &&
72 72 destroy)
73 73 fmd_serd_destroy(hdl, cc->cc_serdnm);
74 74 fmd_hdl_strfree(hdl, cc->cc_serdnm);
75 75 }
76 76 }
77 77
78 78 gmem_fmri_fini(hdl, &dimm->dimm_asru, destroy);
79 79
80 80 for (i = 0; i < GMEM_MAX_CKWDS; i++) {
81 81 while ((q = gmem_list_next(&dimm->mq_root[i])) != NULL) {
82 82 if (q->mq_serdnm != NULL) {
83 83 if (fmd_serd_exists(hdl, q->mq_serdnm))
84 84 fmd_serd_destroy(hdl, q->mq_serdnm);
85 85 fmd_hdl_strfree(hdl, q->mq_serdnm);
86 86 q->mq_serdnm = NULL;
87 87 }
88 88
89 89 for (tsp = gmem_list_next(&q->mq_dupce_tstamp);
90 90 tsp != NULL; tsp = next) {
91 91 next = gmem_list_next(tsp);
92 92 gmem_list_delete(&q->mq_dupce_tstamp,
93 93 &tsp->ts_l);
94 94 fmd_hdl_free(hdl, tsp, sizeof (tstamp_t));
95 95 }
96 96
97 97 gmem_list_delete(&dimm->mq_root[i], q);
98 98 fmd_hdl_free(hdl, q, sizeof (gmem_mq_t));
99 99 }
100 100 }
101 101
102 102 if (destroy)
103 103 fmd_buf_destroy(hdl, NULL, dimm->dimm_bufname);
104 104
105 105 gmem_list_delete(&gmem.gm_dimms, dimm);
106 106 fmd_hdl_free(hdl, dimm, sizeof (gmem_dimm_t));
107 107 }
108 108
109 109 void
110 110 gmem_dimm_destroy(fmd_hdl_t *hdl, gmem_dimm_t *dimm)
111 111 {
112 112 fmd_stat_destroy(hdl, 1, &(dimm->dimm_retstat));
113 113 gmem_dimm_free(hdl, dimm, FMD_B_TRUE);
114 114 }
115 115
116 116 static gmem_dimm_t *
117 117 dimm_lookup_by_serial(const char *serial)
118 118 {
119 119 gmem_dimm_t *dimm;
120 120
121 121 for (dimm = gmem_list_next(&gmem.gm_dimms); dimm != NULL;
122 122 dimm = gmem_list_next(dimm)) {
123 123 if (strcmp(dimm->dimm_serial, serial) == 0)
124 124 return (dimm);
125 125 }
126 126
127 127 return (NULL);
128 128 }
129 129
130 130 gmem_dimm_t *
131 131 gmem_dimm_create(fmd_hdl_t *hdl, nvlist_t *asru, nvlist_t *det)
132 132 {
133 133 gmem_dimm_t *dimm;
134 134 nvlist_t *fmri;
135 135 char *serial;
136 136 uint32_t chip_id;
137 137
138 138 if (nvlist_lookup_string(asru, FM_FMRI_HC_SERIAL_ID, &serial) != 0) {
139 139 fmd_hdl_debug(hdl, "Unable to get dimm serial\n");
140 140 return (NULL);
141 141 }
142 142
143 143 if (nvlist_dup(asru, &fmri, 0) != 0) {
144 144 fmd_hdl_debug(hdl, "dimm create nvlist dup failed");
145 145 return (NULL);
146 146 }
147 147
148 148 (void) gmem_find_dimm_chip(det, &chip_id);
149 149
150 150 fmd_hdl_debug(hdl, "dimm_create: creating new DIMM serial=%s\n",
151 151 serial);
152 152 GMEM_STAT_BUMP(dimm_creat);
153 153
154 154 dimm = fmd_hdl_zalloc(hdl, sizeof (gmem_dimm_t), FMD_SLEEP);
155 155 dimm->dimm_nodetype = GMEM_NT_DIMM;
156 156 dimm->dimm_version = GMEM_DIMM_VERSION;
157 157 dimm->dimm_phys_addr_low = ULLONG_MAX;
158 158 dimm->dimm_phys_addr_hi = 0;
159 159 dimm->dimm_syl_error = USHRT_MAX;
160 160 dimm->dimm_chipid = chip_id;
161 161
162 162 gmem_bufname(dimm->dimm_bufname, sizeof (dimm->dimm_bufname), "dimm_%s",
163 163 serial);
164 164 gmem_fmri_init(hdl, &dimm->dimm_asru, fmri, "dimm_asru_%s", serial);
165 165
166 166 nvlist_free(fmri);
167 167
168 168 (void) nvlist_lookup_string(dimm->dimm_asru_nvl, FM_FMRI_HC_SERIAL_ID,
169 169 (char **)&dimm->dimm_serial);
170 170
171 171 gmem_mem_retirestat_create(hdl, &dimm->dimm_retstat, dimm->dimm_serial,
172 172 0, GMEM_DIMM_STAT_PREFIX);
173 173
174 174 gmem_list_append(&gmem.gm_dimms, dimm);
175 175 gmem_dimm_dirty(hdl, dimm);
176 176
177 177 return (dimm);
178 178 }
179 179
180 180 gmem_dimm_t *
181 181 gmem_dimm_lookup(fmd_hdl_t *hdl, nvlist_t *asru)
182 182 {
183 183 gmem_dimm_t *dimm;
184 184 char *serial;
185 185 int err;
186 186
187 187 err = nvlist_lookup_string(asru, FM_FMRI_HC_SERIAL_ID, &serial);
188 188
189 189 if (err != 0) {
190 190 fmd_hdl_debug(hdl, "Can't get dimm serial number\n");
191 191 GMEM_STAT_BUMP(bad_mem_resource);
192 192 return (NULL);
193 193 }
194 194
195 195 dimm = dimm_lookup_by_serial(serial);
196 196 return (dimm);
197 197 }
198 198
199 199
200 200 static gmem_dimm_t *
201 201 gmem_dimm_v0tov1(fmd_hdl_t *hdl, gmem_dimm_0_t *old, size_t oldsz)
202 202 {
203 203 gmem_dimm_t *new;
204 204 if (oldsz != sizeof (gmem_dimm_0_t)) {
205 205 fmd_hdl_abort(hdl, "size of state doesn't match size of "
206 206 "version 0 state (%u bytes).\n", sizeof (gmem_dimm_0_t));
207 207 }
208 208
209 209 new = fmd_hdl_zalloc(hdl, sizeof (gmem_dimm_t), FMD_SLEEP);
210 210 new->dimm_header = old->dimm0_header;
211 211 new->dimm_version = GMEM_DIMM_VERSION;
212 212 new->dimm_asru = old->dimm0_asru;
213 213 new->dimm_nretired = old->dimm0_nretired;
214 214 new->dimm_phys_addr_hi = 0;
215 215 new->dimm_phys_addr_low = ULLONG_MAX;
216 216
217 217 fmd_hdl_free(hdl, old, oldsz);
218 218 return (new);
219 219 }
220 220
221 221 static gmem_dimm_t *
222 222 gmem_dimm_wrapv1(fmd_hdl_t *hdl, gmem_dimm_pers_t *pers, size_t psz)
223 223 {
224 224 gmem_dimm_t *dimm;
225 225
226 226 if (psz != sizeof (gmem_dimm_pers_t)) {
227 227 fmd_hdl_abort(hdl, "size of state doesn't match size of "
228 228 "version 0 state (%u bytes).\n", sizeof (gmem_dimm_pers_t));
229 229 }
230 230
231 231 dimm = fmd_hdl_zalloc(hdl, sizeof (gmem_dimm_t), FMD_SLEEP);
232 232 bcopy(pers, dimm, sizeof (gmem_dimm_pers_t));
233 233 fmd_hdl_free(hdl, pers, psz);
234 234 return (dimm);
235 235 }
236 236
237 237 void *
238 238 gmem_dimm_restore(fmd_hdl_t *hdl, fmd_case_t *cp, gmem_case_ptr_t *ptr)
239 239 {
240 240 gmem_dimm_t *dimm;
241 241
242 242 for (dimm = gmem_list_next(&gmem.gm_dimms); dimm != NULL;
243 243 dimm = gmem_list_next(dimm)) {
244 244 if (strcmp(dimm->dimm_bufname, ptr->ptr_name) == 0)
245 245 break;
246 246 }
247 247
248 248 if (dimm == NULL) {
249 249 int migrated = 0;
250 250 size_t dimmsz;
251 251
252 252 fmd_hdl_debug(hdl, "restoring dimm from %s\n", ptr->ptr_name);
253 253
254 254 if ((dimmsz = fmd_buf_size(hdl, NULL, ptr->ptr_name)) == 0) {
255 255 fmd_hdl_abort(hdl, "dimm referenced by case %s does "
256 256 "not exist in saved state\n",
257 257 fmd_case_uuid(hdl, cp));
258 258 } else if (dimmsz > GMEM_DIMM_MAXSIZE ||
259 259 dimmsz < GMEM_DIMM_MINSIZE) {
260 260 fmd_hdl_abort(hdl, "dimm buffer referenced by case %s "
261 261 "is out of bounds (is %u bytes, max %u, min %u)\n",
262 262 fmd_case_uuid(hdl, cp), dimmsz,
263 263 GMEM_DIMM_MAXSIZE, GMEM_DIMM_MINSIZE);
264 264 }
265 265
266 266 if ((dimm = gmem_buf_read(hdl, NULL, ptr->ptr_name,
267 267 dimmsz)) == NULL) {
268 268 fmd_hdl_abort(hdl, "failed to read dimm buf %s",
269 269 ptr->ptr_name);
270 270 }
271 271
272 272 fmd_hdl_debug(hdl, "found %d in version field\n",
273 273 dimm->dimm_version);
274 274
275 275 if (GMEM_DIMM_VERSIONED(dimm)) {
276 276
277 277 switch (dimm->dimm_version) {
278 278 case GMEM_DIMM_VERSION_1:
279 279 dimm = gmem_dimm_wrapv1(hdl,
280 280 (gmem_dimm_pers_t *)dimm, dimmsz);
281 281 break;
282 282 default:
283 283 fmd_hdl_abort(hdl, "unknown version (found %d) "
284 284 "for dimm state referenced by case %s.\n",
285 285 dimm->dimm_version, fmd_case_uuid(hdl, cp));
286 286 break;
287 287 }
288 288 } else {
289 289 dimm = gmem_dimm_v0tov1(hdl, (gmem_dimm_0_t *)dimm,
290 290 dimmsz);
291 291 migrated = 1;
292 292 }
293 293
294 294 if (migrated) {
295 295 GMEM_STAT_BUMP(dimm_migrat);
296 296 gmem_dimm_dirty(hdl, dimm);
297 297 }
298 298
299 299 gmem_fmri_restore(hdl, &dimm->dimm_asru);
300 300
301 301 if ((errno = nvlist_lookup_string(dimm->dimm_asru_nvl,
302 302 FM_FMRI_HC_SERIAL_ID, (char **)&dimm->dimm_serial)) != 0)
303 303 fmd_hdl_abort(hdl,
304 304 "failed to retrieve serial from asru");
305 305
306 306
307 307 gmem_mem_retirestat_create(hdl, &dimm->dimm_retstat,
308 308 dimm->dimm_serial, dimm->dimm_nretired,
309 309 GMEM_DIMM_STAT_PREFIX);
310 310
311 311 gmem_list_append(&gmem.gm_dimms, dimm);
312 312 }
313 313
314 314 switch (ptr->ptr_subtype) {
315 315 case GMEM_PTR_DIMM_CASE:
316 316 gmem_mem_case_restore(hdl, &dimm->dimm_case, cp, "dimm",
317 317 dimm->dimm_serial);
318 318 break;
319 319 default:
320 320 fmd_hdl_abort(hdl, "invalid %s subtype %d\n",
321 321 ptr->ptr_name, ptr->ptr_subtype);
322 322 }
323 323
324 324 return (dimm);
325 325 }
326 326
327 327 void
328 328 gmem_dimm_validate(fmd_hdl_t *hdl)
329 329 {
330 330 gmem_dimm_t *dimm, *next;
331 331
332 332 for (dimm = gmem_list_next(&gmem.gm_dimms); dimm != NULL; dimm = next) {
333 333 next = gmem_list_next(dimm);
334 334
335 335 if (!gmem_dimm_present(hdl, dimm->dimm_asru_nvl))
336 336 gmem_dimm_destroy(hdl, dimm);
337 337 }
338 338 }
339 339
340 340 void
341 341 gmem_dimm_dirty(fmd_hdl_t *hdl, gmem_dimm_t *dimm)
342 342 {
343 343 if (fmd_buf_size(hdl, NULL, dimm->dimm_bufname) !=
344 344 sizeof (gmem_dimm_pers_t))
345 345 fmd_buf_destroy(hdl, NULL, dimm->dimm_bufname);
346 346
347 347 /* No need to rewrite the FMRIs in the dimm - they don't change */
348 348 fmd_buf_write(hdl, NULL, dimm->dimm_bufname, &dimm->dimm_pers,
349 349 sizeof (gmem_dimm_pers_t));
350 350 }
351 351
352 352 void
353 353 gmem_dimm_gc(fmd_hdl_t *hdl)
354 354 {
355 355 gmem_dimm_validate(hdl);
356 356 }
357 357
358 358 void
359 359 gmem_dimm_fini(fmd_hdl_t *hdl)
360 360 {
361 361 gmem_dimm_t *dimm;
362 362
363 363 while ((dimm = gmem_list_next(&gmem.gm_dimms)) != NULL)
364 364 gmem_dimm_free(hdl, dimm, FMD_B_FALSE);
365 365 }
366 366
367 367
368 368 /*ARGSUSED*/
369 369 static int
370 370 find_dimm_hc_fmri(topo_hdl_t *thp, tnode_t *node, void *arg)
371 371 {
372 372
373 373 char *topo_sn;
374 374 dimmid_t *dimmid = (dimmid_t *)arg;
375 375 nvlist_t *fru = NULL;
376 376 nvlist_t *rsc = NULL;
377 377 nvlist_t *asru = NULL;
378 378 int err;
379 379
380 380 if (topo_node_fru(node, &fru, NULL, &err) < 0)
381 381 return (TOPO_WALK_NEXT);
382 382
383 383 err = nvlist_lookup_string(fru, FM_FMRI_HC_SERIAL_ID, &topo_sn);
384 384 if (err != 0) {
385 385 nvlist_free(fru);
386 386 return (TOPO_WALK_NEXT);
387 387 }
388 388
389 389 if (strcmp(dimmid->serial, topo_sn) != 0) {
390 390 nvlist_free(fru);
391 391 return (TOPO_WALK_NEXT);
392 392 }
393 393
394 394 switch (dimmid->type) {
395 395 case FINDFRU:
396 396 (void) nvlist_dup(fru, &dimm_nvl, NV_UNIQUE_NAME);
397 397 break;
398 398 case FINDRSC:
399 399 (void) topo_node_resource(node, &rsc, &err);
400 400 if (rsc != NULL) {
401 401 (void) nvlist_dup(rsc, &dimm_nvl,
402 402 NV_UNIQUE_NAME);
403 403 nvlist_free(rsc);
404 404 }
405 405 break;
406 406 case FINDASRU:
407 407 (void) topo_node_asru(node, &asru, NULL, &err);
408 408 if (asru != NULL) {
409 409 (void) nvlist_dup(asru, &dimm_nvl,
410 410 NV_UNIQUE_NAME);
411 411 nvlist_free(asru);
412 412 }
413 413 break;
414 414 default:
415 415 break;
416 416 }
417 417 nvlist_free(fru);
418 418 return (TOPO_WALK_TERMINATE);
419 419 }
420 420
421 421 nvlist_t *
422 422 gmem_find_dimm_by_sn(fmd_hdl_t *hdl, dimmid_t *dimmid) {
423 423 topo_hdl_t *thp;
424 424 topo_walk_t *twp;
425 425 int err;
426 426 dimm_nvl = NULL;
427 427
428 428 if ((thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) == NULL)
429 429 return (NULL);
430 430
431 431 if ((twp = topo_walk_init(thp, FM_FMRI_SCHEME_HC,
432 432 find_dimm_hc_fmri, dimmid, &err)) == NULL) {
433 433 fmd_hdl_topo_rele(hdl, thp);
434 434 return (NULL);
435 435 }
436 436
437 437 (void) topo_walk_step(twp, TOPO_WALK_CHILD);
438 438 topo_walk_fini(twp);
439 439 fmd_hdl_topo_rele(hdl, thp);
440 440 return (dimm_nvl);
441 441 }
442 442
443 443 nvlist_t *
444 444 gmem_find_dimm_fru(fmd_hdl_t *hdl, char *sn)
445 445 {
446 446 dimmid_t fru;
447 447 (void) strcpy(fru.serial, sn);
448 448 fru.type = FINDFRU;
449 449 return (gmem_find_dimm_by_sn(hdl, &fru));
450 450 }
451 451
452 452 nvlist_t *
453 453 gmem_find_dimm_rsc(fmd_hdl_t *hdl, char *sn)
454 454 {
455 455 dimmid_t rsc;
456 456 (void) strcpy(rsc.serial, sn);
457 457 rsc.type = FINDRSC;
458 458 return (gmem_find_dimm_by_sn(hdl, &rsc));
459 459 }
460 460
461 461 nvlist_t *
462 462 gmem_find_dimm_asru(fmd_hdl_t *hdl, char *sn)
463 463 {
464 464 dimmid_t asru;
465 465 (void) strcpy(asru.serial, sn);
466 466 asru.type = FINDASRU;
467 467 return (gmem_find_dimm_by_sn(hdl, &asru));
468 468 }
469 469
470 470 int
471 471 gmem_dimm_present(fmd_hdl_t *hdl, nvlist_t *asru)
472 472 {
473 473 char *sn;
474 474 nvlist_t *dimm = NULL;
↓ open down ↓ |
474 lines elided |
↑ open up ↑ |
475 475
476 476 if (nvlist_lookup_string(asru, FM_FMRI_HC_SERIAL_ID, &sn) != 0) {
477 477 fmd_hdl_debug(hdl, "Unable to get dimm serial\n");
478 478 return (0);
479 479 }
480 480 dimm = gmem_find_dimm_fru(hdl, sn);
481 481 if (dimm == NULL) {
482 482 fmd_hdl_debug(hdl, "Dimm sn=%s is not present\n", sn);
483 483 return (0);
484 484 }
485 - if (dimm != NULL)
486 - nvlist_free(dimm);
485 + nvlist_free(dimm);
487 486 return (1);
488 487 }
489 488
490 489 static int
491 490 gmem_find_dimm_chip(nvlist_t *nvl, uint32_t *chip)
492 491 {
493 492
494 493 char *name, *id, *end;
495 494 nvlist_t **hcl;
496 495 uint_t n;
497 496 int i;
498 497 int rc = 0;
499 498 *chip = ULONG_MAX;
500 499
501 500 if (nvlist_lookup_nvlist_array(nvl, FM_FMRI_HC_LIST, &hcl, &n) < 0)
502 501 return (0);
503 502 for (i = 0; i < n; i++) {
504 503 (void) nvlist_lookup_string(hcl[i], FM_FMRI_HC_NAME, &name);
505 504 (void) nvlist_lookup_string(hcl[i], FM_FMRI_HC_ID, &id);
506 505
507 506 if (strcmp(name, "chip") == 0) {
508 507 *chip = (uint32_t)strtoul(id, &end, 10);
509 508 rc = 1;
510 509 break;
511 510 }
512 511 }
513 512 return (rc);
514 513 }
515 514
516 515 /*ARGSUSED*/
517 516 int
518 517 gmem_same_datapath_dimms(fmd_hdl_t *hdl, gmem_dimm_t *d1, gmem_dimm_t *d2)
519 518 {
520 519
521 520 if (d1->dimm_chipid == ULONG_MAX || d2->dimm_chipid == ULONG_MAX)
522 521 return (0);
523 522
524 523 if (d1->dimm_chipid == d2->dimm_chipid)
525 524 return (1);
526 525
527 526 return (0);
528 527 }
529 528
530 529 int
531 530 gmem_check_symbol_error(fmd_hdl_t *hdl, gmem_dimm_t *d, uint16_t upos)
532 531 {
533 532 gmem_dimm_t *dimm = NULL, *next = NULL;
534 533
535 534 for (dimm = gmem_list_next(&gmem.gm_dimms); dimm != NULL;
536 535 dimm = next) {
537 536 next = gmem_list_next(dimm);
538 537 if (gmem_same_datapath_dimms(hdl, dimm, d) &&
539 538 dimm->dimm_syl_error == upos)
540 539 return (1);
541 540 }
542 541 return (0);
543 542 }
544 543
545 544 void
546 545 gmem_save_symbol_error(fmd_hdl_t *hdl, gmem_dimm_t *d, uint16_t upos)
547 546 {
548 547 gmem_dimm_t *dimm = NULL, *next = NULL;
549 548
550 549 for (dimm = gmem_list_next(&gmem.gm_dimms); dimm != NULL;
551 550 dimm = next) {
552 551 next = gmem_list_next(dimm);
553 552 if (gmem_same_datapath_dimms(hdl, dimm, d))
554 553 dimm->dimm_syl_error = upos;
555 554 }
556 555 }
↓ open down ↓ |
60 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX