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