1*8221SSean.Ye@Sun.COM /*
2*8221SSean.Ye@Sun.COM * CDDL HEADER START
3*8221SSean.Ye@Sun.COM *
4*8221SSean.Ye@Sun.COM * The contents of this file are subject to the terms of the
5*8221SSean.Ye@Sun.COM * Common Development and Distribution License (the "License").
6*8221SSean.Ye@Sun.COM * You may not use this file except in compliance with the License.
7*8221SSean.Ye@Sun.COM *
8*8221SSean.Ye@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*8221SSean.Ye@Sun.COM * or http://www.opensolaris.org/os/licensing.
10*8221SSean.Ye@Sun.COM * See the License for the specific language governing permissions
11*8221SSean.Ye@Sun.COM * and limitations under the License.
12*8221SSean.Ye@Sun.COM *
13*8221SSean.Ye@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
14*8221SSean.Ye@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*8221SSean.Ye@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
16*8221SSean.Ye@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
17*8221SSean.Ye@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
18*8221SSean.Ye@Sun.COM *
19*8221SSean.Ye@Sun.COM * CDDL HEADER END
20*8221SSean.Ye@Sun.COM */
21*8221SSean.Ye@Sun.COM
22*8221SSean.Ye@Sun.COM /*
23*8221SSean.Ye@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24*8221SSean.Ye@Sun.COM * Use is subject to license terms.
25*8221SSean.Ye@Sun.COM */
26*8221SSean.Ye@Sun.COM
27*8221SSean.Ye@Sun.COM #include <strings.h>
28*8221SSean.Ye@Sun.COM #include <string.h>
29*8221SSean.Ye@Sun.COM #include <libnvpair.h>
30*8221SSean.Ye@Sun.COM #include <sys/fm/ldom.h>
31*8221SSean.Ye@Sun.COM #include <fm/libtopo.h>
32*8221SSean.Ye@Sun.COM #include <fm/topo_mod.h>
33*8221SSean.Ye@Sun.COM #include <fm/fmd_fmri.h>
34*8221SSean.Ye@Sun.COM #include <fm/fmd_agent.h>
35*8221SSean.Ye@Sun.COM #include <sys/fm/ldom.h>
36*8221SSean.Ye@Sun.COM
37*8221SSean.Ye@Sun.COM struct cpu_walk_data {
38*8221SSean.Ye@Sun.COM tnode_t *parent; /* walk start node */
39*8221SSean.Ye@Sun.COM ldom_hdl_t *lhp; /* ldom handle */
40*8221SSean.Ye@Sun.COM int (*func)(ldom_hdl_t *, nvlist_t *); /* callback func */
41*8221SSean.Ye@Sun.COM int err; /* walk errors count */
42*8221SSean.Ye@Sun.COM int online; /* online cpus count */
43*8221SSean.Ye@Sun.COM int offline; /* offline cpus count */
44*8221SSean.Ye@Sun.COM int fail; /* callback fails */
45*8221SSean.Ye@Sun.COM };
46*8221SSean.Ye@Sun.COM
47*8221SSean.Ye@Sun.COM static topo_method_f
48*8221SSean.Ye@Sun.COM cpu_retire, cpu_unretire, cpu_service_state,
49*8221SSean.Ye@Sun.COM cpu_unusable, mem_asru_compute, dimm_page_unusable,
50*8221SSean.Ye@Sun.COM dimm_page_service_state, dimm_page_retire, dimm_page_unretire;
51*8221SSean.Ye@Sun.COM
52*8221SSean.Ye@Sun.COM const topo_method_t pi_cpu_methods[] = {
53*8221SSean.Ye@Sun.COM { TOPO_METH_RETIRE, TOPO_METH_RETIRE_DESC,
54*8221SSean.Ye@Sun.COM TOPO_METH_RETIRE_VERSION, TOPO_STABILITY_INTERNAL,
55*8221SSean.Ye@Sun.COM cpu_retire },
56*8221SSean.Ye@Sun.COM { TOPO_METH_UNRETIRE, TOPO_METH_UNRETIRE_DESC,
57*8221SSean.Ye@Sun.COM TOPO_METH_UNRETIRE_VERSION, TOPO_STABILITY_INTERNAL,
58*8221SSean.Ye@Sun.COM cpu_unretire },
59*8221SSean.Ye@Sun.COM { TOPO_METH_SERVICE_STATE, TOPO_METH_SERVICE_STATE_DESC,
60*8221SSean.Ye@Sun.COM TOPO_METH_SERVICE_STATE_VERSION, TOPO_STABILITY_INTERNAL,
61*8221SSean.Ye@Sun.COM cpu_service_state },
62*8221SSean.Ye@Sun.COM { TOPO_METH_UNUSABLE, TOPO_METH_UNUSABLE_DESC,
63*8221SSean.Ye@Sun.COM TOPO_METH_UNUSABLE_VERSION, TOPO_STABILITY_INTERNAL,
64*8221SSean.Ye@Sun.COM cpu_unusable },
65*8221SSean.Ye@Sun.COM { NULL }
66*8221SSean.Ye@Sun.COM };
67*8221SSean.Ye@Sun.COM
68*8221SSean.Ye@Sun.COM const topo_method_t pi_mem_methods[] = {
69*8221SSean.Ye@Sun.COM { TOPO_METH_ASRU_COMPUTE, TOPO_METH_ASRU_COMPUTE_DESC,
70*8221SSean.Ye@Sun.COM TOPO_METH_ASRU_COMPUTE_VERSION, TOPO_STABILITY_INTERNAL,
71*8221SSean.Ye@Sun.COM mem_asru_compute },
72*8221SSean.Ye@Sun.COM { TOPO_METH_SERVICE_STATE, TOPO_METH_SERVICE_STATE_DESC,
73*8221SSean.Ye@Sun.COM TOPO_METH_SERVICE_STATE_VERSION, TOPO_STABILITY_INTERNAL,
74*8221SSean.Ye@Sun.COM dimm_page_service_state },
75*8221SSean.Ye@Sun.COM { TOPO_METH_UNUSABLE, TOPO_METH_UNUSABLE_DESC,
76*8221SSean.Ye@Sun.COM TOPO_METH_UNUSABLE_VERSION, TOPO_STABILITY_INTERNAL,
77*8221SSean.Ye@Sun.COM dimm_page_unusable },
78*8221SSean.Ye@Sun.COM { TOPO_METH_RETIRE, TOPO_METH_RETIRE_DESC,
79*8221SSean.Ye@Sun.COM TOPO_METH_RETIRE_VERSION, TOPO_STABILITY_INTERNAL,
80*8221SSean.Ye@Sun.COM dimm_page_retire },
81*8221SSean.Ye@Sun.COM { TOPO_METH_UNRETIRE, TOPO_METH_UNRETIRE_DESC,
82*8221SSean.Ye@Sun.COM TOPO_METH_UNRETIRE_VERSION, TOPO_STABILITY_INTERNAL,
83*8221SSean.Ye@Sun.COM dimm_page_unretire },
84*8221SSean.Ye@Sun.COM { NULL }
85*8221SSean.Ye@Sun.COM };
86*8221SSean.Ye@Sun.COM
87*8221SSean.Ye@Sun.COM static ldom_hdl_t *pi_lhp = NULL;
88*8221SSean.Ye@Sun.COM
89*8221SSean.Ye@Sun.COM #pragma init(pi_ldom_init)
90*8221SSean.Ye@Sun.COM static void
pi_ldom_init(void)91*8221SSean.Ye@Sun.COM pi_ldom_init(void)
92*8221SSean.Ye@Sun.COM {
93*8221SSean.Ye@Sun.COM pi_lhp = ldom_init(NULL, NULL);
94*8221SSean.Ye@Sun.COM }
95*8221SSean.Ye@Sun.COM
96*8221SSean.Ye@Sun.COM #pragma fini(pi_ldom_fini)
97*8221SSean.Ye@Sun.COM static void
pi_ldom_fini(void)98*8221SSean.Ye@Sun.COM pi_ldom_fini(void)
99*8221SSean.Ye@Sun.COM {
100*8221SSean.Ye@Sun.COM if (pi_lhp != NULL)
101*8221SSean.Ye@Sun.COM ldom_fini(pi_lhp);
102*8221SSean.Ye@Sun.COM }
103*8221SSean.Ye@Sun.COM
104*8221SSean.Ye@Sun.COM static int
set_retnvl(topo_mod_t * mod,nvlist_t ** out,const char * retname,uint32_t ret)105*8221SSean.Ye@Sun.COM set_retnvl(topo_mod_t *mod, nvlist_t **out, const char *retname, uint32_t ret)
106*8221SSean.Ye@Sun.COM {
107*8221SSean.Ye@Sun.COM nvlist_t *nvl;
108*8221SSean.Ye@Sun.COM
109*8221SSean.Ye@Sun.COM topo_mod_dprintf(mod, "topo method set \"%s\" = %u\n", retname, ret);
110*8221SSean.Ye@Sun.COM
111*8221SSean.Ye@Sun.COM if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) < 0)
112*8221SSean.Ye@Sun.COM return (topo_mod_seterrno(mod, EMOD_NOMEM));
113*8221SSean.Ye@Sun.COM
114*8221SSean.Ye@Sun.COM if (nvlist_add_uint32(nvl, retname, ret) != 0) {
115*8221SSean.Ye@Sun.COM nvlist_free(nvl);
116*8221SSean.Ye@Sun.COM return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
117*8221SSean.Ye@Sun.COM }
118*8221SSean.Ye@Sun.COM
119*8221SSean.Ye@Sun.COM *out = nvl;
120*8221SSean.Ye@Sun.COM return (0);
121*8221SSean.Ye@Sun.COM }
122*8221SSean.Ye@Sun.COM
123*8221SSean.Ye@Sun.COM /*
124*8221SSean.Ye@Sun.COM * For each visited cpu node, call the callback function with its ASRU.
125*8221SSean.Ye@Sun.COM */
126*8221SSean.Ye@Sun.COM static int
cpu_walker(topo_mod_t * mod,tnode_t * node,void * pdata)127*8221SSean.Ye@Sun.COM cpu_walker(topo_mod_t *mod, tnode_t *node, void *pdata)
128*8221SSean.Ye@Sun.COM {
129*8221SSean.Ye@Sun.COM struct cpu_walk_data *swdp = pdata;
130*8221SSean.Ye@Sun.COM nvlist_t *asru;
131*8221SSean.Ye@Sun.COM int err, rc;
132*8221SSean.Ye@Sun.COM
133*8221SSean.Ye@Sun.COM /*
134*8221SSean.Ye@Sun.COM * Terminate the walk if we reach start-node's sibling
135*8221SSean.Ye@Sun.COM */
136*8221SSean.Ye@Sun.COM if (node != swdp->parent &&
137*8221SSean.Ye@Sun.COM topo_node_parent(node) == topo_node_parent(swdp->parent))
138*8221SSean.Ye@Sun.COM return (TOPO_WALK_TERMINATE);
139*8221SSean.Ye@Sun.COM
140*8221SSean.Ye@Sun.COM if (strcmp(topo_node_name(node), CPU) != 0 &&
141*8221SSean.Ye@Sun.COM strcmp(topo_node_name(node), STRAND) != 0)
142*8221SSean.Ye@Sun.COM return (TOPO_WALK_NEXT);
143*8221SSean.Ye@Sun.COM
144*8221SSean.Ye@Sun.COM if (topo_node_asru(node, &asru, NULL, &err) != 0) {
145*8221SSean.Ye@Sun.COM swdp->fail++;
146*8221SSean.Ye@Sun.COM return (TOPO_WALK_NEXT);
147*8221SSean.Ye@Sun.COM }
148*8221SSean.Ye@Sun.COM
149*8221SSean.Ye@Sun.COM rc = swdp->func(swdp->lhp, asru);
150*8221SSean.Ye@Sun.COM
151*8221SSean.Ye@Sun.COM /*
152*8221SSean.Ye@Sun.COM * The "offline" and "online" counter are only useful for the "status"
153*8221SSean.Ye@Sun.COM * callback.
154*8221SSean.Ye@Sun.COM */
155*8221SSean.Ye@Sun.COM if (rc == P_OFFLINE || rc == P_FAULTED) {
156*8221SSean.Ye@Sun.COM swdp->offline++;
157*8221SSean.Ye@Sun.COM err = 0;
158*8221SSean.Ye@Sun.COM } else if (rc == P_ONLINE) {
159*8221SSean.Ye@Sun.COM swdp->online++;
160*8221SSean.Ye@Sun.COM err = 0;
161*8221SSean.Ye@Sun.COM } else {
162*8221SSean.Ye@Sun.COM swdp->fail++;
163*8221SSean.Ye@Sun.COM err = errno;
164*8221SSean.Ye@Sun.COM }
165*8221SSean.Ye@Sun.COM
166*8221SSean.Ye@Sun.COM /* dump out status info if debug is turned on. */
167*8221SSean.Ye@Sun.COM if (getenv("TOPOCHIPDBG") != NULL ||
168*8221SSean.Ye@Sun.COM getenv("TOPOSUN4VPIDBG") != NULL) {
169*8221SSean.Ye@Sun.COM const char *op;
170*8221SSean.Ye@Sun.COM char *fmristr = NULL;
171*8221SSean.Ye@Sun.COM
172*8221SSean.Ye@Sun.COM if (swdp->func == ldom_fmri_retire)
173*8221SSean.Ye@Sun.COM op = "retire";
174*8221SSean.Ye@Sun.COM else if (swdp->func == ldom_fmri_unretire)
175*8221SSean.Ye@Sun.COM op = "unretire";
176*8221SSean.Ye@Sun.COM else if (swdp->func == ldom_fmri_status)
177*8221SSean.Ye@Sun.COM op = "check status";
178*8221SSean.Ye@Sun.COM else
179*8221SSean.Ye@Sun.COM op = "unknown op";
180*8221SSean.Ye@Sun.COM
181*8221SSean.Ye@Sun.COM (void) topo_mod_nvl2str(mod, asru, &fmristr);
182*8221SSean.Ye@Sun.COM topo_mod_dprintf(mod, "%s cpu (%s): rc = %d, err = %s\n",
183*8221SSean.Ye@Sun.COM op, fmristr == NULL ? "unknown fmri" : fmristr,
184*8221SSean.Ye@Sun.COM rc, strerror(err));
185*8221SSean.Ye@Sun.COM if (fmristr != NULL)
186*8221SSean.Ye@Sun.COM topo_mod_strfree(mod, fmristr);
187*8221SSean.Ye@Sun.COM }
188*8221SSean.Ye@Sun.COM
189*8221SSean.Ye@Sun.COM nvlist_free(asru);
190*8221SSean.Ye@Sun.COM return (TOPO_WALK_NEXT);
191*8221SSean.Ye@Sun.COM }
192*8221SSean.Ye@Sun.COM
193*8221SSean.Ye@Sun.COM static int
walk_cpus(topo_mod_t * mod,struct cpu_walk_data * swdp,tnode_t * parent,int (* func)(ldom_hdl_t *,nvlist_t *))194*8221SSean.Ye@Sun.COM walk_cpus(topo_mod_t *mod, struct cpu_walk_data *swdp, tnode_t *parent,
195*8221SSean.Ye@Sun.COM int (*func)(ldom_hdl_t *, nvlist_t *))
196*8221SSean.Ye@Sun.COM {
197*8221SSean.Ye@Sun.COM topo_walk_t *twp;
198*8221SSean.Ye@Sun.COM int err;
199*8221SSean.Ye@Sun.COM
200*8221SSean.Ye@Sun.COM swdp->lhp = pi_lhp;
201*8221SSean.Ye@Sun.COM swdp->parent = parent;
202*8221SSean.Ye@Sun.COM swdp->func = func;
203*8221SSean.Ye@Sun.COM swdp->err = swdp->offline = swdp->online = swdp->fail = 0;
204*8221SSean.Ye@Sun.COM
205*8221SSean.Ye@Sun.COM /*
206*8221SSean.Ye@Sun.COM * Return failure if ldom service is not initialized.
207*8221SSean.Ye@Sun.COM */
208*8221SSean.Ye@Sun.COM if (pi_lhp == NULL) {
209*8221SSean.Ye@Sun.COM swdp->fail++;
210*8221SSean.Ye@Sun.COM return (0);
211*8221SSean.Ye@Sun.COM }
212*8221SSean.Ye@Sun.COM
213*8221SSean.Ye@Sun.COM twp = topo_mod_walk_init(mod, parent, cpu_walker, swdp, &err);
214*8221SSean.Ye@Sun.COM if (twp == NULL)
215*8221SSean.Ye@Sun.COM return (-1);
216*8221SSean.Ye@Sun.COM
217*8221SSean.Ye@Sun.COM err = topo_walk_step(twp, TOPO_WALK_CHILD);
218*8221SSean.Ye@Sun.COM topo_walk_fini(twp);
219*8221SSean.Ye@Sun.COM
220*8221SSean.Ye@Sun.COM if (err == TOPO_WALK_ERR || swdp->err > 0)
221*8221SSean.Ye@Sun.COM return (-1);
222*8221SSean.Ye@Sun.COM
223*8221SSean.Ye@Sun.COM return (0);
224*8221SSean.Ye@Sun.COM }
225*8221SSean.Ye@Sun.COM
226*8221SSean.Ye@Sun.COM /* ARGSUSED */
227*8221SSean.Ye@Sun.COM int
cpu_retire(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)228*8221SSean.Ye@Sun.COM cpu_retire(topo_mod_t *mod, tnode_t *node, topo_version_t version,
229*8221SSean.Ye@Sun.COM nvlist_t *in, nvlist_t **out)
230*8221SSean.Ye@Sun.COM {
231*8221SSean.Ye@Sun.COM struct cpu_walk_data swd;
232*8221SSean.Ye@Sun.COM uint32_t rc;
233*8221SSean.Ye@Sun.COM
234*8221SSean.Ye@Sun.COM if (version > TOPO_METH_RETIRE_VERSION)
235*8221SSean.Ye@Sun.COM return (topo_mod_seterrno(mod, EMOD_VER_NEW));
236*8221SSean.Ye@Sun.COM
237*8221SSean.Ye@Sun.COM if (walk_cpus(mod, &swd, node, ldom_fmri_retire) == -1)
238*8221SSean.Ye@Sun.COM return (-1);
239*8221SSean.Ye@Sun.COM
240*8221SSean.Ye@Sun.COM rc = swd.fail > 0 ? FMD_AGENT_RETIRE_FAIL : FMD_AGENT_RETIRE_DONE;
241*8221SSean.Ye@Sun.COM
242*8221SSean.Ye@Sun.COM return (set_retnvl(mod, out, TOPO_METH_RETIRE_RET, rc));
243*8221SSean.Ye@Sun.COM }
244*8221SSean.Ye@Sun.COM
245*8221SSean.Ye@Sun.COM /* ARGSUSED */
246*8221SSean.Ye@Sun.COM int
cpu_unretire(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)247*8221SSean.Ye@Sun.COM cpu_unretire(topo_mod_t *mod, tnode_t *node, topo_version_t version,
248*8221SSean.Ye@Sun.COM nvlist_t *in, nvlist_t **out)
249*8221SSean.Ye@Sun.COM {
250*8221SSean.Ye@Sun.COM struct cpu_walk_data swd;
251*8221SSean.Ye@Sun.COM uint32_t rc;
252*8221SSean.Ye@Sun.COM
253*8221SSean.Ye@Sun.COM if (version > TOPO_METH_UNRETIRE_VERSION)
254*8221SSean.Ye@Sun.COM return (topo_mod_seterrno(mod, EMOD_VER_NEW));
255*8221SSean.Ye@Sun.COM
256*8221SSean.Ye@Sun.COM if (walk_cpus(mod, &swd, node, ldom_fmri_unretire) == -1)
257*8221SSean.Ye@Sun.COM return (-1);
258*8221SSean.Ye@Sun.COM
259*8221SSean.Ye@Sun.COM rc = swd.fail > 0 ? FMD_AGENT_RETIRE_FAIL : FMD_AGENT_RETIRE_DONE;
260*8221SSean.Ye@Sun.COM
261*8221SSean.Ye@Sun.COM return (set_retnvl(mod, out, TOPO_METH_UNRETIRE_RET, rc));
262*8221SSean.Ye@Sun.COM }
263*8221SSean.Ye@Sun.COM
264*8221SSean.Ye@Sun.COM /* ARGSUSED */
265*8221SSean.Ye@Sun.COM int
cpu_service_state(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)266*8221SSean.Ye@Sun.COM cpu_service_state(topo_mod_t *mod, tnode_t *node, topo_version_t version,
267*8221SSean.Ye@Sun.COM nvlist_t *in, nvlist_t **out)
268*8221SSean.Ye@Sun.COM {
269*8221SSean.Ye@Sun.COM struct cpu_walk_data swd;
270*8221SSean.Ye@Sun.COM uint32_t rc;
271*8221SSean.Ye@Sun.COM
272*8221SSean.Ye@Sun.COM if (version > TOPO_METH_SERVICE_STATE_VERSION)
273*8221SSean.Ye@Sun.COM return (topo_mod_seterrno(mod, EMOD_VER_NEW));
274*8221SSean.Ye@Sun.COM
275*8221SSean.Ye@Sun.COM if (walk_cpus(mod, &swd, node, ldom_fmri_status) == -1)
276*8221SSean.Ye@Sun.COM return (-1);
277*8221SSean.Ye@Sun.COM
278*8221SSean.Ye@Sun.COM if (swd.fail > 0)
279*8221SSean.Ye@Sun.COM rc = FMD_SERVICE_STATE_UNKNOWN;
280*8221SSean.Ye@Sun.COM else if (swd.offline > 0)
281*8221SSean.Ye@Sun.COM rc = swd.online > 0 ? FMD_SERVICE_STATE_DEGRADED :
282*8221SSean.Ye@Sun.COM FMD_SERVICE_STATE_UNUSABLE;
283*8221SSean.Ye@Sun.COM else
284*8221SSean.Ye@Sun.COM rc = FMD_SERVICE_STATE_OK;
285*8221SSean.Ye@Sun.COM
286*8221SSean.Ye@Sun.COM return (set_retnvl(mod, out, TOPO_METH_SERVICE_STATE_RET, rc));
287*8221SSean.Ye@Sun.COM }
288*8221SSean.Ye@Sun.COM
289*8221SSean.Ye@Sun.COM /* ARGSUSED */
290*8221SSean.Ye@Sun.COM int
cpu_unusable(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)291*8221SSean.Ye@Sun.COM cpu_unusable(topo_mod_t *mod, tnode_t *node, topo_version_t version,
292*8221SSean.Ye@Sun.COM nvlist_t *in, nvlist_t **out)
293*8221SSean.Ye@Sun.COM {
294*8221SSean.Ye@Sun.COM struct cpu_walk_data swd;
295*8221SSean.Ye@Sun.COM uint32_t rc;
296*8221SSean.Ye@Sun.COM
297*8221SSean.Ye@Sun.COM if (version > TOPO_METH_UNUSABLE_VERSION)
298*8221SSean.Ye@Sun.COM return (topo_mod_seterrno(mod, EMOD_VER_NEW));
299*8221SSean.Ye@Sun.COM
300*8221SSean.Ye@Sun.COM if (walk_cpus(mod, &swd, node, ldom_fmri_status) == -1)
301*8221SSean.Ye@Sun.COM return (-1);
302*8221SSean.Ye@Sun.COM
303*8221SSean.Ye@Sun.COM rc = (swd.offline > 0 && swd.fail + swd.online == 0) ? 1 : 0;
304*8221SSean.Ye@Sun.COM
305*8221SSean.Ye@Sun.COM return (set_retnvl(mod, out, TOPO_METH_UNUSABLE_RET, rc));
306*8221SSean.Ye@Sun.COM }
307*8221SSean.Ye@Sun.COM
308*8221SSean.Ye@Sun.COM static nvlist_t *
mem_fmri_create(topo_mod_t * mod,char * serial,char * label)309*8221SSean.Ye@Sun.COM mem_fmri_create(topo_mod_t *mod, char *serial, char *label)
310*8221SSean.Ye@Sun.COM {
311*8221SSean.Ye@Sun.COM int err;
312*8221SSean.Ye@Sun.COM nvlist_t *fmri;
313*8221SSean.Ye@Sun.COM
314*8221SSean.Ye@Sun.COM if (topo_mod_nvalloc(mod, &fmri, NV_UNIQUE_NAME) != 0)
315*8221SSean.Ye@Sun.COM return (NULL);
316*8221SSean.Ye@Sun.COM err = nvlist_add_uint8(fmri, FM_VERSION, FM_MEM_SCHEME_VERSION);
317*8221SSean.Ye@Sun.COM err |= nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_MEM);
318*8221SSean.Ye@Sun.COM if (serial != NULL)
319*8221SSean.Ye@Sun.COM err |= nvlist_add_string_array(fmri, FM_FMRI_MEM_SERIAL_ID,
320*8221SSean.Ye@Sun.COM &serial, 1);
321*8221SSean.Ye@Sun.COM if (label != NULL)
322*8221SSean.Ye@Sun.COM err |= nvlist_add_string(fmri, FM_FMRI_MEM_UNUM, label);
323*8221SSean.Ye@Sun.COM if (err != 0) {
324*8221SSean.Ye@Sun.COM nvlist_free(fmri);
325*8221SSean.Ye@Sun.COM (void) topo_mod_seterrno(mod, EMOD_FMRI_NVL);
326*8221SSean.Ye@Sun.COM return (NULL);
327*8221SSean.Ye@Sun.COM }
328*8221SSean.Ye@Sun.COM
329*8221SSean.Ye@Sun.COM return (fmri);
330*8221SSean.Ye@Sun.COM }
331*8221SSean.Ye@Sun.COM
332*8221SSean.Ye@Sun.COM /* Topo Methods */
333*8221SSean.Ye@Sun.COM static int
mem_asru_compute(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)334*8221SSean.Ye@Sun.COM mem_asru_compute(topo_mod_t *mod, tnode_t *node, topo_version_t version,
335*8221SSean.Ye@Sun.COM nvlist_t *in, nvlist_t **out)
336*8221SSean.Ye@Sun.COM {
337*8221SSean.Ye@Sun.COM nvlist_t *asru, *pargs, *args, *hcsp;
338*8221SSean.Ye@Sun.COM int err;
339*8221SSean.Ye@Sun.COM char *serial = NULL, *label = NULL;
340*8221SSean.Ye@Sun.COM uint64_t pa, offset;
341*8221SSean.Ye@Sun.COM
342*8221SSean.Ye@Sun.COM if (version > TOPO_METH_ASRU_COMPUTE_VERSION)
343*8221SSean.Ye@Sun.COM return (topo_mod_seterrno(mod, EMOD_VER_NEW));
344*8221SSean.Ye@Sun.COM
345*8221SSean.Ye@Sun.COM if (strcmp(topo_node_name(node), DIMM) != 0)
346*8221SSean.Ye@Sun.COM return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
347*8221SSean.Ye@Sun.COM
348*8221SSean.Ye@Sun.COM pargs = NULL;
349*8221SSean.Ye@Sun.COM
350*8221SSean.Ye@Sun.COM if (nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &pargs) == 0)
351*8221SSean.Ye@Sun.COM (void) nvlist_lookup_string(pargs, FM_FMRI_HC_SERIAL_ID,
352*8221SSean.Ye@Sun.COM &serial);
353*8221SSean.Ye@Sun.COM if (serial == NULL &&
354*8221SSean.Ye@Sun.COM nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args) == 0)
355*8221SSean.Ye@Sun.COM (void) nvlist_lookup_string(args, FM_FMRI_HC_SERIAL_ID,
356*8221SSean.Ye@Sun.COM &serial);
357*8221SSean.Ye@Sun.COM
358*8221SSean.Ye@Sun.COM (void) topo_node_label(node, &label, &err);
359*8221SSean.Ye@Sun.COM
360*8221SSean.Ye@Sun.COM asru = mem_fmri_create(mod, serial, label);
361*8221SSean.Ye@Sun.COM
362*8221SSean.Ye@Sun.COM if (label != NULL)
363*8221SSean.Ye@Sun.COM topo_mod_strfree(mod, label);
364*8221SSean.Ye@Sun.COM
365*8221SSean.Ye@Sun.COM if (asru == NULL)
366*8221SSean.Ye@Sun.COM return (topo_mod_seterrno(mod, EMOD_NOMEM));
367*8221SSean.Ye@Sun.COM
368*8221SSean.Ye@Sun.COM err = 0;
369*8221SSean.Ye@Sun.COM
370*8221SSean.Ye@Sun.COM /*
371*8221SSean.Ye@Sun.COM * For a memory page, 'in' includes an hc-specific member which
372*8221SSean.Ye@Sun.COM * specifies physaddr and/or offset. Set them in asru as well.
373*8221SSean.Ye@Sun.COM */
374*8221SSean.Ye@Sun.COM if (pargs && nvlist_lookup_nvlist(pargs,
375*8221SSean.Ye@Sun.COM FM_FMRI_HC_SPECIFIC, &hcsp) == 0) {
376*8221SSean.Ye@Sun.COM if (nvlist_lookup_uint64(hcsp,
377*8221SSean.Ye@Sun.COM FM_FMRI_HC_SPECIFIC_PHYSADDR, &pa) == 0)
378*8221SSean.Ye@Sun.COM err += nvlist_add_uint64(asru, FM_FMRI_MEM_PHYSADDR,
379*8221SSean.Ye@Sun.COM pa);
380*8221SSean.Ye@Sun.COM if (nvlist_lookup_uint64(hcsp,
381*8221SSean.Ye@Sun.COM FM_FMRI_HC_SPECIFIC_OFFSET, &offset) == 0)
382*8221SSean.Ye@Sun.COM err += nvlist_add_uint64(asru, FM_FMRI_MEM_OFFSET,
383*8221SSean.Ye@Sun.COM offset);
384*8221SSean.Ye@Sun.COM }
385*8221SSean.Ye@Sun.COM
386*8221SSean.Ye@Sun.COM
387*8221SSean.Ye@Sun.COM if (err != 0 || topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) < 0) {
388*8221SSean.Ye@Sun.COM nvlist_free(asru);
389*8221SSean.Ye@Sun.COM return (topo_mod_seterrno(mod, EMOD_NOMEM));
390*8221SSean.Ye@Sun.COM }
391*8221SSean.Ye@Sun.COM
392*8221SSean.Ye@Sun.COM err = nvlist_add_string(*out, TOPO_PROP_VAL_NAME, TOPO_PROP_ASRU);
393*8221SSean.Ye@Sun.COM err |= nvlist_add_uint32(*out, TOPO_PROP_VAL_TYPE, TOPO_TYPE_FMRI);
394*8221SSean.Ye@Sun.COM err |= nvlist_add_nvlist(*out, TOPO_PROP_VAL_VAL, asru);
395*8221SSean.Ye@Sun.COM nvlist_free(asru);
396*8221SSean.Ye@Sun.COM
397*8221SSean.Ye@Sun.COM if (err != 0) {
398*8221SSean.Ye@Sun.COM nvlist_free(*out);
399*8221SSean.Ye@Sun.COM *out = NULL;
400*8221SSean.Ye@Sun.COM return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
401*8221SSean.Ye@Sun.COM }
402*8221SSean.Ye@Sun.COM
403*8221SSean.Ye@Sun.COM return (0);
404*8221SSean.Ye@Sun.COM }
405*8221SSean.Ye@Sun.COM
406*8221SSean.Ye@Sun.COM static boolean_t
is_page_fmri(nvlist_t * nvl)407*8221SSean.Ye@Sun.COM is_page_fmri(nvlist_t *nvl)
408*8221SSean.Ye@Sun.COM {
409*8221SSean.Ye@Sun.COM nvlist_t *hcsp;
410*8221SSean.Ye@Sun.COM uint64_t val;
411*8221SSean.Ye@Sun.COM
412*8221SSean.Ye@Sun.COM if (nvlist_lookup_nvlist(nvl, FM_FMRI_HC_SPECIFIC, &hcsp) == 0 &&
413*8221SSean.Ye@Sun.COM (nvlist_lookup_uint64(hcsp, FM_FMRI_HC_SPECIFIC_OFFSET,
414*8221SSean.Ye@Sun.COM &val) == 0 ||
415*8221SSean.Ye@Sun.COM nvlist_lookup_uint64(hcsp, "asru-" FM_FMRI_HC_SPECIFIC_OFFSET,
416*8221SSean.Ye@Sun.COM &val) == 0 ||
417*8221SSean.Ye@Sun.COM nvlist_lookup_uint64(hcsp, FM_FMRI_HC_SPECIFIC_PHYSADDR,
418*8221SSean.Ye@Sun.COM &val) == 0 ||
419*8221SSean.Ye@Sun.COM nvlist_lookup_uint64(hcsp, "asru-" FM_FMRI_HC_SPECIFIC_PHYSADDR,
420*8221SSean.Ye@Sun.COM &val) == 0))
421*8221SSean.Ye@Sun.COM return (B_TRUE);
422*8221SSean.Ye@Sun.COM
423*8221SSean.Ye@Sun.COM return (B_FALSE);
424*8221SSean.Ye@Sun.COM }
425*8221SSean.Ye@Sun.COM
426*8221SSean.Ye@Sun.COM static int
dimm_page_service_state(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)427*8221SSean.Ye@Sun.COM dimm_page_service_state(topo_mod_t *mod, tnode_t *node, topo_version_t version,
428*8221SSean.Ye@Sun.COM nvlist_t *in, nvlist_t **out)
429*8221SSean.Ye@Sun.COM {
430*8221SSean.Ye@Sun.COM uint32_t rc = FMD_SERVICE_STATE_OK;
431*8221SSean.Ye@Sun.COM nvlist_t *asru;
432*8221SSean.Ye@Sun.COM int err;
433*8221SSean.Ye@Sun.COM
434*8221SSean.Ye@Sun.COM if (version > TOPO_METH_SERVICE_STATE_VERSION)
435*8221SSean.Ye@Sun.COM return (topo_mod_seterrno(mod, EMOD_VER_NEW));
436*8221SSean.Ye@Sun.COM
437*8221SSean.Ye@Sun.COM if (pi_lhp != NULL && is_page_fmri(in) &&
438*8221SSean.Ye@Sun.COM topo_node_asru(node, &asru, in, &err) == 0) {
439*8221SSean.Ye@Sun.COM err = ldom_fmri_status(pi_lhp, asru);
440*8221SSean.Ye@Sun.COM
441*8221SSean.Ye@Sun.COM if (err == 0 || err == EINVAL)
442*8221SSean.Ye@Sun.COM rc = FMD_SERVICE_STATE_UNUSABLE;
443*8221SSean.Ye@Sun.COM else if (err == EAGAIN)
444*8221SSean.Ye@Sun.COM rc = FMD_SERVICE_STATE_ISOLATE_PENDING;
445*8221SSean.Ye@Sun.COM nvlist_free(asru);
446*8221SSean.Ye@Sun.COM }
447*8221SSean.Ye@Sun.COM
448*8221SSean.Ye@Sun.COM return (set_retnvl(mod, out, TOPO_METH_SERVICE_STATE_RET, rc));
449*8221SSean.Ye@Sun.COM }
450*8221SSean.Ye@Sun.COM
451*8221SSean.Ye@Sun.COM static int
dimm_page_unusable(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)452*8221SSean.Ye@Sun.COM dimm_page_unusable(topo_mod_t *mod, tnode_t *node, topo_version_t version,
453*8221SSean.Ye@Sun.COM nvlist_t *in, nvlist_t **out)
454*8221SSean.Ye@Sun.COM {
455*8221SSean.Ye@Sun.COM uint32_t rc = 0;
456*8221SSean.Ye@Sun.COM nvlist_t *asru;
457*8221SSean.Ye@Sun.COM int err;
458*8221SSean.Ye@Sun.COM
459*8221SSean.Ye@Sun.COM if (version > TOPO_METH_UNUSABLE_VERSION)
460*8221SSean.Ye@Sun.COM return (topo_mod_seterrno(mod, EMOD_VER_NEW));
461*8221SSean.Ye@Sun.COM
462*8221SSean.Ye@Sun.COM if (pi_lhp != NULL && is_page_fmri(in) &&
463*8221SSean.Ye@Sun.COM topo_node_asru(node, &asru, in, &err) == 0) {
464*8221SSean.Ye@Sun.COM err = ldom_fmri_status(pi_lhp, asru);
465*8221SSean.Ye@Sun.COM
466*8221SSean.Ye@Sun.COM if (err == 0 || err == EINVAL)
467*8221SSean.Ye@Sun.COM rc = 1;
468*8221SSean.Ye@Sun.COM nvlist_free(asru);
469*8221SSean.Ye@Sun.COM }
470*8221SSean.Ye@Sun.COM
471*8221SSean.Ye@Sun.COM return (set_retnvl(mod, out, TOPO_METH_UNUSABLE_RET, rc));
472*8221SSean.Ye@Sun.COM }
473*8221SSean.Ye@Sun.COM
474*8221SSean.Ye@Sun.COM static int
dimm_page_retire(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)475*8221SSean.Ye@Sun.COM dimm_page_retire(topo_mod_t *mod, tnode_t *node, topo_version_t version,
476*8221SSean.Ye@Sun.COM nvlist_t *in, nvlist_t **out)
477*8221SSean.Ye@Sun.COM {
478*8221SSean.Ye@Sun.COM uint32_t rc = FMD_AGENT_RETIRE_FAIL;
479*8221SSean.Ye@Sun.COM nvlist_t *asru;
480*8221SSean.Ye@Sun.COM int err;
481*8221SSean.Ye@Sun.COM
482*8221SSean.Ye@Sun.COM if (version > TOPO_METH_RETIRE_VERSION)
483*8221SSean.Ye@Sun.COM return (topo_mod_seterrno(mod, EMOD_VER_NEW));
484*8221SSean.Ye@Sun.COM
485*8221SSean.Ye@Sun.COM if (pi_lhp != NULL && is_page_fmri(in) &&
486*8221SSean.Ye@Sun.COM topo_node_asru(node, &asru, in, &err) == 0) {
487*8221SSean.Ye@Sun.COM err = ldom_fmri_retire(pi_lhp, asru);
488*8221SSean.Ye@Sun.COM
489*8221SSean.Ye@Sun.COM if (err == 0 || err == EIO || err == EINVAL)
490*8221SSean.Ye@Sun.COM rc = FMD_AGENT_RETIRE_DONE;
491*8221SSean.Ye@Sun.COM else if (err == EAGAIN)
492*8221SSean.Ye@Sun.COM rc = FMD_AGENT_RETIRE_ASYNC;
493*8221SSean.Ye@Sun.COM nvlist_free(asru);
494*8221SSean.Ye@Sun.COM }
495*8221SSean.Ye@Sun.COM
496*8221SSean.Ye@Sun.COM return (set_retnvl(mod, out, TOPO_METH_RETIRE_RET, rc));
497*8221SSean.Ye@Sun.COM }
498*8221SSean.Ye@Sun.COM
499*8221SSean.Ye@Sun.COM static int
dimm_page_unretire(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)500*8221SSean.Ye@Sun.COM dimm_page_unretire(topo_mod_t *mod, tnode_t *node, topo_version_t version,
501*8221SSean.Ye@Sun.COM nvlist_t *in, nvlist_t **out)
502*8221SSean.Ye@Sun.COM {
503*8221SSean.Ye@Sun.COM uint32_t rc = FMD_AGENT_RETIRE_FAIL;
504*8221SSean.Ye@Sun.COM nvlist_t *asru;
505*8221SSean.Ye@Sun.COM int err;
506*8221SSean.Ye@Sun.COM
507*8221SSean.Ye@Sun.COM if (version > TOPO_METH_UNRETIRE_VERSION)
508*8221SSean.Ye@Sun.COM return (topo_mod_seterrno(mod, EMOD_VER_NEW));
509*8221SSean.Ye@Sun.COM
510*8221SSean.Ye@Sun.COM if (pi_lhp != NULL && is_page_fmri(in) &&
511*8221SSean.Ye@Sun.COM topo_node_asru(node, &asru, in, &err) == 0) {
512*8221SSean.Ye@Sun.COM err = ldom_fmri_unretire(pi_lhp, asru);
513*8221SSean.Ye@Sun.COM
514*8221SSean.Ye@Sun.COM if (err == 0 || err == EIO)
515*8221SSean.Ye@Sun.COM rc = FMD_AGENT_RETIRE_DONE;
516*8221SSean.Ye@Sun.COM nvlist_free(asru);
517*8221SSean.Ye@Sun.COM }
518*8221SSean.Ye@Sun.COM
519*8221SSean.Ye@Sun.COM return (set_retnvl(mod, out, TOPO_METH_UNRETIRE_RET, rc));
520*8221SSean.Ye@Sun.COM }
521