1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * Support function for the i86pc chip enumerator
29 */
30
31 #include <sys/types.h>
32 #include <stdarg.h>
33 #include <strings.h>
34 #include <fm/fmd_fmri.h>
35 #include <sys/systeminfo.h>
36 #include <sys/fm/protocol.h>
37 #include <fm/topo_mod.h>
38 #include <fm/fmd_agent.h>
39
40 #include "chip.h"
41
42 static void fmri_dprint(topo_mod_t *, const char *, uint32_t, nvlist_t *);
43 static boolean_t is_page_fmri(nvlist_t *);
44
45 /*
46 * Whinge a debug message via topo_mod_dprintf and increment the
47 * given error counter.
48 */
49 void
whinge(topo_mod_t * mod,int * nerr,const char * fmt,...)50 whinge(topo_mod_t *mod, int *nerr, const char *fmt, ...)
51 {
52 va_list ap;
53 char buf[160];
54
55 if (nerr != NULL)
56 ++*nerr;
57
58 va_start(ap, fmt);
59 (void) vsnprintf(buf, sizeof (buf), fmt, ap);
60 va_end(ap);
61
62 topo_mod_dprintf(mod, "%s", buf);
63 }
64
65 /*
66 * Given an nvpair of a limited number of data types, extract the property
67 * name and value and add that combination to the given node in the
68 * specified property group using the corresponding topo_prop_set_* function
69 * for the data type. Return 1 on success, otherwise 0.
70 */
71 int
nvprop_add(topo_mod_t * mod,nvpair_t * nvp,const char * pgname,tnode_t * node)72 nvprop_add(topo_mod_t *mod, nvpair_t *nvp, const char *pgname, tnode_t *node)
73 {
74 int success = 0;
75 int err;
76 char *pname = nvpair_name(nvp);
77
78 switch (nvpair_type(nvp)) {
79 case DATA_TYPE_BOOLEAN_VALUE: {
80 boolean_t val;
81
82 if (nvpair_value_boolean_value(nvp, &val) == 0 &&
83 topo_prop_set_string(node, pgname, pname,
84 TOPO_PROP_IMMUTABLE, val ? "true" : "false", &err) == 0)
85 success = 1;
86 break;
87 }
88
89 case DATA_TYPE_UINT32: {
90 uint32_t val;
91
92 if (nvpair_value_uint32(nvp, &val) == 0 &&
93 topo_prop_set_uint32(node, pgname, pname,
94 TOPO_PROP_IMMUTABLE, val, &err) == 0)
95 success = 1;
96 break;
97 }
98
99 case DATA_TYPE_UINT64: {
100 uint64_t val;
101
102 if (nvpair_value_uint64(nvp, &val) == 0 &&
103 topo_prop_set_uint64(node, pgname, pname,
104 TOPO_PROP_IMMUTABLE, val, &err) == 0)
105 success = 1;
106 break;
107 }
108
109 case DATA_TYPE_UINT32_ARRAY: {
110 uint32_t *arrp;
111 uint_t nelem;
112
113 if (nvpair_value_uint32_array(nvp, &arrp, &nelem) == 0 &&
114 nelem > 0 && topo_prop_set_uint32_array(node, pgname, pname,
115 TOPO_PROP_IMMUTABLE, arrp, nelem, &err) == 0)
116 success = 1;
117 break;
118 }
119
120 case DATA_TYPE_STRING: {
121 char *str;
122
123 if (nvpair_value_string(nvp, &str) == 0 &&
124 topo_prop_set_string(node, pgname, pname,
125 TOPO_PROP_IMMUTABLE, str, &err) == 0)
126 success = 1;
127 break;
128 }
129
130 default:
131 whinge(mod, &err, "nvprop_add: Can't handle type %d for "
132 "'%s' in property group %s of %s node\n",
133 nvpair_type(nvp), pname, pgname, topo_node_name(node));
134 break;
135 }
136
137 return (success ? 0 : 1);
138 }
139
140 /*
141 * Lookup string data named pname in the given nvlist and add that
142 * as property named pname in the given property group pgname on the indicated
143 * topo node. Fill pvalp with a pointer to the string value, valid until
144 * nvlist_free is called.
145 */
146 int
add_nvlist_strprop(topo_mod_t * mod,tnode_t * node,nvlist_t * nvl,const char * pgname,const char * pname,const char ** pvalp)147 add_nvlist_strprop(topo_mod_t *mod, tnode_t *node, nvlist_t *nvl,
148 const char *pgname, const char *pname, const char **pvalp)
149 {
150 char *pval;
151 int err = 0;
152
153 if (nvlist_lookup_string(nvl, pname, &pval) != 0)
154 return (-1);
155
156 if (topo_prop_set_string(node, pgname, pname,
157 TOPO_PROP_IMMUTABLE, pval, &err) == 0) {
158 if (pvalp)
159 *pvalp = pval;
160 return (0);
161 } else {
162 whinge(mod, &err, "add_nvlist_strprop: failed to add '%s'\n",
163 pname);
164 return (-1);
165 }
166 }
167
168 /*
169 * Lookup an int32 item named pname in the given nvlist and add that
170 * as property named pname in the given property group pgname on the indicated
171 * topo node. Fill pvalp with the property value.
172 */
173 int
add_nvlist_longprop(topo_mod_t * mod,tnode_t * node,nvlist_t * nvl,const char * pgname,const char * pname,int32_t * pvalp)174 add_nvlist_longprop(topo_mod_t *mod, tnode_t *node, nvlist_t *nvl,
175 const char *pgname, const char *pname, int32_t *pvalp)
176 {
177 int32_t pval;
178 int err;
179
180 if ((nvlist_lookup_int32(nvl, pname, &pval)) != 0)
181 return (-1);
182
183 if (topo_prop_set_int32(node, pgname, pname,
184 TOPO_PROP_IMMUTABLE, pval, &err) == 0) {
185 if (pvalp)
186 *pvalp = pval;
187 return (0);
188 } else {
189 whinge(mod, &err, "add_nvlist_longprop: failed to add '%s'\n",
190 pname);
191 return (-1);
192 }
193 }
194
195 /*
196 * In a given nvlist lookup a variable number of int32 properties named in
197 * const char * varargs and each each in the given property group on the
198 * node. Fill an array of the retrieved values.
199 */
200 int
add_nvlist_longprops(topo_mod_t * mod,tnode_t * node,nvlist_t * nvl,const char * pgname,int32_t * pvalap,...)201 add_nvlist_longprops(topo_mod_t *mod, tnode_t *node, nvlist_t *nvl,
202 const char *pgname, int32_t *pvalap, ...)
203 {
204 const char *pname;
205 va_list ap;
206 int nerr = 0;
207
208 va_start(ap, pvalap);
209 while ((pname = va_arg(ap, const char *)) != NULL) {
210 if (add_nvlist_longprop(mod, node, nvl, pgname, pname,
211 pvalap) != 0)
212 nerr++; /* have whinged elsewhere */
213
214 if (pvalap != NULL)
215 ++pvalap;
216 }
217 va_end(ap);
218
219 return (nerr == 0 ? 0 : -1);
220 }
221
222 /*
223 * Construct an hc scheme resource FMRI for a node named name with
224 * instance number inst, parented by the given parent node pnode.
225 */
226 int
mkrsrc(topo_mod_t * mod,tnode_t * pnode,const char * name,int inst,nvlist_t * auth,nvlist_t ** nvl)227 mkrsrc(topo_mod_t *mod, tnode_t *pnode, const char *name, int inst,
228 nvlist_t *auth, nvlist_t **nvl)
229 {
230 *nvl = topo_mod_hcfmri(mod, pnode, FM_HC_SCHEME_VERSION, name,
231 inst, NULL, auth, NULL, NULL, NULL);
232 return (nvl != NULL ? 0 : -1); /* caller must free nvlist */
233 }
234
235 /*
236 * Construct a cpu scheme FMRI with the given data; the caller must free
237 * the allocated nvlist with nvlist_free().
238 */
239 nvlist_t *
cpu_fmri_create(topo_mod_t * mod,uint32_t cpuid,char * s,uint8_t cpumask)240 cpu_fmri_create(topo_mod_t *mod, uint32_t cpuid, char *s, uint8_t cpumask)
241 {
242 int err;
243 nvlist_t *asru;
244
245 if (topo_mod_nvalloc(mod, &asru, NV_UNIQUE_NAME) != 0)
246 return (NULL);
247
248 err = nvlist_add_uint8(asru, FM_VERSION, FM_CPU_SCHEME_VERSION);
249 err |= nvlist_add_string(asru, FM_FMRI_SCHEME, FM_FMRI_SCHEME_CPU);
250 err |= nvlist_add_uint32(asru, FM_FMRI_CPU_ID, cpuid);
251 err |= nvlist_add_uint8(asru, FM_FMRI_CPU_MASK, cpumask);
252 if (s != NULL)
253 err |= nvlist_add_string(asru, FM_FMRI_CPU_SERIAL_ID, s);
254 if (err != 0) {
255 nvlist_free(asru);
256 (void) topo_mod_seterrno(mod, EMOD_FMRI_NVL);
257 return (NULL);
258 }
259
260 return (asru);
261 }
262
263 /*ARGSUSED*/
264 int
mem_asru_compute(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)265 mem_asru_compute(topo_mod_t *mod, tnode_t *node, topo_version_t version,
266 nvlist_t *in, nvlist_t **out)
267 {
268 nvlist_t *asru, *args, *pargs, *hcsp;
269 int err;
270 uint64_t pa, offset;
271
272 if (strcmp(topo_node_name(node), RANK_NODE_NAME) != 0 &&
273 strcmp(topo_node_name(node), DIMM_NODE_NAME) != 0 &&
274 strcmp(topo_node_name(node), CS_NODE_NAME) != 0)
275 return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
276
277 if (nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args) != 0)
278 return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
279
280 if ((err = nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &pargs)) != 0) {
281 if (err == ENOENT) {
282 pargs = args;
283 } else {
284 return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
285 }
286 }
287
288 if (topo_mod_nvdup(mod, pargs, &asru) != 0)
289 return (topo_mod_seterrno(mod, EMOD_NOMEM));
290
291 err = 0;
292
293 /*
294 * if 'in' includes an hc-specific member which specifies asru-physaddr
295 * or asru-offset then rename them to asru and physaddr respectively.
296 */
297 if (nvlist_lookup_nvlist(asru, FM_FMRI_HC_SPECIFIC, &hcsp) == 0) {
298 if (nvlist_lookup_uint64(hcsp,
299 "asru-"FM_FMRI_HC_SPECIFIC_PHYSADDR, &pa) == 0) {
300 err += nvlist_remove(hcsp,
301 "asru-"FM_FMRI_HC_SPECIFIC_PHYSADDR,
302 DATA_TYPE_UINT64);
303 err += nvlist_add_uint64(hcsp,
304 FM_FMRI_HC_SPECIFIC_PHYSADDR,
305 pa);
306 }
307
308 if (nvlist_lookup_uint64(hcsp,
309 "asru-"FM_FMRI_HC_SPECIFIC_OFFSET, &offset) == 0) {
310 err += nvlist_remove(hcsp,
311 "asru-"FM_FMRI_HC_SPECIFIC_OFFSET,
312 DATA_TYPE_UINT64);
313 err += nvlist_add_uint64(hcsp,
314 FM_FMRI_HC_SPECIFIC_OFFSET,
315 offset);
316 }
317 }
318
319 if (err != 0 || topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) < 0) {
320 nvlist_free(asru);
321 return (topo_mod_seterrno(mod, EMOD_NOMEM));
322 }
323
324 err = nvlist_add_string(*out, TOPO_PROP_VAL_NAME, TOPO_PROP_ASRU);
325 err |= nvlist_add_uint32(*out, TOPO_PROP_VAL_TYPE, TOPO_TYPE_FMRI);
326 err |= nvlist_add_nvlist(*out, TOPO_PROP_VAL_VAL, asru);
327 if (err != 0) {
328 nvlist_free(asru);
329 nvlist_free(*out);
330 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
331 }
332
333 nvlist_free(asru);
334
335 return (0);
336 }
337
338 static int
set_retnvl(topo_mod_t * mod,nvlist_t ** out,const char * retname,uint32_t ret)339 set_retnvl(topo_mod_t *mod, nvlist_t **out, const char *retname, uint32_t ret)
340 {
341 nvlist_t *nvl;
342
343 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) < 0)
344 return (topo_mod_seterrno(mod, EMOD_NOMEM));
345
346 if (nvlist_add_uint32(nvl, retname, ret) != 0) {
347 nvlist_free(nvl);
348 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
349 }
350
351 *out = nvl;
352 return (0);
353 }
354
355 /*
356 * If we're getting called then the question of whether this dimm is plugged
357 * in has already been answered. What we don't know for sure is whether it's
358 * the same dimm or a different one plugged in the same slot. To check, we
359 * try and compare the serial numbers on the dimm in the current topology with
360 * the serial num from the unum fmri that got passed into this function as the
361 * argument.
362 *
363 */
364 static int
fmri_replaced(topo_mod_t * mod,tnode_t * node,nvlist_t * unum,int * errp)365 fmri_replaced(topo_mod_t *mod, tnode_t *node, nvlist_t *unum, int *errp)
366 {
367 tnode_t *dimmnode;
368 nvlist_t *resource;
369 int rc, err;
370 char *old_serial, *curr_serial;
371 fmd_agent_hdl_t *hdl;
372
373 /*
374 * If input is a page, return "replaced" if the offset is invalid.
375 */
376 if (is_page_fmri(unum) &&
377 (hdl = fmd_agent_open(FMD_AGENT_VERSION)) != NULL) {
378 rc = fmd_agent_page_isretired(hdl, unum);
379 err = fmd_agent_errno(hdl);
380 fmd_agent_close(hdl);
381
382 if (rc == FMD_AGENT_RETIRE_DONE &&
383 err == EINVAL)
384 return (FMD_OBJ_STATE_NOT_PRESENT);
385 }
386
387 /*
388 * If a serial number for the dimm was available at the time of the
389 * fault, it will have been added as a string to the unum nvlist
390 */
391 if (nvlist_lookup_string(unum, FM_FMRI_HC_SERIAL_ID, &old_serial))
392 return (FMD_OBJ_STATE_UNKNOWN);
393
394 /*
395 * If the current serial number is available for the DIMM that this rank
396 * belongs to, it will be accessible as a property on the parent (dimm)
397 * node. If there is a serial id in the resource fmri, then use that.
398 * Otherwise fall back to looking for a serial id property in the
399 * protocol group.
400 */
401 dimmnode = topo_node_parent(node);
402 if (topo_node_resource(dimmnode, &resource, &err) != -1) {
403 if (nvlist_lookup_string(resource, FM_FMRI_HC_SERIAL_ID,
404 &curr_serial) == 0) {
405 if (strcmp(old_serial, curr_serial) != 0) {
406 nvlist_free(resource);
407 return (FMD_OBJ_STATE_REPLACED);
408 } else {
409 nvlist_free(resource);
410 return (FMD_OBJ_STATE_STILL_PRESENT);
411 }
412 }
413 nvlist_free(resource);
414 }
415 if (topo_prop_get_string(dimmnode, TOPO_PGROUP_PROTOCOL,
416 FM_FMRI_HC_SERIAL_ID, &curr_serial, &err) != 0) {
417 if (err == ETOPO_PROP_NOENT) {
418 return (FMD_OBJ_STATE_UNKNOWN);
419 } else {
420 *errp = EMOD_NVL_INVAL;
421 whinge(mod, NULL, "rank_fmri_present: Unexpected "
422 "error retrieving serial from node");
423 return (-1);
424 }
425 }
426
427 if (strcmp(old_serial, curr_serial) != 0) {
428 topo_mod_strfree(mod, curr_serial);
429 return (FMD_OBJ_STATE_REPLACED);
430 }
431
432 topo_mod_strfree(mod, curr_serial);
433
434 return (FMD_OBJ_STATE_STILL_PRESENT);
435 }
436
437 /*
438 * In the event we encounter problems comparing serials or if a comparison isn't
439 * possible, we err on the side of caution and set is_present to TRUE.
440 */
441 int
rank_fmri_present(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)442 rank_fmri_present(topo_mod_t *mod, tnode_t *node, topo_version_t version,
443 nvlist_t *in, nvlist_t **out)
444 {
445 int is_present, err;
446
447 if (version > TOPO_METH_PRESENT_VERSION)
448 return (topo_mod_seterrno(mod, EMOD_VER_NEW));
449
450 switch (fmri_replaced(mod, node, in, &err)) {
451 case FMD_OBJ_STATE_REPLACED:
452 case FMD_OBJ_STATE_NOT_PRESENT:
453 is_present = 0;
454 break;
455
456 case FMD_OBJ_STATE_UNKNOWN:
457 case FMD_OBJ_STATE_STILL_PRESENT:
458 is_present = 1;
459 break;
460
461 default:
462 return (topo_mod_seterrno(mod, err));
463 }
464
465 fmri_dprint(mod, "rank_fmri_present", is_present, in);
466
467 return (set_retnvl(mod, out, TOPO_METH_PRESENT_RET, is_present));
468 }
469
470 int
rank_fmri_replaced(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)471 rank_fmri_replaced(topo_mod_t *mod, tnode_t *node, topo_version_t version,
472 nvlist_t *in, nvlist_t **out)
473 {
474 int is_replaced, err;
475
476 if (version > TOPO_METH_REPLACED_VERSION)
477 return (topo_mod_seterrno(mod, EMOD_VER_NEW));
478
479 is_replaced = fmri_replaced(mod, node, in, &err);
480 if (is_replaced == -1)
481 return (topo_mod_seterrno(mod, err));
482
483 fmri_dprint(mod, "rank_fmri_replaced", is_replaced, in);
484
485 return (set_retnvl(mod, out, TOPO_METH_REPLACED_RET, is_replaced));
486 }
487
488 static void
fmri_dprint(topo_mod_t * mod,const char * op,uint32_t rc,nvlist_t * fmri)489 fmri_dprint(topo_mod_t *mod, const char *op, uint32_t rc, nvlist_t *fmri)
490 {
491 char *fmristr;
492 const char *status;
493
494 if (getenv("TOPOCHIPDBG") == NULL)
495 return;
496
497 switch (rc) {
498 case FMD_AGENT_RETIRE_DONE:
499 status = "sync success";
500 break;
501 case FMD_AGENT_RETIRE_ASYNC:
502 status = "async retiring";
503 break;
504 case FMD_AGENT_RETIRE_FAIL:
505 status = "not retired";
506 break;
507 default:
508 status = "unknown status";
509 }
510 if (fmri != NULL && topo_mod_nvl2str(mod, fmri, &fmristr) == 0) {
511 topo_mod_dprintf(mod, "[%s]: %s => %d (\"%s\")\n", fmristr,
512 op, rc, status);
513 topo_mod_strfree(mod, fmristr);
514 }
515 }
516
517 struct strand_walk_data {
518 tnode_t *parent;
519 fmd_agent_hdl_t *hdl;
520 int (*func)(fmd_agent_hdl_t *, int, int, int);
521 int err;
522 int done;
523 int fail;
524 int async;
525 };
526
527 static int
strand_walker(topo_mod_t * mod,tnode_t * node,void * pdata)528 strand_walker(topo_mod_t *mod, tnode_t *node, void *pdata)
529 {
530 struct strand_walk_data *swdp = pdata;
531 int32_t chipid, coreid, strandid;
532 int err, rc;
533
534 /*
535 * Terminate the walk if we reach start-node's sibling
536 */
537 if (node != swdp->parent &&
538 topo_node_parent(node) == topo_node_parent(swdp->parent))
539 return (TOPO_WALK_TERMINATE);
540
541 if (strcmp(topo_node_name(node), STRAND) != 0)
542 return (TOPO_WALK_NEXT);
543
544 if (topo_prop_get_int32(node, PGNAME(STRAND), STRAND_CHIP_ID,
545 &chipid, &err) < 0 ||
546 topo_prop_get_int32(node, PGNAME(STRAND), STRAND_CORE_ID,
547 &coreid, &err) < 0) {
548 swdp->err++;
549 return (TOPO_WALK_NEXT);
550 }
551 strandid = topo_node_instance(node);
552 rc = swdp->func(swdp->hdl, chipid, coreid, strandid);
553
554 if (rc == FMD_AGENT_RETIRE_DONE)
555 swdp->done++;
556 else if (rc == FMD_AGENT_RETIRE_FAIL)
557 swdp->fail++;
558 else if (rc == FMD_AGENT_RETIRE_ASYNC)
559 swdp->async++;
560 else
561 swdp->err++;
562
563 if (getenv("TOPOCHIPDBG") != NULL) {
564 const char *op;
565
566 if (swdp->func == fmd_agent_cpu_retire)
567 op = "retire";
568 else if (swdp->func == fmd_agent_cpu_unretire)
569 op = "unretire";
570 else if (swdp->func == fmd_agent_cpu_isretired)
571 op = "check status";
572 else
573 op = "unknown op";
574
575 topo_mod_dprintf(mod, "%s cpu (%d:%d:%d): rc = %d, err = %s\n",
576 op, (int)chipid, (int)coreid, (int)strandid, rc,
577 fmd_agent_errmsg(swdp->hdl));
578 }
579
580 return (TOPO_WALK_NEXT);
581 }
582
583 static int
walk_strands(topo_mod_t * mod,struct strand_walk_data * swdp,tnode_t * parent,int (* func)(fmd_agent_hdl_t *,int,int,int))584 walk_strands(topo_mod_t *mod, struct strand_walk_data *swdp, tnode_t *parent,
585 int (*func)(fmd_agent_hdl_t *, int, int, int))
586 {
587 topo_walk_t *twp;
588 int err;
589
590 swdp->parent = parent;
591 swdp->func = func;
592 swdp->err = swdp->done = swdp->fail = swdp->async = 0;
593 if ((swdp->hdl = fmd_agent_open(FMD_AGENT_VERSION)) == NULL) {
594 swdp->fail++;
595 return (0);
596 }
597
598 twp = topo_mod_walk_init(mod, parent, strand_walker, swdp, &err);
599 if (twp == NULL) {
600 fmd_agent_close(swdp->hdl);
601 return (-1);
602 }
603
604 err = topo_walk_step(twp, TOPO_WALK_CHILD);
605 topo_walk_fini(twp);
606 fmd_agent_close(swdp->hdl);
607
608 if (err == TOPO_WALK_ERR || swdp->err > 0)
609 return (-1);
610
611 return (0);
612 }
613
614 /* ARGSUSED */
615 int
retire_strands(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)616 retire_strands(topo_mod_t *mod, tnode_t *node, topo_version_t version,
617 nvlist_t *in, nvlist_t **out)
618 {
619 struct strand_walk_data swd;
620 uint32_t rc;
621
622 if (version > TOPO_METH_RETIRE_VERSION)
623 return (topo_mod_seterrno(mod, EMOD_VER_NEW));
624
625 if (walk_strands(mod, &swd, node, fmd_agent_cpu_retire) == -1)
626 return (-1);
627
628 if (swd.fail > 0)
629 rc = FMD_AGENT_RETIRE_FAIL;
630 else if (swd.async > 0)
631 rc = FMD_AGENT_RETIRE_ASYNC;
632 else
633 rc = FMD_AGENT_RETIRE_DONE;
634
635 return (set_retnvl(mod, out, TOPO_METH_RETIRE_RET, rc));
636 }
637
638 /* ARGSUSED */
639 int
unretire_strands(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)640 unretire_strands(topo_mod_t *mod, tnode_t *node, topo_version_t version,
641 nvlist_t *in, nvlist_t **out)
642 {
643 struct strand_walk_data swd;
644 uint32_t rc;
645
646 if (version > TOPO_METH_UNRETIRE_VERSION)
647 return (topo_mod_seterrno(mod, EMOD_VER_NEW));
648
649 if (walk_strands(mod, &swd, node, fmd_agent_cpu_unretire) == -1)
650 return (-1);
651
652 if (swd.fail > 0)
653 rc = FMD_AGENT_RETIRE_FAIL;
654 else if (swd.async > 0)
655 rc = FMD_AGENT_RETIRE_ASYNC;
656 else
657 rc = FMD_AGENT_RETIRE_DONE;
658
659 return (set_retnvl(mod, out, TOPO_METH_UNRETIRE_RET, rc));
660 }
661
662 /* ARGSUSED */
663 int
service_state_strands(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)664 service_state_strands(topo_mod_t *mod, tnode_t *node, topo_version_t version,
665 nvlist_t *in, nvlist_t **out)
666 {
667 struct strand_walk_data swd;
668 uint32_t rc;
669
670 if (version > TOPO_METH_SERVICE_STATE_VERSION)
671 return (topo_mod_seterrno(mod, EMOD_VER_NEW));
672
673 if (walk_strands(mod, &swd, node, fmd_agent_cpu_isretired) == -1)
674 return (-1);
675
676 if (swd.done > 0)
677 rc = (swd.fail + swd.async > 0) ? FMD_SERVICE_STATE_DEGRADED :
678 FMD_SERVICE_STATE_UNUSABLE;
679 else if (swd.async > 0)
680 rc = FMD_SERVICE_STATE_ISOLATE_PENDING;
681 else if (swd.fail > 0)
682 rc = FMD_SERVICE_STATE_OK;
683 else
684 rc = FMD_SERVICE_STATE_UNKNOWN;
685
686 return (set_retnvl(mod, out, TOPO_METH_SERVICE_STATE_RET, rc));
687 }
688
689 /* ARGSUSED */
690 int
unusable_strands(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)691 unusable_strands(topo_mod_t *mod, tnode_t *node, topo_version_t version,
692 nvlist_t *in, nvlist_t **out)
693 {
694 struct strand_walk_data swd;
695 uint32_t rc;
696
697 if (version > TOPO_METH_UNUSABLE_VERSION)
698 return (topo_mod_seterrno(mod, EMOD_VER_NEW));
699
700 if (walk_strands(mod, &swd, node, fmd_agent_cpu_isretired) == -1)
701 return (-1);
702
703 rc = (swd.fail + swd.async > 0 || swd.done == 0) ? 0 : 1;
704
705 return (set_retnvl(mod, out, TOPO_METH_UNUSABLE_RET, rc));
706 }
707
708 static boolean_t
is_page_fmri(nvlist_t * nvl)709 is_page_fmri(nvlist_t *nvl)
710 {
711 nvlist_t *hcsp;
712 uint64_t val;
713
714 if (nvlist_lookup_nvlist(nvl, FM_FMRI_HC_SPECIFIC, &hcsp) == 0 &&
715 (nvlist_lookup_uint64(hcsp, FM_FMRI_HC_SPECIFIC_OFFSET,
716 &val) == 0 ||
717 nvlist_lookup_uint64(hcsp, "asru-" FM_FMRI_HC_SPECIFIC_OFFSET,
718 &val) == 0 ||
719 nvlist_lookup_uint64(hcsp, FM_FMRI_HC_SPECIFIC_PHYSADDR,
720 &val) == 0 ||
721 nvlist_lookup_uint64(hcsp, "asru-" FM_FMRI_HC_SPECIFIC_PHYSADDR,
722 &val) == 0))
723 return (B_TRUE);
724
725 return (B_FALSE);
726 }
727
728 /* ARGSUSED */
729 int
ntv_page_retire(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)730 ntv_page_retire(topo_mod_t *mod, tnode_t *node, topo_version_t version,
731 nvlist_t *in, nvlist_t **out)
732 {
733 fmd_agent_hdl_t *hdl;
734 uint32_t rc = FMD_AGENT_RETIRE_FAIL;
735
736 if (version > TOPO_METH_RETIRE_VERSION)
737 return (topo_mod_seterrno(mod, EMOD_VER_NEW));
738 if (is_page_fmri(in)) {
739 if ((hdl = fmd_agent_open(FMD_AGENT_VERSION)) != NULL) {
740 rc = fmd_agent_page_retire(hdl, in);
741 fmd_agent_close(hdl);
742 }
743 }
744 fmri_dprint(mod, "ntv_page_retire", rc, in);
745 return (set_retnvl(mod, out, TOPO_METH_RETIRE_RET, rc));
746 }
747
748 /* ARGSUSED */
749 int
ntv_page_unretire(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)750 ntv_page_unretire(topo_mod_t *mod, tnode_t *node, topo_version_t version,
751 nvlist_t *in, nvlist_t **out)
752 {
753 fmd_agent_hdl_t *hdl;
754 uint32_t rc = FMD_AGENT_RETIRE_FAIL;
755
756 if (version > TOPO_METH_UNRETIRE_VERSION)
757 return (topo_mod_seterrno(mod, EMOD_VER_NEW));
758 if (is_page_fmri(in)) {
759 if ((hdl = fmd_agent_open(FMD_AGENT_VERSION)) != NULL) {
760 rc = fmd_agent_page_unretire(hdl, in);
761 fmd_agent_close(hdl);
762 }
763 }
764 fmri_dprint(mod, "ntv_page_unretire", rc, in);
765 return (set_retnvl(mod, out, TOPO_METH_UNRETIRE_RET, rc));
766 }
767
768 /* ARGSUSED */
769 int
ntv_page_service_state(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)770 ntv_page_service_state(topo_mod_t *mod, tnode_t *node, topo_version_t version,
771 nvlist_t *in, nvlist_t **out)
772 {
773 fmd_agent_hdl_t *hdl;
774 uint32_t rc = FMD_SERVICE_STATE_UNKNOWN;
775
776 if (version > TOPO_METH_SERVICE_STATE_VERSION)
777 return (topo_mod_seterrno(mod, EMOD_VER_NEW));
778 if (is_page_fmri(in)) {
779 if ((hdl = fmd_agent_open(FMD_AGENT_VERSION)) != NULL) {
780 rc = fmd_agent_page_isretired(hdl, in);
781 fmd_agent_close(hdl);
782 if (rc == FMD_AGENT_RETIRE_DONE)
783 rc = FMD_SERVICE_STATE_UNUSABLE;
784 else if (rc == FMD_AGENT_RETIRE_FAIL)
785 rc = FMD_SERVICE_STATE_OK;
786 else if (rc == FMD_AGENT_RETIRE_ASYNC)
787 rc = FMD_SERVICE_STATE_ISOLATE_PENDING;
788 }
789 }
790
791 topo_mod_dprintf(mod, "ntv_page_service_state: rc = %u\n", rc);
792 return (set_retnvl(mod, out, TOPO_METH_SERVICE_STATE_RET, rc));
793 }
794
795 /* ARGSUSED */
796 int
ntv_page_unusable(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)797 ntv_page_unusable(topo_mod_t *mod, tnode_t *node, topo_version_t version,
798 nvlist_t *in, nvlist_t **out)
799 {
800 fmd_agent_hdl_t *hdl;
801 uint32_t rc = FMD_AGENT_RETIRE_FAIL;
802
803 if (version > TOPO_METH_UNUSABLE_VERSION)
804 return (topo_mod_seterrno(mod, EMOD_VER_NEW));
805 if (is_page_fmri(in)) {
806 if ((hdl = fmd_agent_open(FMD_AGENT_VERSION)) != NULL) {
807 rc = fmd_agent_page_isretired(hdl, in);
808 fmd_agent_close(hdl);
809 }
810 }
811 topo_mod_dprintf(mod, "ntv_page_unusable: rc = %u\n", rc);
812 return (set_retnvl(mod, out, TOPO_METH_UNUSABLE_RET,
813 rc == FMD_AGENT_RETIRE_DONE ? 1 : 0));
814 }
815