/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "srpt_common.h" #define SRPT_PROV_NAME "srpt" /* * Function: srpt_GetConfig() * * Parameters: * cfg Current SRPT configuration in nvlist form * token Configuration generation number. Use this token * if updating the configuration with srpt_SetConfig. * * Return Values: * 0 Success * ENOMEM Could not allocate resources * EINVAL Invalid parameter */ int srpt_GetConfig(nvlist_t **cfg, uint64_t *token) { int ret = 0; nvlist_t *cfg_nv = NULL; uint64_t stmf_token = 0; nvlist_t *hcanv = NULL; if (!cfg) { return (EINVAL); } *cfg = NULL; ret = stmfGetProviderDataProt(SRPT_PROV_NAME, &cfg_nv, STMF_PORT_PROVIDER_TYPE, &stmf_token); if (ret == STMF_STATUS_SUCCESS) { ret = 0; } else if (ret == STMF_ERROR_NOT_FOUND) { /* Not initialized yet */ ret = nvlist_alloc(&cfg_nv, NV_UNIQUE_NAME, 0); if (ret != 0) { return (ret); } /* create the HCA list */ ret = nvlist_alloc(&hcanv, NV_UNIQUE_NAME, 0); if (ret == 0) { ret = nvlist_add_nvlist(cfg_nv, SRPT_PROP_HCALIST, hcanv); if (ret != 0) { nvlist_free(hcanv); } } if (ret != 0) { nvlist_free(cfg_nv); cfg_nv = NULL; } } else if (ret == STMF_ERROR_NOMEM) { ret = ENOMEM; } else { ret = EINVAL; } *cfg = cfg_nv; *token = stmf_token; return (ret); } /* * Function: srpt_SetConfig() * * Parameters: * cfg SRPT configuration in nvlist form * token Configuration generation number from srpt_GetConfig. * Use this token to ensure the configuration hasn't been * updated by another user since the time it was fetched. * * Return Values: * 0 Success * ENOMEM Could not allocate resources * EINVAL Invalid parameter * ECANCELED Configuration updated by another user */ int srpt_SetConfig(nvlist_t *cfg, uint64_t token) { int ret = 0; ret = stmfSetProviderDataProt(SRPT_PROV_NAME, cfg, STMF_PORT_PROVIDER_TYPE, &token); if (ret == STMF_STATUS_SUCCESS) { ret = 0; } else if (ret == STMF_ERROR_NOMEM) { ret = ENOMEM; } else if (ret == STMF_ERROR_PROV_DATA_STALE) { ret = ECANCELED; /* could be a better errno */ } else { ret = EINVAL; } return (ret); } /* * Function: srpt_GetDefaultState() * * Parameters: * enabled If B_TRUE, indicates that targets will be created for all * discovered HCAs that have not been specifically disabled. * If B_FALSE, targets will not be created unless the HCA has * been specifically enabled. See also srpt_SetDefaultState(). * * Return Values: * 0 Success * ENOMEM Could not allocate resources * EINVAL Invalid parameter */ int srpt_GetDefaultState(boolean_t *enabled) { int ret; nvlist_t *cfgnv; uint64_t token; boolean_t val = B_TRUE; if (enabled == NULL) { return (EINVAL); } ret = srpt_GetConfig(&cfgnv, &token); if (ret != 0) { return (ret); } if (cfgnv != NULL) { ret = nvlist_lookup_boolean_value(cfgnv, SRPT_PROP_DEFAULT_ENABLED, &val); if (ret == ENOENT) { ret = 0; } } *enabled = val; return (ret); } /* * Function: srpt_SetDefaultState() * * Parameters: * enabled If B_TRUE, indicates that targets will be created for all * discovered HCAs that have not been specifically disabled. * If B_FALSE, targets will not be created unless the HCA has * been specifically enabled. See also srpt_SetDefaultState(). * * Return Values: * 0 Success * ENOMEM Could not allocate resources * EINVAL Invalid parameter */ int srpt_SetDefaultState(boolean_t enabled) { int ret; nvlist_t *cfgnv; uint64_t token; ret = srpt_GetConfig(&cfgnv, &token); if (ret != 0) { return (ret); } if (cfgnv == NULL) { ret = nvlist_alloc(&cfgnv, NV_UNIQUE_NAME, 0); if (ret != 0) { return (ret); } } ret = nvlist_add_boolean_value(cfgnv, SRPT_PROP_DEFAULT_ENABLED, enabled); if (ret == 0) { ret = srpt_SetConfig(cfgnv, token); } nvlist_free(cfgnv); return (ret); } /* * Function: srpt_SetTargetState() * * Parameters: * hca_guid HCA GUID. See description of srpt_NormalizeGuid * enabled If B_TRUE, indicates that a target will be created for * this HCA when the SRPT SMF service is enabled. If B_FALSE, * a target will not be created * * Return Values: * 0 Success * ENOMEM Could not allocate resources * EINVAL Invalid parameter */ int srpt_SetTargetState(char *hca_guid, boolean_t enabled) { int ret; nvlist_t *cfgnv; uint64_t token; nvlist_t *hcalist; nvlist_t *hcanv; char guid[32]; uint64_t hcaguid; if (hca_guid == NULL) { return (EINVAL); } ret = srpt_NormalizeGuid(hca_guid, guid, sizeof (guid), &hcaguid); if (ret != 0) { return (ret); } ret = srpt_GetConfig(&cfgnv, &token); if (ret != 0) { return (ret); } /* get the list of HCAs */ ret = nvlist_lookup_nvlist(cfgnv, SRPT_PROP_HCALIST, &hcalist); if (ret != 0) { nvlist_free(cfgnv); return (ret); } ret = nvlist_lookup_nvlist(hcalist, guid, &hcanv); if (ret == ENOENT) { /* no entry yet */ ret = nvlist_alloc(&hcanv, NV_UNIQUE_NAME, 0); if (ret == 0) { ret = nvlist_add_uint64(hcanv, SRPT_PROP_GUID, hcaguid); } } if (ret == 0) { ret = nvlist_add_boolean_value(hcanv, SRPT_PROP_ENABLED, enabled); } if (ret == 0) { ret = nvlist_add_nvlist(hcalist, guid, hcanv); } if (ret == 0) { ret = srpt_SetConfig(cfgnv, token); } nvlist_free(cfgnv); return (ret); } /* * Function: srpt_GetTargetState() * * Parameters: * hca_guid HCA GUID. See description of srpt_NormalizeGuid * enabled If B_TRUE, indicates that a target will be created for * this HCA when the SRPT SMF service is enabled. If B_FALSE, * a target will not be created * * Return Values: * 0 Success * ENOMEM Could not allocate resources * EINVAL Invalid parameter */ int srpt_GetTargetState(char *hca_guid, boolean_t *enabled) { int ret; nvlist_t *cfgnv; uint64_t token; nvlist_t *hcalist; nvlist_t *hcanv; boolean_t defaultState = B_TRUE; char guid[32]; if (hca_guid == NULL) { return (EINVAL); } ret = srpt_NormalizeGuid(hca_guid, guid, sizeof (guid), NULL); if (ret != 0) { return (ret); } ret = srpt_GetConfig(&cfgnv, &token); if (ret != 0) { return (ret); } /* get the list of HCAs */ ret = nvlist_lookup_nvlist(cfgnv, SRPT_PROP_HCALIST, &hcalist); if (ret != 0) { nvlist_free(cfgnv); return (ret); } /* * Find the default, for the likely case that this HCA isn't * explicitly set. */ (void) nvlist_lookup_boolean_value(cfgnv, SRPT_PROP_DEFAULT_ENABLED, &defaultState); ret = nvlist_lookup_nvlist(hcalist, guid, &hcanv); if (ret == 0) { ret = nvlist_lookup_boolean_value(hcanv, SRPT_PROP_ENABLED, enabled); } if (ret == ENOENT) { /* not explicitly set, use the default */ *enabled = defaultState; ret = 0; } nvlist_free(cfgnv); return (ret); } /* * Function: srpt_ResetTarget() * * Clears the HCA-specific configuration. Target creation will revert to * the default. * * Parameters: * hca_guid HCA GUID. See description of srpt_NormalizeGuid * * Return Values: * 0 Success * ENOMEM Could not allocate resources * EINVAL Invalid parameter */ int srpt_ResetTarget(char *hca_guid) { int ret; nvlist_t *cfgnv; nvlist_t *hcalist; uint64_t token; char guid[32]; if (hca_guid == NULL) { return (EINVAL); } ret = srpt_NormalizeGuid(hca_guid, guid, sizeof (guid), NULL); if (ret != 0) { return (ret); } ret = srpt_GetConfig(&cfgnv, &token); if (ret != 0) { return (ret); } /* get the list of HCAs */ ret = nvlist_lookup_nvlist(cfgnv, SRPT_PROP_HCALIST, &hcalist); if (ret != 0) { nvlist_free(cfgnv); return (ret); } /* don't set config if we don't actually change anything */ if (nvlist_exists(hcalist, guid)) { (void) nvlist_remove_all(hcalist, guid); if (ret == 0) { ret = srpt_SetConfig(cfgnv, token); } } nvlist_free(cfgnv); return (ret); } /* * srpt_NormalizeGuid() * * Parameters: * in HCA GUID. Must be in one of the following forms: * 3BA000100CD18 - base hex form * 0003BA000100CD18 - base hex form with leading zeroes * hca:3BA000100CD18 - form from cfgadm and/or /dev/cfg * eui.0003BA000100CD18 - EUI form * * buf Buffer to hold normalized guid string. Must be at least * 17 chars long. * buflen Length of provided buffer * int_guid Optional. If not NULL, the integer form of the GUID will also * be returned. * Return Values: * 0 Success * EINVAL Invalid HCA GUID or invalid parameter. */ int srpt_NormalizeGuid(char *in, char *buf, size_t buflen, uint64_t *int_guid) { uint64_t guid; char *bufp = in; char *end = NULL; if ((in == NULL) || (buf == NULL)) { return (EINVAL); } if (strncasecmp(bufp, "eui.", 4) == 0) { /* EUI form */ bufp += 4; } else if (strncasecmp(bufp, "hca:", 4) == 0) { /* cfgadm and /dev/hca form */ bufp += 4; } /* * strtoull() does not return EINVAL as documented. Lucky * for us, neither 0 nor ULLONG_MAX will be valid. Trap on * those and fail. */ guid = strtoull(bufp, &end, 16); if ((guid == 0) || (guid == ULLONG_MAX) || ((end != NULL) && (strlen(end) > 0))) { return (EINVAL); } #if 0 (void) snprintf(buf, buflen, "%llX", guid); #endif SRPT_FORMAT_HCAKEY(buf, buflen, guid); if (int_guid) { *int_guid = guid; } return (0); }