1*2eeaed14Srobj /*
2*2eeaed14Srobj  * CDDL HEADER START
3*2eeaed14Srobj  *
4*2eeaed14Srobj  * The contents of this file are subject to the terms of the
5*2eeaed14Srobj  * Common Development and Distribution License (the "License").
6*2eeaed14Srobj  * You may not use this file except in compliance with the License.
7*2eeaed14Srobj  *
8*2eeaed14Srobj  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*2eeaed14Srobj  * or http://www.opensolaris.org/os/licensing.
10*2eeaed14Srobj  * See the License for the specific language governing permissions
11*2eeaed14Srobj  * and limitations under the License.
12*2eeaed14Srobj  *
13*2eeaed14Srobj  * When distributing Covered Code, include this CDDL HEADER in each
14*2eeaed14Srobj  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*2eeaed14Srobj  * If applicable, add the following below this CDDL HEADER, with the
16*2eeaed14Srobj  * fields enclosed by brackets "[]" replaced with your own identifying
17*2eeaed14Srobj  * information: Portions Copyright [yyyy] [name of copyright owner]
18*2eeaed14Srobj  *
19*2eeaed14Srobj  * CDDL HEADER END
20*2eeaed14Srobj  */
21*2eeaed14Srobj 
22*2eeaed14Srobj /*
23*2eeaed14Srobj  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24*2eeaed14Srobj  * Use is subject to license terms.
25*2eeaed14Srobj  */
26*2eeaed14Srobj 
27*2eeaed14Srobj #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*2eeaed14Srobj 
29*2eeaed14Srobj #include <stdio.h>
30*2eeaed14Srobj #include <stdlib.h>
31*2eeaed14Srobj #include <stdarg.h>
32*2eeaed14Srobj #include <string.h>
33*2eeaed14Srobj #include <strings.h>
34*2eeaed14Srobj #include <libnvpair.h>
35*2eeaed14Srobj #include <sys/types.h>
36*2eeaed14Srobj #include <fm/topo_mod.h>
37*2eeaed14Srobj 
38*2eeaed14Srobj #define	BUFSZ	128
39*2eeaed14Srobj 
40*2eeaed14Srobj static char *
41*2eeaed14Srobj get_fmtstr(topo_mod_t *mod, nvlist_t *in)
42*2eeaed14Srobj {
43*2eeaed14Srobj 	char *fmtstr;
44*2eeaed14Srobj 	nvlist_t *args;
45*2eeaed14Srobj 	int ret;
46*2eeaed14Srobj 
47*2eeaed14Srobj 	topo_mod_dprintf(mod, "get_fmtstr() called\n");
48*2eeaed14Srobj 
49*2eeaed14Srobj 	if ((ret = nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args)) != 0) {
50*2eeaed14Srobj 		topo_mod_dprintf(mod, "Failed to lookup 'args' list (%s)\n",
51*2eeaed14Srobj 		    strerror(ret));
52*2eeaed14Srobj 		(void) topo_mod_seterrno(mod, EMOD_NVL_INVAL);
53*2eeaed14Srobj 		return (NULL);
54*2eeaed14Srobj 	}
55*2eeaed14Srobj 	if ((ret = nvlist_lookup_string(args, "format", &fmtstr)) != 0) {
56*2eeaed14Srobj 		topo_mod_dprintf(mod, "Failed to lookup 'format' arg (%s)\n",
57*2eeaed14Srobj 		    strerror(ret));
58*2eeaed14Srobj 		(void) topo_mod_seterrno(mod, EMOD_NVL_INVAL);
59*2eeaed14Srobj 		return (NULL);
60*2eeaed14Srobj 	}
61*2eeaed14Srobj 	return (fmtstr);
62*2eeaed14Srobj }
63*2eeaed14Srobj 
64*2eeaed14Srobj static int
65*2eeaed14Srobj store_prop_val(topo_mod_t *mod, void *buf, char *propname, topo_type_t type,
66*2eeaed14Srobj     nvlist_t **out)
67*2eeaed14Srobj {
68*2eeaed14Srobj 	if (topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) != 0) {
69*2eeaed14Srobj 		topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
70*2eeaed14Srobj 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
71*2eeaed14Srobj 	}
72*2eeaed14Srobj 	if (nvlist_add_string(*out, TOPO_PROP_VAL_NAME, propname) != 0) {
73*2eeaed14Srobj 		topo_mod_dprintf(mod, "Failed to set '%s'\n",
74*2eeaed14Srobj 		    TOPO_PROP_VAL_NAME);
75*2eeaed14Srobj 		nvlist_free(*out);
76*2eeaed14Srobj 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
77*2eeaed14Srobj 	}
78*2eeaed14Srobj 	if (nvlist_add_uint32(*out, TOPO_PROP_VAL_TYPE, type)
79*2eeaed14Srobj 	    != 0) {
80*2eeaed14Srobj 		topo_mod_dprintf(mod, "Failed to set '%s'\n",
81*2eeaed14Srobj 		    TOPO_PROP_VAL_TYPE);
82*2eeaed14Srobj 		nvlist_free(*out);
83*2eeaed14Srobj 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
84*2eeaed14Srobj 	}
85*2eeaed14Srobj 	if (type == TOPO_TYPE_STRING) {
86*2eeaed14Srobj 		if (nvlist_add_string(*out, TOPO_PROP_VAL_VAL, (char *)buf)
87*2eeaed14Srobj 		    != 0) {
88*2eeaed14Srobj 			topo_mod_dprintf(mod, "Failed to set '%s'\n",
89*2eeaed14Srobj 			    TOPO_PROP_VAL_VAL);
90*2eeaed14Srobj 			nvlist_free(*out);
91*2eeaed14Srobj 			return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
92*2eeaed14Srobj 		}
93*2eeaed14Srobj 	} else if (type == TOPO_TYPE_FMRI)
94*2eeaed14Srobj 		if (nvlist_add_nvlist(*out, TOPO_PROP_VAL_VAL, (nvlist_t *)buf)
95*2eeaed14Srobj 		    != 0) {
96*2eeaed14Srobj 			topo_mod_dprintf(mod, "Failed to set '%s'\n",
97*2eeaed14Srobj 			    TOPO_PROP_VAL_VAL);
98*2eeaed14Srobj 			nvlist_free(*out);
99*2eeaed14Srobj 			return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
100*2eeaed14Srobj 		}
101*2eeaed14Srobj 	return (0);
102*2eeaed14Srobj }
103*2eeaed14Srobj 
104*2eeaed14Srobj /*
105*2eeaed14Srobj  * This is a somewhat generic property method for labelling the PSU and fan
106*2eeaed14Srobj  * FRU's that we're enumerating.  It takes the following three arguments:
107*2eeaed14Srobj  *
108*2eeaed14Srobj  * format:	a string containing a printf-like format with a two %d tokens
109*2eeaed14Srobj  *              for the cpu and dimm slot label numbers, which this method
110*2eeaed14Srobj  *              computes
111*2eeaed14Srobj  *
112*2eeaed14Srobj  *              i.e.: Fan %d
113*2eeaed14Srobj  *
114*2eeaed14Srobj  * offset:      a numeric offset that we'll number the FRU's from.  This is to
115*2eeaed14Srobj  *              allow for the fact that some systems may number the FRU's
116*2eeaed14Srobj  *              from zero while others may start from one
117*2eeaed14Srobj  */
118*2eeaed14Srobj /* ARGSUSED */
119*2eeaed14Srobj int
120*2eeaed14Srobj ipmi_fru_label(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
121*2eeaed14Srobj     nvlist_t *in, nvlist_t **out)
122*2eeaed14Srobj {
123*2eeaed14Srobj 	char *fmtstr, buf[BUFSZ];
124*2eeaed14Srobj 	int ret;
125*2eeaed14Srobj 	uint32_t offset;
126*2eeaed14Srobj 	nvlist_t *args;
127*2eeaed14Srobj 
128*2eeaed14Srobj 	topo_mod_dprintf(mod, "ipmi_fru_label() called\n");
129*2eeaed14Srobj 	if ((ret = nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args)) != 0) {
130*2eeaed14Srobj 		topo_mod_dprintf(mod, "Failed to lookup 'args' list (%s)\n",
131*2eeaed14Srobj 		    strerror(ret));
132*2eeaed14Srobj 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
133*2eeaed14Srobj 	}
134*2eeaed14Srobj 	if ((ret = nvlist_lookup_uint32(args, "offset", &offset)) != 0) {
135*2eeaed14Srobj 		topo_mod_dprintf(mod, "Failed to lookup 'offset' arg (%s)\n",
136*2eeaed14Srobj 		    strerror(ret));
137*2eeaed14Srobj 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
138*2eeaed14Srobj 	}
139*2eeaed14Srobj 
140*2eeaed14Srobj 	if ((fmtstr = get_fmtstr(mod, in)) == NULL) {
141*2eeaed14Srobj 		topo_mod_dprintf(mod, "Failed to retrieve 'format' arg\n");
142*2eeaed14Srobj 		/* topo errno already set */
143*2eeaed14Srobj 		return (-1);
144*2eeaed14Srobj 	}
145*2eeaed14Srobj 
146*2eeaed14Srobj 	/* LINTED: E_SEC_PRINTF_VAR_FMT */
147*2eeaed14Srobj 	(void) snprintf(buf, BUFSZ, fmtstr,
148*2eeaed14Srobj 	    (topo_node_instance(node) + offset));
149*2eeaed14Srobj 
150*2eeaed14Srobj 	if (store_prop_val(mod, (void *)buf, "label", TOPO_TYPE_STRING, out)
151*2eeaed14Srobj 	    != 0) {
152*2eeaed14Srobj 		topo_mod_dprintf(mod, "Failed to set label\n");
153*2eeaed14Srobj 		/* topo errno already set */
154*2eeaed14Srobj 		return (-1);
155*2eeaed14Srobj 	}
156*2eeaed14Srobj 
157*2eeaed14Srobj 	return (0);
158*2eeaed14Srobj }
159*2eeaed14Srobj /*
160*2eeaed14Srobj  * This is a somewhat generic property method for attaching a FRU fmri onto
161*2eeaed14Srobj  * a power supply or fan based on the assumption that the FRU will either be
162*2eeaed14Srobj  * the fan/psu itself or the parent node.
163*2eeaed14Srobj  *
164*2eeaed14Srobj  * entity:	either "self" or "parent"
165*2eeaed14Srobj  */
166*2eeaed14Srobj /* ARGSUSED */
167*2eeaed14Srobj int
168*2eeaed14Srobj ipmi_fru_fmri(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
169*2eeaed14Srobj     nvlist_t *in, nvlist_t **out)
170*2eeaed14Srobj {
171*2eeaed14Srobj 	char *entity;
172*2eeaed14Srobj 	int ret, err;
173*2eeaed14Srobj 	nvlist_t *args, *fru;
174*2eeaed14Srobj 
175*2eeaed14Srobj 	topo_mod_dprintf(mod, "ipmi_fru_fmri() called\n");
176*2eeaed14Srobj 	if ((ret = nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args)) != 0) {
177*2eeaed14Srobj 		topo_mod_dprintf(mod, "Failed to lookup 'args' list (%s)\n",
178*2eeaed14Srobj 		    strerror(ret));
179*2eeaed14Srobj 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
180*2eeaed14Srobj 	}
181*2eeaed14Srobj 	if ((ret = nvlist_lookup_string(args, "entity", &entity)) != 0) {
182*2eeaed14Srobj 		topo_mod_dprintf(mod, "Failed to lookup 'entity' arg (%s)\n",
183*2eeaed14Srobj 		    strerror(ret));
184*2eeaed14Srobj 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
185*2eeaed14Srobj 	}
186*2eeaed14Srobj 
187*2eeaed14Srobj 	if (strcasecmp(entity, "self") == 0) {
188*2eeaed14Srobj 		if (topo_node_resource(node, &fru, &err) != 0)
189*2eeaed14Srobj 			return (-1);
190*2eeaed14Srobj 	} else if (strcasecmp(entity, "parent") == 0) {
191*2eeaed14Srobj 		if (topo_node_resource(topo_node_parent(node), &fru, &err) != 0)
192*2eeaed14Srobj 			return (-1);
193*2eeaed14Srobj 	} else {
194*2eeaed14Srobj 		topo_mod_dprintf(mod, "Invalid 'entity' value\n");
195*2eeaed14Srobj 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
196*2eeaed14Srobj 	}
197*2eeaed14Srobj 
198*2eeaed14Srobj 	if (store_prop_val(mod, (void *)fru, "FRU", TOPO_TYPE_FMRI, out) != 0) {
199*2eeaed14Srobj 		nvlist_free(fru);
200*2eeaed14Srobj 		topo_mod_dprintf(mod, "Failed to set FRU\n");
201*2eeaed14Srobj 		/* topo errno already set */
202*2eeaed14Srobj 		return (-1);
203*2eeaed14Srobj 	}
204*2eeaed14Srobj 
205*2eeaed14Srobj 	nvlist_free(fru);
206*2eeaed14Srobj 
207*2eeaed14Srobj 	return (0);
208*2eeaed14Srobj }
209