xref: /illumos-gate/usr/src/cmd/fm/schemes/hc/scheme.c (revision cbab2b2687744cbfdc12fae90f8088127a0b266c)
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  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <fm/topo_mod.h>
29 #include <fm/fmd_fmri.h>
30 #include <fm/libtopo.h>
31 
32 typedef struct hc_walk_arg {
33 	void	*p;
34 	int	*resultp;
35 } hc_walk_arg_t;
36 
37 static topo_hdl_t	*HC_thp = NULL;
38 static char		*HC_uuid = NULL;
39 
40 int
41 fmd_fmri_init(void)
42 {
43 	int err;
44 
45 	if ((HC_thp = topo_open(TOPO_VERSION, NULL, &err)) == NULL)
46 		return (-1);
47 
48 	return (0);
49 }
50 
51 void
52 fmd_fmri_fini(void)
53 {
54 	if (HC_uuid) {
55 		topo_snap_release(HC_thp);
56 		topo_hdl_strfree(HC_thp, HC_uuid);
57 		HC_uuid = NULL;
58 	}
59 	topo_close(HC_thp);
60 }
61 
62 static int
63 hc_update_topology(void)
64 {
65 	static uint64_t lastgen = 0;
66 	int err;
67 	uint64_t curgen;
68 
69 	if (HC_uuid == NULL ||
70 	    (curgen = fmd_fmri_get_drgen()) > lastgen) {
71 
72 		lastgen = curgen;
73 
74 		if (HC_uuid) {
75 			topo_snap_release(HC_thp);
76 			topo_hdl_strfree(HC_thp, HC_uuid);
77 			HC_uuid = NULL;
78 		}
79 
80 		if ((HC_uuid = topo_snap_hold(HC_thp, NULL, &err)) == NULL) {
81 			return (-1);
82 		}
83 	}
84 	return (0);
85 }
86 
87 static int
88 hc_topo_walk(topo_walk_cb_t fn, void *arg, int *resultp)
89 {
90 	int err, rv;
91 	topo_walk_t *twp;
92 	hc_walk_arg_t hcarg;
93 
94 	hcarg.p = arg;
95 	hcarg.resultp = resultp;
96 
97 	if ((twp = topo_walk_init(HC_thp, FM_FMRI_SCHEME_HC, fn,
98 	    &hcarg, &err)) == NULL)
99 		return (-1);
100 
101 	rv = (topo_walk_step(twp, TOPO_WALK_CHILD) == TOPO_WALK_ERR)
102 	    ? -1 : 0;
103 
104 	topo_walk_fini(twp);
105 	return (rv);
106 }
107 
108 /*
109  * buf_append -- Append str to buf (if it's non-NULL).  Place prepend
110  * in buf in front of str and append behind it (if they're non-NULL).
111  * Continue to update size even if we run out of space to actually
112  * stuff characters in the buffer.
113  */
114 static void
115 buf_append(ssize_t *sz, char *buf, size_t buflen, char *str,
116     char *prepend, char *append)
117 {
118 	ssize_t left;
119 
120 	if (str == NULL)
121 		return;
122 
123 	if (buflen == 0 || (left = buflen - *sz) < 0)
124 		left = 0;
125 
126 	if (buf != NULL && left != 0)
127 		buf += *sz;
128 
129 	if (prepend == NULL && append == NULL)
130 		*sz += snprintf(buf, left, "%s", str);
131 	else if (append == NULL)
132 		*sz += snprintf(buf, left, "%s%s", prepend, str);
133 	else if (prepend == NULL)
134 		*sz += snprintf(buf, left, "%s%s", str, append);
135 	else
136 		*sz += snprintf(buf, left, "%s%s%s", prepend, str, append);
137 }
138 
139 ssize_t
140 fmd_fmri_nvl2str(nvlist_t *nvl, char *buf, size_t buflen)
141 {
142 	nvlist_t **hcprs = NULL;
143 	nvlist_t *anvl = NULL;
144 	uint8_t version;
145 	ssize_t size = 0;
146 	uint_t hcnprs;
147 	char *achas = NULL;
148 	char *adom = NULL;
149 	char *aprod = NULL;
150 	char *asrvr = NULL;
151 	char *ahost = NULL;
152 	char *serial = NULL;
153 	char *part = NULL;
154 	char *root = NULL;
155 	char *rev = NULL;
156 	int more_auth = 0;
157 	int err, i;
158 
159 	if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 ||
160 	    version > FM_HC_SCHEME_VERSION)
161 		return (fmd_fmri_set_errno(EINVAL));
162 
163 	/* Get authority, if present */
164 	err = nvlist_lookup_nvlist(nvl, FM_FMRI_AUTHORITY, &anvl);
165 	if (err != 0 && err != ENOENT)
166 		return (fmd_fmri_set_errno(err));
167 
168 	if ((err = nvlist_lookup_string(nvl, FM_FMRI_HC_ROOT, &root)) != 0)
169 		return (fmd_fmri_set_errno(EINVAL));
170 
171 	err = nvlist_lookup_nvlist_array(nvl, FM_FMRI_HC_LIST, &hcprs, &hcnprs);
172 	if (err != 0 || hcprs == NULL)
173 		return (fmd_fmri_set_errno(EINVAL));
174 
175 	if (anvl != NULL) {
176 		(void) nvlist_lookup_string(anvl,
177 		    FM_FMRI_AUTH_PRODUCT, &aprod);
178 		(void) nvlist_lookup_string(anvl,
179 		    FM_FMRI_AUTH_CHASSIS, &achas);
180 		(void) nvlist_lookup_string(anvl,
181 		    FM_FMRI_AUTH_DOMAIN, &adom);
182 		(void) nvlist_lookup_string(anvl,
183 		    FM_FMRI_AUTH_SERVER, &asrvr);
184 		(void) nvlist_lookup_string(anvl,
185 		    FM_FMRI_AUTH_HOST, &ahost);
186 		if (aprod != NULL)
187 			more_auth++;
188 		if (achas != NULL)
189 			more_auth++;
190 		if (adom != NULL)
191 			more_auth++;
192 		if (asrvr != NULL)
193 			more_auth++;
194 		if (ahost != NULL)
195 			more_auth++;
196 	}
197 
198 	(void) nvlist_lookup_string(nvl, FM_FMRI_HC_SERIAL_ID, &serial);
199 	(void) nvlist_lookup_string(nvl, FM_FMRI_HC_PART, &part);
200 	(void) nvlist_lookup_string(nvl, FM_FMRI_HC_REVISION, &rev);
201 
202 	/* hc:// */
203 	buf_append(&size, buf, buflen, FM_FMRI_SCHEME_HC, NULL, "://");
204 
205 	/* authority, if any */
206 	if (aprod != NULL)
207 		buf_append(&size, buf, buflen, aprod, FM_FMRI_AUTH_PRODUCT "=",
208 		    --more_auth > 0 ? "," : NULL);
209 	if (achas != NULL)
210 		buf_append(&size, buf, buflen, achas, FM_FMRI_AUTH_CHASSIS "=",
211 		    --more_auth > 0 ? "," : NULL);
212 	if (adom != NULL)
213 		buf_append(&size, buf, buflen, adom, FM_FMRI_AUTH_DOMAIN "=",
214 		    --more_auth > 0 ? "," : NULL);
215 	if (asrvr != NULL)
216 		buf_append(&size, buf, buflen, asrvr, FM_FMRI_AUTH_SERVER "=",
217 		    --more_auth > 0 ? "," : NULL);
218 	if (ahost != NULL)
219 		buf_append(&size, buf, buflen, ahost, FM_FMRI_AUTH_HOST "=",
220 		    NULL);
221 
222 	/* separating slash */
223 	if (serial != NULL || part != NULL || rev != NULL)
224 		buf_append(&size, buf, buflen, "/", NULL, NULL);
225 
226 	/* hardware-id part */
227 	buf_append(&size, buf, buflen, serial, ":" FM_FMRI_HC_SERIAL_ID "=",
228 	    NULL);
229 	buf_append(&size, buf, buflen, part, ":" FM_FMRI_HC_PART "=", NULL);
230 	buf_append(&size, buf, buflen, rev, ":" FM_FMRI_HC_REVISION "=", NULL);
231 
232 	/* separating slash */
233 	buf_append(&size, buf, buflen, "/", NULL, NULL);
234 
235 	/* hc-root */
236 	buf_append(&size, buf, buflen, root, NULL, NULL);
237 
238 	/* all the pairs */
239 	for (i = 0; i < hcnprs; i++) {
240 		char *nm = NULL;
241 		char *id = NULL;
242 
243 		if (i > 0)
244 			buf_append(&size, buf, buflen, "/", NULL, NULL);
245 		(void) nvlist_lookup_string(hcprs[i], FM_FMRI_HC_NAME, &nm);
246 		(void) nvlist_lookup_string(hcprs[i], FM_FMRI_HC_ID, &id);
247 		if (nm == NULL || id == NULL)
248 			return (fmd_fmri_set_errno(EINVAL));
249 		buf_append(&size, buf, buflen, nm, NULL, "=");
250 		buf_append(&size, buf, buflen, id, NULL, NULL);
251 	}
252 
253 	return (size);
254 }
255 
256 /*ARGSUSED*/
257 static int
258 hc_topo_present(topo_hdl_t *thp, tnode_t *node, void *arg)
259 {
260 	int cmp, err;
261 	nvlist_t *out = NULL;
262 	nvlist_t *asru;
263 	hc_walk_arg_t *hcargp = (hc_walk_arg_t *)arg;
264 
265 	if (topo_node_asru(node, &asru, NULL, &err) != 0 ||
266 	    asru == NULL) {
267 		return (TOPO_WALK_NEXT);
268 	}
269 
270 	/*
271 	 * Check if the ASRU of this node matches the ASRU passed in
272 	 */
273 	cmp = topo_fmri_compare(thp, asru, (nvlist_t *)hcargp->p, &err);
274 
275 	nvlist_free(asru);
276 
277 	if (cmp <= 0)
278 		return (TOPO_WALK_NEXT);
279 
280 	/*
281 	 * Yes, so try to execute the topo-present method.
282 	 */
283 	cmp = topo_method_invoke(node, TOPO_METH_PRESENT,
284 	    TOPO_METH_PRESENT_VERSION, (nvlist_t *)hcargp->p, &out, &err);
285 
286 	if (out)
287 		nvlist_free(out);
288 
289 	if (cmp == 1) {
290 		*(hcargp->resultp) = 1;
291 		return (TOPO_WALK_TERMINATE);
292 	} else if (cmp == 0) {
293 		*(hcargp->resultp) = 0;
294 		return (TOPO_WALK_TERMINATE);
295 	}
296 
297 	return (TOPO_WALK_NEXT);
298 }
299 
300 
301 /*
302  * fmd_fmri_present() is called by fmadm to determine if a faulty ASRU
303  * is still present in the system.  In general we don't expect to get
304  * ASRUs in this scheme, so it's unlikely this routine will get called.
305  * In case it does, though, we just traverse our libtopo snapshot,
306  * looking for a matching ASRU (minus the serial number information),
307  * then invoke the "topo_present" method to determine presence.
308  */
309 int
310 fmd_fmri_present(nvlist_t *nvl)
311 {
312 	int ispresent = 1;
313 
314 	/*
315 	 * If there's an error during the topology update, punt by
316 	 * indicating presence.
317 	 */
318 	if (hc_update_topology() < 0)
319 		return (1);
320 
321 	(void) hc_topo_walk(hc_topo_present, nvl, &ispresent);
322 
323 	return (ispresent);
324 }
325 
326 /*
327  * fmd_fmri_unusable() is called by fmadm to determine if a faulty ASRU
328  * is usable.  In general we don't expect to get ASRUs in this scheme,
329  * so it's unlikely this routine will get called.  In case it does,
330  * though, we just return false by default, as we have no real way to
331  * find the component or determine the component's usability.
332  */
333 /*ARGSUSED*/
334 int
335 fmd_fmri_unusable(nvlist_t *nvl)
336 {
337 	return (0);
338 }
339