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 (c) 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <limits.h>
28 #include <ctype.h>
29 #include <fcntl.h>
30 #include <errno.h>
31 #include <unistd.h>
32 #include <strings.h>
33 #include <libintl.h>
34 #include <libscf.h>
35 #include <libnvpair.h>
36 
37 #include <libstmf.h>
38 #include <libsrpt.h>
39 
40 #include "srpt_common.h"
41 
42 #define	SRPT_PROV_NAME	"srpt"
43 
44 /*
45  * Function:  srpt_GetConfig()
46  *
47  * Parameters:
48  *    cfg	Current SRPT configuration in nvlist form
49  *    token	Configuration generation number.  Use this token
50  *		if updating the configuration with srpt_SetConfig.
51  *
52  * Return Values:
53  *    0		Success
54  *    ENOMEM	Could not allocate resources
55  *    EINVAL	Invalid parameter
56  */
57 int
srpt_GetConfig(nvlist_t ** cfg,uint64_t * token)58 srpt_GetConfig(nvlist_t **cfg, uint64_t *token)
59 {
60 	int		ret = 0;
61 	nvlist_t	*cfg_nv = NULL;
62 	uint64_t	stmf_token = 0;
63 	nvlist_t	*hcanv = NULL;
64 
65 	if (!cfg) {
66 		return (EINVAL);
67 	}
68 
69 	*cfg = NULL;
70 
71 	ret = stmfGetProviderDataProt(SRPT_PROV_NAME, &cfg_nv,
72 	    STMF_PORT_PROVIDER_TYPE, &stmf_token);
73 
74 	if (ret == STMF_STATUS_SUCCESS) {
75 		ret = 0;
76 	} else if (ret == STMF_ERROR_NOT_FOUND) {
77 		/* Not initialized yet */
78 		ret = nvlist_alloc(&cfg_nv, NV_UNIQUE_NAME, 0);
79 		if (ret != 0) {
80 			return (ret);
81 		}
82 		/* create the HCA list */
83 		ret = nvlist_alloc(&hcanv, NV_UNIQUE_NAME, 0);
84 		if (ret == 0) {
85 			ret = nvlist_add_nvlist(cfg_nv, SRPT_PROP_HCALIST,
86 			    hcanv);
87 			if (ret != 0) {
88 				nvlist_free(hcanv);
89 			}
90 		}
91 		if (ret != 0) {
92 			nvlist_free(cfg_nv);
93 			cfg_nv = NULL;
94 		}
95 	} else if (ret == STMF_ERROR_NOMEM) {
96 		ret = ENOMEM;
97 	} else {
98 		ret = EINVAL;
99 	}
100 
101 	*cfg = cfg_nv;
102 	*token = stmf_token;
103 
104 	return (ret);
105 }
106 
107 /*
108  * Function:  srpt_SetConfig()
109  *
110  * Parameters:
111  *    cfg	SRPT configuration in nvlist form
112  *    token	Configuration generation number from srpt_GetConfig.
113  *		Use this token to ensure the configuration hasn't been
114  *		updated by another user since the time it was fetched.
115  *
116  * Return Values:
117  *    0		Success
118  *    ENOMEM	Could not allocate resources
119  *    EINVAL	Invalid parameter
120  *    ECANCELED Configuration updated by another user
121  */
122 int
srpt_SetConfig(nvlist_t * cfg,uint64_t token)123 srpt_SetConfig(nvlist_t *cfg, uint64_t token)
124 {
125 	int		ret = 0;
126 
127 	ret = stmfSetProviderDataProt(SRPT_PROV_NAME, cfg,
128 	    STMF_PORT_PROVIDER_TYPE, &token);
129 
130 	if (ret == STMF_STATUS_SUCCESS) {
131 		ret = 0;
132 	} else if (ret == STMF_ERROR_NOMEM) {
133 		ret = ENOMEM;
134 	} else if (ret == STMF_ERROR_PROV_DATA_STALE) {
135 		ret = ECANCELED;  /* could be a better errno */
136 	} else {
137 		ret = EINVAL;
138 	}
139 
140 	return (ret);
141 }
142 
143 /*
144  * Function:  srpt_GetDefaultState()
145  *
146  * Parameters:
147  *    enabled	If B_TRUE, indicates that targets will be created for all
148  *		discovered HCAs that have not been specifically disabled.
149  *		If B_FALSE, targets will not be created unless the HCA has
150  *		been specifically enabled.  See also srpt_SetDefaultState().
151  *
152  * Return Values:
153  *    0		Success
154  *    ENOMEM	Could not allocate resources
155  *    EINVAL	Invalid parameter
156  */
157 int
srpt_GetDefaultState(boolean_t * enabled)158 srpt_GetDefaultState(boolean_t *enabled)
159 {
160 	int		ret;
161 	nvlist_t	*cfgnv;
162 	uint64_t	token;
163 	boolean_t	val = B_TRUE;
164 
165 	if (enabled == NULL) {
166 		return (EINVAL);
167 	}
168 
169 	ret = srpt_GetConfig(&cfgnv, &token);
170 	if (ret != 0) {
171 		return (ret);
172 	}
173 
174 	if (cfgnv != NULL) {
175 		ret = nvlist_lookup_boolean_value(cfgnv,
176 		    SRPT_PROP_DEFAULT_ENABLED, &val);
177 
178 		if (ret == ENOENT) {
179 			ret = 0;
180 		}
181 	}
182 
183 	*enabled = val;
184 	return (ret);
185 }
186 
187 /*
188  * Function:  srpt_SetDefaultState()
189  *
190  * Parameters:
191  *    enabled	If B_TRUE, indicates that targets will be created for all
192  *		discovered HCAs that have not been specifically disabled.
193  *		If B_FALSE, targets will not be created unless the HCA has
194  *		been specifically enabled.  See also srpt_SetDefaultState().
195  *
196  * Return Values:
197  *    0		Success
198  *    ENOMEM	Could not allocate resources
199  *    EINVAL	Invalid parameter
200  */
201 int
srpt_SetDefaultState(boolean_t enabled)202 srpt_SetDefaultState(boolean_t enabled)
203 {
204 	int		ret;
205 	nvlist_t	*cfgnv;
206 	uint64_t	token;
207 
208 	ret = srpt_GetConfig(&cfgnv, &token);
209 	if (ret != 0) {
210 		return (ret);
211 	}
212 
213 	if (cfgnv == NULL) {
214 		ret = nvlist_alloc(&cfgnv, NV_UNIQUE_NAME, 0);
215 		if (ret != 0) {
216 			return (ret);
217 		}
218 	}
219 
220 	ret = nvlist_add_boolean_value(cfgnv, SRPT_PROP_DEFAULT_ENABLED,
221 	    enabled);
222 
223 	if (ret == 0) {
224 		ret = srpt_SetConfig(cfgnv, token);
225 	}
226 
227 	nvlist_free(cfgnv);
228 
229 	return (ret);
230 }
231 
232 /*
233  * Function:  srpt_SetTargetState()
234  *
235  * Parameters:
236  *    hca_guid	HCA GUID.  See description of srpt_NormalizeGuid
237  *    enabled	If B_TRUE, indicates that a target will be created for
238  *		this HCA when the SRPT SMF service is enabled.  If B_FALSE,
239  *		a target will not be created
240  *
241  * Return Values:
242  *    0		Success
243  *    ENOMEM	Could not allocate resources
244  *    EINVAL	Invalid parameter
245  */
246 int
srpt_SetTargetState(char * hca_guid,boolean_t enabled)247 srpt_SetTargetState(char *hca_guid, boolean_t enabled)
248 {
249 	int		ret;
250 	nvlist_t	*cfgnv;
251 	uint64_t	token;
252 	nvlist_t	*hcalist;
253 	nvlist_t	*hcanv;
254 	char		guid[32];
255 	uint64_t	hcaguid;
256 
257 	if (hca_guid == NULL) {
258 		return (EINVAL);
259 	}
260 
261 	ret = srpt_NormalizeGuid(hca_guid, guid, sizeof (guid), &hcaguid);
262 	if (ret != 0) {
263 		return (ret);
264 	}
265 
266 	ret = srpt_GetConfig(&cfgnv, &token);
267 	if (ret != 0) {
268 		return (ret);
269 	}
270 
271 	/* get the list of HCAs */
272 	ret = nvlist_lookup_nvlist(cfgnv, SRPT_PROP_HCALIST, &hcalist);
273 	if (ret != 0) {
274 		nvlist_free(cfgnv);
275 		return (ret);
276 	}
277 
278 	ret = nvlist_lookup_nvlist(hcalist, guid, &hcanv);
279 	if (ret == ENOENT) {
280 		/* no entry yet */
281 		ret = nvlist_alloc(&hcanv, NV_UNIQUE_NAME, 0);
282 		if (ret == 0) {
283 			ret = nvlist_add_uint64(hcanv, SRPT_PROP_GUID, hcaguid);
284 		}
285 	}
286 
287 	if (ret == 0) {
288 		ret = nvlist_add_boolean_value(hcanv, SRPT_PROP_ENABLED,
289 		    enabled);
290 	}
291 
292 	if (ret == 0) {
293 		ret = nvlist_add_nvlist(hcalist, guid, hcanv);
294 	}
295 
296 	if (ret == 0) {
297 		ret = srpt_SetConfig(cfgnv, token);
298 	}
299 
300 	nvlist_free(cfgnv);
301 
302 	return (ret);
303 }
304 
305 /*
306  * Function:  srpt_GetTargetState()
307  *
308  * Parameters:
309  *    hca_guid	HCA GUID.  See description of srpt_NormalizeGuid
310  *    enabled	If B_TRUE, indicates that a target will be created for
311  *		this HCA when the SRPT SMF service is enabled.  If B_FALSE,
312  *		a target will not be created
313  *
314  * Return Values:
315  *    0		Success
316  *    ENOMEM	Could not allocate resources
317  *    EINVAL	Invalid parameter
318  */
319 int
srpt_GetTargetState(char * hca_guid,boolean_t * enabled)320 srpt_GetTargetState(char *hca_guid, boolean_t *enabled)
321 {
322 	int		ret;
323 	nvlist_t	*cfgnv;
324 	uint64_t	token;
325 	nvlist_t	*hcalist;
326 	nvlist_t	*hcanv;
327 	boolean_t	defaultState = B_TRUE;
328 	char		guid[32];
329 
330 	if (hca_guid == NULL) {
331 		return (EINVAL);
332 	}
333 
334 	ret = srpt_NormalizeGuid(hca_guid, guid, sizeof (guid), NULL);
335 	if (ret != 0) {
336 		return (ret);
337 	}
338 
339 	ret = srpt_GetConfig(&cfgnv, &token);
340 	if (ret != 0) {
341 		return (ret);
342 	}
343 
344 	/* get the list of HCAs */
345 	ret = nvlist_lookup_nvlist(cfgnv, SRPT_PROP_HCALIST, &hcalist);
346 	if (ret != 0) {
347 		nvlist_free(cfgnv);
348 		return (ret);
349 	}
350 
351 	/*
352 	 * Find the default, for the likely case that this HCA isn't
353 	 * explicitly set.
354 	 */
355 	(void) nvlist_lookup_boolean_value(cfgnv, SRPT_PROP_DEFAULT_ENABLED,
356 	    &defaultState);
357 
358 	ret = nvlist_lookup_nvlist(hcalist, guid, &hcanv);
359 	if (ret == 0) {
360 		ret = nvlist_lookup_boolean_value(hcanv, SRPT_PROP_ENABLED,
361 		    enabled);
362 	}
363 
364 	if (ret == ENOENT) {
365 		/* not explicitly set, use the default */
366 		*enabled = defaultState;
367 		ret = 0;
368 	}
369 
370 	nvlist_free(cfgnv);
371 
372 	return (ret);
373 
374 }
375 
376 /*
377  * Function:  srpt_ResetTarget()
378  *
379  * Clears the HCA-specific configuration.  Target creation will revert to
380  * the default.
381  *
382  * Parameters:
383  *    hca_guid	HCA GUID.  See description of srpt_NormalizeGuid
384  *
385  * Return Values:
386  *    0		Success
387  *    ENOMEM	Could not allocate resources
388  *    EINVAL	Invalid parameter
389  */
390 int
srpt_ResetTarget(char * hca_guid)391 srpt_ResetTarget(char *hca_guid)
392 {
393 	int		ret;
394 	nvlist_t	*cfgnv;
395 	nvlist_t	*hcalist;
396 	uint64_t	token;
397 	char		guid[32];
398 
399 	if (hca_guid == NULL) {
400 		return (EINVAL);
401 	}
402 
403 	ret = srpt_NormalizeGuid(hca_guid, guid, sizeof (guid), NULL);
404 	if (ret != 0) {
405 		return (ret);
406 	}
407 
408 	ret = srpt_GetConfig(&cfgnv, &token);
409 	if (ret != 0) {
410 		return (ret);
411 	}
412 
413 	/* get the list of HCAs */
414 	ret = nvlist_lookup_nvlist(cfgnv, SRPT_PROP_HCALIST, &hcalist);
415 	if (ret != 0) {
416 		nvlist_free(cfgnv);
417 		return (ret);
418 	}
419 
420 	/* don't set config if we don't actually change anything */
421 	if (nvlist_exists(hcalist, guid)) {
422 		(void) nvlist_remove_all(hcalist, guid);
423 
424 		if (ret == 0) {
425 			ret = srpt_SetConfig(cfgnv, token);
426 		}
427 	}
428 
429 	nvlist_free(cfgnv);
430 
431 	return (ret);
432 }
433 
434 /*
435  * srpt_NormalizeGuid()
436  *
437  * Parameters:
438  *    in	HCA GUID.  Must be in one of the following forms:
439  *		    3BA000100CD18	- base hex form
440  *		    0003BA000100CD18	- base hex form with leading zeroes
441  *		    hca:3BA000100CD18	- form from cfgadm and/or /dev/cfg
442  *		    eui.0003BA000100CD18 - EUI form
443  *
444  *    buf	Buffer to hold normalized guid string.  Must be at least
445  *		17 chars long.
446  *    buflen	Length of provided buffer
447  *    int_guid	Optional.  If not NULL, the integer form of the GUID will also
448  *		be returned.
449  * Return Values:
450  *    0		Success
451  *    EINVAL	Invalid HCA GUID or invalid parameter.
452  */
453 int
srpt_NormalizeGuid(char * in,char * buf,size_t buflen,uint64_t * int_guid)454 srpt_NormalizeGuid(char *in, char *buf, size_t buflen, uint64_t *int_guid)
455 {
456 	uint64_t	guid;
457 	char		*bufp = in;
458 	char		*end = NULL;
459 
460 	if ((in == NULL) || (buf == NULL)) {
461 		return (EINVAL);
462 	}
463 
464 	if (strncasecmp(bufp, "eui.", 4) == 0) {
465 		/* EUI form */
466 		bufp += 4;
467 	} else if (strncasecmp(bufp, "hca:", 4) == 0) {
468 		/* cfgadm and /dev/hca form */
469 		bufp += 4;
470 	}
471 
472 	/*
473 	 * strtoull() does not return EINVAL as documented.  Lucky
474 	 * for us, neither 0 nor ULLONG_MAX will be valid.  Trap on
475 	 * those and fail.
476 	 */
477 	guid = strtoull(bufp, &end, 16);
478 	if ((guid == 0) || (guid == ULLONG_MAX) ||
479 	    ((end != NULL) && (strlen(end) > 0))) {
480 		return (EINVAL);
481 	}
482 
483 #if 0
484 	(void) snprintf(buf, buflen, "%llX", guid);
485 #endif
486 	SRPT_FORMAT_HCAKEY(buf, buflen, guid);
487 
488 	if (int_guid) {
489 		*int_guid = guid;
490 	}
491 
492 	return (0);
493 }
494