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 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 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 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 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 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 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 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 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