# # 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 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Copyright (c) 2018, Joyent, Inc. COMMONBASE = ../../common PROG = fcinfo ROOT_PROG_LINK = $(ROOTUSRSBIN)/fcadm MANIFEST = npiv_config.xml SVCMETHOD = npivconfig PRODUCT = $(PROG) $(ROOT_PROG_LINK) : FILEMODE = 0555 LOCAL_OBJS = fcinfo.o fcinfo-list.o fcadm-list.o printAttrs.o fcoeadm.o COMMON_OBJS = cmdparse.o OBJS = $(LOCAL_OBJS) $(COMMON_OBJS) include ../Makefile.cmd POFILE = fcinfo_cmd.po POFILES = fcinfo.po fcinfo-list.po fcadm-list.po printAttrs.po fcoeadm.po CERRWARN += -Wno-unused-variable # not linted SMATCH=off ROOTMANIFESTDIR= $(ROOTSVCNETWORK) LDLIBS += -lHBAAPI LDLIBS += -lfcoe LDLIBS += -lscf INCS += -I. INCS += -I$(SRC)/lib/hbaapi/common INCS += -I$(COMMONBASE)/cmdparse INCS += -I$(SRC)/lib/libfcoe/common CPPFLAGS += -D_LARGEFILE64_SOURCE=1 -D_REENTRANT $(INCS) $(NOT_RELEASE_BUILD)CPPFLAGS += -DDEBUG .KEEP_STATE: all: $(PROG) $(PROG): $(OBJS) $(LINK.c) -o $@ $(OBJS) $(LDLIBS) $(POST_PROCESS) $(ROOT_PROG_LINK): $(ROOTUSRSBIN)/$(PROG) -$(RM) $@ $(LN) $(ROOTUSRSBIN)/$(PROG) $@ install: all $(ROOTMANIFEST) $(ROOTSVCMETHOD) $(ROOTUSRSBINPROG) $(ROOT_PROG_LINK) cmdparse.o: $(COMMONBASE)/cmdparse/cmdparse.c $(COMPILE.c) -o $@ $(COMMONBASE)/cmdparse/cmdparse.c $(POST_PROCESS_O) $(POFILE): $(POFILES) $(RM) $@ $(CAT) $(POFILES) > $@ clean: $(RM) $(OBJS) check: $(CHKMANIFEST) # Links from /usr/sbin to /sbin $(ROOTUSRSBINLINKS): -$(RM) $@; $(SYMLINK) ../../sbin/$(@F) $@ include ../Makefile.targ /* * 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 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #define FCADM_RETRY_TIMES 10 #define FCADM_SLEEP_TIME 1 static char * WWN2str(char *buf, HBA_WWN *wwn) { int j; unsigned char *pc = (unsigned char *)&(wwn->wwn[0]); buf[0] = '\0'; for (j = 0; j < 16; j += 2) { sprintf(&buf[j], "%02X", (int)*pc++); } return (buf); } static int isValidWWN(char *wwn) { int index; if (wwn == NULL) { return (0); } if (strlen(wwn) != 16) { return (0); } for (index = 0; index < 16; index++) { if (isxdigit(wwn[index])) { continue; } return (0); } return (1); } /* * Initialize scf stmf service access * handle - returned handle * service - returned service handle */ static int cfgInit(scf_handle_t **handle, scf_service_t **service) { scf_scope_t *scope = NULL; int ret; if ((*handle = scf_handle_create(SCF_VERSION)) == NULL) { /* log error */ ret = NPIV_ERROR; goto err; } if (scf_handle_bind(*handle) == -1) { /* log error */ ret = NPIV_ERROR; goto err; } if ((*service = scf_service_create(*handle)) == NULL) { /* log error */ ret = NPIV_ERROR; goto err; } if ((scope = scf_scope_create(*handle)) == NULL) { /* log error */ ret = NPIV_ERROR; goto err; } if (scf_handle_get_scope(*handle, SCF_SCOPE_LOCAL, scope) == -1) { /* log error */ ret = NPIV_ERROR; goto err; } if (scf_scope_get_service(scope, NPIV_SERVICE, *service) == -1) { /* log error */ ret = NPIV_ERROR_SERVICE_NOT_FOUND; goto err; } scf_scope_destroy(scope); return (NPIV_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 npivAddRemoveNPIVEntry(char *ppwwn, char *vnwwn, char *vpwwn, int vindex, 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 = NPIV_SUCCESS; boolean_t createProp = B_FALSE; int lastAlloc = 0; char buf[NPIV_PORT_LIST_LENGTH] = {0}; char memberName[NPIV_PORT_LIST_LENGTH] = {0}; boolean_t found = B_FALSE; int i = 0; int valueArraySize = 0; int commitRet; if (vnwwn) { sprintf(memberName, "%s:%s:%s:%d", ppwwn, vpwwn, vnwwn, vindex); } else { sprintf(memberName, "%s:%s", ppwwn, vpwwn); } ret = cfgInit(&handle, &svc); if (ret != NPIV_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 = NPIV_ERROR; goto out; } /* get property group or create it */ if (scf_service_get_pg(svc, NPIV_PG_NAME, pg) == -1) { if ((scf_error() == SCF_ERROR_NOT_FOUND) && (addRemoveFlag == NPIV_ADD)) { if (scf_service_add_pg(svc, NPIV_PG_NAME, SCF_GROUP_APPLICATION, 0, pg) == -1) { syslog(LOG_ERR, "add pg failed - %s", scf_strerror(scf_error())); ret = NPIV_ERROR; } else { createProp = B_TRUE; } } else if (scf_error() == SCF_ERROR_NOT_FOUND) { ret = NPIV_ERROR_NOT_FOUND; } else { syslog(LOG_ERR, "get pg failed - %s", scf_strerror(scf_error())); ret = NPIV_ERROR; } if (ret != NPIV_SUCCESS) { goto out; } } /* Begin the transaction */ if (scf_transaction_start(tran, pg) == -1) { syslog(LOG_ERR, "start transaction failed - %s", scf_strerror(scf_error())); ret = NPIV_ERROR; goto out; } valueSet = (scf_value_t **)calloc(1, sizeof (*valueSet) * (lastAlloc = PORT_LIST_ALLOC)); if (valueSet == NULL) { ret = NPIV_ERROR_NOMEM; goto out; } if (createProp) { if (scf_transaction_property_new(tran, entry, NPIV_PORT_LIST, SCF_TYPE_USTRING) == -1) { if (scf_error() == SCF_ERROR_EXISTS) { ret = NPIV_ERROR_EXISTS; } else { syslog(LOG_ERR, "transaction property new failed - %s", scf_strerror(scf_error())); ret = NPIV_ERROR; } goto out; } } else { if (scf_transaction_property_change(tran, entry, NPIV_PORT_LIST, SCF_TYPE_USTRING) == -1) { syslog(LOG_ERR, "transaction property change failed - %s", scf_strerror(scf_error())); ret = NPIV_ERROR; goto out; } if (scf_pg_get_property(pg, NPIV_PORT_LIST, prop) == -1) { syslog(LOG_ERR, "get property failed - %s", scf_strerror(scf_error())); ret = NPIV_ERROR; goto out; } valueLookup = scf_value_create(handle); if (valueLookup == NULL) { syslog(LOG_ERR, "scf value alloc failed - %s", scf_strerror(scf_error())); ret = NPIV_ERROR; goto out; } if (scf_iter_property_values(valueIter, prop) == -1) { syslog(LOG_ERR, "iter value failed - %s", scf_strerror(scf_error())); ret = NPIV_ERROR; goto out; } while (scf_iter_next_value(valueIter, valueLookup) == 1) { 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 = NPIV_ERROR; break; } if ((strlen(buf) >= strlen(memberName)) && bcmp(buf, memberName, strlen(memberName)) == 0) { if (addRemoveFlag == NPIV_ADD) { ret = NPIV_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 = NPIV_ERROR; break; } if (scf_value_set_ustring(valueSet[i], buf) == -1) { syslog(LOG_ERR, "set value failed - %s", scf_strerror(scf_error())); ret = NPIV_ERROR; break; } if (scf_entry_add_value(entry, valueSet[i]) == -1) { syslog(LOG_ERR, "add value failed - %s", scf_strerror(scf_error())); ret = NPIV_ERROR; break; } i++; if (i >= lastAlloc) { lastAlloc += PORT_LIST_ALLOC; valueSet = realloc(valueSet, sizeof (*valueSet) * lastAlloc); if (valueSet == NULL) { ret = NPIV_ERROR; break; } } } } valueArraySize = i; if (!found && (addRemoveFlag == NPIV_REMOVE)) { ret = NPIV_ERROR_MEMBER_NOT_FOUND; } if (ret != NPIV_SUCCESS) { goto out; } if (addRemoveFlag == NPIV_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 = NPIV_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 - %s", scf_strerror(scf_error())); ret = NPIV_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 = NPIV_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 = NPIV_ERROR_BUSY; } else { ret = NPIV_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); } static int retrieveNPIVAttrs(HBA_HANDLE handle, HBA_WWN portWWN, HBA_PORTNPIVATTRIBUTES *npivattrs, HBA_UINT32 *portIndex) { HBA_STATUS status; HBA_ADAPTERATTRIBUTES attrs; HBA_PORTATTRIBUTES portattrs; int portCtr; int times = 0; /* argument checking */ if (npivattrs == NULL || portIndex == NULL) { return (1); } memset(&attrs, 0, sizeof (HBA_ADAPTERATTRIBUTES)); status = HBA_GetAdapterAttributes(handle, &attrs); while ((status == HBA_STATUS_ERROR_TRY_AGAIN || status == HBA_STATUS_ERROR_BUSY) && times++ < 130) { status = HBA_GetAdapterAttributes(handle, &attrs); if (status == HBA_STATUS_OK) { break; } (void) sleep(1); } if (status != HBA_STATUS_OK) { return (1); } memset(&portattrs, 0, sizeof (HBA_PORTATTRIBUTES)); for (portCtr = 0; portCtr < attrs.NumberOfPorts; portCtr++) { status = HBA_GetAdapterPortAttributes(handle, portCtr, &portattrs); times = 0; while ((status == HBA_STATUS_ERROR_TRY_AGAIN || status == HBA_STATUS_ERROR_BUSY) && times++ < HBA_MAX_RETRIES) { status = HBA_GetAdapterPortAttributes(handle, portCtr, &portattrs); if (status == HBA_STATUS_OK) { break; } (void) sleep(1); } if (status != HBA_STATUS_OK) { return (1); } if (memcmp(portWWN.wwn, portattrs.PortWWN.wwn, sizeof (portattrs.PortWWN.wwn)) == 0) { break; } } if (portCtr >= attrs.NumberOfPorts) { *portIndex = 0; return (1); } *portIndex = portCtr; status = Sun_HBA_GetPortNPIVAttributes(handle, portCtr, npivattrs); times = 0; while ((status == HBA_STATUS_ERROR_TRY_AGAIN || status == HBA_STATUS_ERROR_BUSY) && times++ < HBA_MAX_RETRIES) { status = Sun_HBA_GetPortNPIVAttributes(handle, portCtr, npivattrs); if (status == HBA_STATUS_OK) { break; } (void) sleep(1); } if (status != HBA_STATUS_OK) { return (1); } return (0); } int fc_util_delete_npivport(int wwnCount, char **wwn_argv, cmdOptions_t *options) { uint64_t physicalportWWN, virtualportWWN; HBA_WWN portWWN, vportWWN; HBA_STATUS status; HBA_HANDLE handle; HBA_PORTNPIVATTRIBUTES npivattrs; HBA_UINT32 portIndex; char pwwn[17]; int times; if (wwnCount != 1) { fprintf(stderr, gettext("Invalid Parameter\n")); return (1); } for (; options->optval; options++) { switch (options->optval) { case 'p': if (!isValidWWN(options->optarg)) { fprintf(stderr, gettext("Invalid Port WWN\n")); return (1); } sscanf(options->optarg, "%016llx", &virtualportWWN); break; default: return (1); } } if (!isValidWWN(wwn_argv[0])) { fprintf(stderr, gettext("Invalid Physical Port WWN\n")); return (1); } if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) { fprintf(stderr, gettext("Failed to load FC-HBA common library\n")); printStatus(status); fprintf(stderr, "\n"); return (1); } sscanf(wwn_argv[0], "%016llx", &physicalportWWN); physicalportWWN = htonll(physicalportWWN); memcpy(portWWN.wwn, &physicalportWWN, sizeof (physicalportWWN)); virtualportWWN = htonll(virtualportWWN); memcpy(vportWWN.wwn, &virtualportWWN, sizeof (virtualportWWN)); status = HBA_OpenAdapterByWWN(&handle, portWWN); if (status != HBA_STATUS_OK) { fprintf(stderr, gettext("Error: HBA port %s: not found\n"), wwn_argv[0]); HBA_FreeLibrary(); return (1); } /* Get physical port NPIV attributes */ if (retrieveNPIVAttrs(handle, portWWN, &npivattrs, &portIndex) == 0) { /* Check port NPIV attributes */ if (npivattrs.MaxNumberOfNPIVPorts == 0) { fprintf(stderr, gettext("Error: NPIV not Supported\n")); HBA_CloseAdapter(handle); HBA_FreeLibrary(); return (1); } /* Delete a virtual port */ status = Sun_HBA_DeleteNPIVPort(handle, portIndex, vportWWN); times = 0; while ((status == HBA_STATUS_ERROR_TRY_AGAIN || status == HBA_STATUS_ERROR_BUSY) && times++ < HBA_MAX_RETRIES) { (void) sleep(1); status = Sun_HBA_DeleteNPIVPort(handle, portIndex, vportWWN); if (status == HBA_STATUS_OK) { break; } } if (status != HBA_STATUS_OK) { fprintf(stderr, gettext("Error: failed to delete a npiv port\n")); HBA_CloseAdapter(handle); HBA_FreeLibrary(); return (1); } } else { fprintf(stderr, gettext("Error: failed to get port NPIV attributes\n")); HBA_CloseAdapter(handle); HBA_FreeLibrary(); return (1); } HBA_CloseAdapter(handle); HBA_FreeLibrary(); WWN2str(pwwn, &vportWWN); npivAddRemoveNPIVEntry(wwn_argv[0], NULL, pwwn, 0, NPIV_REMOVE); return (0); } int fc_util_create_npivport(int wwnCount, char **wwn_argv, cmdOptions_t *options) { uint64_t physicalportWWN, virtualnodeWWN, virtualportWWN; HBA_WWN portWWN, vnodeWWN, vportWWN; HBA_STATUS status; HBA_HANDLE handle; HBA_PORTNPIVATTRIBUTES npivattrs; HBA_UINT32 portIndex; HBA_UINT32 npivportIndex = 0; char nwwn[17], pwwn[17]; int randomflag = 0; int times; if (wwnCount != 1) { fprintf(stderr, gettext("Invalid Parameter\n")); return (1); } for (; options->optval; options++) { switch (options->optval) { case 'p': if (!isValidWWN(options->optarg)) { fprintf(stderr, gettext("Invalid Port WWN\n")); return (1); } sscanf(options->optarg, "%016llx", &virtualportWWN); randomflag++; break; case 'n': if (!isValidWWN(options->optarg)) { fprintf(stderr, gettext("Invalid Node WWN\n")); return (1); } sscanf(options->optarg, "%016llx", &virtualnodeWWN); randomflag++; break; default: return (1); } } if (!isValidWWN(wwn_argv[0])) { fprintf(stderr, gettext("Invalid Physical Port WWN\n")); wwnCount = 0; return (1); } if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) { fprintf(stderr, gettext("Failed to load FC-HBA common library\n")); printStatus(status); fprintf(stderr, "\n"); return (1); } sscanf(wwn_argv[0], "%016llx", &physicalportWWN); physicalportWWN = htonll(physicalportWWN); memcpy(portWWN.wwn, &physicalportWWN, sizeof (physicalportWWN)); status = HBA_OpenAdapterByWWN(&handle, portWWN); if (status != HBA_STATUS_OK) { fprintf(stderr, gettext("Error: HBA port %s: not found\n"), wwn_argv[0]); HBA_FreeLibrary(); return (1); } if (randomflag != 2) { status = Sun_HBA_AdapterCreateWWN(handle, 0, &vnodeWWN, &vportWWN, NULL, HBA_CREATE_WWN_RANDOM); if (status != HBA_STATUS_OK) { fprintf(stderr, gettext("Error: Fail to get Random WWN\n")); HBA_CloseAdapter(handle); HBA_FreeLibrary(); return (1); } } else { virtualnodeWWN = htonll(virtualnodeWWN); memcpy(vnodeWWN.wwn, &virtualnodeWWN, sizeof (virtualnodeWWN)); virtualportWWN = htonll(virtualportWWN); memcpy(vportWWN.wwn, &virtualportWWN, sizeof (virtualportWWN)); } if (memcmp(vnodeWWN.wwn, vportWWN.wwn, 8) == 0) { fprintf(stderr, gettext("Error: Port WWN is same as Node WWN\n")); HBA_CloseAdapter(handle); HBA_FreeLibrary(); return (1); } /* Get physical port NPIV attributes */ if (retrieveNPIVAttrs(handle, portWWN, &npivattrs, &portIndex) == 0) { /* Check port NPIV attributes */ if (npivattrs.MaxNumberOfNPIVPorts == 0) { fprintf(stderr, gettext("Error: NPIV not Supported\n")); HBA_CloseAdapter(handle); HBA_FreeLibrary(); return (1); } if (npivattrs.MaxNumberOfNPIVPorts == npivattrs.NumberOfNPIVPorts) { fprintf(stderr, gettext("Error: Can not create more NPIV port\n")); HBA_CloseAdapter(handle); HBA_FreeLibrary(); return (1); } /* Create a virtual port */ status = Sun_HBA_CreateNPIVPort(handle, portIndex, vnodeWWN, vportWWN, &npivportIndex); times = 0; while ((status == HBA_STATUS_ERROR_TRY_AGAIN || status == HBA_STATUS_ERROR_BUSY) && times++ < HBA_MAX_RETRIES) { (void) sleep(1); status = Sun_HBA_CreateNPIVPort(handle, portIndex, vnodeWWN, vportWWN, &npivportIndex); if (status == HBA_STATUS_OK) { break; } } if (status != HBA_STATUS_OK) { fprintf(stderr, gettext("Error: failed to create a npiv port\n")); HBA_CloseAdapter(handle); HBA_FreeLibrary(); return (1); } } else { fprintf(stderr, gettext("Error: failed to get port NPIV attributes\n")); HBA_CloseAdapter(handle); HBA_FreeLibrary(); return (1); } HBA_CloseAdapter(handle); HBA_FreeLibrary(); WWN2str(nwwn, &vnodeWWN); WWN2str(pwwn, &vportWWN); npivAddRemoveNPIVEntry(wwn_argv[0], nwwn, pwwn, npivportIndex, NPIV_ADD); return (0); } int create_npivport(char *ppwwn_str, char *vnwwn_str, char *vpwwn_str, int vindex) { uint64_t physicalportWWN, virtualnodeWWN, virtualportWWN; HBA_WWN portWWN, vnodeWWN, vportWWN; HBA_STATUS status; HBA_HANDLE handle; HBA_PORTNPIVATTRIBUTES npivattrs; HBA_UINT32 portIndex; HBA_UINT32 npivportIndex; int times = 0; sscanf(ppwwn_str, "%016llx", &physicalportWWN); physicalportWWN = htonll(physicalportWWN); memcpy(portWWN.wwn, &physicalportWWN, sizeof (physicalportWWN)); sscanf(vnwwn_str, "%016llx", &virtualnodeWWN); virtualnodeWWN = htonll(virtualnodeWWN); memcpy(vnodeWWN.wwn, &virtualnodeWWN, sizeof (virtualnodeWWN)); sscanf(vpwwn_str, "%016llx", &virtualportWWN); virtualportWWN = htonll(virtualportWWN); memcpy(vportWWN.wwn, &virtualportWWN, sizeof (virtualportWWN)); npivportIndex = vindex; status = HBA_OpenAdapterByWWN(&handle, portWWN); while (status == HBA_STATUS_ERROR_TRY_AGAIN || status == HBA_STATUS_ERROR_BUSY) { (void) sleep(FCADM_SLEEP_TIME); status = HBA_OpenAdapterByWWN(&handle, portWWN); if (times++ > FCADM_RETRY_TIMES) { return (1); } } /* Get physical port NPIV attributes */ if (retrieveNPIVAttrs(handle, portWWN, &npivattrs, &portIndex) == 0) { /* Check port NPIV attributes */ if (npivattrs.MaxNumberOfNPIVPorts == 0) { goto failed; } if (npivattrs.MaxNumberOfNPIVPorts == npivattrs.NumberOfNPIVPorts) { goto failed; } /* Create a virtual port */ status = Sun_HBA_CreateNPIVPort(handle, portIndex, vnodeWWN, vportWWN, &npivportIndex); times = 0; while (status == HBA_STATUS_ERROR_TRY_AGAIN || status == HBA_STATUS_ERROR_BUSY) { (void) sleep(FCADM_SLEEP_TIME); status = Sun_HBA_CreateNPIVPort(handle, portIndex, vnodeWWN, vportWWN, &npivportIndex); if (times++ > FCADM_RETRY_TIMES) { goto failed; } } } failed: HBA_CloseAdapter(handle); return (0); } int fc_util_create_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[NPIV_PORT_LIST_LENGTH] = {0}; int commitRet; commitRet = cfgInit(&handle, &svc); if (commitRet != NPIV_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; } /* get property group or create it */ if (scf_service_get_pg(svc, NPIV_PG_NAME, pg) == -1) { goto out; } if (scf_pg_get_property(pg, NPIV_PORT_LIST, prop) == -1) { syslog(LOG_ERR, "get property failed - %s", scf_strerror(scf_error())); goto out; } valueLookup = scf_value_create(handle); if (valueLookup == NULL) { syslog(LOG_ERR, "scf value alloc failed - %s", scf_strerror(scf_error())); goto out; } if (scf_iter_property_values(valueIter, prop) == -1) { syslog(LOG_ERR, "iter value failed - %s", scf_strerror(scf_error())); goto out; } if (HBA_LoadLibrary() != HBA_STATUS_OK) { goto out; } HBA_GetNumberOfAdapters(); while (scf_iter_next_value(valueIter, valueLookup) == 1) { char ppwwn[17] = {0}; char vnwwn[17] = {0}; char vpwwn[17] = {0}; int vindex = 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())); break; } sscanf(buf, "%16s:%16s:%16s:%d", ppwwn, vpwwn, vnwwn, &vindex); create_npivport(ppwwn, vnwwn, vpwwn, vindex); } HBA_FreeLibrary(); 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); } return (0); } /* ARGSUSED */ int fc_util_force_lip(int objects, char *argv[]) { uint64_t hbaWWN; HBA_WWN myWWN; HBA_HANDLE handle; HBA_STATUS status; int rval = 0; if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) { fprintf(stderr, gettext("Failed to load FC-HBA library\n")); printStatus(status); fprintf(stderr, "\n"); return (1); } sscanf(argv[0], "%016llx", &hbaWWN); hbaWWN = htonll(hbaWWN); memcpy(myWWN.wwn, &hbaWWN, sizeof (hbaWWN)); /* * Try target mode first */ if ((status = Sun_HBA_OpenTgtAdapterByWWN(&handle, myWWN)) != HBA_STATUS_OK) { /* * Continue to try initiator mode */ if ((status = HBA_OpenAdapterByWWN(&handle, myWWN)) != HBA_STATUS_OK) { fprintf(stderr, gettext("Error: HBA %s not found\n"), argv[0]); return (0); } } status = Sun_HBA_ForceLip(handle, &rval); if ((status != HBA_STATUS_OK) || (rval != 0)) { fprintf(stderr, gettext("Error: Failed to reinitialize the " "link of HBA %s\n"), argv[0]); } return (0); } /* * 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 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include "fcinfo.h" #include struct lun { uchar_t val[8]; }; typedef enum { HBA_PORT, REMOTE_PORT, LOGICAL_UNIT } resource_type; typedef struct rep_luns_rsp { uint32_t length; uint32_t rsrvd; struct lun lun[1]; } rep_luns_rsp_t; static int getTargetMapping(HBA_HANDLE, HBA_WWN myhbaPortWWN, HBA_FCPTARGETMAPPINGV2 **mapping); static int processHBA(HBA_HANDLE handle, HBA_ADAPTERATTRIBUTES attrs, int portIndex, HBA_PORTATTRIBUTES port, HBA_FCPTARGETMAPPINGV2 *map, int resourceType, int flags, int mode); static void processRemotePort(HBA_HANDLE handle, HBA_WWN portWWN, HBA_FCPTARGETMAPPINGV2 *map, int wwnCount, char **wwn_argv, int flags); static void handleRemotePort(HBA_HANDLE handle, HBA_WWN portWWN, HBA_WWN myRemotePortWWN, HBA_PORTATTRIBUTES *discPort); static void printLinkStat(HBA_HANDLE handle, HBA_WWN hbaportWWN, HBA_WWN destWWN); static void handleScsiTarget(HBA_HANDLE handle, HBA_WWN hbaPortWWN, HBA_WWN scsiTargetWWN, HBA_FCPTARGETMAPPINGV2 *map); static int retrieveAttrs(HBA_HANDLE handle, HBA_WWN hbaPortWWN, HBA_ADAPTERATTRIBUTES *attrs, HBA_PORTATTRIBUTES *port, int *portIndex); static void searchDevice(discoveredDevice **devList, HBA_FCPSCSIENTRYV2 entry, HBA_WWN initiatorPortWWN, HBA_HANDLE handle, boolean_t verbose); /* * This function retrieve the adapater attributes, port attributes, and * portIndex for the given handle and hba port WWN. * * Arguments: * handle an HBA_HANDLE to a adapter * hbaPortWWN WWN of the port on the adapter to which to retrieve * HBA_PORTATTRIBUTES from * attrs pointer to a HBA_ADAPTERATTRIBUTES structure. Upon * successful completion, this structure will be filled in * port pointer to a HBA_PORTATTRIBUTES structure. Upon successful * completion, this structure will be fill in * portIndex the Index count of the port on the adapter that is * associated with the WWN. * * Returns * 0 successfully retrieve all information * >0 otherwise */ static int retrieveAttrs(HBA_HANDLE handle, HBA_WWN hbaPortWWN, HBA_ADAPTERATTRIBUTES *attrs, HBA_PORTATTRIBUTES *port, int *portIndex) { HBA_STATUS status; int portCtr; int times; /* argument checking */ if (attrs == NULL || port == NULL || portIndex == NULL) { fprintf(stderr, gettext("Error: Invalid arguments to " "retreiveAttrs\n")); return (1); } /* retrieve Adapter attributes */ memset(attrs, 0, sizeof (HBA_ADAPTERATTRIBUTES)); status = HBA_GetAdapterAttributes(handle, attrs); times = 0; while ((status == HBA_STATUS_ERROR_TRY_AGAIN || status == HBA_STATUS_ERROR_BUSY) && times++ < HBA_MAX_RETRIES) { (void) sleep(1); status = HBA_GetAdapterAttributes(handle, attrs); if (status == HBA_STATUS_OK) { break; } } if (status != HBA_STATUS_OK) { fprintf(stderr, gettext("Failed to get adapter " "attributes handle(%d) Reason: "), handle); printStatus(status); fprintf(stderr, "\n"); return (1); } /* * find the corresponding port on the adapter and retrieve * port attributes as well as the port index */ memset(port, 0, sizeof (HBA_PORTATTRIBUTES)); for (portCtr = 0; portCtr < attrs->NumberOfPorts; portCtr++) { if ((status = HBA_GetAdapterPortAttributes(handle, portCtr, port)) != HBA_STATUS_OK) { fprintf(stderr, gettext("Error: Failed to get port (%d) " "attributes reason: "), portCtr); printStatus(status); fprintf(stderr, "\n"); return (1); } if (memcmp(hbaPortWWN.wwn, port->PortWWN.wwn, sizeof (port->PortWWN.wwn)) == 0) { break; } } if (portCtr >= attrs->NumberOfPorts) { /* * not able to find corresponding port WWN * returning an error */ *portIndex = 0; return (1); } *portIndex = portCtr; return (0); } /* * This function retrieves target mapping information for the HBA port WWN. * This function will allocate space for the mapping structure which the caller * must free when they are finished * * Arguments: * handle - a handle to a HBA that we will be processing * hbaPortWWN - the port WWN for the HBA port to retrieve the mappings for * mapping - a pointer to a pointer for the target mapping structure * Upon successful completion of this function, *mapping will contain * the target mapping information * * returns: * 0 if successful * 1 otherwise */ static int getTargetMapping(HBA_HANDLE handle, HBA_WWN hbaPortWWN, HBA_FCPTARGETMAPPINGV2 **mapping) { HBA_FCPTARGETMAPPINGV2 *map; HBA_STATUS status; int count; /* argument sanity checking */ if (mapping == NULL) { fprintf(stderr, gettext("Internal Error: mapping is NULL")); return (1); } *mapping = NULL; if ((map = calloc(1, sizeof (HBA_FCPTARGETMAPPINGV2))) == NULL) { fprintf(stderr, gettext("Internal Error: Unable to calloc map")); return (1); } status = HBA_GetFcpTargetMappingV2(handle, hbaPortWWN, map); count = map->NumberOfEntries; if (status == HBA_STATUS_ERROR_MORE_DATA) { free(map); if ((map = calloc(1, (sizeof (HBA_FCPSCSIENTRYV2)*(count-1)) + sizeof (HBA_FCPTARGETMAPPINGV2))) == NULL) { fprintf(stderr, gettext("Unable to calloc map of size: %d"), count); return (1); } map->NumberOfEntries = count; status = HBA_GetFcpTargetMappingV2(handle, hbaPortWWN, map); } if (status != HBA_STATUS_OK) { fprintf(stderr, gettext("Error: Unable to get Target Mapping\n")); printStatus(status); fprintf(stderr, "\n"); free(map); return (1); } *mapping = map; return (0); } /* * This function handles the remoteport object. It will issue a report lun * to determine whether it is a scsi-target and then print the information. * * Arguments: * handle - a handle to a HBA that we will be processing * portWWN - the port WWN for the HBA port we will be issuing the SCSI * ReportLUNS through * remotePortWWN - the port WWN we will be issuing the report lun call to * discPort - PORTATTRIBUTES structure for the remotePortWWN */ static void handleRemotePort(HBA_HANDLE handle, HBA_WWN portWWN, HBA_WWN remotePortWWN, HBA_PORTATTRIBUTES *discPort) { HBA_STATUS status; int scsiTargetType; uchar_t raw_luns[LUN_LENGTH]; HBA_UINT32 responseSize = LUN_LENGTH; struct scsi_extended_sense sense; HBA_UINT32 senseSize = sizeof (struct scsi_extended_sense); HBA_UINT8 rep_luns_status; /* argument checking */ if (discPort == NULL) { return; } memset(raw_luns, 0, sizeof (raw_luns)); /* going to issue a report lun to check if this is a scsi-target */ status = HBA_ScsiReportLUNsV2(handle, portWWN, remotePortWWN, (void *)raw_luns, &responseSize, &rep_luns_status, (void *)&sense, &senseSize); if (status == HBA_STATUS_OK) { scsiTargetType = SCSI_TARGET_TYPE_YES; } else if (status == HBA_STATUS_ERROR_NOT_A_TARGET) { scsiTargetType = SCSI_TARGET_TYPE_NO; } else { scsiTargetType = SCSI_TARGET_TYPE_UNKNOWN; } printDiscoPortInfo(discPort, scsiTargetType); } /* * This function will issue the RLS and print out the port statistics for * the given destWWN * * Arguments * handle - a handle to a HBA that we will be processing * hbaPortWWN - the hba port WWN through which the RLS will be sent * destWWN - the remote port to which the RLS will be sent */ static void printLinkStat(HBA_HANDLE handle, HBA_WWN hbaPortWWN, HBA_WWN destWWN) { HBA_STATUS status; fc_rls_acc_t rls_payload; uint32_t rls_payload_size; memset(&rls_payload, 0, sizeof (rls_payload)); rls_payload_size = sizeof (rls_payload); status = HBA_SendRLS(handle, hbaPortWWN, destWWN, &rls_payload, &rls_payload_size); if (status != HBA_STATUS_OK) { fprintf(stderr, gettext("Error: SendRLS failed for %016llx\n"), wwnConversion(destWWN.wwn)); } else { printPortStat(&rls_payload); } } int printHBANPIVPortInfo(HBA_HANDLE handle, int portindex) { HBA_PORTNPIVATTRIBUTES portattrs; HBA_NPIVATTRIBUTES npivattrs; HBA_STATUS status; int index; int times = 0; status = Sun_HBA_GetPortNPIVAttributes(handle, portindex, &portattrs); while (status == HBA_STATUS_ERROR_TRY_AGAIN || status == HBA_STATUS_ERROR_BUSY) { (void) sleep(1); status = Sun_HBA_GetPortNPIVAttributes( handle, portindex, &portattrs); if (times++ > HBA_MAX_RETRIES) { break; } } if (status == HBA_STATUS_ERROR_NOT_SUPPORTED) { fprintf(stdout, gettext("\tNPIV Not Supported\n")); return (0); } if (status != HBA_STATUS_OK) { fprintf(stderr, gettext("Error: Failed to get port (%d) " "npiv attributes reason: "), portindex); printStatus(status); fprintf(stderr, "\n"); return (1); } if (portattrs.MaxNumberOfNPIVPorts) { fprintf(stdout, gettext("\tMax NPIV Ports: %d\n"), portattrs.MaxNumberOfNPIVPorts); } else { fprintf(stdout, gettext("\tNPIV Not Supported\n")); return (0); } fprintf(stdout, gettext("\tNPIV port list:\n")); for (index = 0; index < portattrs.NumberOfNPIVPorts; index++) { int times = 0; status = Sun_HBA_GetNPIVPortInfo(handle, portindex, index, &npivattrs); while (status == HBA_STATUS_ERROR_TRY_AGAIN || status == HBA_STATUS_ERROR_BUSY) { (void) sleep(1); status = Sun_HBA_GetNPIVPortInfo(handle, portindex, index, &npivattrs); if (times++ > HBA_MAX_RETRIES) { break; } } if (status != HBA_STATUS_OK) { fprintf(stderr, gettext("Error: Failed to get npiv port (%d) " "attributes reason: "), index); printStatus(status); fprintf(stderr, "\n"); return (1); } else { fprintf(stdout, gettext("\t Virtual Port%d:\n"), index+1); fprintf(stdout, gettext("\t\tNode WWN: %016llx\n"), wwnConversion(npivattrs.NodeWWN.wwn)); fprintf(stdout, gettext("\t\tPort WWN: %016llx\n"), wwnConversion(npivattrs.PortWWN.wwn)); } } return (0); } /* * This function will process hba port, remote port and scsi-target information * for the given handle. * * Arguments: * handle - a handle to a HBA that we will be processing * resourceType - resourceType flag * possible values include: HBA_PORT, REMOTE_PORT * flags - represents options passed in by the user * * Return Value: * 0 sucessfully processed handle * 1 error has occured */ static int processHBA(HBA_HANDLE handle, HBA_ADAPTERATTRIBUTES attrs, int portIndex, HBA_PORTATTRIBUTES port, HBA_FCPTARGETMAPPINGV2 *map, int resourceType, int flags, int mode) { HBA_PORTATTRIBUTES discPort; HBA_STATUS status; int discPortCount; if (resourceType == HBA_PORT) { if ((flags & PRINT_FCOE) == PRINT_FCOE && attrs.VendorSpecificID != 0xFC0E) { return (0); } printHBAPortInfo(&port, &attrs, mode); if ((flags & PRINT_LINKSTAT) == PRINT_LINKSTAT) { printLinkStat(handle, port.PortWWN, port.PortWWN); } return (0); } /* * process each of the remote targets from this hba port */ for (discPortCount = 0; discPortCount < port.NumberofDiscoveredPorts; discPortCount++) { status = HBA_GetDiscoveredPortAttributes(handle, portIndex, discPortCount, &discPort); if (status != HBA_STATUS_OK) { fprintf(stderr, gettext("Failed to get discovered port (%d)" " attributes reason :"), discPortCount); printStatus(status); fprintf(stderr, "\n"); continue; } if (resourceType == REMOTE_PORT) { handleRemotePort(handle, port.PortWWN, discPort.PortWWN, &discPort); if ((flags & PRINT_LINKSTAT) == PRINT_LINKSTAT) { printLinkStat(handle, port.PortWWN, discPort.PortWWN); } if ((flags & PRINT_SCSI_TARGET) == PRINT_SCSI_TARGET) { handleScsiTarget(handle, port.PortWWN, discPort.PortWWN, map); } } } return (0); } /* * This function will process remote port information for the given handle. * * Arguments: * handle - a handle to a HBA that we will be processing * portWWN - the port WWN for the HBA port we will be issuing the SCSI * ReportLUNS through * wwnCount - the number of wwns in wwn_argv * wwn_argv - argument vector of WWNs */ static void processRemotePort(HBA_HANDLE handle, HBA_WWN portWWN, HBA_FCPTARGETMAPPINGV2 *map, int wwnCount, char **wwn_argv, int flags) { int remote_wwn_counter; uint64_t remotePortWWN; HBA_WWN myremotePortWWN; HBA_PORTATTRIBUTES discPort; HBA_STATUS status; for (remote_wwn_counter = 0; remote_wwn_counter < wwnCount; remote_wwn_counter++) { int times = 0; sscanf(wwn_argv[remote_wwn_counter], "%016llx", &remotePortWWN); remotePortWWN = htonll(remotePortWWN); memcpy(myremotePortWWN.wwn, &remotePortWWN, sizeof (remotePortWWN)); memset(&discPort, 0, sizeof (discPort)); status = HBA_GetPortAttributesByWWN(handle, myremotePortWWN, &discPort); while (status == HBA_STATUS_ERROR_TRY_AGAIN || status == HBA_STATUS_ERROR_BUSY) { (void) sleep(1); status = HBA_GetPortAttributesByWWN(handle, myremotePortWWN, &discPort); if (times++ > HBA_MAX_RETRIES) { break; } } if (status != HBA_STATUS_OK) { fprintf(stderr, gettext("HBA_GetPortAttributesByWWN " "failed: reason: ")); printStatus(status); fprintf(stderr, "\n"); continue; } handleRemotePort(handle, portWWN, myremotePortWWN, &discPort); if ((flags & PRINT_LINKSTAT) == PRINT_LINKSTAT) { printLinkStat(handle, portWWN, myremotePortWWN); } if ((flags & PRINT_SCSI_TARGET) == PRINT_SCSI_TARGET) { handleScsiTarget(handle, portWWN, myremotePortWWN, map); } } } /* * This function handles printing Scsi target information for remote ports * * Arguments: * handle - a handle to a HBA that we will be processing * hbaPortWWN - the port WWN for the HBA port through which the SCSI call * is being sent * scsiTargetWWN - target port WWN of the remote target the SCSI call is * being sent to * map - a pointer to the target mapping structure for the given HBA port */ static void handleScsiTarget(HBA_HANDLE handle, HBA_WWN hbaPortWWN, HBA_WWN scsiTargetWWN, HBA_FCPTARGETMAPPINGV2 *map) { HBA_STATUS status; struct scsi_inquiry inq; struct scsi_extended_sense sense; HBA_UINT32 responseSize, senseSize = 0; HBA_UINT8 inq_status; uchar_t raw_luns[DEFAULT_LUN_LENGTH], *lun_string; HBA_UINT8 rep_luns_status; rep_luns_rsp_t *lun_resp; uint64_t fcLUN; int lunNum, numberOfLun, lunCount, count; uint32_t lunlength, tmp_lunlength; responseSize = DEFAULT_LUN_LENGTH; senseSize = sizeof (struct scsi_extended_sense); memset(&sense, 0, sizeof (sense)); status = HBA_ScsiReportLUNsV2(handle, hbaPortWWN, scsiTargetWWN, (void *)raw_luns, &responseSize, &rep_luns_status, (void *)&sense, &senseSize); /* * if HBA_STATUS_ERROR_NOT_A_TARGET is return, we can assume this is * a remote HBA and move on */ if (status == HBA_STATUS_ERROR_NOT_A_TARGET) { return; } else if (status != HBA_STATUS_OK) { fprintf(stderr, gettext("Error has occured. " "HBA_ScsiReportLUNsV2 failed. reason ")); printStatus(status); fprintf(stderr, "\n"); return; } lun_resp = (rep_luns_rsp_t *)raw_luns; memcpy(&tmp_lunlength, &(lun_resp->length), sizeof (tmp_lunlength)); lunlength = htonl(tmp_lunlength); memcpy(&numberOfLun, &lunlength, sizeof (numberOfLun)); for (lunCount = 0; lunCount < (numberOfLun / 8); lunCount++) { /* * now issue standard inquiry to get Vendor * and product information */ responseSize = sizeof (struct scsi_inquiry); senseSize = sizeof (struct scsi_extended_sense); memset(&inq, 0, sizeof (struct scsi_inquiry)); memset(&sense, 0, sizeof (sense)); fcLUN = ntohll(wwnConversion(lun_resp->lun[lunCount].val)); status = HBA_ScsiInquiryV2( handle, hbaPortWWN, scsiTargetWWN, fcLUN, 0, /* EVPD */ 0, &inq, &responseSize, &inq_status, &sense, &senseSize); if (status != HBA_STATUS_OK) { fprintf(stderr, gettext("Not able to issue Inquiry.\n")); printStatus(status); fprintf(stderr, "\n"); strcpy(inq.inq_vid, "Unknown"); strcpy(inq.inq_pid, "Unknown"); } if (map != NULL) { for (count = 0; count < map->NumberOfEntries; count++) { if ((memcmp(map->entry[count].FcpId.PortWWN.wwn, scsiTargetWWN.wwn, sizeof (scsiTargetWWN.wwn)) == 0) && (memcmp(&(map->entry[count].FcpId.FcpLun), &fcLUN, sizeof (fcLUN)) == 0)) { printLUNInfo(&inq, map->entry[count].ScsiId.ScsiOSLun, map->entry[count].ScsiId.OSDeviceName); break; } } if (count == map->NumberOfEntries) { lun_string = lun_resp->lun[lunCount].val; lunNum = ((lun_string[0] & 0x3F) << 8) | lun_string[1]; printLUNInfo(&inq, lunNum, "Unknown"); } } else { /* Not able to get any target mapping information */ lun_string = lun_resp->lun[lunCount].val; lunNum = ((lun_string[0] & 0x3F) << 8) | lun_string[1]; printLUNInfo(&inq, lunNum, "Unknown"); } } } /* * function to handle the list remoteport command * * Arguments: * wwnCount - the number of wwns in wwn_argv * if wwnCount == 0, then print information on all * remote ports. wwn_argv will not be used in this case * if wwnCount > 0, then print information for the WWNs * given in wwn_argv * wwn_argv - argument vector of WWNs * options - any options specified by the caller * * returns: * 0 if successful * 1 otherwise */ int fc_util_list_remoteport(int wwnCount, char **wwn_argv, cmdOptions_t *options) { HBA_STATUS status; HBA_FCPTARGETMAPPINGV2 *map = NULL; HBA_PORTATTRIBUTES port; HBA_ADAPTERATTRIBUTES attrs; HBA_HANDLE handle; uint64_t hbaPortWWN; HBA_WWN myhbaPortWWN; int processHBA_flags = 0, portCount = 0; int mode; /* grab the hba port wwn from the -p option */ for (; options->optval; options++) { if (options->optval == 'p') { sscanf(options->optarg, "%016llx", &hbaPortWWN); } else if (options->optval == 's') { processHBA_flags |= PRINT_SCSI_TARGET; } else if (options->optval == 'l') { processHBA_flags |= PRINT_LINKSTAT; } else { fprintf(stderr, gettext("Error: Illegal option: %c.\n"), options->optval); return (1); } } /* * -h option was not specified, this should not happen either. * cmdparse should catch this problem, but checking anyways */ if (hbaPortWWN == 0) { fprintf(stderr, gettext("Error: -p option was not specified.\n")); return (1); } if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) { fprintf(stderr, gettext("Failed to load FC-HBA common library\n")); printStatus(status); fprintf(stderr, "\n"); return (1); } hbaPortWWN = htonll(hbaPortWWN); memcpy(myhbaPortWWN.wwn, &hbaPortWWN, sizeof (hbaPortWWN)); if ((status = HBA_OpenAdapterByWWN(&handle, myhbaPortWWN)) != HBA_STATUS_OK) { status = Sun_HBA_OpenTgtAdapterByWWN(&handle, myhbaPortWWN); if (status != HBA_STATUS_OK) { fprintf(stderr, gettext("Error: Failed to open adapter port. Reason ")); printStatus(status); fprintf(stderr, "\n"); HBA_FreeLibrary(); return (1); } else { if ((processHBA_flags & PRINT_SCSI_TARGET) == PRINT_SCSI_TARGET) { fprintf(stderr, gettext( "Error: Unsupported option for target mode: %c.\n"), 's'); HBA_FreeLibrary(); return (1); } mode = TARGET_MODE; } } else { mode = INITIATOR_MODE; } if ((processHBA_flags & PRINT_SCSI_TARGET) == PRINT_SCSI_TARGET) { getTargetMapping(handle, myhbaPortWWN, &map); } if (wwnCount == 0) { /* get adapater attributes for the given handle */ memset(&attrs, 0, sizeof (attrs)); memset(&port, 0, sizeof (port)); if (retrieveAttrs(handle, myhbaPortWWN, &attrs, &port, &portCount) != 0) { if (map != NULL) { free(map); } HBA_CloseAdapter(handle); HBA_FreeLibrary(); return (1); } processHBA(handle, attrs, portCount, port, map, REMOTE_PORT, processHBA_flags, mode); } else { processRemotePort(handle, myhbaPortWWN, map, wwnCount, wwn_argv, processHBA_flags); } if (map != NULL) { free(map); } HBA_CloseAdapter(handle); HBA_FreeLibrary(); return (0); } /* * process the hbaport object * * Arguments: * wwnCount - count of the number of WWNs in wwn_argv * if wwnCount > 0, then we will only print information for * the hba ports listed in wwn_argv * if wwnCount == 0, then we will print information on all hba ports * wwn_argv - argument array of hba port WWNs * options - any options specified by the caller * * returns: * 0 if successful * 1 otherwise */ int fc_util_list_hbaport(int wwnCount, char **wwn_argv, cmdOptions_t *options) { int port_wwn_counter, numAdapters = 0, numTgtAdapters = 0, i; HBA_STATUS status; char adapterName[256]; HBA_HANDLE handle; uint64_t hbaWWN; HBA_WWN myWWN; int processHBA_flags = 0; HBA_PORTATTRIBUTES port; HBA_ADAPTERATTRIBUTES attrs; int portIndex = 0, err_cnt = 0; int mode; /* process each of the options */ for (; options->optval; options++) { if (options->optval == 'l') { processHBA_flags |= PRINT_LINKSTAT; } else if (options->optval == 'i') { processHBA_flags |= PRINT_INITIATOR; } else if (options->optval == 't') { processHBA_flags |= PRINT_TARGET; } else if (options->optval == 'e') { processHBA_flags |= PRINT_FCOE; } } /* * Print both initiator and target if no initiator/target flag * specified. */ if (((processHBA_flags & PRINT_INITIATOR) == 0) && ((processHBA_flags & PRINT_TARGET) == 0)) { processHBA_flags |= PRINT_INITIATOR | PRINT_TARGET; } if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) { fprintf(stderr, gettext("Failed to load FC-HBA common library\n")); printStatus(status); fprintf(stderr, "\n"); return (1); } if (wwnCount > 0) { /* list only ports given in wwn_argv */ for (port_wwn_counter = 0; port_wwn_counter < wwnCount; port_wwn_counter++) { sscanf(wwn_argv[port_wwn_counter], "%016llx", &hbaWWN); hbaWWN = htonll(hbaWWN); memcpy(myWWN.wwn, &hbaWWN, sizeof (hbaWWN)); /* first check to see if it is an initiator port. */ if ((processHBA_flags & PRINT_INITIATOR) == PRINT_INITIATOR) { int times = 0; status = HBA_OpenAdapterByWWN(&handle, myWWN); while (status == HBA_STATUS_ERROR_TRY_AGAIN || status == HBA_STATUS_ERROR_BUSY) { (void) sleep(1); status = HBA_OpenAdapterByWWN(&handle, myWWN); if (times++ > HBA_MAX_RETRIES) { break; } } if (status != HBA_STATUS_OK) { /* now see if it is a target mode FC port */ if ((processHBA_flags & PRINT_TARGET) == PRINT_TARGET) { status = Sun_HBA_OpenTgtAdapterByWWN(&handle, myWWN); if (status != HBA_STATUS_OK) { fprintf(stderr, gettext( "Error: HBA port %s: not found\n"), wwn_argv[port_wwn_counter]); err_cnt++; continue; } else { /* set the port mode. */ mode = TARGET_MODE; } } else { fprintf(stderr, gettext( "Error: HBA port %s: not found\n"), wwn_argv[port_wwn_counter]); err_cnt++; continue; } } else { /* set the port mode. */ mode = INITIATOR_MODE; } /* try target mode discovery if print target is set. */ } else if ((processHBA_flags & PRINT_TARGET) == PRINT_TARGET) { status = Sun_HBA_OpenTgtAdapterByWWN(&handle, myWWN); if (status != HBA_STATUS_OK) { fprintf(stderr, gettext( "Error: HBA port %s: not found\n"), wwn_argv[port_wwn_counter]); err_cnt++; continue; } else { /* set the port mode. */ mode = TARGET_MODE; } } else { /* should not get here. */ fprintf(stderr, gettext( "Error: HBA port %s: not found\n"), wwn_argv[port_wwn_counter]); err_cnt++; continue; } memset(&attrs, 0, sizeof (attrs)); memset(&port, 0, sizeof (port)); if (retrieveAttrs(handle, myWWN, &attrs, &port, &portIndex) != 0) { HBA_CloseAdapter(handle); continue; } processHBA(handle, attrs, portIndex, port, NULL, HBA_PORT, processHBA_flags, mode); if ((processHBA_flags & PRINT_FCOE) != PRINT_FCOE && attrs.VendorSpecificID != 0xFC0E && printHBANPIVPortInfo(handle, portIndex) != 0) { err_cnt++; } HBA_CloseAdapter(handle); } } else { /* * if PRINT_INITIATOR is specified, get the list of initiator * mod port. */ if ((processHBA_flags & PRINT_INITIATOR) == PRINT_INITIATOR) { numAdapters = HBA_GetNumberOfAdapters(); if ((numAdapters == 0) && ((processHBA_flags & ~PRINT_INITIATOR) == 0)) { fprintf(stdout, gettext("No Adapters Found.\n")); } for (i = 0; i < numAdapters; i++) { int times = 0; status = HBA_GetAdapterName(i, adapterName); if (status != HBA_STATUS_OK) { fprintf(stderr, gettext( "failed to get adapter %d. Reason: "), i); printStatus(status); fprintf(stderr, "\n"); continue; } if ((handle = HBA_OpenAdapter(adapterName)) == 0) { fprintf(stderr, gettext( "Failed to open adapter %s.\n"), adapterName); continue; } /* get adapater attributes for the given handle */ memset(&attrs, 0, sizeof (attrs)); status = Sun_HBA_NPIVGetAdapterAttributes(handle, &attrs); while ((status == HBA_STATUS_ERROR_TRY_AGAIN || status == HBA_STATUS_ERROR_BUSY) && times++ < HBA_MAX_RETRIES) { (void) sleep(1); status = Sun_HBA_NPIVGetAdapterAttributes(handle, &attrs); if (status == HBA_STATUS_OK) { break; } } if (status != HBA_STATUS_OK) { fprintf(stderr, gettext("Failed to get adapter attributes " "handle(%d) Reason: "), handle); printStatus(status); fprintf(stderr, "\n"); HBA_CloseAdapter(handle); continue; } /* process each port on the given adatpter */ for (portIndex = 0; portIndex < attrs.NumberOfPorts; portIndex++) { memset(&port, 0, sizeof (port)); if ((status = HBA_GetAdapterPortAttributes( handle, portIndex, &port)) != HBA_STATUS_OK) { /* * not able to get port attributes. * print out error * message and move * on to the next port */ fprintf(stderr, gettext("Error: Failed to get port " "(%d) attributes reason: "), portIndex); printStatus(status); fprintf(stderr, "\n"); continue; } processHBA(handle, attrs, portIndex, port, NULL, HBA_PORT, processHBA_flags, INITIATOR_MODE); if ((processHBA_flags & PRINT_FCOE) != PRINT_FCOE && attrs.VendorSpecificID != 0xFC0E && printHBANPIVPortInfo(handle, portIndex) != 0) { err_cnt++; } } HBA_CloseAdapter(handle); } } /* * Get the info on the target mode FC port if PRINT_TARGET * is specified. */ if ((processHBA_flags & PRINT_TARGET) == PRINT_TARGET) { numTgtAdapters = Sun_HBA_GetNumberOfTgtAdapters(); if (numTgtAdapters == 0 && numAdapters == 0) { fprintf(stdout, gettext("No Adapters Found.\n")); } for (i = 0; i < numTgtAdapters; i++) { status = Sun_HBA_GetTgtAdapterName(i, adapterName); if (status != HBA_STATUS_OK) { fprintf(stderr, gettext( "failed to get adapter %d. Reason: "), i); printStatus(status); fprintf(stderr, "\n"); continue; } if ((handle = Sun_HBA_OpenTgtAdapter(adapterName)) == 0) { fprintf(stderr, gettext( "Failed to open adapter %s.\n"), adapterName); continue; } /* get adapater attributes for the given handle */ memset(&attrs, 0, sizeof (attrs)); if ((status = HBA_GetAdapterAttributes(handle, &attrs)) != HBA_STATUS_OK) { fprintf(stderr, gettext("Failed to get target mode adapter" "attributes handle(%d) Reason: "), handle); printStatus(status); fprintf(stderr, "\n"); continue; } /* process each port on the given adatpter */ for (portIndex = 0; portIndex < attrs.NumberOfPorts; portIndex++) { memset(&port, 0, sizeof (port)); if ((status = HBA_GetAdapterPortAttributes( handle, portIndex, &port)) != HBA_STATUS_OK) { /* * not able to get port attributes. * print out error * message and move * on to the next port */ fprintf(stderr, gettext("Error: Failed to get port " "(%d) attributes reason: "), portIndex); printStatus(status); fprintf(stderr, "\n"); continue; } processHBA(handle, attrs, portIndex, port, NULL, HBA_PORT, processHBA_flags, TARGET_MODE); } HBA_CloseAdapter(handle); } } } HBA_FreeLibrary(); /* * print additional error msg for partial failure when more than * one wwn is specified. */ if (err_cnt != 0) { if (wwnCount > 1) { if (err_cnt == wwnCount) { fprintf(stderr, gettext( "Error: All specified HBA ports are not found\n")); } else { fprintf(stderr, gettext( "Error: Some of specified HBA ports are not found\n")); } } return (1); } return (0); } /* * Search the existing device list * * Take one of two actions: * * Add an entry if an entry doesn't exist * Add WWN data to it if an entry does exist * * Arguments: * devList - OS device path list * map - target mapping data * index - index into target mapping data * initiatorPortWWN - HBA port WWN * verbose - boolean indicating whether to get additional data * * returns: * none */ static void searchDevice(discoveredDevice **devList, HBA_FCPSCSIENTRYV2 entry, HBA_WWN initiatorPortWWN, HBA_HANDLE handle, boolean_t verbose) { discoveredDevice *discoveredDevList, *newDevice; portWWNList *WWNList, *newWWN; tgtPortWWNList *newTgtWWN; boolean_t foundDevice = B_FALSE, foundWWN; struct scsi_inquiry inq; struct scsi_extended_sense sense; HBA_UINT32 responseSize, senseSize = 0; HBA_UINT8 inq_status; HBA_STATUS status; for (discoveredDevList = *devList; discoveredDevList != NULL; discoveredDevList = discoveredDevList->next) { if (strcmp(entry.ScsiId.OSDeviceName, discoveredDevList->OSDeviceName) == 0) { /* * if only device names are requested, * no reason to go any further */ if (verbose == B_FALSE) { return; } foundDevice = B_TRUE; break; } } if (foundDevice == B_TRUE) { /* add initiator Port WWN if it doesn't exist */ for (WWNList = discoveredDevList->HBAPortWWN, foundWWN = B_FALSE; WWNList != NULL; WWNList = WWNList->next) { if (memcmp((void *)&(WWNList->portWWN), (void *)&initiatorPortWWN, sizeof (HBA_WWN)) == 0) { foundWWN = B_TRUE; break; } } if (discoveredDevList->inqSuccess == B_FALSE) { responseSize = sizeof (struct scsi_inquiry); senseSize = sizeof (struct scsi_extended_sense); memset(&inq, 0, sizeof (struct scsi_inquiry)); memset(&sense, 0, sizeof (sense)); status = HBA_ScsiInquiryV2( handle, initiatorPortWWN, entry.FcpId.PortWWN, entry.FcpId.FcpLun, 0, /* CDB Byte 1 */ 0, /* CDB Byte 2 */ &inq, &responseSize, &inq_status, &sense, &senseSize); if (status == HBA_STATUS_OK) { memcpy(discoveredDevList->VID, inq.inq_vid, sizeof (discoveredDevList->VID)); memcpy(discoveredDevList->PID, inq.inq_pid, sizeof (discoveredDevList->PID)); discoveredDevList->dType = inq.inq_dtype; discoveredDevList->inqSuccess = B_TRUE; } } if (foundWWN == B_FALSE) { newWWN = (portWWNList *)calloc(1, sizeof (portWWNList)); if (newWWN == NULL) { perror("Out of memory"); exit(1); } /* insert at head */ newWWN->next = discoveredDevList->HBAPortWWN; discoveredDevList->HBAPortWWN = newWWN; memcpy((void *)&(newWWN->portWWN), (void *)&initiatorPortWWN, sizeof (newWWN->portWWN)); /* add Target Port */ newWWN->tgtPortWWN = (tgtPortWWNList *)calloc(1, sizeof (tgtPortWWNList)); if (newWWN->tgtPortWWN == NULL) { perror("Out of memory"); exit(1); } memcpy((void *)&(newWWN->tgtPortWWN->portWWN), (void *)&(entry.FcpId.PortWWN), sizeof (newWWN->tgtPortWWN->portWWN)); /* Set LUN data */ newWWN->tgtPortWWN->scsiOSLun = entry.ScsiId.ScsiOSLun; } else { /* add it to existing */ newTgtWWN = (tgtPortWWNList *)calloc(1, sizeof (tgtPortWWNList)); if (newTgtWWN == NULL) { perror("Out of memory"); exit(1); } /* insert at head */ newTgtWWN->next = WWNList->tgtPortWWN; WWNList->tgtPortWWN = newTgtWWN; memcpy((void *)&(newTgtWWN->portWWN), (void *)&(entry.FcpId.PortWWN), sizeof (newTgtWWN->portWWN)); /* Set LUN data */ newTgtWWN->scsiOSLun = entry.ScsiId.ScsiOSLun; } } else { /* add new entry */ newDevice = (discoveredDevice *)calloc(1, sizeof (discoveredDevice)); if (newDevice == NULL) { perror("Out of memory"); exit(1); } newDevice->next = *devList; /* insert at head */ *devList = newDevice; /* set new head */ /* Copy device name */ strncpy(newDevice->OSDeviceName, entry.ScsiId.OSDeviceName, sizeof (newDevice->OSDeviceName) - 1); /* * if only device names are requested, * no reason to go any further */ if (verbose == B_FALSE) { return; } /* * copy WWN data */ newDevice->HBAPortWWN = (portWWNList *)calloc(1, sizeof (portWWNList)); if (newDevice->HBAPortWWN == NULL) { perror("Out of memory"); exit(1); } memcpy((void *)&(newDevice->HBAPortWWN->portWWN), (void *)&initiatorPortWWN, sizeof (newWWN->portWWN)); newDevice->HBAPortWWN->tgtPortWWN = (tgtPortWWNList *)calloc(1, sizeof (tgtPortWWNList)); if (newDevice->HBAPortWWN->tgtPortWWN == NULL) { perror("Out of memory"); exit(1); } memcpy((void *)&(newDevice->HBAPortWWN->tgtPortWWN->portWWN), (void *)&(entry.FcpId.PortWWN), sizeof (newDevice->HBAPortWWN->tgtPortWWN->portWWN)); /* Set LUN data */ newDevice->HBAPortWWN->tgtPortWWN->scsiOSLun = entry.ScsiId.ScsiOSLun; responseSize = sizeof (struct scsi_inquiry); senseSize = sizeof (struct scsi_extended_sense); memset(&inq, 0, sizeof (struct scsi_inquiry)); memset(&sense, 0, sizeof (sense)); status = HBA_ScsiInquiryV2( handle, initiatorPortWWN, entry.FcpId.PortWWN, entry.FcpId.FcpLun, 0, /* CDB Byte 1 */ 0, /* CDB Byte 2 */ &inq, &responseSize, &inq_status, &sense, &senseSize); if (status != HBA_STATUS_OK) { /* initialize VID/PID/dType as "Unknown" */ strcpy(newDevice->VID, "Unknown"); strcpy(newDevice->PID, "Unknown"); newDevice->dType = DTYPE_UNKNOWN; /* initialize inq status */ newDevice->inqSuccess = B_FALSE; } else { memcpy(newDevice->VID, inq.inq_vid, sizeof (newDevice->VID)); memcpy(newDevice->PID, inq.inq_pid, sizeof (newDevice->PID)); newDevice->dType = inq.inq_dtype; /* initialize inq status */ newDevice->inqSuccess = B_TRUE; } } } /* * process the logical-unit object * * Arguments: * luCount - count of the number of device paths in paths_argv * if pathCount > 0, then we will only print information for * the device paths listed in paths_argv * if pathCount == 0, then we will print information on all device * paths * luArgv - argument array of device paths * options - any options specified by the caller * * returns: * 0 if successful * > 0 otherwise */ int fc_util_list_logicalunit(int luCount, char **luArgv, cmdOptions_t *options) { int pathCtr, numAdapters, i, count; HBA_STATUS status; char adapterName[256]; HBA_HANDLE handle; HBA_PORTATTRIBUTES port; HBA_ADAPTERATTRIBUTES attrs; int portIndex = 0; int ret = 0; boolean_t verbose = B_FALSE; HBA_FCPTARGETMAPPINGV2 *map = NULL; discoveredDevice *devListWalk, *devList = NULL; boolean_t pathFound; /* process each of the options */ for (; options->optval; options++) { if (options->optval == 'v') { verbose = B_TRUE; } } if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) { fprintf(stderr, gettext("Failed to load FC-HBA common library\n")); printStatus(status); fprintf(stderr, "\n"); return (1); } /* * Retrieve all device paths. We'll need to traverse the list * until we find the input paths or all paths if none were given. We * cannot print as we go since there can be duplicate paths returned */ numAdapters = HBA_GetNumberOfAdapters(); if (numAdapters == 0) { return (0); } for (i = 0; i < numAdapters; i++) { int times; status = HBA_GetAdapterName(i, adapterName); if (status != HBA_STATUS_OK) { fprintf(stderr, gettext( "Failed to get adapter %d. Reason: "), i); printStatus(status); fprintf(stderr, "\n"); ret++; continue; } if ((handle = HBA_OpenAdapter(adapterName)) == 0) { fprintf(stderr, gettext("Failed to open adapter %s\n"), adapterName); ret++; continue; } /* get adapter attributes for the given handle */ memset(&attrs, 0, sizeof (attrs)); times = 0; status = HBA_GetAdapterAttributes(handle, &attrs); while ((status == HBA_STATUS_ERROR_TRY_AGAIN || status == HBA_STATUS_ERROR_BUSY) && times++ < HBA_MAX_RETRIES) { (void) sleep(1); status = HBA_GetAdapterAttributes(handle, &attrs); if (status == HBA_STATUS_OK) { break; } } if (status != HBA_STATUS_OK) { fprintf(stderr, gettext("Failed to get adapter attributes " "handle(%d) Reason: "), handle); printStatus(status); fprintf(stderr, "\n"); ret++; HBA_CloseAdapter(handle); continue; } /* process each port on adapter */ for (portIndex = 0; portIndex < attrs.NumberOfPorts; portIndex++) { memset(&port, 0, sizeof (port)); if ((status = HBA_GetAdapterPortAttributes(handle, portIndex, &port)) != HBA_STATUS_OK) { /* * not able to get port attributes. * print out error message and move * on to the next port */ fprintf(stderr, gettext("Failed to get port " "(%d) attributes reason: "), portIndex); printStatus(status); fprintf(stderr, "\n"); ret++; continue; } /* get OS Device Paths */ getTargetMapping(handle, port.PortWWN, &map); if (map != NULL) { for (count = 0; count < map->NumberOfEntries; count++) { searchDevice(&devList, map->entry[count], port.PortWWN, handle, verbose); } } } HBA_CloseAdapter(handle); } HBA_FreeLibrary(); if (luCount == 0) { /* list all paths */ for (devListWalk = devList; devListWalk != NULL; devListWalk = devListWalk->next) { printOSDeviceNameInfo(devListWalk, verbose); } } else { /* * list any paths not found first * this gives the user cleaner output */ for (pathCtr = 0; pathCtr < luCount; pathCtr++) { for (devListWalk = devList, pathFound = B_FALSE; devListWalk != NULL; devListWalk = devListWalk->next) { if (strcmp(devListWalk->OSDeviceName, luArgv[pathCtr]) == 0) { pathFound = B_TRUE; } } if (pathFound == B_FALSE) { fprintf(stderr, "%s: no such path\n", luArgv[pathCtr]); ret++; } } /* list all paths requested in order requested */ for (pathCtr = 0; pathCtr < luCount; pathCtr++) { for (devListWalk = devList; devListWalk != NULL; devListWalk = devListWalk->next) { if (strcmp(devListWalk->OSDeviceName, luArgv[pathCtr]) == 0) { printOSDeviceNameInfo(devListWalk, verbose); } } } } return (ret); } /* * 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 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #define VERSION_STRING_MAX_LEN 10 /* * Version number: * MAJOR - This should only change when there is an incompatible change made * to the interfaces or the output. * * MINOR - This should change whenever there is a new command or new feature * with no incompatible change. */ #define VERSION_STRING_MAJOR "1" #define VERSION_STRING_MINOR "0" #define OPTIONSTRING1 "HBA Port WWN" #define OPTIONSTRING2 "HBA Node WWN" /* forward declarations */ static int listHbaPortFunc(int, char **, cmdOptions_t *, void *); static int listRemotePortFunc(int, char **, cmdOptions_t *, void *); static int listLogicalUnitFunc(int, char **, cmdOptions_t *, void *); static int npivCreatePortFunc(int, char **, cmdOptions_t *, void *); static int npivDeletePortFunc(int, char **, cmdOptions_t *, void *); static int npivCreatePortListFunc(int, char **, cmdOptions_t *, void *); static int npivListHbaPortFunc(int, char **, cmdOptions_t *, void *); static int npivListRemotePortFunc(int, char **, cmdOptions_t *, void *); static int fcoeAdmCreatePortFunc(int, char **, cmdOptions_t *, void *); static int fcoeListPortsFunc(int, char **, cmdOptions_t *, void *); static int fcoeAdmDeletePortFunc(int, char **, cmdOptions_t *, void *); static int fcadmForceLipFunc(int, char **, cmdOptions_t *, void *); static char *getExecBasename(char *); /* * Add new options here * * Optional option-arguments are not allowed by CLIP */ optionTbl_t fcinfolongOptions[] = { {"port", required_argument, 'p', OPTIONSTRING1}, {"target", no_argument, 't', NULL}, {"initiator", no_argument, 'i', NULL}, {"linkstat", no_argument, 'l', NULL}, {"scsi-target", no_argument, 's', NULL}, {"fcoe", no_argument, 'e', NULL}, {"verbose", no_argument, 'v', NULL}, {NULL, 0, 0} }; optionTbl_t fcadmlongOptions[] = { {"port", required_argument, 'p', OPTIONSTRING1}, {"node", required_argument, 'n', OPTIONSTRING2}, {"linkstat", no_argument, 'l', NULL}, {"scsi-target", no_argument, 's', NULL}, {"fcoe-force-promisc", no_argument, 'f', NULL}, {"target", no_argument, 't', NULL}, {"initiator", no_argument, 'i', NULL}, {NULL, 0, 0} }; /* * Add new subcommands here */ subCommandProps_t fcinfosubcommands[] = { {"hba-port", listHbaPortFunc, "itel", NULL, NULL, OPERAND_OPTIONAL_MULTIPLE, "WWN"}, {"remote-port", listRemotePortFunc, "lsp", "p", NULL, OPERAND_OPTIONAL_MULTIPLE, "WWN"}, {"logical-unit", listLogicalUnitFunc, "v", NULL, NULL, OPERAND_OPTIONAL_MULTIPLE, "OS Device Path"}, {"lu", listLogicalUnitFunc, "v", NULL, NULL, OPERAND_OPTIONAL_MULTIPLE, "OS Device Path"}, {NULL, 0, NULL, NULL, NULL, 0, NULL, NULL} }; subCommandProps_t fcadmsubcommands[] = { {"create-npiv-port", npivCreatePortFunc, "pn", NULL, NULL, OPERAND_MANDATORY_SINGLE, "WWN"}, {"delete-npiv-port", npivDeletePortFunc, "p", "p", NULL, OPERAND_MANDATORY_SINGLE, "WWN"}, {"hba-port", npivListHbaPortFunc, "l", NULL, NULL, OPERAND_OPTIONAL_MULTIPLE, "WWN"}, {"remote-port", npivListRemotePortFunc, "psl", "p", NULL, OPERAND_OPTIONAL_MULTIPLE, "WWN"}, {"create-port-list", npivCreatePortListFunc, NULL, NULL, NULL, OPERAND_NONE, NULL}, {"create-fcoe-port", fcoeAdmCreatePortFunc, "itpnf", NULL, NULL, OPERAND_MANDATORY_SINGLE, "Network Interface Name"}, {"delete-fcoe-port", fcoeAdmDeletePortFunc, NULL, NULL, NULL, OPERAND_MANDATORY_SINGLE, "Network Interface Name"}, {"list-fcoe-ports", fcoeListPortsFunc, "it", NULL, NULL, OPERAND_NONE, NULL}, {"force-lip", fcadmForceLipFunc, NULL, NULL, NULL, OPERAND_MANDATORY_SINGLE, "WWN"}, {NULL, 0, NULL, NULL, NULL, 0, NULL, NULL} }; /* * Pass in options/arguments, rest of arguments */ /*ARGSUSED*/ static int listHbaPortFunc(int objects, char *argv[], cmdOptions_t *options, void *addArgs) { return (fc_util_list_hbaport(objects, argv, options)); } /* * Pass in options/arguments, rest of arguments */ /*ARGSUSED*/ static int listRemotePortFunc(int objects, char *argv[], cmdOptions_t *options, void *addArgs) { return (fc_util_list_remoteport(objects, argv, options)); } /* * Pass in options/arguments, rest of arguments */ /*ARGSUSED*/ static int listLogicalUnitFunc(int objects, char *argv[], cmdOptions_t *options, void *addArgs) { return (fc_util_list_logicalunit(objects, argv, options)); } /* * Pass in options/arguments, rest of arguments */ /*ARGSUSED*/ static int npivCreatePortFunc(int objects, char *argv[], cmdOptions_t *options, void *addArgs) { return (fc_util_create_npivport(objects, argv, options)); } static int npivCreatePortListFunc(int objects, char *argv[], cmdOptions_t *options, void *addArgs) { if ((objects == 0) && addArgs && options && argv) { objects = 1; } return (fc_util_create_portlist()); } /* * Pass in options/arguments, rest of arguments */ /*ARGSUSED*/ static int npivDeletePortFunc(int objects, char *argv[], cmdOptions_t *options, void *addArgs) { return (fc_util_delete_npivport(objects, argv, options)); } /* * Pass in options/arguments, rest of arguments */ /*ARGSUSED*/ static int npivListHbaPortFunc(int objects, char *argv[], cmdOptions_t *options, void *addArgs) { return (fc_util_list_hbaport(objects, argv, options)); } /* * Pass in options/arguments, rest of arguments */ /*ARGSUSED*/ static int npivListRemotePortFunc(int objects, char *argv[], cmdOptions_t *options, void *addArgs) { return (fc_util_list_remoteport(objects, argv, options)); } /* * Pass in options/arguments, rest of arguments */ /*ARGSUSED*/ static int fcoeAdmCreatePortFunc(int objects, char *argv[], cmdOptions_t *options, void *addArgs) { return (fcoe_adm_create_port(objects, argv, options)); } /* * Pass in options/arguments, rest of arguments */ /*ARGSUSED*/ static int fcoeAdmDeletePortFunc(int objects, char *argv[], cmdOptions_t *options, void *addArgs) { return (fcoe_adm_delete_port(objects, argv)); } /* * Pass in options/arguments, rest of arguments */ /*ARGSUSED*/ static int fcoeListPortsFunc(int objects, char *argv[], cmdOptions_t *options, void *addArgs) { return (fcoe_adm_list_ports(options)); } /* * Pass in options/arguments, rest of arguments */ /*ARGSUSED*/ static int fcadmForceLipFunc(int objects, char *argv[], cmdOptions_t *options, void *addArgs) { return (fc_util_force_lip(objects, argv)); } /* * input: * execFullName - exec name of program (argv[0]) * * Returns: * command name portion of execFullName */ static char * getExecBasename(char *execFullname) { char *lastSlash, *execBasename; /* guard against '/' at end of command invocation */ for (;;) { lastSlash = strrchr(execFullname, '/'); if (lastSlash == NULL) { execBasename = execFullname; break; } else { execBasename = lastSlash + 1; if (*execBasename == '\0') { *lastSlash = '\0'; continue; } break; } } return (execBasename); } /* * main calls a parser that checks syntax of the input command against * various rules tables. * * The parser provides usage feedback based upon same tables by calling * two usage functions, usage and subUsage, handling command and subcommand * usage respectively. * * The parser handles all printing of usage syntactical errors * * When syntax is successfully validated, the parser calls the associated * function using the subcommands table functions. * * Syntax is as follows: * command subcommand [options] resource-type [] * * The return value from the function is placed in funcRet */ int main(int argc, char *argv[]) { synTables_t synTables; char versionString[VERSION_STRING_MAX_LEN]; int ret; int funcRet; void *subcommandArgs = NULL; (void) setlocale(LC_ALL, ""); #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ #endif (void) textdomain(TEXT_DOMAIN); /* set global command name */ cmdName = getExecBasename(argv[0]); sprintf(versionString, "%s.%s", VERSION_STRING_MAJOR, VERSION_STRING_MINOR); synTables.versionString = versionString; if (strcmp(cmdName, "fcadm") == 0) { synTables.longOptionTbl = &fcadmlongOptions[0]; synTables.subCommandPropsTbl = &fcadmsubcommands[0]; } else { synTables.longOptionTbl = &fcinfolongOptions[0]; synTables.subCommandPropsTbl = &fcinfosubcommands[0]; } /* call the CLI parser */ ret = cmdParse(argc, argv, synTables, subcommandArgs, &funcRet); if (ret == 1) { fprintf(stdout, "%s %s(8)\n", gettext("For more information, please see"), cmdName); return (1); } else if (ret == -1) { perror(cmdName); return (1); } if (funcRet != 0) { return (1); } return (0); } /* * 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 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _FCINFO_H #define _FCINFO_H #ifdef __cplusplus extern "C" { #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef _BIG_ENDIAN #define htonll(x) (x) #define ntohll(x) (x) #else #define htonll(x) ((((unsigned long long)htonl(x)) << 32) + htonl(x >> 32)) #define ntohll(x) ((((unsigned long long)ntohl(x)) << 32) + ntohl(x >> 32)) #endif /* DEFINES */ /* SCSI TARGET TYPES */ #define SCSI_TARGET_TYPE_UNKNOWN 0 #define SCSI_TARGET_TYPE_NO 1 #define SCSI_TARGET_TYPE_YES 2 #define DEFAULT_LUN_COUNT 1024 #define LUN_SIZE 8 #define LUN_HEADER_SIZE 8 #define LUN_LENGTH LUN_SIZE + LUN_HEADER_SIZE #define DEFAULT_LUN_LENGTH DEFAULT_LUN_COUNT * \ LUN_SIZE + \ LUN_HEADER_SIZE #define HBA_MAX_RETRIES 20 #define PORT_LIST_ALLOC 100 #define NPIV_PORT_LIST_LENGTH 255 #define NPIV_ADD 0 #define NPIV_REMOVE 1 #define NPIV_SUCCESS 0 #define NPIV_ERROR 1 #define NPIV_ERROR_NOT_FOUND 2 #define NPIV_ERROR_EXISTS 3 #define NPIV_ERROR_SERVICE_NOT_FOUND 4 #define NPIV_ERROR_NOMEM 5 #define NPIV_ERROR_MEMBER_NOT_FOUND 6 #define NPIV_ERROR_BUSY 7 #define NPIV_SERVICE "network/npiv_config" #define NPIV_PG_NAME "npiv-port-list" #define NPIV_PORT_LIST "port_list" /* flags that are needed to be passed into processHBA */ #define PRINT_LINKSTAT 0x00000001 /* print link statistics information */ #define PRINT_SCSI_TARGET 0x00000010 /* print Scsi target information */ #define PRINT_INITIATOR 0x00000100 /* print intiator port information */ #define PRINT_TARGET 0x00001000 /* print target port information */ #define PRINT_FCOE 0x00010000 /* print fcoe port information */ /* flags for Adpater/port mode */ #define INITIATOR_MODE 0x00000001 #define TARGET_MODE 0x00000010 /* FCOE */ #define FCOE_USER_RAW_FRAME_SIZE 224 typedef struct _tgtPortWWNList { HBA_WWN portWWN; HBA_UINT32 scsiOSLun; struct _tgtPortWWNList *next; } tgtPortWWNList; typedef struct _portWWNList { HBA_WWN portWWN; tgtPortWWNList *tgtPortWWN; struct _portWWNList *next; } portWWNList; /* Discovered ports structure */ typedef struct _discoveredDevice { char OSDeviceName[MAXPATHLEN]; portWWNList *HBAPortWWN; char VID[8]; char PID[16]; boolean_t inqSuccess; uchar_t dType; struct _discoveredDevice *next; } discoveredDevice; /* globals */ static char *cmdName; /* print helper functions */ void printHBAPortInfo(HBA_PORTATTRIBUTES *port, HBA_ADAPTERATTRIBUTES *attrs, int mode); void printDiscoPortInfo(HBA_PORTATTRIBUTES *discoPort, int scsiTargetType); void printLUNInfo(struct scsi_inquiry *inq, HBA_UINT32 scsiLUN, char *devpath); void printPortStat(fc_rls_acc_t *rls_payload); void printScsiTarget(HBA_WWN); void printStatus(HBA_STATUS status); void printOSDeviceNameInfo(discoveredDevice *devListWalk, boolean_t verbose); uint64_t wwnConversion(uchar_t *wwn); int fc_util_list_hbaport(int wwnCount, char **wwn_argv, cmdOptions_t *options); int fc_util_list_remoteport(int wwnCount, char **argv, cmdOptions_t *options); int fc_util_list_logicalunit(int pathCount, char **argv, cmdOptions_t *options); int fc_util_delete_npivport(int wwnCount, char **argv, cmdOptions_t *options); int fc_util_create_npivport(int wwnCount, char **argv, cmdOptions_t *options); int fc_util_create_portlist(); int fc_util_force_lip(int objects, char *argv[]); int fcoe_adm_create_port(int objects, char *argv[], cmdOptions_t *options); int fcoe_adm_delete_port(int objects, char *argv[]); int fcoe_adm_list_ports(cmdOptions_t *options); #ifdef __cplusplus } #endif #endif /* _FCINFO_H */ /* * 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 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include "fcinfo.h" #include #include #include #include #include #include #include #include #include #include static const char *FCOE_DRIVER_PATH = "/devices/fcoe:admin"; static int isValidWWN(char *wwn) { int index; if (wwn == NULL) { return (0); } if (strlen(wwn) != 16) { return (0); } for (index = 0; index < 16; index++) { if (isxdigit(wwn[index])) { continue; } return (0); } return (1); } static uint64_t wwnconvert(uchar_t *wwn) { uint64_t tmp; memcpy(&tmp, wwn, sizeof (uint64_t)); return (ntohll(tmp)); } /* * prints out all the HBA port information */ void printFCOEPortInfo(FCOE_PORT_ATTRIBUTE *attr) { int i; if (attr == NULL) { return; } fprintf(stdout, gettext("HBA Port WWN: %016llx\n"), wwnconvert((unsigned char *)&attr->port_wwn)); fprintf(stdout, gettext("\tPort Type: %s\n"), (attr->port_type == 0) ? "Initiator" : "Target"); fprintf(stdout, gettext("\tMAC Name: %s\n"), attr->mac_link_name); fprintf(stdout, gettext("\tMTU Size: %d\n"), attr->mtu_size); fprintf(stdout, gettext("\tPrimary MAC Address: ")); for (i = 0; i < 6; i++) { fprintf(stdout, gettext("%02x"), attr->mac_factory_addr[i]); } fprintf(stdout, gettext("\n\tCurrent MAC Address: ")); for (i = 0; i < 6; i++) { fprintf(stdout, gettext("%02x"), attr->mac_current_addr[i]); } fprintf(stdout, gettext("\n\tPromiscuous Mode: %s\n"), attr->mac_promisc == 1 ? "On" : "Off"); } int fcoe_adm_create_port(int objects, char *argv[], cmdOptions_t *options) { FCOE_STATUS status = FCOE_STATUS_OK; uint64_t nodeWWN, portWWN; FCOE_PORT_WWN pwwn, nwwn; FCOE_UINT8 macLinkName[FCOE_MAX_MAC_NAME_LEN]; FCOE_UINT8 promiscuous = 0; int createini = 0, createtgt = 0; /* check the mac name operand */ assert(objects == 1); strcpy((char *)macLinkName, argv[0]); bzero(&pwwn, 8); bzero(&nwwn, 8); for (; options->optval; options++) { switch (options->optval) { case 'i': createini = 1; break; case 't': createtgt = 1; break; case 'p': if (!isValidWWN(options->optarg)) { fprintf(stderr, gettext("Error: Invalid Port WWN\n")); return (1); } sscanf(options->optarg, "%016llx", &portWWN); portWWN = htonll(portWWN); memcpy(&pwwn, &portWWN, sizeof (portWWN)); break; case 'n': if (!isValidWWN(options->optarg)) { fprintf(stderr, gettext("Error: Invalid Node WWN\n")); return (1); } sscanf(options->optarg, "%016llx", &nodeWWN); nodeWWN = htonll(nodeWWN); memcpy(&nwwn, &nodeWWN, sizeof (nodeWWN)); break; case 'f': promiscuous = 1; break; default: fprintf(stderr, gettext("Error: Illegal option: %c\n"), options->optval); return (1); } } if (createini == 1 && createtgt == 1) { fprintf(stderr, "Error: Option -i and -t should " "not be both specified\n"); return (1); } status = FCOE_CreatePort(macLinkName, createtgt == 1 ? FCOE_PORTTYPE_TARGET : FCOE_PORTTYPE_INITIATOR, pwwn, nwwn, promiscuous); if (status != FCOE_STATUS_OK) { switch (status) { case FCOE_STATUS_ERROR_BUSY: fprintf(stderr, gettext("Error: fcoe driver is busy\n")); break; case FCOE_STATUS_ERROR_ALREADY: fprintf(stderr, gettext("Error: Existing FCoE port " "found on the specified MAC link\n")); break; case FCOE_STATUS_ERROR_PERM: fprintf(stderr, gettext("Error: Not enough permission to " "open fcoe device\n")); break; case FCOE_STATUS_ERROR_OPEN_DEV: fprintf(stderr, gettext("Error: Failed to open fcoe device\n")); break; case FCOE_STATUS_ERROR_WWN_SAME: fprintf(stderr, gettext("Error: Port WWN is same as Node " "WWN\n")); break; case FCOE_STATUS_ERROR_MAC_LEN: fprintf(stderr, gettext("Error: MAC name exceeds maximum " "length\n")); break; case FCOE_STATUS_ERROR_PWWN_CONFLICTED: fprintf(stderr, gettext("Error: The specified Port WWN " "is already in use\n")); break; case FCOE_STATUS_ERROR_NWWN_CONFLICTED: fprintf(stderr, gettext("Error: The specified Node WWN " "is already in use\n")); break; case FCOE_STATUS_ERROR_NEED_JUMBO_FRAME: fprintf(stderr, gettext("Error: MTU size of the specified " "MAC link needs to be increased to 2500 " "or above\n")); break; case FCOE_STATUS_ERROR_CREATE_MAC: fprintf(stderr, gettext("Error: Out of memory\n")); break; case FCOE_STATUS_ERROR_OPEN_MAC: fprintf(stderr, gettext("Error: Failed to open the " "specified MAC link\n")); break; case FCOE_STATUS_ERROR_CREATE_PORT: fprintf(stderr, gettext("Error: Failed to create FCoE " "port on the specified MAC link\n")); break; case FCOE_STATUS_ERROR_CLASS_UNSUPPORT: fprintf(stderr, gettext("Error: Link class other than physical " "link is not supported\n")); break; case FCOE_STATUS_ERROR_GET_LINKINFO: fprintf(stderr, gettext("Error: Failed to get link information " "for %s\n"), macLinkName); break; case FCOE_STATUS_ERROR: default: fprintf(stderr, gettext("Error: Due to reason code %d\n"), status); } return (1); } else { return (0); } } int fcoe_adm_delete_port(int objects, char *argv[]) { FCOE_STATUS status; FCOE_UINT8 *macLinkName; FCOE_UINT32 port_num; FCOE_PORT_ATTRIBUTE *portlist = NULL; int i; /* check the mac name operand */ assert(objects == 1); macLinkName = (FCOE_UINT8 *) argv[0]; status = FCOE_DeletePort(macLinkName); if (status != FCOE_STATUS_OK) { switch (status) { case FCOE_STATUS_ERROR_BUSY: fprintf(stderr, gettext("Error: fcoe driver is busy\n")); break; case FCOE_STATUS_ERROR_ALREADY: fprintf(stderr, gettext("Error: FCoE port not found on the " "specified MAC link\n")); break; case FCOE_STATUS_ERROR_PERM: fprintf(stderr, gettext("Error: Not enough permission to " "open fcoe device\n")); break; case FCOE_STATUS_ERROR_MAC_LEN: fprintf(stderr, gettext("Failed: MAC name exceeds maximum " "length 32\n")); break; case FCOE_STATUS_ERROR_OPEN_DEV: fprintf(stderr, gettext("Error: Failed to open fcoe device\n")); break; case FCOE_STATUS_ERROR_MAC_NOT_FOUND: fprintf(stderr, gettext("Error: FCoE port not found on the " "specified MAC link\n")); break; case FCOE_STATUS_ERROR_OFFLINE_DEV: status = FCOE_GetPortList(&port_num, &portlist); if (status != FCOE_STATUS_OK || port_num == 0) { fprintf(stderr, gettext("Error: FCoE port not found on the " "specified MAC link\n")); break; } for (i = 0; i < port_num; i++) { if (strcmp( (char *)portlist[i].mac_link_name, (char *)macLinkName) == 0) { if (portlist[i].port_type == FCOE_PORTTYPE_TARGET) { fprintf(stderr, gettext("Error: Please use " "stmfadm to offline the " "FCoE target first\n")); } else { fprintf(stderr, gettext("Error: Failed to " "delete FCoE port because " "unable to offline the " "device\n")); } break; } } free(portlist); if (i == port_num) { fprintf(stderr, gettext("Error: FCoE port not found on the " "specified MAC link\n")); } break; case FCOE_STATUS_ERROR_GET_LINKINFO: fprintf(stderr, gettext("Error: Failed to get link information " "for %s\n"), macLinkName); break; case FCOE_STATUS_ERROR: default: fprintf(stderr, gettext("Error: Due to reason code %d\n"), status); } return (1); } else { return (0); } } int fcoe_adm_list_ports(cmdOptions_t *options) { FCOE_STATUS status; int showini = 0, showtgt = 0; FCOE_UINT32 port_num; FCOE_PORT_ATTRIBUTE *portlist = NULL; int i; int ret; for (; options->optval; options++) { switch (options->optval) { case 'i': showini = 1; break; case 't': showtgt = 1; break; default: fprintf(stderr, gettext("Error: Illegal option: %c\n"), options->optval); return (1); } } if (showini == 0 && showtgt == 0) { showini = 1; showtgt = 1; } status = FCOE_GetPortList(&port_num, &portlist); if (status != FCOE_STATUS_OK) { switch (status) { case FCOE_STATUS_ERROR_BUSY: fprintf(stderr, gettext("Error: fcoe driver is busy\n")); break; case FCOE_STATUS_ERROR_PERM: fprintf(stderr, gettext("Error: Not enough permission to " "open fcoe device\n")); break; case FCOE_STATUS_ERROR_OPEN_DEV: fprintf(stderr, gettext("Error: Failed to open fcoe device\n")); break; case FCOE_STATUS_ERROR_INVAL_ARG: fprintf(stderr, gettext("Error: Invalid argument\n")); break; case FCOE_STATUS_ERROR_MORE_DATA: fprintf(stderr, gettext("Error: More data\n")); break; case FCOE_STATUS_ERROR: default: fprintf(stderr, gettext("Error: Due to reason code %d\n"), status); } ret = 1; } else { if (port_num == 0) { fprintf(stdout, gettext("No FCoE Ports Found!\n")); } else { for (i = 0; i < port_num; i++) { if ((portlist[i].port_type == FCOE_PORTTYPE_INITIATOR && showini == 1) || (showtgt == 1 && portlist[i].port_type == FCOE_PORTTYPE_TARGET)) { printFCOEPortInfo(&portlist[i]); } } } ret = 0; } if (portlist != NULL) { free(portlist); } return (ret); } #!/sbin/sh # # 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 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # # This script is used to reconfigure fabric device(s) which were configured # prior to boot. The luxadm command used below is an expert level command # and has a restrictive usage for boot time reconfiguration of fabric # devices. # # DO NOT USE the command for any other purpose. # /usr/sbin/fcadm create-port-list /* * 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 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * Copyright 2020 RackTop Systems, Inc. */ #include #include #include #include #include #include #include #include "fcinfo.h" #ifdef _BIG_ENDIAN #define htonll(x) (x) #define ntohll(x) (x) #else #define htonll(x) ((((unsigned long long)htonl(x)) << 32) + htonl(x >> 32)) #define ntohll(x) ((((unsigned long long)ntohl(x)) << 32) + ntohl(x >> 32)) #endif /* Fc4 Types Format */ #define FC4_TYPE_WORD_POS(x) ((uint_t)((uint_t)(x) >> 5)) #define FC4_TYPE_BIT_POS(x) ((uchar_t)(x) & 0x1F) #define TYPE_IP_FC 0x05 #define TYPE_SCSI_FCP 0x08 static int fc4_map_is_set(uint32_t *map, uchar_t ulp_type); static char *getPortType(HBA_PORTTYPE portType); static char *getPortState(HBA_PORTSTATE portState); static void printPortSpeed(HBA_PORTSPEED portSpeed); static char *getDTypeString(uchar_t dType); uint64_t wwnConversion(uchar_t *wwn) { uint64_t tmp; memcpy(&tmp, wwn, sizeof (uint64_t)); return (ntohll(tmp)); } static char * getPortType(HBA_PORTTYPE portType) { switch (portType) { case HBA_PORTTYPE_UNKNOWN: return ("unknown"); case HBA_PORTTYPE_OTHER: return ("other"); case HBA_PORTTYPE_NOTPRESENT: return ("not present"); case HBA_PORTTYPE_NPORT: return ("N-port"); case HBA_PORTTYPE_NLPORT: return ("NL-port"); case HBA_PORTTYPE_FLPORT: return ("FL-port"); case HBA_PORTTYPE_FPORT: return ("F-port"); case HBA_PORTTYPE_LPORT: return ("L-port"); case HBA_PORTTYPE_PTP: return ("point-to-point"); default: return ("unrecognized type"); } } static char * getPortState(HBA_PORTSTATE portState) { switch (portState) { case HBA_PORTSTATE_UNKNOWN: return ("unknown"); case HBA_PORTSTATE_ONLINE: return ("online"); case HBA_PORTSTATE_OFFLINE: return ("offline"); case HBA_PORTSTATE_BYPASSED: return ("bypassed"); case HBA_PORTSTATE_DIAGNOSTICS: return ("diagnostics"); case HBA_PORTSTATE_LINKDOWN: return ("link down"); case HBA_PORTSTATE_ERROR: return ("error"); case HBA_PORTSTATE_LOOPBACK: return ("loopback"); default: return ("unrecognized state"); } } static void printPortSpeed(HBA_PORTSPEED portSpeed) { int foundSpeed = 0; if ((portSpeed & HBA_PORTSPEED_1GBIT) == HBA_PORTSPEED_1GBIT) { fprintf(stdout, "1Gb "); foundSpeed = 1; } if ((portSpeed & HBA_PORTSPEED_2GBIT) == HBA_PORTSPEED_2GBIT) { fprintf(stdout, "2Gb "); foundSpeed = 1; } if ((portSpeed & HBA_PORTSPEED_4GBIT) == HBA_PORTSPEED_4GBIT) { fprintf(stdout, "4Gb "); foundSpeed = 1; } if ((portSpeed & HBA_PORTSPEED_8GBIT) == HBA_PORTSPEED_8GBIT) { fprintf(stdout, "8Gb "); foundSpeed = 1; } if ((portSpeed & HBA_PORTSPEED_10GBIT) == HBA_PORTSPEED_10GBIT) { fprintf(stdout, "10Gb "); foundSpeed = 1; } if ((portSpeed & HBA_PORTSPEED_16GBIT) == HBA_PORTSPEED_16GBIT) { fprintf(stdout, "16Gb "); foundSpeed = 1; } if ((portSpeed & HBA_PORTSPEED_32GBIT) == HBA_PORTSPEED_32GBIT) { fprintf(stdout, "32Gb "); foundSpeed = 1; } if ((portSpeed & HBA_PORTSPEED_NOT_NEGOTIATED) == HBA_PORTSPEED_NOT_NEGOTIATED) { fprintf(stdout, "not established "); foundSpeed = 1; } if (foundSpeed == 0) { fprintf(stdout, "not established "); } } void printDiscoPortInfo(HBA_PORTATTRIBUTES *discoPort, int scsiTargetType) { int fc4_types = 0; fprintf(stdout, gettext("Remote Port WWN: %016llx\n"), wwnConversion(discoPort->PortWWN.wwn)); fprintf(stdout, gettext("\tActive FC4 Types: ")); if (fc4_map_is_set( (uint32_t *)discoPort->PortActiveFc4Types.bits, TYPE_SCSI_FCP)) { fprintf(stdout, gettext("SCSI")); fc4_types++; } if (fc4_map_is_set( (uint32_t *)discoPort->PortActiveFc4Types.bits, TYPE_IP_FC)) { if (fc4_types != 0) { fprintf(stdout, ","); } fprintf(stdout, gettext("IP")); fc4_types++; } fprintf(stdout, "\n"); /* print out scsi target type information */ fprintf(stdout, gettext("\tSCSI Target: ")); if (scsiTargetType == SCSI_TARGET_TYPE_YES) { fprintf(stdout, gettext("yes\n")); } else if (scsiTargetType == SCSI_TARGET_TYPE_NO) { fprintf(stdout, gettext("no\n")); } else { fprintf(stdout, gettext("unknown\n")); } fprintf(stdout, gettext("\tPort Symbolic Name: %s\n"), discoPort->PortSymbolicName); fprintf(stdout, gettext("\tNode WWN: %016llx\n"), wwnConversion(discoPort->NodeWWN.wwn)); } /* * scan the bitmap array for the specifed ULP type. The bit map array * is 32 bytes long */ static int fc4_map_is_set(uint32_t *map, uchar_t ulp_type) { map += FC4_TYPE_WORD_POS(ulp_type) * 4; if (ntohl((*(uint32_t *)map)) & (1 << FC4_TYPE_BIT_POS(ulp_type))) { return (1); } return (0); } /* * prints out all the HBA port information */ void printHBAPortInfo(HBA_PORTATTRIBUTES *port, HBA_ADAPTERATTRIBUTES *attrs, int mode) { if (attrs == NULL || port == NULL) { return; } fprintf(stdout, gettext("HBA Port WWN: %016llx\n"), wwnConversion(port->PortWWN.wwn)); fprintf(stdout, gettext("\tPort Mode: %s\n"), (mode == INITIATOR_MODE) ? "Initiator" : "Target"); fprintf(stdout, gettext("\tPort ID: %x\n"), port->PortFcId); fprintf(stdout, gettext("\tOS Device Name: %s\n"), port->OSDeviceName); fprintf(stdout, gettext("\tManufacturer: %s\n"), attrs->Manufacturer); fprintf(stdout, gettext("\tModel: %s\n"), attrs->Model); fprintf(stdout, gettext("\tFirmware Version: %s\n"), attrs->FirmwareVersion); fprintf(stdout, gettext("\tFCode/BIOS Version: %s\n"), attrs->OptionROMVersion); fprintf(stdout, gettext("\tSerial Number: %s\n"), attrs->SerialNumber[0] == 0? "not available":attrs->SerialNumber); fprintf(stdout, gettext("\tDriver Name: %s\n"), attrs->DriverName[0] == 0? "not available":attrs->DriverName); fprintf(stdout, gettext("\tDriver Version: %s\n"), attrs->DriverVersion[0] == 0? "not available":attrs->DriverVersion); fprintf(stdout, gettext("\tType: %s\n"), getPortType(port->PortType)); fprintf(stdout, gettext("\tState: %s\n"), getPortState(port->PortState)); fprintf(stdout, gettext("\tSupported Speeds: ")); printPortSpeed(port->PortSupportedSpeed); fprintf(stdout, "\n"); fprintf(stdout, gettext("\tCurrent Speed: ")); printPortSpeed(port->PortSpeed); fprintf(stdout, "\n"); fprintf(stdout, gettext("\tNode WWN: %016llx\n"), wwnConversion(port->NodeWWN.wwn)); } void printStatus(HBA_STATUS status) { switch (status) { case HBA_STATUS_OK: fprintf(stderr, gettext("OK")); return; case HBA_STATUS_ERROR: fprintf(stderr, gettext("ERROR")); return; case HBA_STATUS_ERROR_NOT_SUPPORTED: fprintf(stderr, gettext("NOT SUPPORTED")); return; case HBA_STATUS_ERROR_INVALID_HANDLE: fprintf(stderr, gettext("INVALID HANDLE")); return; case HBA_STATUS_ERROR_ARG: fprintf(stderr, gettext("ERROR ARG")); return; case HBA_STATUS_ERROR_ILLEGAL_WWN: fprintf(stderr, gettext("ILLEGAL WWN")); return; case HBA_STATUS_ERROR_ILLEGAL_INDEX: fprintf(stderr, gettext("ILLEGAL INDEX")); return; case HBA_STATUS_ERROR_MORE_DATA: fprintf(stderr, gettext("MORE DATA")); return; case HBA_STATUS_ERROR_STALE_DATA: fprintf(stderr, gettext("STALE DATA")); return; case HBA_STATUS_SCSI_CHECK_CONDITION: fprintf(stderr, gettext("SCSI CHECK CONDITION")); return; case HBA_STATUS_ERROR_BUSY: fprintf(stderr, gettext("BUSY")); return; case HBA_STATUS_ERROR_TRY_AGAIN: fprintf(stderr, gettext("TRY AGAIN")); return; case HBA_STATUS_ERROR_UNAVAILABLE: fprintf(stderr, gettext("UNAVAILABLE")); return; default: fprintf(stderr, "%s %d", gettext("Undefined error code "), status); return; } } void printLUNInfo(struct scsi_inquiry *inq, HBA_UINT32 scsiLUN, char *devpath) { fprintf(stdout, "\tLUN: %d\n", scsiLUN); fprintf(stdout, "\t Vendor: %c%c%c%c%c%c%c%c\n", inq->inq_vid[0], inq->inq_vid[1], inq->inq_vid[2], inq->inq_vid[3], inq->inq_vid[4], inq->inq_vid[5], inq->inq_vid[6], inq->inq_vid[7]); fprintf(stdout, "\t Product: %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", inq->inq_pid[0], inq->inq_pid[1], inq->inq_pid[2], inq->inq_pid[3], inq->inq_pid[4], inq->inq_pid[5], inq->inq_pid[6], inq->inq_pid[7], inq->inq_pid[8], inq->inq_pid[9], inq->inq_pid[10], inq->inq_pid[11], inq->inq_pid[12], inq->inq_pid[13], inq->inq_pid[14], inq->inq_pid[15]); fprintf(stdout, gettext("\t OS Device Name: %s\n"), devpath); } void printPortStat(fc_rls_acc_t *rls_payload) { fprintf(stdout, gettext("\tLink Error Statistics:\n")); fprintf(stdout, gettext("\t\tLink Failure Count: %u\n"), rls_payload->rls_link_fail); fprintf(stdout, gettext("\t\tLoss of Sync Count: %u\n"), rls_payload->rls_sync_loss); fprintf(stdout, gettext("\t\tLoss of Signal Count: %u\n"), rls_payload->rls_sig_loss); fprintf(stdout, gettext("\t\tPrimitive Seq Protocol Error Count: %u\n"), rls_payload->rls_prim_seq_err); fprintf(stdout, gettext("\t\tInvalid Tx Word Count: %u\n"), rls_payload->rls_invalid_word); fprintf(stdout, gettext("\t\tInvalid CRC Count: %u\n"), rls_payload->rls_invalid_crc); } /* * return device type description * * Arguments: * dType - Device type returned from Standard INQUIRY * Returns: * char string description for device type */ static char * getDTypeString(uchar_t dType) { switch (dType & DTYPE_MASK) { case DTYPE_DIRECT: return ("Disk Device"); case DTYPE_SEQUENTIAL: return ("Tape Device"); case DTYPE_PRINTER: return ("Printer Device"); case DTYPE_PROCESSOR: return ("Processor Device"); case DTYPE_WORM: return ("WORM Device"); case DTYPE_RODIRECT: return ("CD/DVD Device"); case DTYPE_SCANNER: return ("Scanner Device"); case DTYPE_OPTICAL: return ("Optical Memory Device"); case DTYPE_CHANGER: return ("Medium Changer Device"); case DTYPE_COMM: return ("Communications Device"); case DTYPE_ARRAY_CTRL: return ("Storage Array Controller Device"); case DTYPE_ESI: return ("Enclosure Services Device"); case DTYPE_RBC: return ("Simplified Direct-access Device"); case DTYPE_OCRW: return ("Optical Card Reader/Writer Device"); case DTYPE_BCC: return ("Bridge Controller Commands"); case DTYPE_OSD: return ("Object-based Storage Device"); case DTYPE_ADC: return ("Automation/Drive Interface"); case DTYPE_WELLKNOWN: return ("Well Known Logical Unit"); case DTYPE_UNKNOWN: return ("Unknown Device"); default: return ("Undefined"); } } /* * print the OS device name for the logical-unit object * * Arguments: * devListWalk - OS device path info * verbose - boolean indicating whether to display additional info * * returns: * none */ void printOSDeviceNameInfo(discoveredDevice *devListWalk, boolean_t verbose) { portWWNList *WWNList; tgtPortWWNList *tgtWWNList; int i, count; fprintf(stdout, "OS Device Name: %s\n", devListWalk->OSDeviceName); if (verbose == B_TRUE) { for (WWNList = devListWalk->HBAPortWWN; WWNList != NULL; WWNList = WWNList->next) { fprintf(stdout, "\tHBA Port WWN: "); fprintf(stdout, "%016llx", wwnConversion(WWNList->portWWN.wwn)); for (tgtWWNList = WWNList->tgtPortWWN; tgtWWNList != NULL; tgtWWNList = tgtWWNList->next) { fprintf(stdout, "\n\t\tRemote Port WWN: "); fprintf(stdout, "%016llx", wwnConversion(tgtWWNList->portWWN.wwn)); fprintf(stdout, "\n\t\t\tLUN: %d", tgtWWNList->scsiOSLun); } fprintf(stdout, "\n"); } fprintf(stdout, "\tVendor: "); for (count = sizeof (devListWalk->VID), i = 0; i < count; i++) { if (isprint(devListWalk->VID[i])) fprintf(stdout, "%c", devListWalk->VID[i]); } fprintf(stdout, "\n\tProduct: "); for (count = sizeof (devListWalk->PID), i = 0; i < count; i++) { if (isprint(devListWalk->PID[i])) fprintf(stdout, "%c", devListWalk->PID[i]); } fprintf(stdout, "\n\tDevice Type: %s\n", getDTypeString(devListWalk->dType)); } }