summaryrefslogtreecommitdiff
path: root/usr/src/lib/libfcoe/common/libfcoe.c
diff options
context:
space:
mode:
authorKevin Yu <Kevin.Yu@Sun.COM>2009-06-18 10:55:44 +0800
committerKevin Yu <Kevin.Yu@Sun.COM>2009-06-18 10:55:44 +0800
commite6eb57e72471348376359efe9105d50bf487a312 (patch)
tree8e0a7c0b207b77b702216abff15e74f3776fd40d /usr/src/lib/libfcoe/common/libfcoe.c
parentd20abfaa275f62e387fe9d814375fb3829fdb91f (diff)
downloadillumos-joyent-e6eb57e72471348376359efe9105d50bf487a312.tar.gz
6818210 Remove fcadm create-fcoe-ports subcommand and implement the function in fcoeconfig
Diffstat (limited to 'usr/src/lib/libfcoe/common/libfcoe.c')
-rw-r--r--usr/src/lib/libfcoe/common/libfcoe.c580
1 files changed, 577 insertions, 3 deletions
diff --git a/usr/src/lib/libfcoe/common/libfcoe.c b/usr/src/lib/libfcoe/common/libfcoe.c
index a71c217a70..6e10527046 100644
--- a/usr/src/lib/libfcoe/common/libfcoe.c
+++ b/usr/src/lib/libfcoe/common/libfcoe.c
@@ -39,6 +39,8 @@
#include <libfcoe.h>
#include <libdllink.h>
#include <fcoeio.h>
+#include <libscf.h>
+#include <inttypes.h>
#define FCOE_DEV_PATH "/devices/fcoe:admin"
@@ -71,6 +73,16 @@ openFcoe(int flag, int *fd)
return (ret);
}
+static void
+WWN2str(char *buf, FCOE_PORT_WWN *wwn) {
+ int j;
+ unsigned char *pc = (unsigned char *)&(wwn->wwn[0]);
+ buf[0] = '\0';
+ for (j = 0; j < 16; j += 2) {
+ (void) sprintf(&buf[j], "%02X", (int)*pc++);
+ }
+}
+
static int
isWWNZero(FCOE_PORT_WWN portwwn)
{
@@ -85,6 +97,378 @@ isWWNZero(FCOE_PORT_WWN portwwn)
return (1);
}
+/*
+ * Initialize scf fcoe service access
+ * handle - returned handle
+ * service - returned service handle
+ */
+static int
+fcoe_cfg_scf_init(scf_handle_t **handle, scf_service_t **service, int is_target)
+{
+ scf_scope_t *scope = NULL;
+ int ret;
+
+ if ((*handle = scf_handle_create(SCF_VERSION)) == NULL) {
+ syslog(LOG_ERR, "scf_handle_create failed - %s",
+ scf_strerror(scf_error()));
+ ret = FCOE_ERROR;
+ goto err;
+ }
+
+ if (scf_handle_bind(*handle) == -1) {
+ syslog(LOG_ERR, "scf_handle_bind failed - %s",
+ scf_strerror(scf_error()));
+ ret = FCOE_ERROR;
+ goto err;
+ }
+
+ if ((*service = scf_service_create(*handle)) == NULL) {
+ syslog(LOG_ERR, "scf_service_create failed - %s",
+ scf_strerror(scf_error()));
+ ret = FCOE_ERROR;
+ goto err;
+ }
+
+ if ((scope = scf_scope_create(*handle)) == NULL) {
+ syslog(LOG_ERR, "scf_scope_create failed - %s",
+ scf_strerror(scf_error()));
+ ret = FCOE_ERROR;
+ goto err;
+ }
+
+ if (scf_handle_get_scope(*handle, SCF_SCOPE_LOCAL, scope) == -1) {
+ syslog(LOG_ERR, "scf_handle_get_scope failed - %s",
+ scf_strerror(scf_error()));
+ ret = FCOE_ERROR;
+ goto err;
+ }
+
+ if (scf_scope_get_service(scope,
+ is_target ? FCOE_TARGET_SERVICE: FCOE_INITIATOR_SERVICE,
+ *service) == -1) {
+ syslog(LOG_ERR, "scf_scope_get_service failed - %s",
+ scf_strerror(scf_error()));
+ ret = FCOE_ERROR_SERVICE_NOT_FOUND;
+ goto err;
+ }
+
+ scf_scope_destroy(scope);
+
+ return (FCOE_SUCCESS);
+
+err:
+ if (*handle != NULL) {
+ scf_handle_destroy(*handle);
+ }
+ if (*service != NULL) {
+ scf_service_destroy(*service);
+ *service = NULL;
+ }
+ if (scope != NULL) {
+ scf_scope_destroy(scope);
+ }
+ return (ret);
+}
+
+static int
+fcoe_add_remove_scf_entry(char *mac_name,
+ char *pwwn, char *nwwn,
+ int is_target, int is_promiscuous, int addRemoveFlag)
+{
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+ scf_propertygroup_t *pg = NULL;
+ scf_transaction_t *tran = NULL;
+ scf_transaction_entry_t *entry = NULL;
+ scf_property_t *prop = NULL;
+ scf_value_t *valueLookup = NULL;
+ scf_iter_t *valueIter = NULL;
+ scf_value_t **valueSet = NULL;
+ int ret = FCOE_SUCCESS;
+ boolean_t createProp = B_FALSE;
+ int lastAlloc = 0;
+ char buf[FCOE_PORT_LIST_LENGTH] = {0};
+ char memberName[FCOE_PORT_LIST_LENGTH] = {0};
+ boolean_t found = B_FALSE;
+ int i = 0;
+ int valueArraySize = 0;
+ int commitRet;
+ int portListAlloc = 100;
+
+ (void) snprintf(memberName, FCOE_PORT_LIST_LENGTH,
+ "%s:%s:%s:%d:%d", mac_name, pwwn, nwwn,
+ is_target, is_promiscuous);
+
+ ret = fcoe_cfg_scf_init(&handle, &svc, is_target);
+ if (ret != FCOE_SUCCESS) {
+ goto out;
+ }
+
+ if (((pg = scf_pg_create(handle)) == NULL) ||
+ ((tran = scf_transaction_create(handle)) == NULL) ||
+ ((entry = scf_entry_create(handle)) == NULL) ||
+ ((prop = scf_property_create(handle)) == NULL) ||
+ ((valueIter = scf_iter_create(handle)) == NULL)) {
+ ret = FCOE_ERROR;
+ goto out;
+ }
+
+ /* get property group or create it */
+ if (scf_service_get_pg(svc, FCOE_PG_NAME, pg) == -1) {
+ if ((scf_error() == SCF_ERROR_NOT_FOUND)) {
+ if (scf_service_add_pg(svc, FCOE_PG_NAME,
+ SCF_GROUP_APPLICATION, 0, pg) == -1) {
+ syslog(LOG_ERR, "add pg failed - %s",
+ scf_strerror(scf_error()));
+ ret = FCOE_ERROR;
+ } else {
+ createProp = B_TRUE;
+ }
+ } else {
+ syslog(LOG_ERR, "get pg failed - %s",
+ scf_strerror(scf_error()));
+ ret = FCOE_ERROR;
+ }
+ if (ret != FCOE_SUCCESS) {
+ goto out;
+ }
+ }
+
+ /* to make sure property exists */
+ if (createProp == B_FALSE) {
+ if (scf_pg_get_property(pg, FCOE_PORT_LIST, prop) == -1) {
+ if ((scf_error() == SCF_ERROR_NOT_FOUND)) {
+ createProp = B_TRUE;
+ } else {
+ syslog(LOG_ERR, "get property failed - %s",
+ scf_strerror(scf_error()));
+ ret = FCOE_ERROR;
+ goto out;
+ }
+ }
+ }
+
+ /* Begin the transaction */
+ if (scf_transaction_start(tran, pg) == -1) {
+ syslog(LOG_ERR, "start transaction failed - %s",
+ scf_strerror(scf_error()));
+ ret = FCOE_ERROR;
+ goto out;
+ }
+
+ valueSet = (scf_value_t **)calloc(1, sizeof (*valueSet)
+ * (lastAlloc = portListAlloc));
+ if (valueSet == NULL) {
+ ret = FCOE_ERROR_NOMEM;
+ goto out;
+ }
+
+ if (createProp) {
+ if (scf_transaction_property_new(tran, entry, FCOE_PORT_LIST,
+ SCF_TYPE_USTRING) == -1) {
+ if (scf_error() == SCF_ERROR_EXISTS) {
+ ret = FCOE_ERROR_EXISTS;
+ } else {
+ syslog(LOG_ERR,
+ "transaction property new failed - %s",
+ scf_strerror(scf_error()));
+ ret = FCOE_ERROR;
+ }
+ goto out;
+ }
+ } else {
+ if (scf_transaction_property_change(tran, entry,
+ FCOE_PORT_LIST, SCF_TYPE_USTRING) == -1) {
+ syslog(LOG_ERR,
+ "transaction property change failed - %s",
+ scf_strerror(scf_error()));
+ ret = FCOE_ERROR;
+ goto out;
+ }
+
+ if (scf_pg_get_property(pg, FCOE_PORT_LIST, prop) == -1) {
+ syslog(LOG_ERR, "get property failed - %s",
+ scf_strerror(scf_error()));
+ ret = FCOE_ERROR;
+ goto out;
+ }
+
+ valueLookup = scf_value_create(handle);
+ if (valueLookup == NULL) {
+ syslog(LOG_ERR, "scf value alloc failed - %s",
+ scf_strerror(scf_error()));
+ ret = FCOE_ERROR;
+ goto out;
+ }
+
+ if (scf_iter_property_values(valueIter, prop) == -1) {
+ syslog(LOG_ERR, "iter value failed - %s",
+ scf_strerror(scf_error()));
+ ret = FCOE_ERROR;
+ goto out;
+ }
+
+ while (scf_iter_next_value(valueIter, valueLookup) == 1) {
+ char *macnameIter = NULL;
+ char buftmp[FCOE_PORT_LIST_LENGTH] = {0};
+
+ bzero(buf, sizeof (buf));
+ if (scf_value_get_ustring(valueLookup,
+ buf, MAXNAMELEN) == -1) {
+ syslog(LOG_ERR, "iter value failed- %s",
+ scf_strerror(scf_error()));
+ ret = FCOE_ERROR;
+ break;
+ }
+ (void) strcpy(buftmp, buf);
+ macnameIter = strtok(buftmp, ":");
+ if (strcmp(macnameIter, mac_name) == 0) {
+ if (addRemoveFlag == FCOE_SCF_ADD) {
+ ret = FCOE_ERROR_EXISTS;
+ break;
+ } else {
+ found = B_TRUE;
+ continue;
+ }
+ }
+
+ valueSet[i] = scf_value_create(handle);
+ if (valueSet[i] == NULL) {
+ syslog(LOG_ERR, "scf value alloc failed - %s",
+ scf_strerror(scf_error()));
+ ret = FCOE_ERROR;
+ break;
+ }
+
+ if (scf_value_set_ustring(valueSet[i], buf) == -1) {
+ syslog(LOG_ERR, "set value failed 1- %s",
+ scf_strerror(scf_error()));
+ ret = FCOE_ERROR;
+ break;
+ }
+
+ if (scf_entry_add_value(entry, valueSet[i]) == -1) {
+ syslog(LOG_ERR, "add value failed - %s",
+ scf_strerror(scf_error()));
+ ret = FCOE_ERROR;
+ break;
+ }
+
+ i++;
+
+ if (i >= lastAlloc) {
+ lastAlloc += portListAlloc;
+ valueSet = realloc(valueSet,
+ sizeof (*valueSet) * lastAlloc);
+ if (valueSet == NULL) {
+ ret = FCOE_ERROR;
+ break;
+ }
+ }
+ }
+ }
+
+ valueArraySize = i;
+ if (!found && (addRemoveFlag == FCOE_SCF_REMOVE)) {
+ ret = FCOE_ERROR_MEMBER_NOT_FOUND;
+ }
+ if (ret != FCOE_SUCCESS) {
+ goto out;
+ }
+
+ if (addRemoveFlag == FCOE_SCF_ADD) {
+ /*
+ * Now create the new entry
+ */
+ valueSet[i] = scf_value_create(handle);
+ if (valueSet[i] == NULL) {
+ syslog(LOG_ERR, "scf value alloc failed - %s",
+ scf_strerror(scf_error()));
+ ret = FCOE_ERROR;
+ goto out;
+ } else {
+ valueArraySize++;
+ }
+
+ /*
+ * Set the new member name
+ */
+ if (scf_value_set_ustring(valueSet[i], memberName) == -1) {
+ syslog(LOG_ERR, "set value failed 2- %s",
+ scf_strerror(scf_error()));
+ ret = FCOE_ERROR;
+ goto out;
+ }
+
+ /*
+ * Add the new member
+ */
+ if (scf_entry_add_value(entry, valueSet[i]) == -1) {
+ syslog(LOG_ERR, "add value failed - %s",
+ scf_strerror(scf_error()));
+ ret = FCOE_ERROR;
+ goto out;
+ }
+ }
+
+ if ((commitRet = scf_transaction_commit(tran)) != 1) {
+ syslog(LOG_ERR, "transaction commit failed - %s",
+ scf_strerror(scf_error()));
+ if (commitRet == 0) {
+ ret = FCOE_ERROR_BUSY;
+ } else {
+ ret = FCOE_ERROR;
+ }
+ goto out;
+ }
+
+out:
+ /*
+ * Free resources
+ */
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+ if (pg != NULL) {
+ scf_pg_destroy(pg);
+ }
+ if (tran != NULL) {
+ scf_transaction_destroy(tran);
+ }
+ if (entry != NULL) {
+ scf_entry_destroy(entry);
+ }
+ if (prop != NULL) {
+ scf_property_destroy(prop);
+ }
+ if (valueIter != NULL) {
+ scf_iter_destroy(valueIter);
+ }
+ if (valueLookup != NULL) {
+ scf_value_destroy(valueLookup);
+ }
+
+ /*
+ * Free valueSet scf resources
+ */
+ if (valueArraySize > 0) {
+ for (i = 0; i < valueArraySize; i++) {
+ scf_value_destroy(valueSet[i]);
+ }
+ }
+ /*
+ * Now free the pointer array to the resources
+ */
+ if (valueSet != NULL) {
+ free(valueSet);
+ }
+
+ return (ret);
+}
+
FCOE_STATUS
FCOE_CreatePort(
const FCOE_UINT8 *macLinkName,
@@ -93,7 +477,7 @@ FCOE_CreatePort(
FCOE_PORT_WWN nwwn,
FCOE_UINT8 promiscuous)
{
- FCOE_STATUS status = FCOE_STATUS_OK;
+ FCOE_STATUS status;
int fcoe_fd;
fcoeio_t fcoeio;
fcoeio_create_port_param_t param;
@@ -118,6 +502,12 @@ FCOE_CreatePort(
if (dladm_name2info(handle, (const char *)macLinkName,
&linkid, NULL, &class, NULL) != DLADM_STATUS_OK) {
dladm_close(handle);
+ (void) fcoe_add_remove_scf_entry((char *)macLinkName,
+ "",
+ "",
+ portType,
+ 0,
+ FCOE_SCF_REMOVE);
return (FCOE_STATUS_ERROR_GET_LINKINFO);
}
dladm_close(handle);
@@ -204,6 +594,17 @@ FCOE_CreatePort(
status = FCOE_STATUS_ERROR;
}
} else {
+ char cpwwn[17], cnwwn[17];
+
+ WWN2str(cpwwn, &pwwn);
+ WWN2str(cnwwn, &nwwn);
+
+ (void) fcoe_add_remove_scf_entry((char *)macLinkName,
+ cpwwn,
+ cnwwn,
+ portType,
+ promiscuous,
+ FCOE_SCF_ADD);
status = FCOE_STATUS_OK;
}
(void) close(fcoe_fd);
@@ -219,6 +620,8 @@ FCOE_DeletePort(const FCOE_UINT8 *macLinkName)
dladm_handle_t handle;
datalink_id_t linkid;
fcoeio_delete_port_param_t fc_del_port;
+ uint64_t is_target = 0;
+ int io_ret = 0;
if (macLinkName == NULL) {
return (FCOE_STATUS_ERROR_INVAL_ARG);
@@ -249,10 +652,13 @@ FCOE_DeletePort(const FCOE_UINT8 *macLinkName)
/* only 4 bytes here, need to change */
fcoeio.fcoeio_ilen = sizeof (fcoeio_delete_port_param_t);
- fcoeio.fcoeio_xfer = FCOEIO_XFER_WRITE;
+ fcoeio.fcoeio_olen = sizeof (uint64_t);
+ fcoeio.fcoeio_xfer = FCOEIO_XFER_RW;
fcoeio.fcoeio_ibuf = (uintptr_t)&fc_del_port;
+ fcoeio.fcoeio_obuf = (uintptr_t)&is_target;
- if (ioctl(fcoe_fd, FCOEIO_CMD, &fcoeio) != 0) {
+ io_ret = ioctl(fcoe_fd, FCOEIO_CMD, &fcoeio);
+ if (io_ret != 0) {
switch (fcoeio.fcoeio_status) {
case FCOEIOE_INVAL_ARG:
status = FCOE_STATUS_ERROR_INVAL_ARG;
@@ -278,8 +684,29 @@ FCOE_DeletePort(const FCOE_UINT8 *macLinkName)
status = FCOE_STATUS_ERROR;
}
} else {
+ (void) fcoe_add_remove_scf_entry((char *)macLinkName,
+ "",
+ "",
+ is_target,
+ 0,
+ FCOE_SCF_REMOVE);
status = FCOE_STATUS_OK;
}
+
+ if (io_ret == FCOEIOE_MAC_NOT_FOUND) {
+ (void) fcoe_add_remove_scf_entry((char *)macLinkName,
+ "",
+ "",
+ 0,
+ 0,
+ FCOE_SCF_REMOVE);
+ (void) fcoe_add_remove_scf_entry((char *)macLinkName,
+ "",
+ "",
+ 1,
+ 0,
+ FCOE_SCF_REMOVE);
+ }
(void) close(fcoe_fd);
return (status);
}
@@ -344,6 +771,8 @@ FCOE_GetPortList(
retry++;
default:
status = FCOE_STATUS_ERROR;
+ (void) close(fcoe_fd);
+ return (status);
}
} else {
status = FCOE_STATUS_OK;
@@ -396,3 +825,148 @@ FCOE_GetPortList(
(void) close(fcoe_fd);
return (status);
}
+
+FCOE_STATUS FCOE_LoadConfig(
+ FCOE_UINT8 portType,
+ FCOE_SMF_PORT_LIST **portlist)
+{
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+ scf_propertygroup_t *pg = NULL;
+ scf_transaction_t *tran = NULL;
+ scf_transaction_entry_t *entry = NULL;
+ scf_property_t *prop = NULL;
+ scf_value_t *valueLookup = NULL;
+ scf_iter_t *valueIter = NULL;
+ char buf[FCOE_PORT_LIST_LENGTH] = {0};
+ int commitRet;
+ FCOE_UINT32 portIndex;
+ int bufsize, retry;
+ int size = 10; /* default first attempt */
+ int pg_or_prop_not_found = 0;
+
+ commitRet = fcoe_cfg_scf_init(&handle, &svc, portType);
+ if (commitRet != FCOE_SUCCESS) {
+ goto out;
+ }
+
+ if (((pg = scf_pg_create(handle)) == NULL) ||
+ ((tran = scf_transaction_create(handle)) == NULL) ||
+ ((entry = scf_entry_create(handle)) == NULL) ||
+ ((prop = scf_property_create(handle)) == NULL) ||
+ ((valueIter = scf_iter_create(handle)) == NULL)) {
+ goto out;
+ }
+
+ if (scf_service_get_pg(svc, FCOE_PG_NAME, pg) == -1) {
+ pg_or_prop_not_found = 1;
+ goto out;
+ }
+
+ if (scf_pg_get_property(pg, FCOE_PORT_LIST, prop) == -1) {
+ pg_or_prop_not_found = 1;
+ goto out;
+ }
+
+ valueLookup = scf_value_create(handle);
+ if (valueLookup == NULL) {
+ syslog(LOG_ERR, "scf value alloc failed - %s",
+ scf_strerror(scf_error()));
+ goto out;
+ }
+
+ portIndex = 0;
+
+ do {
+ if (scf_iter_property_values(valueIter, prop) == -1) {
+ syslog(LOG_ERR, "iter value failed - %s",
+ scf_strerror(scf_error()));
+ goto out;
+ }
+
+ retry = 0;
+ bufsize = sizeof (FCOE_SMF_PORT_INSTANCE) * (size - 1) +
+ sizeof (FCOE_SMF_PORT_LIST);
+ *portlist = (PFCOE_SMF_PORT_LIST)malloc(bufsize);
+
+ while (scf_iter_next_value(valueIter, valueLookup) == 1) {
+ uint8_t *macLinkName = NULL;
+ char *remainder = NULL;
+ uint64_t nodeWWN, portWWN;
+ int is_target, is_promiscuous;
+
+ bzero(buf, sizeof (buf));
+ if (scf_value_get_ustring(valueLookup, buf,
+ MAXNAMELEN) == -1) {
+ syslog(LOG_ERR, "iter value failed - %s",
+ scf_strerror(scf_error()));
+ break;
+ }
+ macLinkName = (uint8_t *)strtok(buf, ":");
+ remainder = strtok(NULL, "#");
+ (void) sscanf(remainder,
+ "%016" PRIx64 ":%016" PRIx64 ":%d:%d",
+ &portWWN, &nodeWWN, &is_target, &is_promiscuous);
+
+ if (portIndex >= size) {
+ free(*portlist);
+ retry = 1;
+ size *= 2;
+ break;
+ } else {
+ PFCOE_SMF_PORT_INSTANCE pi =
+ &(*portlist)->ports[portIndex++];
+ (void) strcpy((char *)pi->mac_link_name,
+ (char *)macLinkName);
+ pi->port_type = is_target ?
+ FCOE_PORTTYPE_TARGET:
+ FCOE_PORTTYPE_INITIATOR;
+ portWWN = htonll(portWWN);
+ nodeWWN = htonll(nodeWWN);
+ (void) memcpy(&pi->port_pwwn, &portWWN,
+ sizeof (FCOE_PORT_WWN));
+ (void) memcpy(&pi->port_nwwn, &nodeWWN,
+ sizeof (FCOE_PORT_WWN));
+ pi->mac_promisc = is_promiscuous;
+ }
+ }
+
+ (*portlist)->port_num = portIndex;
+ } while (retry == 1);
+
+ return (FCOE_STATUS_OK);
+out:
+ /*
+ * Free resources
+ */
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+ if (pg != NULL) {
+ scf_pg_destroy(pg);
+ }
+ if (tran != NULL) {
+ scf_transaction_destroy(tran);
+ }
+ if (entry != NULL) {
+ scf_entry_destroy(entry);
+ }
+ if (prop != NULL) {
+ scf_property_destroy(prop);
+ }
+ if (valueIter != NULL) {
+ scf_iter_destroy(valueIter);
+ }
+ if (valueLookup != NULL) {
+ scf_value_destroy(valueLookup);
+ }
+
+ if (pg_or_prop_not_found == 1) {
+ return (FCOE_STATUS_OK);
+ } else {
+ return (FCOE_STATUS_ERROR);
+ }
+}