diff options
author | Zhong Wang <Zhong.Wang@Sun.COM> | 2009-03-19 03:03:46 +0800 |
---|---|---|
committer | Zhong Wang <Zhong.Wang@Sun.COM> | 2009-03-19 03:03:46 +0800 |
commit | 2a8164df8a5f42c8a00f10c67d7bc84f80ae9c41 (patch) | |
tree | 5ef9c65f09194743324b20261093e076d4eeea6b | |
parent | bfe6f8f50e1ad7cfc72f4665989dc9e25e82e872 (diff) | |
download | illumos-joyent-2a8164df8a5f42c8a00f10c67d7bc84f80ae9c41.tar.gz |
PSARC/2008/310 FCoE (Fibre Channel over Ethernet) Target
6701027 Need FCoE target for Solaris
6812750 Change in stmf/fct/stmf_sbd needed for support FCoE
76 files changed, 10164 insertions, 32 deletions
diff --git a/usr/src/Makefile.lint b/usr/src/Makefile.lint index 635ce2f6d9..cde949e045 100644 --- a/usr/src/Makefile.lint +++ b/usr/src/Makefile.lint @@ -20,7 +20,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -356,6 +356,7 @@ COMMON_SUBDIRS = \ lib/libefi \ lib/libelfsign \ lib/libexacct \ + lib/libfcoe \ lib/libgen \ lib/libgss \ lib/libidmap \ diff --git a/usr/src/cmd/fcinfo/Makefile b/usr/src/cmd/fcinfo/Makefile index d625bde799..814e952fd5 100644 --- a/usr/src/cmd/fcinfo/Makefile +++ b/usr/src/cmd/fcinfo/Makefile @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # @@ -30,12 +30,14 @@ COMMONBASE = ../../common PROG = fcinfo ROOT_PROG_LINK = $(ROOTUSRSBIN)/fcadm MANIFEST = npiv_config.xml +MANIFEST += fcoe_config.xml SVCMETHOD = npivconfig +SVCMETHOD += fcoeconfig PRODUCT = $(PROG) $(ROOT_PROG_LINK) := FILEMODE = 0555 -LOCAL_OBJS = fcinfo.o fcinfo-list.o fcadm-list.o printAttrs.o +LOCAL_OBJS = fcinfo.o fcinfo-list.o fcadm-list.o printAttrs.o fcoeadm.o COMMON_OBJS = cmdparse.o LOCAL_SRCS = $(LOCAL_OBJS:%.o=%.c) COMMON_SRCS = $(COMMON_OBJS:%.o=$(COMMONBASE)/cmdparse/%.c) @@ -44,14 +46,19 @@ SRCS = $(LOCAL_SRCS) $(COMMON_SRCS) include ../Makefile.cmd +POFILE = fcinfo_cmd.po +POFILES = fcinfo.po fcinfo-list.po fcadm-list.po printAttrs.po fcoeadm.po + 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 @@ -81,6 +88,9 @@ install: all $(ROOTMANIFEST) $(ROOTSVCMETHOD) $(ROOTUSRSBINPROG) $(ROOT_PROG_LIN cmdparse.o: $(COMMONBASE)/cmdparse/cmdparse.c $(COMPILE.c) -o $@ $(COMMONBASE)/cmdparse/cmdparse.c $(POST_PROCESS_O) +$(POFILE): $(POFILES) + $(RM) $@ + $(CAT) $(POFILES) > $@ clean: $(RM) $(OBJS) diff --git a/usr/src/cmd/fcinfo/fcinfo-list.c b/usr/src/cmd/fcinfo/fcinfo-list.c index 5b33cf449b..2030441d44 100644 --- a/usr/src/cmd/fcinfo/fcinfo-list.c +++ b/usr/src/cmd/fcinfo/fcinfo-list.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -377,6 +377,10 @@ processHBA(HBA_HANDLE handle, HBA_ADAPTERATTRIBUTES attrs, int portIndex, 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); @@ -736,6 +740,8 @@ fc_util_list_hbaport(int wwnCount, char **wwn_argv, cmdOptions_t *options) processHBA_flags |= PRINT_INITIATOR; } else if (options->optval == 't') { processHBA_flags |= PRINT_TARGET; + } else if (options->optval == 'e') { + processHBA_flags |= PRINT_FCOE; } } @@ -837,8 +843,9 @@ fc_util_list_hbaport(int wwnCount, char **wwn_argv, cmdOptions_t *options) } processHBA(handle, attrs, portIndex, port, NULL, HBA_PORT, processHBA_flags, mode); - if (printHBANPIVPortInfo(handle, portIndex) - != 0) { + if ((processHBA_flags & PRINT_FCOE) != PRINT_FCOE && + attrs.VendorSpecificID != 0xFC0E && + printHBANPIVPortInfo(handle, portIndex) != 0) { err_cnt++; } HBA_CloseAdapter(handle); @@ -920,8 +927,11 @@ fc_util_list_hbaport(int wwnCount, char **wwn_argv, cmdOptions_t *options) processHBA(handle, attrs, portIndex, port, NULL, HBA_PORT, processHBA_flags, INITIATOR_MODE); - if (printHBANPIVPortInfo(handle, portIndex) - != 0) { + if ((processHBA_flags & PRINT_FCOE) != + PRINT_FCOE && + attrs.VendorSpecificID != 0xFC0E && + printHBANPIVPortInfo(handle, + portIndex) != 0) { err_cnt++; } } diff --git a/usr/src/cmd/fcinfo/fcinfo.c b/usr/src/cmd/fcinfo/fcinfo.c index 9da68b8b06..396647d9fb 100644 --- a/usr/src/cmd/fcinfo/fcinfo.c +++ b/usr/src/cmd/fcinfo/fcinfo.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -50,6 +50,10 @@ 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 fcoeAdmCreatePortListFunc(int, char **, cmdOptions_t *, void *); static char *getExecBasename(char *); /* @@ -63,6 +67,7 @@ optionTbl_t fcinfolongOptions[] = { {"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} }; @@ -72,6 +77,8 @@ optionTbl_t fcadmlongOptions[] = { {"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}, {NULL, 0, 0} }; @@ -79,7 +86,7 @@ optionTbl_t fcadmlongOptions[] = { * Add new subcommands here */ subCommandProps_t fcinfosubcommands[] = { - {"hba-port", listHbaPortFunc, "itl", NULL, NULL, + {"hba-port", listHbaPortFunc, "itel", NULL, NULL, OPERAND_OPTIONAL_MULTIPLE, "WWN"}, {"remote-port", listRemotePortFunc, "lsp", "p", NULL, OPERAND_OPTIONAL_MULTIPLE, "WWN"}, @@ -106,8 +113,21 @@ subCommandProps_t fcadmsubcommands[] = { {"create-port-list", npivCreatePortListFunc, NULL, NULL, NULL, OPERAND_NONE, NULL}, + {"create-fcoe-port", + fcoeAdmCreatePortFunc, "tpnf", "t", NULL, + OPERAND_MANDATORY_SINGLE, "Network Interface Name"}, + {"delete-fcoe-port", + fcoeAdmDeletePortFunc, NULL, NULL, NULL, + OPERAND_MANDATORY_SINGLE, "Network Interface Name"}, + {"list-fcoe-ports", + fcoeListPortsFunc, "t", NULL, NULL, + OPERAND_NONE, NULL}, + {"create-fcoe-ports", + fcoeAdmCreatePortListFunc, "t", NULL, NULL, + OPERAND_NONE, NULL}, {NULL, 0, NULL, NULL, NULL, 0, NULL, NULL} }; + /* * Pass in options/arguments, rest of arguments */ @@ -190,6 +210,50 @@ npivListRemotePortFunc(int objects, char *argv[], } /* + * 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 +fcoeAdmCreatePortListFunc(int objects, char *argv[], cmdOptions_t *options, + void *addArgs) +{ + return (fcoe_adm_create_portlist(options)); +} + +/* * input: * execFullName - exec name of program (argv[0]) * @@ -246,6 +310,12 @@ main(int argc, char *argv[]) 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]); diff --git a/usr/src/cmd/fcinfo/fcinfo.h b/usr/src/cmd/fcinfo/fcinfo.h index 343c379de2..4047ccaf4b 100644 --- a/usr/src/cmd/fcinfo/fcinfo.h +++ b/usr/src/cmd/fcinfo/fcinfo.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -44,6 +44,7 @@ extern "C" { #include <netinet/in.h> #include <inttypes.h> #include <cmdparse.h> +#include <locale.h> #ifdef _BIG_ENDIAN #define htonll(x) (x) @@ -88,16 +89,39 @@ extern "C" { #define NPIV_PG_NAME "npiv-port-list" #define NPIV_PORT_LIST "port_list" +#define FCOE_SCF_ADD 0 +#define FCOE_SCF_REMOVE 1 + +#define FCOE_SUCCESS 0 +#define FCOE_ERROR 1 +#define FCOE_ERROR_NOT_FOUND 2 +#define FCOE_ERROR_EXISTS 3 +#define FCOE_ERROR_SERVICE_NOT_FOUND 4 +#define FCOE_ERROR_NOMEM 5 +#define FCOE_ERROR_MEMBER_NOT_FOUND 6 +#define FCOE_ERROR_BUSY 7 + +#define FCOE_PORT_LIST_LENGTH 255 + +#define FCOE_SERVICE "network/fcoe_config" +#define FCOE_PG_NAME "fcoe-port-list-pg" +#define FCOE_PORT_LIST "port_list_p" + /* 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_MAX_MAC_NAME_LEN 32 +#define FCOE_USER_RAW_FRAME_SIZE 224 + typedef struct _tgtPortWWNList { HBA_WWN portWWN; HBA_UINT32 scsiOSLun; @@ -142,6 +166,13 @@ 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 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); +int fcoe_adm_create_portlist(cmdOptions_t *options); + + #ifdef __cplusplus } #endif diff --git a/usr/src/cmd/fcinfo/fcoe_config.xml b/usr/src/cmd/fcinfo/fcoe_config.xml new file mode 100644 index 0000000000..10dcbc4f60 --- /dev/null +++ b/usr/src/cmd/fcinfo/fcoe_config.xml @@ -0,0 +1,94 @@ +<?xml version="1.0"?> +<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1"> + +<!-- + +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. + + +Service manifests for the FCOE configure + + +--> + +<!-- + +--> + +<service_bundle type='manifest' name='SUNWfcprt:fcoe_config'> + +<service + name='network/fcoe_config' + type='service' + version='1'> + + <create_default_instance enabled='true' /> + + <single_instance/> + + <dependency + name='fcoesysevent' + grouping='require_all' + restart_on='none' + type='service'> + <service_fmri value='svc:/system/sysevent' /> + </dependency> + + <dependent + name='fcoe-filesystem' + grouping='require_all' + restart_on='none'> + <service_fmri value='svc:/system/filesystem/local' /> + </dependent> + + <dependent + name='fcoe-fc' + grouping='require_all' + restart_on='none'> + <service_fmri value='svc:/system/device/fc-fabric' /> + </dependent> + + <exec_method + type='method' + name='start' + exec='/lib/svc/method/fcoeconfig' + timeout_seconds='1200'> + </exec_method> + + <exec_method + type='method' + name='stop' + exec=':true' + timeout_seconds='60'> + </exec_method> + + <property_group name='startd' type='framework'> + <propval name='duration' type='astring' + value='transient' /> + </property_group> + + <stability value='Unstable' /> + +</service> + +</service_bundle> diff --git a/usr/src/cmd/fcinfo/fcoeadm.c b/usr/src/cmd/fcinfo/fcoeadm.c new file mode 100644 index 0000000000..340d33dfa9 --- /dev/null +++ b/usr/src/cmd/fcinfo/fcoeadm.c @@ -0,0 +1,949 @@ +/* + * 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 <libintl.h> +#include <fcntl.h> +#include <errno.h> +#include <assert.h> +#include <ctype.h> +#include <sys/list.h> +#include <stddef.h> +#include <strings.h> +#include <libfcoe.h> +#include <libscf.h> +#include <syslog.h> + +static const char *FCOE_DRIVER_PATH = "/devices/fcoe:admin"; + +static char * +WWN2str(char *buf, FCOE_PORT_WWN *wwn) { + int j; + unsigned char *pc = (unsigned char *)&(wwn->wwn[0]); + buf[0] = '\0'; + for (j = 0; j < 16; j += 2) { + 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); +} + +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("\tMAC Factory Address: ")); + for (i = 0; i < 6; i++) { + fprintf(stdout, gettext("%02x"), attr->mac_factory_addr[i]); + } + fprintf(stdout, gettext("\n\tMAC Current 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"); +} + +/* + * Initialize scf fcoe service access + * handle - returned handle + * service - returned service handle + */ +static int +fcoe_cfg_scf_init(scf_handle_t **handle, scf_service_t **service) +{ + scf_scope_t *scope = NULL; + int ret; + + if ((*handle = scf_handle_create(SCF_VERSION)) == NULL) { + syslog(LOG_ERR, "scf_handle_create failed - %s", + scf_strerror(scf_error())); + ret = FCOE_ERROR; + goto err; + } + + if (scf_handle_bind(*handle) == -1) { + syslog(LOG_ERR, "scf_handle_bind failed - %s", + scf_strerror(scf_error())); + ret = FCOE_ERROR; + goto err; + } + + if ((*service = scf_service_create(*handle)) == NULL) { + syslog(LOG_ERR, "scf_service_create failed - %s", + scf_strerror(scf_error())); + ret = FCOE_ERROR; + goto err; + } + + if ((scope = scf_scope_create(*handle)) == NULL) { + syslog(LOG_ERR, "scf_scope_create failed - %s", + scf_strerror(scf_error())); + ret = FCOE_ERROR; + goto err; + } + + if (scf_handle_get_scope(*handle, SCF_SCOPE_LOCAL, scope) == -1) { + syslog(LOG_ERR, "scf_handle_get_scope failed - %s", + scf_strerror(scf_error())); + ret = FCOE_ERROR; + goto err; + } + + if (scf_scope_get_service(scope, FCOE_SERVICE, *service) == -1) { + syslog(LOG_ERR, "scf_scope_get_service failed - %s", + scf_strerror(scf_error())); + ret = FCOE_ERROR_SERVICE_NOT_FOUND; + goto err; + } + + scf_scope_destroy(scope); + + return (FCOE_SUCCESS); + +err: + if (*handle != NULL) { + scf_handle_destroy(*handle); + } + if (*service != NULL) { + scf_service_destroy(*service); + *service = NULL; + } + if (scope != NULL) { + scf_scope_destroy(scope); + } + return (ret); +} + + +static int +fcoe_adm_add_remove_scf_entry(char *mac_name, + char *pwwn, char *nwwn, + int is_target, int is_promiscuous, int addRemoveFlag) +{ + scf_handle_t *handle = NULL; + scf_service_t *svc = NULL; + scf_propertygroup_t *pg = NULL; + scf_transaction_t *tran = NULL; + scf_transaction_entry_t *entry = NULL; + scf_property_t *prop = NULL; + scf_value_t *valueLookup = NULL; + scf_iter_t *valueIter = NULL; + scf_value_t **valueSet = NULL; + int ret = FCOE_SUCCESS; + boolean_t createProp = B_FALSE; + int lastAlloc = 0; + char buf[FCOE_PORT_LIST_LENGTH] = {0}; + char memberName[FCOE_PORT_LIST_LENGTH] = {0}; + boolean_t found = B_FALSE; + int i = 0; + int valueArraySize = 0; + int commitRet; + + sprintf(memberName, "%s:%s:%s:%d:%d", mac_name, pwwn, nwwn, + is_target, is_promiscuous); + + ret = fcoe_cfg_scf_init(&handle, &svc); + if (ret != FCOE_SUCCESS) { + goto out; + } + + if (((pg = scf_pg_create(handle)) == NULL) || + ((tran = scf_transaction_create(handle)) == NULL) || + ((entry = scf_entry_create(handle)) == NULL) || + ((prop = scf_property_create(handle)) == NULL) || + ((valueIter = scf_iter_create(handle)) == NULL)) { + ret = FCOE_ERROR; + goto out; + } + + /* get property group or create it */ + if (scf_service_get_pg(svc, FCOE_PG_NAME, pg) == -1) { + if ((scf_error() == SCF_ERROR_NOT_FOUND)) { + if (scf_service_add_pg(svc, FCOE_PG_NAME, + SCF_GROUP_APPLICATION, 0, pg) == -1) { + syslog(LOG_ERR, "add pg failed - %s", + scf_strerror(scf_error())); + ret = FCOE_ERROR; + } else { + createProp = B_TRUE; + } + } else { + syslog(LOG_ERR, "get pg failed - %s", + scf_strerror(scf_error())); + ret = FCOE_ERROR; + } + if (ret != FCOE_SUCCESS) { + goto out; + } + } + + /* to make sure property exists */ + if (createProp == B_FALSE) { + if (scf_pg_get_property(pg, FCOE_PORT_LIST, prop) == -1) { + if ((scf_error() == SCF_ERROR_NOT_FOUND)) { + createProp = B_TRUE; + } else { + syslog(LOG_ERR, "get property failed - %s", + scf_strerror(scf_error())); + ret = FCOE_ERROR; + goto out; + } + } + } + + /* Begin the transaction */ + if (scf_transaction_start(tran, pg) == -1) { + syslog(LOG_ERR, "start transaction failed - %s", + scf_strerror(scf_error())); + ret = FCOE_ERROR; + goto out; + } + + valueSet = (scf_value_t **)calloc(1, sizeof (*valueSet) + * (lastAlloc = PORT_LIST_ALLOC)); + if (valueSet == NULL) { + ret = FCOE_ERROR_NOMEM; + goto out; + } + + if (createProp) { + if (scf_transaction_property_new(tran, entry, FCOE_PORT_LIST, + SCF_TYPE_USTRING) == -1) { + if (scf_error() == SCF_ERROR_EXISTS) { + ret = FCOE_ERROR_EXISTS; + } else { + syslog(LOG_ERR, + "transaction property new failed - %s", + scf_strerror(scf_error())); + ret = FCOE_ERROR; + } + goto out; + } + } else { + if (scf_transaction_property_change(tran, entry, + FCOE_PORT_LIST, SCF_TYPE_USTRING) == -1) { + syslog(LOG_ERR, + "transaction property change failed - %s", + scf_strerror(scf_error())); + ret = FCOE_ERROR; + goto out; + } + + if (scf_pg_get_property(pg, FCOE_PORT_LIST, prop) == -1) { + syslog(LOG_ERR, "get property failed - %s", + scf_strerror(scf_error())); + ret = FCOE_ERROR; + goto out; + } + + valueLookup = scf_value_create(handle); + if (valueLookup == NULL) { + syslog(LOG_ERR, "scf value alloc failed - %s", + scf_strerror(scf_error())); + ret = FCOE_ERROR; + goto out; + } + + if (scf_iter_property_values(valueIter, prop) == -1) { + syslog(LOG_ERR, "iter value failed - %s", + scf_strerror(scf_error())); + ret = FCOE_ERROR; + goto out; + } + + while (scf_iter_next_value(valueIter, valueLookup) == 1) { + char *macnameIter = NULL; + char buftmp[FCOE_PORT_LIST_LENGTH] = {0}; + + bzero(buf, sizeof (buf)); + if (scf_value_get_ustring(valueLookup, + buf, MAXNAMELEN) == -1) { + syslog(LOG_ERR, "iter value failed- %s", + scf_strerror(scf_error())); + ret = FCOE_ERROR; + break; + } + strcpy(buftmp, buf); + macnameIter = strtok(buftmp, ":"); + if (bcmp(macnameIter, mac_name, + strlen(mac_name)) == 0) { + if (addRemoveFlag == FCOE_SCF_ADD) { + ret = FCOE_ERROR_EXISTS; + break; + } else { + found = B_TRUE; + continue; + } + } + + valueSet[i] = scf_value_create(handle); + if (valueSet[i] == NULL) { + syslog(LOG_ERR, "scf value alloc failed - %s", + scf_strerror(scf_error())); + ret = FCOE_ERROR; + break; + } + + if (scf_value_set_ustring(valueSet[i], buf) == -1) { + syslog(LOG_ERR, "set value failed 1- %s", + scf_strerror(scf_error())); + ret = FCOE_ERROR; + break; + } + + if (scf_entry_add_value(entry, valueSet[i]) == -1) { + syslog(LOG_ERR, "add value failed - %s", + scf_strerror(scf_error())); + ret = FCOE_ERROR; + break; + } + + i++; + + if (i >= lastAlloc) { + lastAlloc += PORT_LIST_ALLOC; + valueSet = realloc(valueSet, + sizeof (*valueSet) * lastAlloc); + if (valueSet == NULL) { + ret = FCOE_ERROR; + break; + } + } + } + } + + valueArraySize = i; + if (!found && (addRemoveFlag == FCOE_SCF_REMOVE)) { + ret = FCOE_ERROR_MEMBER_NOT_FOUND; + } + if (ret != FCOE_SUCCESS) { + goto out; + } + + if (addRemoveFlag == FCOE_SCF_ADD) { + /* + * Now create the new entry + */ + valueSet[i] = scf_value_create(handle); + if (valueSet[i] == NULL) { + syslog(LOG_ERR, "scf value alloc failed - %s", + scf_strerror(scf_error())); + ret = FCOE_ERROR; + goto out; + } else { + valueArraySize++; + } + + /* + * Set the new member name + */ + if (scf_value_set_ustring(valueSet[i], memberName) == -1) { + syslog(LOG_ERR, "set value failed 2- %s", + scf_strerror(scf_error())); + ret = FCOE_ERROR; + goto out; + } + + /* + * Add the new member + */ + if (scf_entry_add_value(entry, valueSet[i]) == -1) { + syslog(LOG_ERR, "add value failed - %s", + scf_strerror(scf_error())); + ret = FCOE_ERROR; + goto out; + } + } + + if ((commitRet = scf_transaction_commit(tran)) != 1) { + syslog(LOG_ERR, "transaction commit failed - %s", + scf_strerror(scf_error())); + if (commitRet == 0) { + ret = FCOE_ERROR_BUSY; + } else { + ret = FCOE_ERROR; + } + goto out; + } + +out: + /* + * Free resources + */ + if (handle != NULL) { + scf_handle_destroy(handle); + } + if (svc != NULL) { + scf_service_destroy(svc); + } + if (pg != NULL) { + scf_pg_destroy(pg); + } + if (tran != NULL) { + scf_transaction_destroy(tran); + } + if (entry != NULL) { + scf_entry_destroy(entry); + } + if (prop != NULL) { + scf_property_destroy(prop); + } + if (valueIter != NULL) { + scf_iter_destroy(valueIter); + } + if (valueLookup != NULL) { + scf_value_destroy(valueLookup); + } + + /* + * Free valueSet scf resources + */ + if (valueArraySize > 0) { + for (i = 0; i < valueArraySize; i++) { + scf_value_destroy(valueSet[i]); + } + } + /* + * Now free the pointer array to the resources + */ + if (valueSet != NULL) { + free(valueSet); + } + + return (ret); +} + +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_VNIC_UNSUPPORT: + fprintf(stderr, + gettext("Error: VNIC is not supported\n")); + break; + + case FCOE_STATUS_ERROR: + default: + fprintf(stderr, + gettext("Error: Due to reason code %d\n"), status); + } + return (1); + } else { + char cpwwn[17], cnwwn[17]; + + WWN2str(cpwwn, &pwwn); + WWN2str(cnwwn, &nwwn); + + fcoe_adm_add_remove_scf_entry((char *)macLinkName, + cpwwn, + cnwwn, + createtgt, + promiscuous, + FCOE_SCF_ADD); + return (0); + } +} + +int +fcoe_adm_delete_port(int objects, char *argv[]) +{ + FCOE_STATUS status; + FCOE_UINT8 *macLinkName; + + /* 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: + fprintf(stderr, + gettext("Error: Please use stmfadm to offline " + "the FCoE target first\n")); + break; + + case FCOE_STATUS_ERROR: + default: + fprintf(stderr, + gettext("Error: Due to reason code %d\n"), status); + } + return (1); + } else { + fcoe_adm_add_remove_scf_entry((char *)macLinkName, + "", + "", + 0, + 0, + FCOE_SCF_REMOVE); + 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); + +} + +int +fcoe_adm_create_portlist(cmdOptions_t *options) +{ + scf_handle_t *handle = NULL; + scf_service_t *svc = NULL; + scf_propertygroup_t *pg = NULL; + scf_transaction_t *tran = NULL; + scf_transaction_entry_t *entry = NULL; + scf_property_t *prop = NULL; + scf_value_t *valueLookup = NULL; + scf_iter_t *valueIter = NULL; + char buf[FCOE_PORT_LIST_LENGTH] = {0}; + int commitRet; + int create_target = 0, create_initiator = 0; + + /* Check what type of port list will be created */ + for (; options->optval; options++) { + switch (options->optval) { + case 'i': + create_initiator = 1; + break; + case 't': + create_target = 1; + break; + default: + fprintf(stderr, gettext("Error: Illegal option: %c\n"), + options->optval); + return (1); + } + } + + if (create_initiator == 0 && create_target == 0) { + create_initiator = 1; + create_target = 1; + } + + commitRet = fcoe_cfg_scf_init(&handle, &svc); + if (commitRet != FCOE_SUCCESS) { + goto out; + } + + if (((pg = scf_pg_create(handle)) == NULL) || + ((tran = scf_transaction_create(handle)) == NULL) || + ((entry = scf_entry_create(handle)) == NULL) || + ((prop = scf_property_create(handle)) == NULL) || + ((valueIter = scf_iter_create(handle)) == NULL)) { + goto out; + } + + /* get property group or create it */ + if (scf_service_get_pg(svc, FCOE_PG_NAME, pg) == -1) { + goto out; + } + + if (scf_pg_get_property(pg, FCOE_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; + } + while (scf_iter_next_value(valueIter, valueLookup) == 1) { + uint8_t *macLinkName = NULL; + char *remainder = NULL; + FCOE_PORT_WWN pwwn, nwwn; + uint64_t nodeWWN, portWWN; + int is_target, is_promiscuous; + + bzero(buf, sizeof (buf)); + bzero(&pwwn, sizeof (pwwn)); + bzero(&nwwn, sizeof (nwwn)); + if (scf_value_get_ustring(valueLookup, buf, MAXNAMELEN) == -1) { + syslog(LOG_ERR, "iter value failed - %s", + scf_strerror(scf_error())); + break; + } + macLinkName = (uint8_t *)strtok(buf, ":"); + remainder = strtok(NULL, "#"); + sscanf(remainder, "%016llx:%016llx:%d:%d", + &portWWN, &nodeWWN, &is_target, &is_promiscuous); + if ((!create_target && is_target) || + (!create_initiator && !is_target)) { + continue; + } + + nodeWWN = htonll(nodeWWN); + memcpy(&nwwn, &nodeWWN, sizeof (nodeWWN)); + portWWN = htonll(portWWN); + memcpy(&pwwn, &portWWN, sizeof (portWWN)); + + FCOE_CreatePort(macLinkName, + is_target ? FCOE_PORTTYPE_TARGET : FCOE_PORTTYPE_INITIATOR, + pwwn, nwwn, is_promiscuous); + } + +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); +} diff --git a/usr/src/cmd/fcinfo/fcoeconfig b/usr/src/cmd/fcinfo/fcoeconfig new file mode 100644 index 0000000000..ba47b22c69 --- /dev/null +++ b/usr/src/cmd/fcinfo/fcoeconfig @@ -0,0 +1,35 @@ +#!/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 2009 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-fcoe-ports diff --git a/usr/src/lib/Makefile b/usr/src/lib/Makefile index 2ec74c85d6..4dc4077d5a 100644 --- a/usr/src/lib/Makefile +++ b/usr/src/lib/Makefile @@ -152,6 +152,7 @@ SUBDIRS += \ libkrb5 .WAIT \ krb5 .WAIT \ libsmbfs \ + libfcoe \ libstmf \ libnsctl \ libunistat \ @@ -430,6 +431,7 @@ HDRSUBDIRS= \ libslp \ libsmedia \ libsqlite \ + libfcoe \ libstmf \ libsum \ libsysevent \ diff --git a/usr/src/lib/libfcoe/Makefile b/usr/src/lib/libfcoe/Makefile new file mode 100644 index 0000000000..e9b7036a1f --- /dev/null +++ b/usr/src/lib/libfcoe/Makefile @@ -0,0 +1,55 @@ +# +# 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 ../Makefile.lib + +SUBDIRS = $(MACH) +$(BUILD64)SUBDIRS += $(MACH64) + +all := TARGET= all +clean := TARGET= clean +clobber := TARGET= clobber +install := TARGET= install +install_h := TARGET= install_h +lint := TARGET= lint + + +HDRS= libfcoe.h +HDRDIR= common + +.KEEP_STATE: + +all clean clobber install lint: $(SUBDIRS) + +install_h: $(ROOTHDRS) + +check: $(CHECKHDRS) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: + +include ../Makefile.targ diff --git a/usr/src/lib/libfcoe/Makefile.com b/usr/src/lib/libfcoe/Makefile.com new file mode 100644 index 0000000000..8fd5bfd695 --- /dev/null +++ b/usr/src/lib/libfcoe/Makefile.com @@ -0,0 +1,53 @@ +# +# 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. +# + +LIBRARY= libfcoe.a +VERS= .1 + +OBJECTS= libfcoe.o + +include ../../Makefile.lib + +LIBS= $(DYNLIB) $(LINTLIB) + +SRCDIR = ../common + +INCS += -I$(SRCDIR) +INCS += -I$(SRC)/uts/common/sys/fcoe + +LDLIBS += -lc +C99MODE= -xc99=%all +C99LMODE= -Xc99=%all +CPPFLAGS += $(INCS) -D_REENTRANT + +$(LINTLIB) := SRCS= $(SRCDIR)/$(LINTSRC) + +.KEEP_STATE: + +all: $(LIBS) + +lint: lintcheck + +include ../../Makefile.targ diff --git a/usr/src/lib/libfcoe/amd64/Makefile b/usr/src/lib/libfcoe/amd64/Makefile new file mode 100644 index 0000000000..9e8a127855 --- /dev/null +++ b/usr/src/lib/libfcoe/amd64/Makefile @@ -0,0 +1,32 @@ +# +# 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 ../Makefile.com +include ../../Makefile.lib.64 + +all: $(LIBS) + +install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT) diff --git a/usr/src/lib/libfcoe/common/libfcoe.c b/usr/src/lib/libfcoe/common/libfcoe.c new file mode 100644 index 0000000000..f06a620f26 --- /dev/null +++ b/usr/src/lib/libfcoe/common/libfcoe.c @@ -0,0 +1,347 @@ +/* + * 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 <stdlib.h> +#include <stdio.h> +#include <wchar.h> +#include <strings.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <libintl.h> +#include <errno.h> +#include <string.h> +#include <assert.h> +#include <syslog.h> +#include <libfcoe.h> +#include <fcoeio.h> + +#define FCOE_DEV_PATH "/devices/fcoe:admin" + +#define OPEN_FCOE 0 +#define OPEN_EXCL_FCOE O_EXCL + +/* + * Open for fcoe module + * + * flag - open flag (OPEN_FCOE, OPEN_EXCL_FCOE) + * fd - pointer to integer. On success, contains the fcoe file descriptor + */ +static int +openFcoe(int flag, int *fd) +{ + int ret = FCOE_STATUS_ERROR; + + if ((*fd = open(FCOE_DEV_PATH, O_NDELAY | O_RDONLY | flag)) != -1) { + ret = FCOE_STATUS_OK; + } else { + if (errno == EPERM || errno == EACCES) { + ret = FCOE_STATUS_ERROR_PERM; + } else { + ret = FCOE_STATUS_ERROR_OPEN_DEV; + } + syslog(LOG_DEBUG, "openFcoe:open failure:%s:errno(%d)", + FCOE_DEV_PATH, errno); + } + + return (ret); +} + +static int +isWWNZero(FCOE_PORT_WWN portwwn) +{ + int i; + int size = sizeof (FCOE_PORT_WWN); + + for (i = 0; i < size; i++) { + if (portwwn.wwn[i] != 0) { + return (0); + } + } + return (1); +} + +FCOE_STATUS +FCOE_CreatePort( + const FCOE_UINT8 *macLinkName, + FCOE_UINT8 portType, + FCOE_PORT_WWN pwwn, + FCOE_PORT_WWN nwwn, + FCOE_UINT8 promiscuous) +{ + FCOE_STATUS status = FCOE_STATUS_OK; + int fcoe_fd; + fcoeio_t fcoeio; + fcoeio_create_port_param_t param; + + bzero(¶m, sizeof (fcoeio_create_port_param_t)); + + if (macLinkName == NULL) { + return (FCOE_STATUS_ERROR_INVAL_ARG); + } + + if (portType != FCOE_PORTTYPE_INITIATOR && + portType != FCOE_PORTTYPE_TARGET) { + return (FCOE_STATUS_ERROR_INVAL_ARG); + } + + if (!isWWNZero(pwwn)) { + param.fcp_pwwn_provided = 1; + bcopy(pwwn.wwn, param.fcp_pwwn, 8); + } + + if (!isWWNZero(nwwn)) { + param.fcp_nwwn_provided = 1; + bcopy(nwwn.wwn, param.fcp_nwwn, 8); + } + + if (param.fcp_pwwn_provided == 1 && + param.fcp_nwwn_provided == 1 && + bcmp(&pwwn, &nwwn, 8) == 0) { + return (FCOE_STATUS_ERROR_WWN_SAME); + } + + if (strlen((char *)macLinkName) > FCOE_MAX_MAC_NAME_LEN-1) { + return (FCOE_STATUS_ERROR_MAC_LEN); + } + + param.fcp_force_promisc = promiscuous; + (void) strcpy((char *)param.fcp_mac_name, (char *)macLinkName); + param.fcp_port_type = (fcoe_cli_type_t)portType; + + if ((status = openFcoe(OPEN_FCOE, &fcoe_fd)) != FCOE_STATUS_OK) { + return (status); + } + + (void) memset(&fcoeio, 0, sizeof (fcoeio)); + fcoeio.fcoeio_cmd = FCOEIO_CREATE_FCOE_PORT; + + fcoeio.fcoeio_ilen = sizeof (param); + fcoeio.fcoeio_xfer = FCOEIO_XFER_WRITE; + fcoeio.fcoeio_ibuf = (uintptr_t)¶m; + + if (ioctl(fcoe_fd, FCOEIO_CMD, &fcoeio) != 0) { + switch (fcoeio.fcoeio_status) { + case FCOEIOE_INVAL_ARG: + status = FCOE_STATUS_ERROR_INVAL_ARG; + break; + + case FCOEIOE_BUSY: + status = FCOE_STATUS_ERROR_BUSY; + break; + + case FCOEIOE_ALREADY: + status = FCOE_STATUS_ERROR_ALREADY; + break; + + case FCOEIOE_PWWN_CONFLICTED: + status = FCOE_STATUS_ERROR_PWWN_CONFLICTED; + break; + + case FCOEIOE_NWWN_CONFLICTED: + status = FCOE_STATUS_ERROR_NWWN_CONFLICTED; + break; + + case FCOEIOE_CREATE_MAC: + status = FCOE_STATUS_ERROR_CREATE_MAC; + break; + + case FCOEIOE_OPEN_MAC: + status = FCOE_STATUS_ERROR_OPEN_MAC; + break; + + case FCOEIOE_CREATE_PORT: + status = FCOE_STATUS_ERROR_CREATE_PORT; + break; + + case FCOEIOE_NEED_JUMBO_FRAME: + status = FCOE_STATUS_ERROR_NEED_JUMBO_FRAME; + break; + + case FCOEIOE_VNIC_UNSUPPORT: + status = FCOE_STATUS_ERROR_VNIC_UNSUPPORT; + break; + + default: + status = FCOE_STATUS_ERROR; + } + } else { + status = FCOE_STATUS_OK; + } + (void) close(fcoe_fd); + return (status); +} + +FCOE_STATUS +FCOE_DeletePort(const FCOE_UINT8 *macLinkName) +{ + FCOE_STATUS status = FCOE_STATUS_OK; + int fcoe_fd; + fcoeio_t fcoeio; + + if (macLinkName == NULL) { + return (FCOE_STATUS_ERROR_INVAL_ARG); + } + + if (strlen((char *)macLinkName) > FCOE_MAX_MAC_NAME_LEN-1) { + return (FCOE_STATUS_ERROR_MAC_LEN); + } + + if ((status = openFcoe(OPEN_FCOE, &fcoe_fd)) != FCOE_STATUS_OK) { + return (status); + } + + (void) memset(&fcoeio, 0, sizeof (fcoeio)); + fcoeio.fcoeio_cmd = FCOEIO_DELETE_FCOE_PORT; + + fcoeio.fcoeio_ilen = strlen((char *)macLinkName)+1; + fcoeio.fcoeio_xfer = FCOEIO_XFER_WRITE; + fcoeio.fcoeio_ibuf = (uintptr_t)macLinkName; + + if (ioctl(fcoe_fd, FCOEIO_CMD, &fcoeio) != 0) { + switch (fcoeio.fcoeio_status) { + case FCOEIOE_INVAL_ARG: + status = FCOE_STATUS_ERROR_INVAL_ARG; + break; + + case FCOEIOE_BUSY: + status = FCOE_STATUS_ERROR_BUSY; + break; + + case FCOEIOE_ALREADY: + status = FCOE_STATUS_ERROR_ALREADY; + break; + + case FCOEIOE_MAC_NOT_FOUND: + status = FCOE_STATUS_ERROR_MAC_NOT_FOUND; + break; + + case FCOEIOE_OFFLINE_FAILURE: + status = FCOE_STATUS_ERROR_OFFLINE_DEV; + break; + + default: + status = FCOE_STATUS_ERROR; + } + } else { + status = FCOE_STATUS_OK; + } + (void) close(fcoe_fd); + return (status); +} + +FCOE_STATUS +FCOE_GetPortList( + FCOE_UINT32 *port_num, + FCOE_PORT_ATTRIBUTE **portlist) +{ + FCOE_STATUS status = FCOE_STATUS_OK; + int fcoe_fd; + fcoeio_t fcoeio; + fcoe_port_list_t *inportlist = NULL; + FCOE_PORT_ATTRIBUTE *outportlist = NULL; + int i; + int size = 64; /* default first attempt */ + int retry = 0; + int bufsize; + + if (port_num == NULL || portlist == NULL) { + return (FCOE_STATUS_ERROR_INVAL_ARG); + } + *port_num = 0; + + if ((status = openFcoe(OPEN_FCOE, &fcoe_fd)) != FCOE_STATUS_OK) { + return (status); + } + + /* Get fcoe port list */ + (void) memset(&fcoeio, 0, sizeof (fcoeio)); + retry = 0; + + do { + bufsize = sizeof (fcoe_port_instance_t) * (size - 1) + + sizeof (fcoe_port_list_t); + inportlist = (fcoe_port_list_t *)malloc(bufsize); + fcoeio.fcoeio_cmd = FCOEIO_GET_FCOE_PORT_LIST; + fcoeio.fcoeio_olen = bufsize; + fcoeio.fcoeio_xfer = FCOEIO_XFER_READ; + fcoeio.fcoeio_obuf = (uintptr_t)inportlist; + + if (ioctl(fcoe_fd, FCOEIO_CMD, &fcoeio) != 0) { + if (fcoeio.fcoeio_status == FCOEIOE_MORE_DATA) { + size = inportlist->numPorts; + } + free(inportlist); + switch (fcoeio.fcoeio_status) { + case FCOEIOE_INVAL_ARG: + status = FCOE_STATUS_ERROR_INVAL_ARG; + (void) close(fcoe_fd); + return (status); + + case FCOEIOE_BUSY: + status = FCOE_STATUS_ERROR_BUSY; + retry++; + break; + + case FCOEIOE_MORE_DATA: + status = FCOE_STATUS_ERROR_MORE_DATA; + retry++; + default: + status = FCOE_STATUS_ERROR; + } + } else { + status = FCOE_STATUS_OK; + break; + } + } while (retry <= 3 && status != FCOE_STATUS_OK); + + if (status == FCOE_STATUS_OK) { + outportlist = (PFCOE_PORT_ATTRIBUTE) + malloc(sizeof (FCOE_PORT_ATTRIBUTE) * inportlist->numPorts); + + for (i = 0; i < inportlist->numPorts; i++) { + fcoe_port_instance_t *pi = &inportlist->ports[i]; + FCOE_PORT_ATTRIBUTE *po = &outportlist[i]; + bcopy(pi->fpi_pwwn, &po->port_wwn, 8); + bcopy(pi->fpi_mac_link_name, po->mac_link_name, 32); + bcopy(pi->fpi_mac_factory_addr, + po->mac_factory_addr, 6); + bcopy(pi->fpi_mac_current_addr, + po->mac_current_addr, 6); + po->port_type = (FCOE_UINT8)pi->fpi_port_type; + po->mtu_size = pi->fpi_mtu_size; + po->mac_promisc = pi->fpi_mac_promisc; + } + *port_num = inportlist->numPorts; + *portlist = outportlist; + free(inportlist); + } else { + *port_num = 0; + *portlist = NULL; + } + (void) close(fcoe_fd); + return (status); +} diff --git a/usr/src/lib/libfcoe/common/libfcoe.h b/usr/src/lib/libfcoe/common/libfcoe.h new file mode 100644 index 0000000000..30570205a7 --- /dev/null +++ b/usr/src/lib/libfcoe/common/libfcoe.h @@ -0,0 +1,120 @@ +/* + * 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 _LIBFCOE_H +#define _LIBFCOE_H + +#include <time.h> +#include <wchar.h> +#include <sys/param.h> +#include <sys/ethernet.h> +#include <libnvpair.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * FCOE Port Type + */ +#define FCOE_PORTTYPE_INITIATOR 0 +#define FCOE_PORTTYPE_TARGET 1 + +#define FCOE_MAX_MAC_NAME_LEN 32 +typedef unsigned char FCOE_UINT8; +typedef char FCOE_INT8; +typedef unsigned short FCOE_UINT16; +typedef short FCOE_INT16; +typedef unsigned int FCOE_UINT32; +typedef int FCOE_INT32; + +typedef unsigned int FCOE_STATUS; + +#define FCOE_STATUS_OK 0 +#define FCOE_STATUS_ERROR 1 +#define FCOE_STATUS_ERROR_INVAL_ARG 2 +#define FCOE_STATUS_ERROR_BUSY 3 +#define FCOE_STATUS_ERROR_ALREADY 4 +#define FCOE_STATUS_ERROR_PERM 5 +#define FCOE_STATUS_ERROR_OPEN_DEV 6 +#define FCOE_STATUS_ERROR_WWN_SAME 7 +#define FCOE_STATUS_ERROR_MAC_LEN 8 +#define FCOE_STATUS_ERROR_PWWN_CONFLICTED 9 +#define FCOE_STATUS_ERROR_NWWN_CONFLICTED 10 +#define FCOE_STATUS_ERROR_NEED_JUMBO_FRAME 11 +#define FCOE_STATUS_ERROR_CREATE_MAC 12 +#define FCOE_STATUS_ERROR_OPEN_MAC 13 +#define FCOE_STATUS_ERROR_CREATE_PORT 14 +#define FCOE_STATUS_ERROR_MAC_NOT_FOUND 15 +#define FCOE_STATUS_ERROR_OFFLINE_DEV 16 +#define FCOE_STATUS_ERROR_MORE_DATA 17 +#define FCOE_STATUS_ERROR_VNIC_UNSUPPORT 18 + +typedef struct fcoe_port_wwn { + uchar_t wwn[8]; +} FCOE_PORT_WWN, *PFCOE_PORT_WWN; + +typedef struct fcoe_port_attr { + FCOE_PORT_WWN port_wwn; + FCOE_UINT8 mac_link_name[MAXLINKNAMELEN]; + FCOE_UINT8 mac_factory_addr[ETHERADDRL]; + FCOE_UINT8 mac_current_addr[ETHERADDRL]; + FCOE_UINT8 port_type; + FCOE_UINT32 mtu_size; + FCOE_UINT8 mac_promisc; +} FCOE_PORT_ATTRIBUTE, *PFCOE_PORT_ATTRIBUTE; + +/* + * macLinkName: mac name with maximum lenth 32 + * portType: 0 (Initiator)/ 1(Target) + * pwwn: Port WWN + * nwwn: Nodw WWN + * promiscous: to enable promisc mode for mac interface + */ +FCOE_STATUS FCOE_CreatePort( + const FCOE_UINT8 *macLinkName, /* maximum len: 32 */ + FCOE_UINT8 portType, + FCOE_PORT_WWN pwwn, + FCOE_PORT_WWN nwwn, + FCOE_UINT8 promiscusous +); + +FCOE_STATUS FCOE_DeletePort( + const FCOE_UINT8 *macLinkName +); + +/* + * Make sure to free the memory pointed by portlist + */ +FCOE_STATUS FCOE_GetPortList( + FCOE_UINT32 *port_num, + FCOE_PORT_ATTRIBUTE **portlist +); + +#ifdef __cplusplus +} +#endif + +#endif /* _LIBFCOE_H */ diff --git a/usr/src/lib/libfcoe/common/llib-lfcoe b/usr/src/lib/libfcoe/common/llib-lfcoe new file mode 100644 index 0000000000..888c17113e --- /dev/null +++ b/usr/src/lib/libfcoe/common/llib-lfcoe @@ -0,0 +1,29 @@ +/* + * 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. + */ + +/*LINTLIBRARY*/ +/*PROTOLIB1*/ + +#include <libfcoe.h> diff --git a/usr/src/lib/libfcoe/common/mapfile-vers b/usr/src/lib/libfcoe/common/mapfile-vers new file mode 100644 index 0000000000..ba73d9e4dd --- /dev/null +++ b/usr/src/lib/libfcoe/common/mapfile-vers @@ -0,0 +1,48 @@ +# +# 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. +# + +# +# MAPFILE HEADER START +# +# WARNING: STOP NOW. DO NOT MODIFY THIS FILE. +# Object versioning must comply with the rules detailed in +# +# usr/src/lib/README.mapfiles +# +# You should not be making modifications here until you've read the most current +# copy of that file. If you need help, contact a gatekeeper for guidance. +# +# MAPFILE HEADER END +# + +SUNWprivate { + global: + FCOE_CreatePort; + FCOE_DeletePort; + FCOE_GetPortList; + + local: + *; +}; diff --git a/usr/src/lib/libfcoe/i386/Makefile b/usr/src/lib/libfcoe/i386/Makefile new file mode 100644 index 0000000000..433a471ad6 --- /dev/null +++ b/usr/src/lib/libfcoe/i386/Makefile @@ -0,0 +1,31 @@ +# +# 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 ../Makefile.com + +all: $(LIBS) + +install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT) diff --git a/usr/src/lib/libfcoe/sparc/Makefile b/usr/src/lib/libfcoe/sparc/Makefile new file mode 100644 index 0000000000..948a3578b3 --- /dev/null +++ b/usr/src/lib/libfcoe/sparc/Makefile @@ -0,0 +1,29 @@ +# +# 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 ../Makefile.com + +all: $(LIBS) + +install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT) diff --git a/usr/src/lib/libfcoe/sparcv9/Makefile b/usr/src/lib/libfcoe/sparcv9/Makefile new file mode 100644 index 0000000000..3f8aa611ca --- /dev/null +++ b/usr/src/lib/libfcoe/sparcv9/Makefile @@ -0,0 +1,34 @@ +# +# 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 ../Makefile.com +include ../../Makefile.lib.64 + +LIBS = $(DYNLIB) $(LINTLIB) + +all: $(LIBS) + +install: all $(ROOTLIBS64) $(ROOTLINKS64) diff --git a/usr/src/pkgdefs/Makefile b/usr/src/pkgdefs/Makefile index 1711bdda5c..f882753640 100644 --- a/usr/src/pkgdefs/Makefile +++ b/usr/src/pkgdefs/Makefile @@ -242,6 +242,9 @@ COMMON_SUBDIRS= \ SUNWfcprtr \ SUNWfcsm \ SUNWfctl \ + SUNWfcoe \ + SUNWfcoeu \ + SUNWfcoet \ SUNWfilebench \ SUNWfmd \ SUNWfmdr \ diff --git a/usr/src/pkgdefs/SUNWfcoe/Makefile b/usr/src/pkgdefs/SUNWfcoe/Makefile new file mode 100644 index 0000000000..0c86629d67 --- /dev/null +++ b/usr/src/pkgdefs/SUNWfcoe/Makefile @@ -0,0 +1,33 @@ +# +# 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 ../Makefile.com + +.KEEP_STATE: + +all: $(FILES) depend preremove postinstall +install: all pkg + +include ../Makefile.targ diff --git a/usr/src/pkgdefs/SUNWfcoe/depend b/usr/src/pkgdefs/SUNWfcoe/depend new file mode 100644 index 0000000000..31be17a927 --- /dev/null +++ b/usr/src/pkgdefs/SUNWfcoe/depend @@ -0,0 +1,50 @@ +# +# 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. +# +# +# This package information file defines software dependencies associated +# with the pkg. You can define three types of pkg dependencies with this file: +# P indicates a prerequisite for installation +# I indicates an incompatible package +# R indicates a reverse dependency +# <pkg.abbr> see pkginfo(4), PKG parameter +# <name> see pkginfo(4), NAME parameter +# <version> see pkginfo(4), VERSION parameter +# <arch> see pkginfo(4), ARCH parameter +# <type> <pkg.abbr> <name> +# (<arch>)<version> +# (<arch>)<version> +# ... +# <type> <pkg.abbr> <name> +# ... + +P SUNWcar Core Architecture, (Root) +P SUNWcakr Core Solaris Kernel Architecture (Root) +P SUNWkvm Core Architecture, (Kvm) +P SUNWcsr Core Solaris, (Root) +P SUNWckr Core Solaris Kernel (Root) +P SUNWcnetr Core Solaris Network Infrastructure (Root) +P SUNWcsu Core Solaris, (Usr) +P SUNWcsd Core Solaris Devices +P SUNWcsl Core Solaris Libraries diff --git a/usr/src/pkgdefs/SUNWfcoe/pkginfo.tmpl b/usr/src/pkgdefs/SUNWfcoe/pkginfo.tmpl new file mode 100644 index 0000000000..c4a84e2dfa --- /dev/null +++ b/usr/src/pkgdefs/SUNWfcoe/pkginfo.tmpl @@ -0,0 +1,50 @@ +# +# 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. +# +# +# +# This required package information file describes characteristics of the +# package, such as package abbreviation, full package name, package version, +# and package architecture. +# + +PKG="SUNWfcoe" +NAME="Sun FCoE Transport Driver" +ARCH="ISA" +CATEGORY="system" +BASEDIR=/ +SUNW_PKGVERS="1.0" +SUNW_PKGTYPE="root" +CLASSES="none" +DESC="Sun FCoE (Fibre Channel over Ethernet) Transport Driver" +SUNW_PRODNAME="SunOS" +SUNW_PRODVERS="RELEASE/VERSION" +VERSION="ONVERS,REV=0.0.0" +VENDOR="Sun Microsystems, Inc." +HOTLINE="Please contact your local service provider" +EMAIL="" +MAXINST="1000" +SUNW_PKG_ALLZONES="true" +SUNW_PKG_HOLLOW="true" +SUNW_PKG_THISZONE="false" diff --git a/usr/src/pkgdefs/SUNWfcoe/postinstall b/usr/src/pkgdefs/SUNWfcoe/postinstall new file mode 100644 index 0000000000..4b9d341eed --- /dev/null +++ b/usr/src/pkgdefs/SUNWfcoe/postinstall @@ -0,0 +1,54 @@ +#!/bin/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 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# + +PATH=/usr/bin:/usr/sbin:$PATH; export PATH + +# Driver definitions +DRVR_NAME=fcoe +DRVR_PERM="-m '* 0600 root sys'" +DRVR_CLASS="" +DRVR_ALIASES="" + + +if [ -z "${BASEDIR}" ]; then + echo "\n$0 Failed: BASEDIR is not set.\n" >&2 + exit 1 +fi + +# Remove existing definition, if it exists. +/usr/sbin/rem_drv -b "${BASEDIR}" ${DRVR_NAME} > /dev/null 2>&1 + +ADD_DRV="add_drv -n -b ${BASEDIR}" + +eval ${ADD_DRV} "${DRVR_PERM}" ${DRVR_CLASS} "${DRVR_ALIASES}" ${DRVR_NAME} +if [ $? -ne 0 ]; then + echo "\nCommand Failed:\n${ADD_DRV} "${DRVR_PERM}" ${DRVR_CLASS} \ + "${DRVR_ALIASES}" ${DRVR_NAME}\n" >&2 + exit 1 +fi + +exit 0 diff --git a/usr/src/pkgdefs/SUNWfcoe/preremove b/usr/src/pkgdefs/SUNWfcoe/preremove new file mode 100644 index 0000000000..d7ef233dc6 --- /dev/null +++ b/usr/src/pkgdefs/SUNWfcoe/preremove @@ -0,0 +1,33 @@ +#!/bin/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 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# + +DRVR_NAME=fcoe + +# Remove the driver entries but leave it attached. +/usr/sbin/rem_drv -b ${BASEDIR} ${DRVR_NAME} + +exit 0 diff --git a/usr/src/pkgdefs/SUNWfcoe/prototype_com b/usr/src/pkgdefs/SUNWfcoe/prototype_com new file mode 100644 index 0000000000..497cf4a41d --- /dev/null +++ b/usr/src/pkgdefs/SUNWfcoe/prototype_com @@ -0,0 +1,41 @@ +# +# 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. +# +# +# This required package information file contains a list of package contents. +# The 'pkgmk' command uses this file to identify the contents of a package +# and their location on the development machine when building the package. +# Can be created via a text editor or through use of the 'pkgproto' command. + +#!search <pathname pathname ...> # where to find pkg objects +#!include <filename> # include another 'prototype' file +#!default <mode> <owner> <group> # default used if not specified on entry +#!<param>=<value> # puts parameter in pkg environment + +# +# +i copyright +i pkginfo +i depend +i postinstall +i preremove diff --git a/usr/src/pkgdefs/SUNWfcoe/prototype_i386 b/usr/src/pkgdefs/SUNWfcoe/prototype_i386 new file mode 100644 index 0000000000..d551918064 --- /dev/null +++ b/usr/src/pkgdefs/SUNWfcoe/prototype_i386 @@ -0,0 +1,53 @@ +# +# 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. +# +# +# This required package information file contains a list of package contents. +# The 'pkgmk' command uses this file to identify the contents of a package +# and their location on the development machine when building the package. +# Can be created via a text editor or through use of the 'pkgproto' command. + +#!search <pathname pathname ...> # where to find pkg objects +#!include <filename> # include another 'prototype' file +#!default <mode> <owner> <group> # default used if not specified on entry +#!<param>=<value> # puts parameter in pkg environment +# +# Include ISA independent files (prototype_com) +# +!include prototype_com +# +# +# List files which are Intel specific here +# +# source locations relative to the prototype file +# +# +# SUNWfcoe +# +d none kernel 0755 root sys +d none kernel/drv 0755 root sys +d none kernel/drv/amd64 0755 root sys +f none kernel/drv/fcoe.conf 0644 root sys +f none kernel/drv/fcoe 0755 root sys +f none kernel/drv/amd64/fcoe 0755 root sys diff --git a/usr/src/pkgdefs/SUNWfcoe/prototype_sparc b/usr/src/pkgdefs/SUNWfcoe/prototype_sparc new file mode 100644 index 0000000000..6c8079b01a --- /dev/null +++ b/usr/src/pkgdefs/SUNWfcoe/prototype_sparc @@ -0,0 +1,52 @@ +# +# 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. +# +# +# This required package information file contains a list of package contents. +# The 'pkgmk' command uses this file to identify the contents of a package +# and their location on the development machine when building the package. +# Can be created via a text editor or through use of the 'pkgproto' command. + +#!search <pathname pathname ...> # where to find pkg objects +#!include <filename> # include another 'prototype' file +#!default <mode> <owner> <group> # default used if not specified on entry +#!<param>=<value> # puts parameter in pkg environment +# +# Include ISA independent files (prototype_com) +# +!include prototype_com +# +# +# List files which are SPARC specific here +# +# source locations relative to the prototype file +# +# +# SUNWfcoe +# +d none kernel 0755 root sys +d none kernel/drv 0755 root sys +f none kernel/drv/fcoe.conf 0644 root sys +d none kernel/drv/sparcv9 0755 root sys +f none kernel/drv/sparcv9/fcoe 0755 root sys diff --git a/usr/src/pkgdefs/SUNWfcoet/Makefile b/usr/src/pkgdefs/SUNWfcoet/Makefile new file mode 100644 index 0000000000..0c86629d67 --- /dev/null +++ b/usr/src/pkgdefs/SUNWfcoet/Makefile @@ -0,0 +1,33 @@ +# +# 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 ../Makefile.com + +.KEEP_STATE: + +all: $(FILES) depend preremove postinstall +install: all pkg + +include ../Makefile.targ diff --git a/usr/src/pkgdefs/SUNWfcoet/depend b/usr/src/pkgdefs/SUNWfcoet/depend new file mode 100644 index 0000000000..d7fda4ce50 --- /dev/null +++ b/usr/src/pkgdefs/SUNWfcoet/depend @@ -0,0 +1,52 @@ +# +# 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. +# +# +# This package information file defines software dependencies associated +# with the pkg. You can define three types of pkg dependencies with this file: +# P indicates a prerequisite for installation +# I indicates an incompatible package +# R indicates a reverse dependency +# <pkg.abbr> see pkginfo(4), PKG parameter +# <name> see pkginfo(4), NAME parameter +# <version> see pkginfo(4), VERSION parameter +# <arch> see pkginfo(4), ARCH parameter +# <type> <pkg.abbr> <name> +# (<arch>)<version> +# (<arch>)<version> +# ... +# <type> <pkg.abbr> <name> +# ... + +P SUNWcar Core Architecture, (Root) +P SUNWcakr Core Solaris Kernel Architecture (Root) +P SUNWkvm Core Architecture, (Kvm) +P SUNWcsr Core Solaris, (Root) +P SUNWckr Core Solaris Kernel (Root) +P SUNWcnetr Core Solaris Network Infrastructure (Root) +P SUNWcsu Core Solaris, (Usr) +P SUNWcsd Core Solaris Devices +P SUNWcsl Core Solaris Libraries +P SUNWfcoe SUN FCoE Transport Driver +P SUNWstmf Sun Common Multiprotocol SCSI Target diff --git a/usr/src/pkgdefs/SUNWfcoet/pkginfo.tmpl b/usr/src/pkgdefs/SUNWfcoet/pkginfo.tmpl new file mode 100644 index 0000000000..422a84b86c --- /dev/null +++ b/usr/src/pkgdefs/SUNWfcoet/pkginfo.tmpl @@ -0,0 +1,50 @@ +# +# 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. +# +# +# +# This required package information file describes characteristics of the +# package, such as package abbreviation, full package name, package version, +# and package architecture. +# + +PKG="SUNWfcoet" +NAME="Sun FCoE COMSTAR Driver" +ARCH="ISA" +CATEGORY="system" +BASEDIR=/ +SUNW_PKGVERS="1.0" +SUNW_PKGTYPE="root" +CLASSES="none" +DESC="Sun FCoE (Fibre Channel over Ethernet) COMSTAR Driver" +SUNW_PRODNAME="SunOS" +SUNW_PRODVERS="RELEASE/VERSION" +VERSION="ONVERS,REV=0.0.0" +VENDOR="Sun Microsystems, Inc." +HOTLINE="Please contact your local service provider" +EMAIL="" +MAXINST="1000" +SUNW_PKG_ALLZONES="true" +SUNW_PKG_HOLLOW="true" +SUNW_PKG_THISZONE="false" diff --git a/usr/src/pkgdefs/SUNWfcoet/postinstall b/usr/src/pkgdefs/SUNWfcoet/postinstall new file mode 100644 index 0000000000..ef6442a273 --- /dev/null +++ b/usr/src/pkgdefs/SUNWfcoet/postinstall @@ -0,0 +1,54 @@ +#!/bin/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 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# + +PATH=/usr/bin:/usr/sbin:$PATH; export PATH + +# Driver definitions +DRVR_NAME=fcoet +DRVR_PERM="-m '* 0600 root sys'" +DRVR_CLASS="" +DRVR_ALIASES="" + + +if [ -z "${BASEDIR}" ]; then + echo "\n$0 Failed: BASEDIR is not set.\n" >&2 + exit 1 +fi + +# Remove existing definition, if it exists. +/usr/sbin/rem_drv -b "${BASEDIR}" ${DRVR_NAME} > /dev/null 2>&1 + +ADD_DRV="add_drv -n -b ${BASEDIR}" + +eval ${ADD_DRV} "${DRVR_PERM}" ${DRVR_CLASS} "${DRVR_ALIASES}" ${DRVR_NAME} +if [ $? -ne 0 ]; then + echo "\nCommand Failed:\n${ADD_DRV} "${DRVR_PERM}" ${DRVR_CLASS} \ + "${DRVR_ALIASES}" ${DRVR_NAME}\n" >&2 + exit 1 +fi + +exit 0 diff --git a/usr/src/pkgdefs/SUNWfcoet/preremove b/usr/src/pkgdefs/SUNWfcoet/preremove new file mode 100644 index 0000000000..59e1ab1fff --- /dev/null +++ b/usr/src/pkgdefs/SUNWfcoet/preremove @@ -0,0 +1,33 @@ +#!/bin/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 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# + +DRVR_NAME=fcoet + +# Remove the driver entries but leave it attached. +/usr/sbin/rem_drv -b ${BASEDIR} ${DRVR_NAME} + +exit 0 diff --git a/usr/src/pkgdefs/SUNWfcoet/prototype_com b/usr/src/pkgdefs/SUNWfcoet/prototype_com new file mode 100644 index 0000000000..497cf4a41d --- /dev/null +++ b/usr/src/pkgdefs/SUNWfcoet/prototype_com @@ -0,0 +1,41 @@ +# +# 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. +# +# +# This required package information file contains a list of package contents. +# The 'pkgmk' command uses this file to identify the contents of a package +# and their location on the development machine when building the package. +# Can be created via a text editor or through use of the 'pkgproto' command. + +#!search <pathname pathname ...> # where to find pkg objects +#!include <filename> # include another 'prototype' file +#!default <mode> <owner> <group> # default used if not specified on entry +#!<param>=<value> # puts parameter in pkg environment + +# +# +i copyright +i pkginfo +i depend +i postinstall +i preremove diff --git a/usr/src/pkgdefs/SUNWfcoet/prototype_i386 b/usr/src/pkgdefs/SUNWfcoet/prototype_i386 new file mode 100644 index 0000000000..26213fc6ce --- /dev/null +++ b/usr/src/pkgdefs/SUNWfcoet/prototype_i386 @@ -0,0 +1,52 @@ +# +# 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. +# +# +# This required package information file contains a list of package contents. +# The 'pkgmk' command uses this file to identify the contents of a package +# and their location on the development machine when building the package. +# Can be created via a text editor or through use of the 'pkgproto' command. + +#!search <pathname pathname ...> # where to find pkg objects +#!include <filename> # include another 'prototype' file +#!default <mode> <owner> <group> # default used if not specified on entry +#!<param>=<value> # puts parameter in pkg environment +# +# Include ISA independent files (prototype_com) +# +!include prototype_com +# +# +# List files which are Intel specific here +# +# source locations relative to the prototype file +# +# +# SUNWfcoet +# +d none kernel 0755 root sys +d none kernel/drv 0755 root sys +d none kernel/drv/amd64 0755 root sys +f none kernel/drv/fcoet 0755 root sys +f none kernel/drv/amd64/fcoet 0755 root sys diff --git a/usr/src/pkgdefs/SUNWfcoet/prototype_sparc b/usr/src/pkgdefs/SUNWfcoet/prototype_sparc new file mode 100644 index 0000000000..dba42598c9 --- /dev/null +++ b/usr/src/pkgdefs/SUNWfcoet/prototype_sparc @@ -0,0 +1,51 @@ +# +# 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. +# +# +# This required package information file contains a list of package contents. +# The 'pkgmk' command uses this file to identify the contents of a package +# and their location on the development machine when building the package. +# Can be created via a text editor or through use of the 'pkgproto' command. + +#!search <pathname pathname ...> # where to find pkg objects +#!include <filename> # include another 'prototype' file +#!default <mode> <owner> <group> # default used if not specified on entry +#!<param>=<value> # puts parameter in pkg environment +# +# Include ISA independent files (prototype_com) +# +!include prototype_com +# +# +# List files which are SPARC specific here +# +# source locations relative to the prototype file +# +# +# SUNWfcoet +# +d none kernel 0755 root sys +d none kernel/drv 0755 root sys +d none kernel/drv/sparcv9 0755 root sys +f none kernel/drv/sparcv9/fcoet 0755 root sys diff --git a/usr/src/pkgdefs/SUNWfcoeu/Makefile b/usr/src/pkgdefs/SUNWfcoeu/Makefile new file mode 100644 index 0000000000..5f3bd3a917 --- /dev/null +++ b/usr/src/pkgdefs/SUNWfcoeu/Makefile @@ -0,0 +1,34 @@ +# +# 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 ../Makefile.com + +.KEEP_STATE: + +all: $(FILES) depend + +install: all pkg + +include ../Makefile.targ diff --git a/usr/src/pkgdefs/SUNWfcoeu/depend b/usr/src/pkgdefs/SUNWfcoeu/depend new file mode 100644 index 0000000000..f81330f9a8 --- /dev/null +++ b/usr/src/pkgdefs/SUNWfcoeu/depend @@ -0,0 +1,50 @@ +# +# 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. +# +# +# This package information file defines software dependencies associated +# with the pkg. You can define three types of pkg dependencies with this file: +# P indicates a prerequisite for installation +# I indicates an incompatible package +# R indicates a reverse dependency +# <pkg.abbr> see pkginfo(4), PKG parameter +# <name> see pkginfo(4), NAME parameter +# <version> see pkginfo(4), VERSION parameter +# <arch> see pkginfo(4), ARCH parameter +# <type> <pkg.abbr> <name> +# (<arch>)<version> +# (<arch>)<version> +# ... +# <type> <pkg.abbr> <name> +# ... + +P SUNWcar Core Architecture, (Root) +P SUNWcakr Core Solaris Kernel Architecture (Root) +P SUNWkvm Core Architecture, (Kvm) +P SUNWcsr Core Solaris, (Root) +P SUNWckr Core Solaris Kernel (Root) +P SUNWcnetr Core Solaris Network Infrastructure (Root) +P SUNWcsu Core Solaris, (Usr) +P SUNWcsd Core Solaris Devices +P SUNWcsl Core Solaris Libraries diff --git a/usr/src/pkgdefs/SUNWfcoeu/pkginfo.tmpl b/usr/src/pkgdefs/SUNWfcoeu/pkginfo.tmpl new file mode 100644 index 0000000000..ea21cdce9f --- /dev/null +++ b/usr/src/pkgdefs/SUNWfcoeu/pkginfo.tmpl @@ -0,0 +1,48 @@ +# +# 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. +# +# +# This required package information file describes characteristics of the +# package, such as package abbreviation, full package name, package version, +# and package architecture. +# +PKG="SUNWfcoeu" +NAME="Sun FCoE Port Management Library" +ARCH="ISA" +CATEGORY="system" +BASEDIR=/ +SUNW_PKGVERS="1.0" +SUNW_PKGTYPE="usr" +CLASSES="none" +DESC="Sun FCoE (Fibre Channel over Ethernet) Port Management Library" +SUNW_PRODNAME="SunOS" +SUNW_PRODVERS="RELEASE/VERSION" +VERSION="ONVERS,REV=0.0.0" +VENDOR="Sun Microsystems, Inc." +HOTLINE="Please contact your local service provider" +EMAIL="" +MAXINST="1000" +SUNW_PKG_ALLZONES="true" +SUNW_PKG_HOLLOW="false" +SUNW_PKG_THISZONE="false" diff --git a/usr/src/pkgdefs/SUNWfcoeu/prototype_com b/usr/src/pkgdefs/SUNWfcoeu/prototype_com new file mode 100644 index 0000000000..345a0cbb0b --- /dev/null +++ b/usr/src/pkgdefs/SUNWfcoeu/prototype_com @@ -0,0 +1,45 @@ +# +# 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. +# +# This required package information file contains a list of package contents. +# The 'pkgmk' command uses this file to identify the contents of a package +# and their location on the development machine when building the package. +# Can be created via a text editor or through use of the 'pkgproto' command. + +#!search <pathname pathname ...> # where to find pkg objects +#!include <filename> # include another 'prototype' file +#!default <mode> <owner> <group> # default used if not specified on entry +#!<param>=<value> # puts parameter in pkg environment + +i copyright +i pkginfo +i depend +d none usr 755 root sys +d none usr/lib 755 root bin +f none usr/lib/libfcoe.so.1 755 root bin +s none usr/lib/libfcoe.so=libfcoe.so.1 +f none usr/lib/llib-lfcoe 644 root bin +f none usr/lib/llib-lfcoe.ln 644 root bin +d none usr/include 755 root bin +f none usr/include/libfcoe.h 644 root bin diff --git a/usr/src/pkgdefs/SUNWfcoeu/prototype_i386 b/usr/src/pkgdefs/SUNWfcoeu/prototype_i386 new file mode 100644 index 0000000000..1ce5151e29 --- /dev/null +++ b/usr/src/pkgdefs/SUNWfcoeu/prototype_i386 @@ -0,0 +1,48 @@ +# +# 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. +# +# This required package information file contains a list of package contents. +# The 'pkgmk' command uses this file to identify the contents of a package +# and their location on the development machine when building the package. +# Can be created via a text editor or through use of the 'pkgproto' command. + +#!search <pathname pathname ...> # where to find pkg objects +#!include <filename> # include another 'prototype' file +#!default <mode> <owner> <group> # default used if not specified on entry +#!<param>=<value> # puts parameter in pkg environment + +# +# Include ISA independent files (prototype_com) +# +!include prototype_com +# +# +# List files which are Intel specific here +# +# source locations relative to the prototype file +# +d none usr/lib/amd64 0755 root bin +f none usr/lib/amd64/libfcoe.so.1 0755 root bin +s none usr/lib/amd64/libfcoe.so=libfcoe.so.1 +f none usr/lib/amd64/llib-lfcoe.ln 644 root bin diff --git a/usr/src/pkgdefs/SUNWfcoeu/prototype_sparc b/usr/src/pkgdefs/SUNWfcoeu/prototype_sparc new file mode 100644 index 0000000000..ee12ab97c1 --- /dev/null +++ b/usr/src/pkgdefs/SUNWfcoeu/prototype_sparc @@ -0,0 +1,47 @@ +# +# 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. +# +# This required package information file contains a list of package contents. +# The 'pkgmk' command uses this file to identify the contents of a package +# and their location on the development machine when building the package. +# Can be created via a text editor or through use of the 'pkgproto' command. + +#!search <pathname pathname ...> # where to find pkg objects +#!include <filename> # include another 'prototype' file +#!default <mode> <owner> <group> # default used if not specified on entry +#!<param>=<value> # puts parameter in pkg environment +# +# Include ISA independent files (prototype_com) +# +!include prototype_com +# +# +# List files which are SPARC specific here +# +# source locations relative to the prototype file +# +d none usr/lib/sparcv9 0755 root bin +f none usr/lib/sparcv9/libfcoe.so.1 0755 root bin +s none usr/lib/sparcv9/libfcoe.so=libfcoe.so.1 +f none usr/lib/sparcv9/llib-lfcoe.ln 644 root bin diff --git a/usr/src/pkgdefs/SUNWfcprt/depend b/usr/src/pkgdefs/SUNWfcprt/depend index 4b530fcac6..51027a794f 100644 --- a/usr/src/pkgdefs/SUNWfcprt/depend +++ b/usr/src/pkgdefs/SUNWfcprt/depend @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # @@ -50,4 +50,5 @@ P SUNWcsu Core Solaris, (Usr) P SUNWcsd Core Solaris Devices P SUNWcsl Core Solaris Libraries P SUNWcfcl Common Fibre Channel HBA API Library (Usr) +P SUNWfcoeu SUN FCoE Port Management Library diff --git a/usr/src/pkgdefs/SUNWfcprtr/preremove b/usr/src/pkgdefs/SUNWfcprtr/preremove index 140041498f..ab22a73816 100644 --- a/usr/src/pkgdefs/SUNWfcprtr/preremove +++ b/usr/src/pkgdefs/SUNWfcprtr/preremove @@ -20,7 +20,7 @@ # CDDL HEADER END # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # @@ -57,4 +57,25 @@ if [ "${SVCPROP}" = "true" ]; then fi svcadm refresh ${SERVICE} fi + +SERVICE="svc:/network/fcoe_config:default" + +# +# Confirm service is installed, otherwise exit. +# +/usr/bin/svcprop -q ${SERVICE} || exit 0 + +SVCPROP=`svcprop -p general/enabled ${SERVICE}` + +# +# Check to see if the service is running and if so disable it. +# +if [ "${SVCPROP}" = "true" ]; then + svcadm disable ${SERVICE} + if [ $? -ne 0 ]; then + echo "\n$0 Disabling of ${SERVICE} failed!\n" >&2 + exit 1 + fi + svcadm refresh ${SERVICE} +fi exit 0 diff --git a/usr/src/pkgdefs/SUNWfcprtr/prototype_com b/usr/src/pkgdefs/SUNWfcprtr/prototype_com index 5a82fd393f..580312340a 100644 --- a/usr/src/pkgdefs/SUNWfcprtr/prototype_com +++ b/usr/src/pkgdefs/SUNWfcprtr/prototype_com @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # @@ -45,7 +45,9 @@ d none var/svc 755 root sys d none var/svc/manifest 755 root sys d none var/svc/manifest/network 0755 root sys f manifest var/svc/manifest/network/npiv_config.xml 0444 root sys +f manifest var/svc/manifest/network/fcoe_config.xml 0444 root sys d none lib 755 root bin d none lib/svc 755 root bin d none lib/svc/method 755 root bin f none lib/svc/method/npivconfig 0555 root bin +f none lib/svc/method/fcoeconfig 0555 root bin diff --git a/usr/src/tools/scripts/bfu.sh b/usr/src/tools/scripts/bfu.sh index debf200d36..4becf60fae 100644 --- a/usr/src/tools/scripts/bfu.sh +++ b/usr/src/tools/scripts/bfu.sh @@ -305,6 +305,7 @@ superfluous_nonglobal_zone_files=" lib/svc/method/fc-fabric lib/svc/method/iscsid lib/svc/method/npivconfig + lib/svc/method/fcoeconfig lib/svc/method/sf880dr lib/svc/method/svc-cvcd lib/svc/method/svc-dcs @@ -362,6 +363,7 @@ superfluous_nonglobal_zone_files=" var/log/pool var/svc/manifest/network/iscsi_initiator.xml var/svc/manifest/network/npiv_config.xml + var/svc/manifest/network/fcoe_config.xml var/svc/manifest/network/rpc/mdcomm.xml var/svc/manifest/network/rpc/meta.xml var/svc/manifest/network/rpc/metamed.xml diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files index f97b615a4d..e6a73bd8aa 100644 --- a/usr/src/uts/common/Makefile.files +++ b/usr/src/uts/common/Makefile.files @@ -840,6 +840,10 @@ FCT_OBJS += discovery.o fct.o QLT_OBJS += 2400.o 2500.o qlt.o qlt_dma.o +FCOE_OBJS += fcoe.o fcoe_eth.o fcoe_fc.o + +FCOET_OBJS += fcoet.o fcoet_eth.o fcoet_fc.o + ISCSIT_SHARED_OBJS += \ iscsit_common.o diff --git a/usr/src/uts/common/Makefile.rules b/usr/src/uts/common/Makefile.rules index 1832617643..46f2e67e5d 100644 --- a/usr/src/uts/common/Makefile.rules +++ b/usr/src/uts/common/Makefile.rules @@ -576,6 +576,11 @@ $(OBJS_DIR)/%.o: $(UTSBASE)/common/io/comstar/port/qlt/%.c $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) +$(OBJS_DIR)/%.o: $(UTSBASE)/common/io/comstar/port/fcoet/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + + $(OBJS_DIR)/%.o: $(COMMONBASE)/iscsit/%.c $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) @@ -604,6 +609,10 @@ $(OBJS_DIR)/%.o: $(UTSBASE)/common/io/drm/%.c $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) +$(OBJS_DIR)/%.o: $(UTSBASE)/common/io/fcoe/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + $(OBJS_DIR)/%.o: $(UTSBASE)/common/io/hotplug/hpcsvc/%.c $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) @@ -1671,6 +1680,9 @@ $(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/comstar/port/qlt/%.c $(LINTS_DIR)/%.ln: $(COMMONBASE)/iscsit/%.c @($(LHEAD) $(LINT.c) $< $(LTAIL)) +$(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/comstar/port/fcoet/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + $(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/comstar/port/iscsit/%.c @($(LHEAD) $(LINT.c) $< $(LTAIL)) @@ -1689,6 +1701,9 @@ $(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/dmfe/%.c $(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/drm/%.c @($(LHEAD) $(LINT.c) $< $(LTAIL)) +$(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/fcoe/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + $(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/hotplug/hpcsvc/%.c @($(LHEAD) $(LINT.c) $< $(LTAIL)) diff --git a/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_scsi.c b/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_scsi.c index 022fa217f7..462fdc8c52 100644 --- a/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_scsi.c +++ b/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_scsi.c @@ -83,7 +83,7 @@ sbd_do_read_xfer(struct scsi_task *task, sbd_cmd_t *scmd, if (iolen == 0) break; if (sst->sst_data_read(sst, laddr, (uint64_t)iolen, - dbuf->db_sglist[0].seg_addr) != STMF_SUCCESS) { + dbuf->db_sglist[ndx].seg_addr) != STMF_SUCCESS) { scmd->flags |= SBD_SCSI_CMD_XFER_FAIL; /* Do not need to do xfer anymore, just complete it */ dbuf->db_data_size = 0; @@ -146,6 +146,27 @@ sbd_handle_read_xfer_completion(struct scsi_task *task, sbd_cmd_t *scmd, stmf_scsilib_send_status(task, STATUS_GOOD, 0); return; } + if (dbuf->db_flags & DB_DONT_REUSE) { + /* allocate new dbuf */ + uint32_t maxsize, minsize, old_minsize; + stmf_free_dbuf(task, dbuf); + + maxsize = (scmd->len > (128*1024)) ? 128*1024 : scmd->len; + minsize = maxsize >> 2; + do { + old_minsize = minsize; + dbuf = stmf_alloc_dbuf(task, maxsize, &minsize, 0); + } while ((dbuf == NULL) && (old_minsize > minsize) && + (minsize >= 512)); + if (dbuf == NULL) { + scmd->nbufs --; + if (scmd->nbufs == 0) { + stmf_abort(STMF_QUEUE_TASK_ABORT, task, + STMF_ALLOC_FAILURE, NULL); + } + return; + } + } sbd_do_read_xfer(task, scmd, dbuf); } @@ -329,7 +350,7 @@ sbd_handle_write_xfer_completion(struct scsi_task *task, sbd_cmd_t *scmd, if (iolen == 0) break; if (sst->sst_data_write(sst, laddr, (uint64_t)iolen, - dbuf->db_sglist[0].seg_addr) != STMF_SUCCESS) { + dbuf->db_sglist[ndx].seg_addr) != STMF_SUCCESS) { scmd->flags |= SBD_SCSI_CMD_XFER_FAIL; break; } @@ -351,7 +372,7 @@ WRITE_XFER_DONE: stmf_scsilib_send_status(task, STATUS_GOOD, 0); return; } - if (dbuf_reusable == 0) { + if (dbuf->db_flags & DB_DONT_REUSE || dbuf_reusable == 0) { uint32_t maxsize, minsize, old_minsize; /* free current dbuf and allocate a new one */ stmf_free_dbuf(task, dbuf); @@ -746,9 +767,9 @@ void sbd_handle_inquiry(struct scsi_task *task, struct stmf_data_buf *initial_dbuf, uint8_t *p, int bsize) { - uint8_t *cdbp = (uint8_t *)&task->task_cdb[0]; - uint32_t cmd_size; - uint8_t page_length; + uint8_t *cdbp = (uint8_t *)&task->task_cdb[0]; + uint32_t cmd_size; + uint8_t page_length; /* * Basic protocol checks. diff --git a/usr/src/uts/common/io/comstar/port/fcoet/fcoet.c b/usr/src/uts/common/io/comstar/port/fcoet/fcoet.c new file mode 100644 index 0000000000..2a22709bb6 --- /dev/null +++ b/usr/src/uts/common/io/comstar/port/fcoet/fcoet.c @@ -0,0 +1,1035 @@ +/* + * 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. + */ + +/* + * The following notice accompanied the original version of this file: + * + * BSD LICENSE + * + * Copyright(c) 2007 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Driver kernel header files + */ +#include <sys/conf.h> +#include <sys/ddi.h> +#include <sys/stat.h> +#include <sys/pci.h> +#include <sys/sunddi.h> +#include <sys/modctl.h> +#include <sys/file.h> +#include <sys/cred.h> +#include <sys/byteorder.h> +#include <sys/atomic.h> +#include <sys/modhash.h> +#include <sys/scsi/scsi.h> +#include <sys/ethernet.h> + +/* + * COMSTAR header files + */ +#include <sys/stmf_defines.h> +#include <sys/fct_defines.h> +#include <sys/stmf.h> +#include <sys/portif.h> +#include <sys/fct.h> + +/* + * FCoE header files + */ +#include <sys/fcoe/fcoe_common.h> + +/* + * Driver's own header files + */ +#include <fcoet.h> +#include <fcoet_eth.h> +#include <fcoet_fc.h> + +/* + * static function forward declaration + */ +static int fcoet_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); +static int fcoet_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); +static int fcoet_open(dev_t *devp, int flag, int otype, cred_t *credp); +static int fcoet_close(dev_t dev, int flag, int otype, cred_t *credp); +static int fcoet_ioctl(dev_t dev, int cmd, intptr_t data, int mode, + cred_t *credp, int *rval); +static fct_status_t fcoet_attach_init(fcoet_soft_state_t *ss); +static fct_status_t fcoet_detach_uninit(fcoet_soft_state_t *ss); +static void fcoet_watchdog(void *arg); +static void fcoet_handle_sol_flogi(fcoet_soft_state_t *ss); +static stmf_data_buf_t *fcoet_dbuf_alloc(fct_local_port_t *port, + uint32_t size, uint32_t *pminsize, uint32_t flags); +static void fcoet_dbuf_free(fct_dbuf_store_t *fds, stmf_data_buf_t *dbuf); +static int fcoet_dbuf_init(fcoet_soft_state_t *ss); +static void fcoet_dbuf_destroy(fcoet_soft_state_t *ss); +static uint_t +fcoet_sol_oxid_hash_empty(mod_hash_key_t key, mod_hash_val_t *val, void *arg); +static uint_t +fcoet_unsol_rxid_hash_empty(mod_hash_key_t key, mod_hash_val_t *val, void *arg); + +/* + * Driver identificaton stuff + */ +static struct cb_ops fcoet_cb_ops = { + fcoet_open, + fcoet_close, + nodev, + nodev, + nodev, + nodev, + nodev, + fcoet_ioctl, + nodev, + nodev, + nodev, + nochpoll, + ddi_prop_op, + 0, + D_MP | D_NEW +}; + +static struct dev_ops fcoet_ops = { + DEVO_REV, + 0, + nodev, + nulldev, + nulldev, + fcoet_attach, + fcoet_detach, + nodev, + &fcoet_cb_ops, + NULL, + ddi_power +}; + +static struct modldrv modldrv = { + &mod_driverops, + FCOET_MOD_NAME, + &fcoet_ops, +}; + +static struct modlinkage modlinkage = { + MODREV_1, &modldrv, NULL +}; + +/* + * Driver's global variables + */ +static kmutex_t fcoet_mutex; +static void *fcoet_state = NULL; + +int fcoet_use_ext_log = 1; +static char fcoet_provider_name[] = "fcoet"; +static struct stmf_port_provider *fcoet_pp = NULL; + +/* + * Common loadable module entry points _init, _fini, _info + */ + +int +_init(void) +{ + int ret; + + ret = ddi_soft_state_init(&fcoet_state, sizeof (fcoet_soft_state_t), 0); + if (ret == 0) { + fcoet_pp = (stmf_port_provider_t *) + stmf_alloc(STMF_STRUCT_PORT_PROVIDER, 0, 0); + fcoet_pp->pp_portif_rev = PORTIF_REV_1; + fcoet_pp->pp_name = fcoet_provider_name; + if (stmf_register_port_provider(fcoet_pp) != STMF_SUCCESS) { + stmf_free(fcoet_pp); + ddi_soft_state_fini(&fcoet_state); + return (EIO); + } + + mutex_init(&fcoet_mutex, 0, MUTEX_DRIVER, 0); + ret = mod_install(&modlinkage); + if (ret) { + stmf_deregister_port_provider(fcoet_pp); + stmf_free(fcoet_pp); + mutex_destroy(&fcoet_mutex); + ddi_soft_state_fini(&fcoet_state); + } + } + + FCOET_LOG("_init", "exit _init with %x", ret); + return (ret); +} + +int +_fini(void) +{ + int ret; + + ret = mod_remove(&modlinkage); + if (ret == 0) { + stmf_deregister_port_provider(fcoet_pp); + stmf_free(fcoet_pp); + mutex_destroy(&fcoet_mutex); + ddi_soft_state_fini(&fcoet_state); + } + + FCOET_LOG("_fini", "exit _fini with %x", ret); + return (ret); +} + +int +_info(struct modinfo *modinfop) +{ + return (mod_info(&modlinkage, modinfop)); +} + +/* + * Autoconfiguration entry points: attach, detach, getinfo + */ + +static int +fcoet_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) +{ + int ret = DDI_FAILURE; + int instance; + fcoet_soft_state_t *ss; + + instance = ddi_get_instance(dip); + FCOET_LOG("fcoet_attach", "get instance %d", instance); + + switch (cmd) { + case DDI_ATTACH: + ret = ddi_soft_state_zalloc(fcoet_state, instance); + if (ret != DDI_SUCCESS) { + return (ret); + } + + ss = ddi_get_soft_state(fcoet_state, instance); + ss->ss_instance = instance; + ss->ss_dip = dip; + + ret = fcoet_attach_init(ss); + if (ret != FCOE_SUCCESS) { + ddi_soft_state_free(fcoet_state, instance); + ret = DDI_FAILURE; + } + + FCOET_LOG("fcoet_attach", "end with-%x", ret); + break; + + case DDI_RESUME: + ret = DDI_SUCCESS; + break; + + default: + FCOET_LOG("fcoet_attach", "unspported attach cmd-%x", cmd); + break; + } + + return (ret); +} + +static int +fcoet_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) +{ + int ret = DDI_FAILURE; + int fcoe_ret; + int instance; + fcoet_soft_state_t *ss; + + instance = ddi_get_instance(dip); + ss = ddi_get_soft_state(fcoet_state, instance); + if (ss == NULL) { + return (ret); + } + + switch (cmd) { + case DDI_DETACH: + fcoe_ret = fcoet_detach_uninit(ss); + if (fcoe_ret == FCOE_SUCCESS) { + ret = DDI_SUCCESS; + } + + FCOET_LOG("fcoet_detach", "fcoet_detach_uninit end with-%x", + fcoe_ret); + break; + + case DDI_SUSPEND: + ret = DDI_SUCCESS; + break; + + default: + FCOET_LOG("fcoet_detach", "unsupported detach cmd-%x", cmd); + break; + } + + return (ret); +} + +/* + * Device access entry points + */ +static int +fcoet_open(dev_t *devp, int flag, int otype, cred_t *credp) +{ + int instance; + fcoet_soft_state_t *ss; + + if (otype != OTYP_CHR) { + return (EINVAL); + } + + /* + * Since this is for debugging only, only allow root to issue ioctl now + */ + if (drv_priv(credp)) { + return (EPERM); + } + + instance = (int)getminor(*devp); + ss = ddi_get_soft_state(fcoet_state, instance); + if (ss == NULL) { + return (ENXIO); + } + + mutex_enter(&ss->ss_ioctl_mutex); + if (ss->ss_ioctl_flags & FCOET_IOCTL_FLAG_EXCL) { + /* + * It is already open for exclusive access. + * So shut the door on this caller. + */ + mutex_exit(&ss->ss_ioctl_mutex); + return (EBUSY); + } + + if (flag & FEXCL) { + if (ss->ss_ioctl_flags & FCOET_IOCTL_FLAG_OPEN) { + /* + * Exclusive operation not possible + * as it is already opened + */ + mutex_exit(&ss->ss_ioctl_mutex); + return (EBUSY); + } + ss->ss_ioctl_flags |= FCOET_IOCTL_FLAG_EXCL; + } + ss->ss_ioctl_flags |= FCOET_IOCTL_FLAG_OPEN; + mutex_exit(&ss->ss_ioctl_mutex); + + return (0); +} + +/* ARGSUSED */ +static int +fcoet_close(dev_t dev, int flag, int otype, cred_t *credp) +{ + int instance; + fcoet_soft_state_t *ss; + + if (otype != OTYP_CHR) { + return (EINVAL); + } + + instance = (int)getminor(dev); + ss = ddi_get_soft_state(fcoet_state, instance); + if (ss == NULL) { + return (ENXIO); + } + + mutex_enter(&ss->ss_ioctl_mutex); + if ((ss->ss_ioctl_flags & FCOET_IOCTL_FLAG_OPEN) == 0) { + mutex_exit(&ss->ss_ioctl_mutex); + return (ENODEV); + } + + /* + * It looks there's one hole here, maybe there could several concurrent + * shareed open session, but we never check this case. + * But it will not hurt too much, disregard it now. + */ + ss->ss_ioctl_flags &= ~FCOET_IOCTL_FLAG_MASK; + mutex_exit(&ss->ss_ioctl_mutex); + + return (0); +} + +/* ARGSUSED */ +static int +fcoet_ioctl(dev_t dev, int cmd, intptr_t data, int mode, + cred_t *credp, int *rval) +{ + fcoet_soft_state_t *ss; + int ret = 0; + + if (drv_priv(credp) != 0) { + return (EPERM); + } + + ss = ddi_get_soft_state(fcoet_state, (int32_t)getminor(dev)); + if (ss == NULL) { + return (ENXIO); + } + + switch (cmd) { + default: + FCOET_LOG("fcoet_ioctl", "ioctl-0x%02X", cmd); + ret = ENOTTY; + break; + } + + *rval = ret; + return (ret); +} + +static fct_status_t +fcoet_attach_init(fcoet_soft_state_t *ss) +{ + fcoe_client_t client_fcoet; + fcoe_port_t *eport; + fct_local_port_t *port; + fct_dbuf_store_t *fds; + char *mac_name; + char taskq_name[32]; + int ret; + + /* + * FCoE (fcoe is fcoet's dependent driver) + * First we need register fcoet to FCoE as one client + */ + client_fcoet.ect_eport_flags = EPORT_FLAG_TGT_MODE | + EPORT_FLAG_IS_DIRECT_P2P; + client_fcoet.ect_max_fc_frame_size = 2136; + client_fcoet.ect_private_frame_struct_size = sizeof (fcoet_frame_t); + client_fcoet.ect_rx_frame = fcoet_rx_frame; + client_fcoet.ect_port_event = fcoet_port_event; + client_fcoet.ect_release_sol_frame = fcoet_release_sol_frame; + client_fcoet.ect_client_port_struct = ss; + ret = ddi_prop_lookup_string(DDI_DEV_T_ANY, ss->ss_dip, + DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "mac_name", &mac_name); + if (ret != DDI_PROP_SUCCESS) { + FCOET_LOG("fcoet_attach_init", "lookup_string failed"); + return (DDI_FAILURE); + } else { + bcopy(mac_name, client_fcoet.ect_channel_name, + strlen(mac_name)); + client_fcoet.ect_channel_name[strlen(mac_name)] = 0; + ddi_prop_free(mac_name); + } + FCOET_LOG("fcoet_attach_init", "channel_name is %s", + client_fcoet.ect_channel_name); + + /* + * It's FCoE's responsiblity to initialize eport's all elements + */ + eport = fcoe_register_client(&client_fcoet); + if (eport == NULL) { + goto fail_register_client; + } + + /* + * Now it's time to register local port to FCT + */ + if (fcoet_dbuf_init(ss) != FCOE_SUCCESS) { + goto fail_init_dbuf; + } + + fds = (fct_dbuf_store_t *)fct_alloc(FCT_STRUCT_DBUF_STORE, 0, 0); + if (fds == NULL) { + goto fail_alloc_dbuf; + } else { + fds->fds_alloc_data_buf = fcoet_dbuf_alloc; + fds->fds_free_data_buf = fcoet_dbuf_free; + fds->fds_fca_private = (void *)ss; + } + + port = (fct_local_port_t *)fct_alloc(FCT_STRUCT_LOCAL_PORT, 0, 0); + if (port == NULL) { + goto fail_alloc_port; + } else { + /* + * Do ss's initialization now + */ + (void) snprintf(ss->ss_alias, sizeof (ss->ss_alias), "fcoet%d", + ss->ss_instance); + ret = ddi_create_minor_node(ss->ss_dip, "admin", + S_IFCHR, ss->ss_instance, DDI_NT_STMF_PP, 0); + if (ret != DDI_SUCCESS) { + goto fail_minor_node; + } + + ss->ss_state = FCT_STATE_OFFLINE; + ss->ss_state_not_acked = 1; + ss->ss_flags = 0; + ss->ss_port = port; + ss->ss_eport = eport; + FCOE_SET_DEFAULT_FPORT_ADDR(eport->eport_efh_dst); + + ss->ss_rportid_in_dereg = 0; + ss->ss_rport_dereg_state = 0; + + ss->ss_next_sol_oxid = 0xFFFF; + ss->ss_next_unsol_rxid = 0xFFFF; + ss->ss_sol_oxid_hash = mod_hash_create_idhash( + "ss_sol_oxid_hash", FCOET_SOL_HASH_SIZE, + mod_hash_null_valdtor); + ss->ss_unsol_rxid_hash = mod_hash_create_idhash( + "ss_unsol_rxid_hash", FCOET_SOL_HASH_SIZE, + mod_hash_null_valdtor); + + ss->ss_watch_count = 0; + mutex_init(&ss->ss_watch_mutex, 0, MUTEX_DRIVER, 0); + cv_init(&ss->ss_watch_cv, NULL, CV_DRIVER, NULL); + + list_create(&ss->ss_abort_xchg_list, sizeof (fcoet_exchange_t), + offsetof(fcoet_exchange_t, xch_abort_node)); + + ss->ss_sol_flogi = NULL; + ss->ss_sol_flogi_state = SFS_WAIT_LINKUP; + + bzero(&ss->ss_link_info, sizeof (fct_link_info_t)); + + ss->ss_ioctl_flags = 0; + mutex_init(&ss->ss_ioctl_mutex, 0, MUTEX_DRIVER, 0); + + ss->ss_change_state_flags = 0; + } + + /* + * Do port's initialization + * + * port_fct_private and port_lport have been initialized by fct_alloc + */ + port->port_fca_private = ss; + bcopy(ss->ss_eport->eport_nodewwn, port->port_nwwn, 8); + bcopy(ss->ss_eport->eport_portwwn, port->port_pwwn, 8); + port->port_default_alias = ss->ss_alias; + port->port_sym_node_name = NULL; + port->port_sym_port_name = NULL; + + port->port_pp = fcoet_pp; + + port->port_hard_address = 0; + port->port_max_logins = FCOET_MAX_LOGINS; + port->port_max_xchges = FCOET_MAX_XCHGES; + port->port_fca_fcp_cmd_size = sizeof (fcoet_exchange_t); + port->port_fca_rp_private_size = 0; + port->port_fca_sol_els_private_size = sizeof (fcoet_exchange_t); + port->port_fca_sol_ct_private_size = sizeof (fcoet_exchange_t); + + port->port_fca_abort_timeout = 5 * 1000; /* 5 seconds */ + port->port_fds = fds; + + port->port_get_link_info = fcoet_get_link_info; + port->port_register_remote_port = fcoet_register_remote_port; + port->port_deregister_remote_port = fcoet_deregister_remote_port; + port->port_send_cmd = fcoet_send_cmd; + port->port_xfer_scsi_data = fcoet_xfer_scsi_data; + port->port_send_cmd_response = fcoet_send_cmd_response; + port->port_abort_cmd = fcoet_abort_cmd; + port->port_ctl = fcoet_ctl; + port->port_flogi_xchg = fcoet_do_flogi; + port->port_populate_hba_details = fcoet_populate_hba_fru_details; + if (fct_register_local_port(port) != FCT_SUCCESS) { + goto fail_register_port; + } + + /* + * Start watchdog thread + */ + (void) snprintf(taskq_name, 32, "stmf_fct_fcoet_%d_taskq", + ss->ss_instance); + taskq_name[31] = 0; + if ((ss->ss_watchdog_taskq = ddi_taskq_create(NULL, + taskq_name, 2, TASKQ_DEFAULTPRI, 0)) == NULL) { + goto fail_create_taskq; + } + + atomic_and_32(&ss->ss_flags, ~SS_FLAG_TERMINATE_WATCHDOG); + (void) ddi_taskq_dispatch(ss->ss_watchdog_taskq, + fcoet_watchdog, ss, DDI_SLEEP); + while ((ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) == 0) { + delay(10); + } + + ddi_report_dev(ss->ss_dip); + return (DDI_SUCCESS); + +fail_create_taskq: + if (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) { + atomic_or_32(&ss->ss_flags, SS_FLAG_TERMINATE_WATCHDOG); + cv_broadcast(&ss->ss_watch_cv); + while (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) { + delay(10); + } + } + + ddi_taskq_destroy(ss->ss_watchdog_taskq); + FCOET_LOG("fcoet_attach_init", "fail_register_port"); + +fail_register_port: + mutex_destroy(&ss->ss_ioctl_mutex); + mutex_destroy(&ss->ss_watch_mutex); + cv_destroy(&ss->ss_watch_cv); + mod_hash_destroy_hash(ss->ss_sol_oxid_hash); + mod_hash_destroy_hash(ss->ss_unsol_rxid_hash); + list_destroy(&ss->ss_abort_xchg_list); + FCOET_LOG("fcoet_attach_init", "fail_create_taskq"); + +fail_minor_node: + fct_free(port); + FCOET_LOG("fcoet_attach_init", "fail_minor_node"); + +fail_alloc_port: + fct_free(fds); + FCOET_LOG("fcoet_attach_init", "fail_alloc_port"); + +fail_alloc_dbuf: + fcoet_dbuf_destroy(ss); + FCOET_LOG("fcoet_attach_init", "fail_alloc_dbuf"); + +fail_init_dbuf: + ss->ss_eport->eport_deregister_client(ss->ss_eport); + FCOET_LOG("fcoet_attach_init", "fail_init_dbuf"); + +fail_register_client: + FCOET_LOG("fcoet_attach_init", "fail_register_client"); + return (DDI_FAILURE); +} + +static fct_status_t +fcoet_detach_uninit(fcoet_soft_state_t *ss) +{ + if ((ss->ss_state != FCT_STATE_OFFLINE) || + ss->ss_state_not_acked) { + return (FCOE_FAILURE); + } + + /* + * Avoid modunload before running fcinfo remove-target-port + */ + if (ss->ss_eport != NULL && + ss->ss_eport->eport_flags & EPORT_FLAG_MAC_IN_USE) { + return (FCOE_FAILURE); + } + + if (ss->ss_port == NULL) { + return (FCOE_SUCCESS); + } + + ss->ss_sol_oxid_hash_empty = 1; + ss->ss_unsol_rxid_hash_empty = 1; + mod_hash_walk(ss->ss_sol_oxid_hash, fcoet_sol_oxid_hash_empty, ss); + mod_hash_walk(ss->ss_unsol_rxid_hash, fcoet_unsol_rxid_hash_empty, ss); + if ((!ss->ss_sol_oxid_hash_empty) || (!ss->ss_unsol_rxid_hash_empty)) { + return (FCOE_FAILURE); + } + + /* + * We need offline the port manually, before we want to detach it + * or it will not succeed. + */ + if (fct_deregister_local_port(ss->ss_port) != FCT_SUCCESS) { + FCOET_LOG("fcoet_detach_uninit", + "fct_deregister_local_port failed"); + return (FCOE_FAILURE); + } + + /* + * Stop watchdog + */ + if (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) { + atomic_or_32(&ss->ss_flags, SS_FLAG_TERMINATE_WATCHDOG); + cv_broadcast(&ss->ss_watch_cv); + while (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) { + delay(10); + } + } + + ddi_taskq_destroy(ss->ss_watchdog_taskq); + + /* + * Release all resources + */ + mutex_destroy(&ss->ss_ioctl_mutex); + mutex_destroy(&ss->ss_watch_mutex); + cv_destroy(&ss->ss_watch_cv); + mod_hash_destroy_hash(ss->ss_sol_oxid_hash); + mod_hash_destroy_hash(ss->ss_unsol_rxid_hash); + list_destroy(&ss->ss_abort_xchg_list); + + fct_free(ss->ss_port->port_fds); + fct_free(ss->ss_port); + ss->ss_port = NULL; + + fcoet_dbuf_destroy(ss); + + if (ss->ss_eport != NULL && + ss->ss_eport->eport_deregister_client != NULL) { + ss->ss_eport->eport_deregister_client(ss->ss_eport); + } + ddi_soft_state_free(fcoet_state, ss->ss_instance); + return (FCOE_SUCCESS); +} + +static void +fcoet_watchdog(void *arg) +{ + fcoet_soft_state_t *ss = (fcoet_soft_state_t *)arg; + clock_t tmp_delay = 0; + fcoet_exchange_t *xchg, *xchg_next; + + FCOET_LOG("fcoet_watchdog", "fcoet_soft_state is %p", ss); + + mutex_enter(&ss->ss_watch_mutex); + atomic_or_32(&ss->ss_flags, SS_FLAG_WATCHDOG_RUNNING); + tmp_delay = STMF_SEC2TICK(1)/2; + + while ((ss->ss_flags & SS_FLAG_TERMINATE_WATCHDOG) == 0) { + ss->ss_watch_count++; + + if (ss->ss_sol_flogi_state != SFS_FLOGI_DONE) { + fcoet_handle_sol_flogi(ss); + } + for (xchg = list_head(&ss->ss_abort_xchg_list); xchg; ) { + xchg_next = list_next(&ss->ss_abort_xchg_list, xchg); + if (xchg->xch_ref == 0) { + list_remove(&ss->ss_abort_xchg_list, xchg); + mutex_exit(&ss->ss_watch_mutex); + /* xchg abort done */ + if (xchg->xch_dbuf_num) { + kmem_free((void*)xchg->xch_dbufs, + xchg->xch_dbuf_num * + sizeof (void *)); + xchg->xch_dbufs = NULL; + xchg->xch_dbuf_num = 0; + } + fct_cmd_fca_aborted(xchg->xch_cmd, + FCT_ABORT_SUCCESS, FCT_IOF_FCA_DONE); + mutex_enter(&ss->ss_watch_mutex); + } + xchg = xchg_next; + } + + atomic_or_32(&ss->ss_flags, SS_FLAG_DOG_WAITING); + (void) cv_timedwait(&ss->ss_watch_cv, + &ss->ss_watch_mutex, ddi_get_lbolt() + + (clock_t)tmp_delay); + atomic_and_32(&ss->ss_flags, ~SS_FLAG_DOG_WAITING); + } + + /* + * Ensure no ongoing FLOGI, before terminate the watchdog + */ + if (ss->ss_sol_flogi) { + fcoet_clear_sol_exchange(ss->ss_sol_flogi); + fct_free(ss->ss_sol_flogi->xch_cmd); + ss->ss_sol_flogi = NULL; + } + + atomic_and_32(&ss->ss_flags, ~SS_FLAG_WATCHDOG_RUNNING); + mutex_exit(&ss->ss_watch_mutex); +} + +static void +fcoet_handle_sol_flogi(fcoet_soft_state_t *ss) +{ + clock_t twosec = STMF_SEC2TICK(2); + +check_state_again: + if (ss->ss_flags & SS_FLAG_PORT_DISABLED) { + ss->ss_sol_flogi_state = SFS_WAIT_LINKUP; + } + + switch (ss->ss_sol_flogi_state) { + case SFS_WAIT_LINKUP: + if (ss->ss_sol_flogi) { + if (ss->ss_sol_flogi->xch_ref == 0) { + fcoet_clear_sol_exchange(ss->ss_sol_flogi); + fct_free(ss->ss_sol_flogi->xch_cmd); + ss->ss_sol_flogi = NULL; + } + } + break; + + case SFS_FLOGI_INIT: + if (ss->ss_sol_flogi) { + /* + * wait for the response to finish + */ + ss->ss_sol_flogi_state = SFS_CLEAR_FLOGI; + break; + } + fcoet_send_sol_flogi(ss); + ss->ss_sol_flogi_state++; + break; + + case SFS_FLOGI_CHECK_TIMEOUT: + if ((ss->ss_sol_flogi->xch_start_time + twosec) < + ddi_get_lbolt()) { + ss->ss_sol_flogi_state++; + } + break; + + case SFS_ABTS_INIT: + fcoet_send_sol_abts(ss->ss_sol_flogi); + ss->ss_sol_flogi_state++; + break; + + case SFS_CLEAR_FLOGI: + if (ss->ss_sol_flogi) { + if (ss->ss_sol_flogi->xch_ref) { + break; + } + fcoet_clear_sol_exchange(ss->ss_sol_flogi); + fct_free(ss->ss_sol_flogi->xch_cmd); + ss->ss_sol_flogi = NULL; + } + ss->ss_sol_flogi_state = SFS_FLOGI_INIT; + goto check_state_again; + + case SFS_FLOGI_ACC: + ss->ss_sol_flogi_state++; + goto check_state_again; + + case SFS_FLOGI_DONE: + if (!(ss->ss_flags & SS_FLAG_PORT_DISABLED) && + ss->ss_sol_flogi) { + fcoet_clear_sol_exchange(ss->ss_sol_flogi); + fct_free(ss->ss_sol_flogi->xch_cmd); + ss->ss_sol_flogi = NULL; + } + + /* + * We'd better to offline it first, and delay 0.1 seconds, + * before we say it's on again. + */ + fct_handle_event(ss->ss_port, + FCT_EVENT_LINK_DOWN, 0, NULL); + delay(STMF_SEC2TICK(1)/10); + fct_handle_event(ss->ss_port, + FCT_EVENT_LINK_UP, 0, NULL); + break; + + default: + ASSERT(0); + break; + } +} + +/* ARGSUSED */ +static int +fcoet_dbuf_init(fcoet_soft_state_t *ss) +{ + return (FCOE_SUCCESS); +} + +/* ARGSUSED */ +static void +fcoet_dbuf_destroy(fcoet_soft_state_t *ss) +{ + +} + +/* ARGSUSED */ +static stmf_data_buf_t * +fcoet_dbuf_alloc(fct_local_port_t *port, uint32_t size, uint32_t *pminsize, + uint32_t flags) +{ + stmf_data_buf_t *dbuf; + int add_size; + int sge_num; + int sge_size; + int idx; + int ii; + void *netb; + uint8_t *fc_buf; + fcoet_soft_state_t *ss = + (fcoet_soft_state_t *)port->port_fca_private; + + if (size > FCOET_MAX_DBUF_LEN) { + if (*pminsize > FCOET_MAX_DBUF_LEN) { + return (NULL); + } + + size = FCOET_MAX_DBUF_LEN; + } + + sge_num = (size - 1) / ss->ss_fcp_data_payload_size + 1; + add_size = (sge_num - 1) * sizeof (struct stmf_sglist_ent) + + sge_num * sizeof (mblk_t *); + dbuf = stmf_alloc(STMF_STRUCT_DATA_BUF, add_size, 0); + if (dbuf == NULL) { + return (NULL); + } + dbuf->db_buf_size = size; + dbuf->db_data_size = size; + dbuf->db_sglist_length = 0; + dbuf->db_flags |= DB_DONT_REUSE; + FCOET_SET_SEG_NUM(dbuf, sge_num); + + /* + * Initialize non-last sg entries + */ + for (idx = 0; idx < sge_num - 1; idx++) { + sge_size = ss->ss_fcp_data_payload_size; + netb = ss->ss_eport->eport_alloc_netb( + ss->ss_eport, sizeof (fcoe_fc_frame_header_t) + + sge_size, &fc_buf); + if (netb == NULL) { + for (ii = 0; ii < idx; ii++) { + ss->ss_eport->eport_free_netb( + FCOET_GET_NETB(dbuf, ii)); + } + stmf_free(dbuf); + FCOET_LOG("fcoe_dbuf_alloc", "no netb"); + return (NULL); + } + FCOET_SET_NETB(dbuf, idx, netb); + dbuf->db_sglist[idx].seg_addr = fc_buf + + sizeof (fcoe_fc_frame_header_t); + dbuf->db_sglist[idx].seg_length = sge_size; + } + + /* + * Initialize the last sg entry + */ + if (size % ss->ss_fcp_data_payload_size) { + sge_size = P2ROUNDUP(size % ss->ss_fcp_data_payload_size, 4); + } else { + sge_size = ss->ss_fcp_data_payload_size; + } + + netb = ss->ss_eport->eport_alloc_netb( + ss->ss_eport, + sizeof (fcoe_fc_frame_header_t) + + sge_size, &fc_buf); + if (netb == NULL) { + for (ii = 0; ii < idx; ii++) { + ss->ss_eport->eport_free_netb( + FCOET_GET_NETB(dbuf, ii)); + } + stmf_free(dbuf); + FCOET_LOG("fcoe_dbuf_alloc", "no netb"); + return (NULL); + } + + FCOET_SET_NETB(dbuf, idx, netb); + dbuf->db_sglist[idx].seg_addr = fc_buf + + sizeof (fcoe_fc_frame_header_t); + dbuf->db_sglist[idx].seg_length = sge_size; + + /* + * Let COMSTAR know how many sg entries we will use + */ + dbuf->db_sglist_length = idx + 1; + + return (dbuf); +} + +static void +fcoet_dbuf_free(fct_dbuf_store_t *fds, stmf_data_buf_t *dbuf) +{ + int idx; + fcoet_soft_state_t *ss = + (fcoet_soft_state_t *)fds->fds_fca_private; + + for (idx = 0; idx < FCOET_GET_SEG_NUM(dbuf); idx++) { + if (FCOET_GET_NETB(dbuf, idx)) { + ss->ss_eport->eport_free_netb( + FCOET_GET_NETB(dbuf, idx)); + } + } + + stmf_free(dbuf); +} + +/* + * We should have initialized fcoe_frame_t before + */ +void +fcoet_init_tfm(fcoe_frame_t *frm, fcoet_exchange_t *xch) +{ + FRM2TFM(frm)->tfm_fcoe_frame = frm; + FRM2TFM(frm)->tfm_xch = xch; + FRM2TFM(frm)->tfm_seq = NULL; +} + +/* ARGSUSED */ +static uint_t +fcoet_sol_oxid_hash_empty(mod_hash_key_t key, mod_hash_val_t *val, void *arg) +{ + fcoet_soft_state_t *ss = (fcoet_soft_state_t *)arg; + + ss->ss_sol_oxid_hash_empty = 0; + FCOET_LOG("fcoet_sol_oxid_hash_empty", "one ongoing xch: %p", val); + return (MH_WALK_CONTINUE); +} + +/* ARGSUSED */ +static uint_t +fcoet_unsol_rxid_hash_empty(mod_hash_key_t key, mod_hash_val_t *val, void *arg) +{ + fcoet_soft_state_t *ss = (fcoet_soft_state_t *)arg; + + ss->ss_sol_oxid_hash_empty = 0; + FCOET_LOG("fcoet_unsol_rxid_hash_empty", "one ongoing xch: %p", val); + return (MH_WALK_CONTINUE); +} + +/* ARGSUSED */ +void +fcoet_modhash_find_cb(mod_hash_key_t key, mod_hash_val_t val) +{ + ASSERT(val != NULL); + fcoet_exchange_t *xch = (fcoet_exchange_t *)val; + FCOET_BUSY_XCHG(xch); +} diff --git a/usr/src/uts/common/io/comstar/port/fcoet/fcoet.h b/usr/src/uts/common/io/comstar/port/fcoet/fcoet.h new file mode 100644 index 0000000000..e2859d7f17 --- /dev/null +++ b/usr/src/uts/common/io/comstar/port/fcoet/fcoet.h @@ -0,0 +1,307 @@ +/* + * 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 _FCOET_H +#define _FCOET_H + +#include <sys/stmf_defines.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _KERNEL + +#define FCOET_VERSION "v20090311-1.00" +#define FCOET_NAME "COMSTAR FCoET " +#define FCOET_MOD_NAME FCOET_NAME FCOET_VERSION + +/* + * FCOET logging + */ +extern int fcoet_use_ext_log; + +/* + * Caution: 1) LOG will be available in debug/non-debug mode + * 2) Anything which can potentially flood the log should be under + * extended logging, and use FCOET_EXT_LOG. + * 3) Don't use FCOET_EXT_LOG in performance-critical code path, such + * as normal SCSI I/O code path. It could hurt system performance. + * 4) Use kmdb to change focet_use_ext_log in the fly to adjust + * tracing + */ +#define FCOET_EXT_LOG(log_ident, ...) \ + { \ + if (fcoet_use_ext_log) { \ + fcoe_trace(log_ident, __VA_ARGS__); \ + } \ + } + +#define FCOET_LOG(log_ident, ...) \ + fcoe_trace(log_ident, __VA_ARGS__) + +/* + * define common-used constants + */ +#define FCOET_MAX_LOGINS 2048 +#define FCOET_MAX_XCHGES 2048 +#define FCOET_SOL_HASH_SIZE 128 +#define FCOET_UNSOL_HASH_SIZE 2048 + +typedef enum fcoet_sol_flogi_state { + SFS_WAIT_LINKUP = 0, + SFS_FLOGI_INIT, + SFS_FLOGI_CHECK_TIMEOUT, + SFS_ABTS_INIT, + SFS_CLEAR_FLOGI, + SFS_FLOGI_ACC, + SFS_FLOGI_DONE +} fcoet_sol_flogi_state_t; + +/* + * define data structures + */ +struct fcoet_exchange; +typedef struct fcoet_soft_state { + /* + * basic information + */ + dev_info_t *ss_dip; + int ss_instance; + uint32_t ss_flags; + fct_local_port_t *ss_port; + fcoe_port_t *ss_eport; + char ss_alias[32]; + uint32_t ss_fcp_data_payload_size; + + /* + * support degregister remote port + */ + uint32_t ss_rportid_in_dereg; + uint32_t ss_rport_dereg_state; + + /* + * oxid/rxid + */ + mod_hash_t *ss_sol_oxid_hash; + mod_hash_t *ss_unsol_rxid_hash; + uint16_t ss_next_sol_oxid; + uint16_t ss_next_unsol_rxid; + int ss_sol_oxid_hash_empty; + int ss_unsol_rxid_hash_empty; + + /* + * watch thread related stuff + */ + ddi_taskq_t *ss_watchdog_taskq; + kcondvar_t ss_watch_cv; + kmutex_t ss_watch_mutex; + uint64_t ss_watch_count; + list_t ss_abort_xchg_list; + + /* + * topology discovery + */ + struct fcoet_exchange *ss_sol_flogi; + fcoet_sol_flogi_state_t ss_sol_flogi_state; + fct_link_info_t ss_link_info; + + /* + * ioctl related stuff + */ + uint32_t ss_ioctl_flags; + kmutex_t ss_ioctl_mutex; + + /* + * special stuff + */ + uint32_t ss_change_state_flags; + uint8_t ss_state:7, + ss_state_not_acked:1; +} fcoet_soft_state_t; + +#define SS_FLAG_UNSOL_FLOGI_DONE 0x0001 +#define SS_FLAG_REPORT_TO_FCT 0x0002 +#define SS_FLAG_PORT_DISABLED 0x0004 +#define SS_FLAG_STOP_WATCH 0x0008 +#define SS_FLAG_TERMINATE_WATCHDOG 0x0010 +#define SS_FLAG_WATCHDOG_RUNNING 0x0020 +#define SS_FLAG_DOG_WAITING 0x0040 +#define SS_FLAG_DELAY_PLOGI 0x0080 + +/* + * Sequence and frame are transient objects, so their definition is simple. + */ + +/* + * Sequence. + * we will not use sequence in current implementation + */ +typedef struct fcoet_sequence { + list_t seq_frame_list; + struct fcoet_exchange *seq_exchange; +} fcoet_sequence_t; + +/* + * Frame + */ +typedef struct fcoet_frame { + list_node_t tfm_seq_node; + fcoe_frame_t *tfm_fcoe_frame; + + struct fcoet_exchange *tfm_xch; + struct fcoet_sequence *tfm_seq; + uint8_t tfm_rctl; + uint8_t tfm_buf_idx; +} fcoet_frame_t; + +/* + * FCOET_MAX_DBUF_LEN should better be consistent with sbd_scsi.c. Since + * sbd_scsi.c use 128k as the max dbuf size, we'd better define this between + * 32k - 128k. + */ +#define FCOET_MAX_DBUF_LEN 0x20000 /* 128 * 1024 */ +/* + * exchange - cmd alias + */ +typedef struct fcoet_exchange { + /* + * it is only used for ss_abort_xchg_list + */ + list_node_t xch_abort_node; + + /* + * We don't believe oxid/rxid in fct_cmd_t + */ + uint16_t xch_oxid; + uint16_t xch_rxid; + + uint32_t xch_flags; + fcoet_soft_state_t *xch_ss; + fct_cmd_t *xch_cmd; + + fcoet_sequence_t *xch_current_seq; + clock_t xch_start_time; + + stmf_data_buf_t **xch_dbufs; + uint8_t xch_dbuf_num; + uint8_t xch_sequence_no; + uint8_t xch_ref; + + int xch_left_data_size; +} fcoet_exchange_t; +/* + * Add the reference to avoid such situation: + * 1, Frame received, then abort happen (maybe because local port offline, or + * remote port abort the cmd), cmd is aborted and then freed right after we + * get the exchange from hash table in fcoet_rx_frame. + * 2, Frame sent out, then queued in fcoe for release. then abort happen, cmd + * is aborted and then freed before fcoe_watchdog() call up to release the + * frame. + * These two situation should seldom happen. But just invoke this seems won't + * downgrade the performance too much, so we keep it. + */ +#define FCOET_BUSY_XCHG(xch) atomic_add_8(&(xch)->xch_ref, 1) +#define FCOET_RELE_XCHG(xch) atomic_add_8(&(xch)->xch_ref, -1) + +#define XCH_FLAG_NONFCP_REQ_SENT 0x0001 +#define XCH_FLAG_NONFCP_RESP_SENT 0x0002 +#define XCH_FLAG_FCP_CMD_RCVD 0x0004 +#define XCH_FLAG_INI_ASKED_ABORT 0x0008 +#define XCH_FLAG_FCT_CALLED_ABORT 0x0010 +#define XCH_FLAG_IN_HASH_TABLE 0x0020 + +/* + * IOCTL supporting stuff + */ +#define FCOET_IOCTL_FLAG_MASK 0xFF +#define FCOET_IOCTL_FLAG_IDLE 0x00 +#define FCOET_IOCTL_FLAG_OPEN 0x01 +#define FCOET_IOCTL_FLAG_EXCL 0x02 + +/* + * define common-used conversion and calculation macros + */ +#define FRM2SS(x_frm) \ + ((fcoet_soft_state_t *)(x_frm)->frm_eport->eport_client_private) +#define FRM2TFM(x_frm) ((fcoet_frame_t *)(x_frm)->frm_client_private) + +#define PORT2SS(x_port) ((fcoet_soft_state_t *)(x_port)->port_fca_private) +#define EPORT2SS(x_port) ((fcoet_soft_state_t *)(x_port)->eport_client_private) + +#define XCH2ELS(x_xch) ((fct_els_t *)x_xch->xch_cmd->cmd_specific) +#define XCH2CT(x_xch) ((fct_ct_t *)x_xch->xch_cmd->cmd_specific) +#define XCH2TASK(x_xch) ((scsi_task_t *)x_xch->xch_cmd->cmd_specific) + +#define CMD2ELS(x_cmd) ((fct_els_t *)x_cmd->cmd_specific) +#define CMD2CT(x_cmd) ((fct_sol_ct_t *)x_cmd->cmd_specific) +#define CMD2TASK(x_cmd) ((scsi_task_t *)x_cmd->cmd_specific) +#define CMD2XCH(x_cmd) ((fcoet_exchange_t *)x_cmd->cmd_fca_private) +#define CMD2SS(x_cmd) \ + ((fcoet_soft_state_t *)(x_cmd)->cmd_port->port_fca_private) + +void fcoet_init_tfm(fcoe_frame_t *frm, fcoet_exchange_t *xch); +fct_status_t fcoet_send_status(fct_cmd_t *cmd); +void fcoet_modhash_find_cb(mod_hash_key_t, mod_hash_val_t); + +/* + * DBUF stuff + */ +#define FCOET_DB_SEG_NUM(x_db) (x_db->db_port_private) +#define FCOET_DB_NETB(x_db) \ + (((uintptr_t)FCOET_DB_SEG_NUM(x_db)) * \ + sizeof (struct stmf_sglist_ent) + (uintptr_t)(x_db)->db_sglist) + +#define FCOET_SET_SEG_NUM(x_db, x_num) \ + { \ + FCOET_DB_SEG_NUM(x_db) = (void *)(unsigned long)x_num; \ + } + +#define FCOET_GET_SEG_NUM(x_db) ((int)(unsigned long)FCOET_DB_SEG_NUM(x_db)) + + +#define FCOET_SET_NETB(x_db, x_idx, x_netb) \ + { \ + ((void **)FCOET_DB_NETB(x_db))[x_idx] = x_netb; \ + } + +#define FCOET_GET_NETB(x_db, x_idx) \ + (((void **)FCOET_DB_NETB(x_db))[x_idx]) + +#define PRT_FRM_HDR(x_p, x_f) \ + { \ + FCOET_LOG(x_p, "rctl/%x, type/%x, fctl/%x, oxid/%x", \ + FCOE_B2V_1((x_f)->frm_hdr->hdr_r_ctl), \ + FCOE_B2V_1((x_f)->frm_hdr->hdr_type), \ + FCOE_B2V_3((x_f)->frm_hdr->hdr_f_ctl), \ + FCOE_B2V_4((x_f)->frm_hdr->hdr_oxid)); \ + } + +#endif /* _KERNEL */ + +#ifdef __cplusplus +} +#endif + +#endif /* _FCOET_H */ diff --git a/usr/src/uts/common/io/comstar/port/fcoet/fcoet_eth.c b/usr/src/uts/common/io/comstar/port/fcoet/fcoet_eth.c new file mode 100644 index 0000000000..99d5962ca2 --- /dev/null +++ b/usr/src/uts/common/io/comstar/port/fcoet/fcoet_eth.c @@ -0,0 +1,1187 @@ +/* + * 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. + */ + +/* + * The following notice accompanied the original version of this file: + * + * BSD LICENSE + * + * Copyright(c) 2007 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This file defines interfaces between fcoe and fcoet driver. + */ + +/* + * Driver kernel header files + */ +#include <sys/conf.h> +#include <sys/ddi.h> +#include <sys/stat.h> +#include <sys/pci.h> +#include <sys/sunddi.h> +#include <sys/modctl.h> +#include <sys/file.h> +#include <sys/cred.h> +#include <sys/byteorder.h> +#include <sys/atomic.h> +#include <sys/modhash.h> +#include <sys/scsi/scsi.h> +#include <sys/ethernet.h> + +/* + * COMSTAR header files + */ +#include <sys/stmf_defines.h> +#include <sys/fct_defines.h> +#include <sys/stmf.h> +#include <sys/portif.h> +#include <sys/fct.h> + +/* + * FCoE header files + */ +#include <sys/fcoe/fcoe_common.h> + +/* + * Driver's own header files + */ +#include <fcoet.h> +#include <fcoet_eth.h> + +/* + * function forward declaration + */ +static fcoet_exchange_t *fcoet_create_unsol_exchange(fcoe_frame_t *frame); +static int fcoet_process_sol_fcp_data(fcoe_frame_t *frm); +static int fcoet_process_unsol_fcp_cmd(fcoe_frame_t *frm); +static int fcoet_process_unsol_els_req(fcoe_frame_t *frm); +static int fcoet_process_sol_els_rsp(fcoe_frame_t *frm); +static int fcoet_process_unsol_abts_req(fcoe_frame_t *frame); +static int fcoet_process_sol_abts_acc(fcoe_frame_t *frame); +static int fcoet_process_sol_abts_rjt(fcoe_frame_t *frame); +static int fcoet_process_unsol_ct_req(fcoe_frame_t *frm); +static int fcoet_process_sol_ct_rsp(fcoe_frame_t *frame); +static int fcoet_process_sol_flogi_rsp(fcoe_frame_t *frame); +static int fcoet_send_sol_fcp_data_done(fcoe_frame_t *frm); +static int fcoet_send_fcp_status_done(fcoe_frame_t *frm); +static int fcoet_send_unsol_els_rsp_done(fcoe_frame_t *frm); +static int fcoet_send_sol_els_req_done(fcoe_frame_t *frm); +static int fcoet_send_unsol_bls_acc_done(fcoe_frame_t *frm); +static int fcoet_send_unsol_bls_rjt_done(fcoe_frame_t *frm); +static int fcoet_send_sol_bls_req_done(fcoe_frame_t *frm); +static int fcoet_send_sol_ct_req_done(fcoe_frame_t *frm); +static int fcoet_process_unsol_flogi_req(fcoet_exchange_t *xch); + +/* + * rx_frame & release_sol_frame + * There should be no same OXID/RXID in on-going exchanges. + * RXID -> unsol_rxid_hash + * OXID -> sol_oxid_hash + */ + +void +fcoet_rx_frame(fcoe_frame_t *frm) +{ + uint8_t rctl = FRM_R_CTL(frm); + + switch (rctl) { + case 0x01: + /* + * Solicited data + */ + if (fcoet_process_sol_fcp_data(frm)) { + FCOET_LOG("fcoet_rx_frame", + "fcoet_process_sol_fcp_data failed"); + } + break; + + case 0x06: + /* + * Unsolicited fcp_cmnd + */ + if (fcoet_process_unsol_fcp_cmd(frm)) { + FCOET_LOG("fcoet_rx_frame", + "fcoet_process_unsol_fcp_cmd failed"); + } + break; + + case 0x22: + /* + * unsolicited ELS req + */ + if (fcoet_process_unsol_els_req(frm)) { + FCOET_LOG("fcoet_rx_frame", + "fcoet_process_unsol_els_req failed"); + } + break; + + case 0x23: + /* + * solicited ELS rsp + */ + if (fcoet_process_sol_els_rsp(frm)) { + FCOET_LOG("fcoet_rx_frame", + "fcoet_process_sol_els_rsp failed"); + } + break; + + case 0x81: + /* + * unsolicted ABTS req + */ + if (fcoet_process_unsol_abts_req(frm)) { + FCOET_LOG("fcoet_rx_frame", + "fcoet_process_unsol_abts_req failed"); + } + break; + + case 0x84: + /* + * solicited ABTS acc response + */ + if (fcoet_process_sol_abts_acc(frm)) { + FCOET_LOG("fcoet_rx_frame", + "fcoet_process_sol_abts_acc failed"); + } + break; + case 0x85: + /* + * solcited ABTS rjt response + */ + if (fcoet_process_sol_abts_rjt(frm)) { + FCOET_LOG("fcoet_rx_frame", + "fcoet_process_sol_abts_rjt failed"); + } + break; + + case 0x02: + /* + * unsolicited CT req + */ + if (fcoet_process_unsol_ct_req(frm)) { + FCOET_LOG("fcoet_rx_frame", + "fcoet_process_sol_ct_rsp failed"); + } + break; + + case 0x03: + /* + * sol ct rsp + */ + if (fcoet_process_sol_ct_rsp(frm)) { + FCOET_LOG("fcoet_rx_frame", + "fcoet_process_sol_ct_rsp failed"); + } + break; + + default: + /* + * Unsupported frame + */ + PRT_FRM_HDR("Unsupported unsol frame: ", frm); + break; + } + + /* + * Release the frame in the end + */ + frm->frm_eport->eport_free_netb(frm->frm_netb); + frm->frm_eport->eport_release_frame(frm); +} + +/* + * For solicited frames, after FCoE has sent it out, it will call this + * to notify client(FCoEI/FCoET) about its completion. + */ +void +fcoet_release_sol_frame(fcoe_frame_t *frm) +{ + fcoet_exchange_t *xch = FRM2TFM(frm)->tfm_xch; + + /* + * From now, we should not access both frm_hdr and frm_payload. Its + * mblk could have been released by MAC driver. + */ + switch (FRM2TFM(frm)->tfm_rctl) { + case 0x01: + if (xch && xch->xch_flags & XCH_FLAG_FCT_CALLED_ABORT) { + FCOET_RELE_XCHG(xch); + break; + } + if (fcoet_send_sol_fcp_data_done(frm)) { + ASSERT(0); + } + break; + + case 0x05: + break; + + case 0x07: + if (xch && xch->xch_flags & XCH_FLAG_FCT_CALLED_ABORT) { + FCOET_RELE_XCHG(xch); + break; + } + + if (fcoet_send_fcp_status_done(frm)) { + ASSERT(0); + } + break; + + case 0x23: + if (xch && xch->xch_flags & XCH_FLAG_FCT_CALLED_ABORT) { + FCOET_RELE_XCHG(xch); + break; + } + if (fcoet_send_unsol_els_rsp_done(frm)) { + ASSERT(0); + } + break; + + case 0x22: + if (fcoet_send_sol_els_req_done(frm)) { + ASSERT(0); + } + break; + + case 0x84: + if (fcoet_send_unsol_bls_acc_done(frm)) { + ASSERT(0); + } + break; + + case 0x85: + if (fcoet_send_unsol_bls_rjt_done(frm)) { + ASSERT(0); + } + break; + + case 0x81: + if (fcoet_send_sol_bls_req_done(frm)) { + ASSERT(0); + } + break; + + case 0x02: + if (fcoet_send_sol_ct_req_done(frm)) { + ASSERT(0); + } + break; + + case 0x03: + default: + /* + * Unsupported frame + */ + PRT_FRM_HDR("Unsupported sol frame: ", frm); + break; + } + + /* + * We should release the frame + */ + FRM2SS(frm)->ss_eport->eport_release_frame(frm); +} + +void +fcoet_port_event(fcoe_port_t *eport, uint32_t event) +{ + fcoet_soft_state_t *ss = EPORT2SS(eport); + switch (event) { + case FCOE_NOTIFY_EPORT_LINK_UP: + if (eport->eport_mtu >= FCOE_MIN_MTU_SIZE) { + ss->ss_fcp_data_payload_size = + FCOE_DEFAULT_FCP_DATA_PAYLOAD_SIZE; + } else { + ss->ss_fcp_data_payload_size = + FCOE_MIN_FCP_DATA_PAYLOAD_SIZE; + } + FCOET_LOG("fcoet_port_event", "LINK UP notified"); + mutex_enter(&ss->ss_watch_mutex); + ss->ss_sol_flogi_state = SFS_FLOGI_INIT; + cv_signal(&ss->ss_watch_cv); + mutex_exit(&ss->ss_watch_mutex); + break; + case FCOE_NOTIFY_EPORT_LINK_DOWN: + fct_handle_event(ss->ss_port, + FCT_EVENT_LINK_DOWN, 0, 0); + /* Need clear up all other things */ + FCOET_LOG("fcoet_port_event", "LINK DOWN notified"); + ss->ss_sol_flogi_state = SFS_WAIT_LINKUP; + break; + default: + break; + } +} + +/* + * For unsolicited exchanges, FCoET is only responsible for allocation of + * req_payload. FCT will allocate resp_payload after the exchange is + * passed on. + */ +static fcoet_exchange_t * +fcoet_create_unsol_exchange(fcoe_frame_t *frm) +{ + uint8_t r_ctl; + int cdb_size; + fcoet_exchange_t *xch, *xch_tmp; + fct_cmd_t *cmd; + fcoe_fcp_cmnd_t *ffc; + uint32_t task_expected_len = 0; + + r_ctl = FRM_R_CTL(frm); + switch (r_ctl) { + case 0x22: + /* + * FCoET's unsolicited ELS + */ + cmd = (fct_cmd_t *)fct_alloc(FCT_STRUCT_CMD_RCVD_ELS, + GET_STRUCT_SIZE(fcoet_exchange_t) + + frm->frm_payload_size, 0); + if (cmd == NULL) { + FCOET_EXT_LOG(0, "can't get cmd"); + return (NULL); + } + break; + + case 0x06: + /* + * FCoET's unsolicited SCSI cmd + */ + cdb_size = 16; /* need improve later */ + cmd = fct_scsi_task_alloc(FRM2SS(frm)->ss_port, FCT_HANDLE_NONE, + FRM_S_ID(frm), frm->frm_payload, cdb_size, + STMF_TASK_EXT_NONE); + if (cmd == NULL) { + FCOET_EXT_LOG(0, "can't get fcp cmd"); + return (NULL); + } + ffc = (fcoe_fcp_cmnd_t *)frm->frm_payload; + task_expected_len = FCOE_B2V_4(ffc->ffc_fcp_dl); + break; + + default: + FCOET_EXT_LOG(0, "unsupported R_CTL: %x", r_ctl); + return (NULL); + } + + /* + * xch initialization + */ + xch = CMD2XCH(cmd); + xch->xch_oxid = FRM_OXID(frm); + xch->xch_flags = 0; + xch->xch_ss = FRM2SS(frm); + xch->xch_cmd = cmd; + xch->xch_current_seq = NULL; + xch->xch_left_data_size = 0; + if (task_expected_len) { + xch->xch_dbuf_num = + (task_expected_len + FCOET_MAX_DBUF_LEN - 1) / + FCOET_MAX_DBUF_LEN; + xch->xch_dbufs = + kmem_zalloc(xch->xch_dbuf_num * sizeof (stmf_data_buf_t *), + KM_SLEEP); + } + xch->xch_start_time = ddi_get_lbolt(); + do { + xch->xch_rxid = atomic_add_16_nv( + &xch->xch_ss->ss_next_unsol_rxid, 1); + if (xch->xch_rxid == 0xFFFF) { + xch->xch_rxid = atomic_add_16_nv( + &xch->xch_ss->ss_next_unsol_rxid, 1); + } + } while (mod_hash_find(FRM2SS(frm)->ss_unsol_rxid_hash, + (mod_hash_key_t)(intptr_t)xch->xch_rxid, + (mod_hash_val_t)&xch_tmp) == 0); + + xch->xch_sequence_no = 0; + xch->xch_ref = 0; + (void) mod_hash_insert(xch->xch_ss->ss_unsol_rxid_hash, + (mod_hash_key_t)(intptr_t)xch->xch_rxid, (mod_hash_val_t)xch); + xch->xch_flags |= XCH_FLAG_IN_HASH_TABLE; + + /* + * cmd initialization + */ + cmd->cmd_port = FRM2SS(frm)->ss_port; + cmd->cmd_rp_handle = FCT_HANDLE_NONE; + cmd->cmd_rportid = FRM_S_ID(frm); + cmd->cmd_lportid = FRM_D_ID(frm); + cmd->cmd_oxid = xch->xch_oxid; + cmd->cmd_rxid = xch->xch_rxid; + + fcoet_init_tfm(frm, xch); + return (xch); +} + +int +fcoet_clear_unsol_exchange(fcoet_exchange_t *xch) +{ + mod_hash_val_t val = NULL; + + if (mod_hash_remove(xch->xch_ss->ss_unsol_rxid_hash, + (mod_hash_key_t)(intptr_t)xch->xch_rxid, &val) == 0) { + if (xch->xch_dbuf_num) { + kmem_free((void*)xch->xch_dbufs, + xch->xch_dbuf_num * sizeof (void *)); + xch->xch_dbufs = NULL; + xch->xch_dbuf_num = 0; + } + ASSERT(xch->xch_flags & XCH_FLAG_IN_HASH_TABLE); + ASSERT((fcoet_exchange_t *)val == xch); + xch->xch_flags &= ~XCH_FLAG_IN_HASH_TABLE; + return (FCOE_SUCCESS); + } + + FCOET_LOG("fcoet_clear_unsol_exchange", "xch %p already cleared from " + "hash table", xch); + return (FCOE_FAILURE); +} + +void +fcoet_clear_sol_exchange(fcoet_exchange_t *xch) +{ + mod_hash_val_t val = NULL; + + if (xch->xch_flags & XCH_FLAG_IN_HASH_TABLE) { + (void) mod_hash_remove(xch->xch_ss->ss_sol_oxid_hash, + (mod_hash_key_t)(intptr_t)xch->xch_oxid, &val); + ASSERT((fcoet_exchange_t *)val == xch); + xch->xch_flags &= ~XCH_FLAG_IN_HASH_TABLE; + } +} + +static int +fcoet_process_sol_fcp_data(fcoe_frame_t *frm) +{ + fcoet_exchange_t *xch = NULL; + fcoet_soft_state_t *ss = NULL; + fct_status_t fc_st; + uint32_t iof; + uint16_t unsol_rxid; + int sge_idx; + stmf_data_buf_t *dbuf; + int data_offset; + + unsol_rxid = FRM_RXID(frm); + if (mod_hash_find_cb(FRM2SS(frm)->ss_unsol_rxid_hash, + (mod_hash_key_t)(intptr_t)unsol_rxid, + (mod_hash_val_t)&xch, fcoet_modhash_find_cb) != 0) { + return (FCOE_FAILURE); + } + + /* + * we will always have a buf waiting there + */ + data_offset = FRM_PARAM(frm); + dbuf = xch->xch_dbufs[data_offset/FCOET_MAX_DBUF_LEN]; + ASSERT(dbuf); + ss = xch->xch_ss; + sge_idx = (data_offset % FCOET_MAX_DBUF_LEN)/ + ss->ss_fcp_data_payload_size; + + ASSERT(((sge_idx < FCOET_GET_SEG_NUM(dbuf) - 1) && + (frm->frm_payload_size == ss->ss_fcp_data_payload_size)) || + ((sge_idx == FCOET_GET_SEG_NUM(dbuf) - 1) && + (frm->frm_payload_size % ss->ss_fcp_data_payload_size == + dbuf->db_data_size % ss->ss_fcp_data_payload_size))); + + bcopy(frm->frm_payload, dbuf->db_sglist[sge_idx].seg_addr, + frm->frm_payload_size); + + xch->xch_left_data_size -= frm->frm_payload_size; + if (xch->xch_left_data_size <= 0) { + fc_st = FCT_SUCCESS; + iof = 0; + dbuf->db_xfer_status = fc_st; + dbuf->db_flags |= DB_DONT_REUSE; + fct_scsi_data_xfer_done(xch->xch_cmd, dbuf, iof); + } + + FCOET_RELE_XCHG(xch); + return (FCOE_SUCCESS); +} + +static int +fcoet_process_unsol_fcp_cmd(fcoe_frame_t *frm) +{ + fcoet_exchange_t *xch; + fcoe_fcp_cmnd_t *ffc; + uint8_t tm; + scsi_task_t *task; + + xch = fcoet_create_unsol_exchange(frm); + if (xch == NULL) { + FCOET_LOG("fcoet_process_unsol_fcp_cmd", "can't get exchange"); + return (FCOE_FAILURE); + } + + ffc = (fcoe_fcp_cmnd_t *)frm->frm_payload; + task = XCH2TASK(xch); + task->task_csn_size = 8; + task->task_max_nbufs = 1; + task->task_cmd_seq_no = FCOE_B2V_1(ffc->ffc_ref_num); + task->task_flags = FCOE_B2V_1(ffc->ffc_attribute) & 0x07; + task->task_flags |= + (FCOE_B2V_1(ffc->ffc_addlen_rdwr) & 0x03) << 5; + task->task_expected_xfer_length = FCOE_B2V_4(ffc->ffc_fcp_dl); + + tm = FCOE_B2V_1(ffc->ffc_management_flags); + if (tm) { + if (tm & BIT_1) { + task->task_mgmt_function = TM_ABORT_TASK_SET; + } else if (tm & BIT_2) { + task->task_mgmt_function = TM_CLEAR_TASK_SET; + } else if (tm & BIT_4) { + task->task_mgmt_function = TM_LUN_RESET; + } else if (tm & BIT_5) { + task->task_mgmt_function = TM_TARGET_COLD_RESET; + } else if (tm & BIT_6) { + task->task_mgmt_function = TM_CLEAR_ACA; + } else { + task->task_mgmt_function = TM_ABORT_TASK; + } + } + + bcopy(ffc->ffc_cdb, task->task_cdb, 16); + fct_post_rcvd_cmd(xch->xch_cmd, NULL); + return (FCOE_SUCCESS); +} +/* + * It must be from link + * req_payload has been allocated when create_unsol_exchange + */ +static int +fcoet_process_unsol_els_req(fcoe_frame_t *frm) +{ + int ret = FCOE_SUCCESS; + fcoet_exchange_t *xch; + + xch = fcoet_create_unsol_exchange(frm); + ASSERT(xch); + ASSERT(FRM_IS_LAST_FRAME(frm)); + + /* + * For the reason of keeping symmetric, we do copy here as in + * process_sol_els instead of in create_unsol_exchange. + * req_payload depends on how to allocate buf in create_unsol_exchange + */ + XCH2ELS(xch)->els_req_alloc_size = 0; + XCH2ELS(xch)->els_req_size = frm->frm_payload_size; + XCH2ELS(xch)->els_req_payload = + GET_BYTE_OFFSET(xch, GET_STRUCT_SIZE(fcoet_exchange_t)); + bcopy(frm->frm_payload, XCH2ELS(xch)->els_req_payload, + XCH2ELS(xch)->els_req_size); + if (XCH2ELS(xch)->els_req_payload[0] != ELS_OP_FLOGI) { + /* + * Ensure LINK_UP event has been handled, or PLOIG has + * been processed by FCT, or else it will be discarded. + * It need more consideration later ??? + */ + if ((XCH2ELS(xch)->els_req_payload[0] == ELS_OP_PLOGI) && + (xch->xch_ss->ss_flags & SS_FLAG_DELAY_PLOGI)) { + delay(STMF_SEC2TICK(1)/2); + } + + if ((XCH2ELS(xch)->els_req_payload[0] == ELS_OP_PRLI) && + (xch->xch_ss->ss_flags & SS_FLAG_DELAY_PLOGI)) { + atomic_and_32(&xch->xch_ss->ss_flags, + ~SS_FLAG_DELAY_PLOGI); + delay(STMF_SEC2TICK(1)/3); + } + fct_post_rcvd_cmd(xch->xch_cmd, NULL); + } else { + /* + * We always handle FLOGI internally + * Save dst mac address from FLOGI request to restore later + */ + bcopy((char *)frm->frm_hdr-22, + frm->frm_eport->eport_efh_dst, ETHERADDRL); + ret = fcoet_process_unsol_flogi_req(xch); + } + return (ret); +} + + +/* + * It must be from link, but could be incomplete because of network problems + */ +static int +fcoet_process_sol_els_rsp(fcoe_frame_t *frm) +{ + uint32_t actual_size; + fct_status_t fc_st; + uint32_t iof; + uint16_t sol_oxid; + fcoet_exchange_t *xch = NULL; + fct_els_t *els = NULL; + int ret = FCOE_SUCCESS; + + sol_oxid = FRM_OXID(frm); + if (mod_hash_find_cb(FRM2SS(frm)->ss_sol_oxid_hash, + (mod_hash_key_t)(intptr_t)sol_oxid, + (mod_hash_val_t *)&xch, fcoet_modhash_find_cb) != 0) { + return (FCOE_FAILURE); + } + if (xch != FRM2SS(frm)->ss_sol_flogi) { + fcoet_clear_sol_exchange(xch); + } + + fcoet_init_tfm(frm, xch); + els = CMD2ELS(xch->xch_cmd); + ASSERT(FRM_IS_LAST_FRAME(frm)); + actual_size = els->els_resp_size; + if (actual_size > frm->frm_payload_size) { + actual_size = frm->frm_payload_size; + } + + els->els_resp_size = (uint16_t)actual_size; + bcopy(frm->frm_payload, els->els_resp_payload, actual_size); + + if (xch->xch_ss->ss_sol_flogi == xch) { + /* + * We handle FLOGI internally + */ + ret = fcoet_process_sol_flogi_rsp(frm); + FCOET_RELE_XCHG(xch); + } else { + fc_st = FCT_SUCCESS; + iof = FCT_IOF_FCA_DONE; + FCOET_RELE_XCHG(xch); + fct_send_cmd_done(xch->xch_cmd, fc_st, iof); + } + return (ret); +} + +/* + * It's still in the context of being aborted exchange, but FCT can't support + * this scheme, so there are two fct_cmd_t that are bound with one exchange. + */ +static int +fcoet_process_unsol_abts_req(fcoe_frame_t *frm) +{ + fct_cmd_t *cmd; + fcoet_exchange_t *xch = NULL; + uint16_t unsol_rxid; + + FCOET_LOG("fcoet_process_unsol_abts_req", "ABTS: %x/%x", + FRM_OXID(frm), FRM_RXID(frm)); + unsol_rxid = FRM_RXID(frm); + if (mod_hash_find_cb(FRM2SS(frm)->ss_unsol_rxid_hash, + (mod_hash_key_t)(intptr_t)unsol_rxid, + (mod_hash_val_t *)&xch, fcoet_modhash_find_cb) != 0) { + FCOET_LOG("fcoet_process_unsol_abts_req", + "can't find aborted exchange"); + return (FCOE_SUCCESS); + } + + fcoet_init_tfm(frm, xch); + if (!FRM_IS_LAST_FRAME(frm)) { + FCOET_LOG("fcoet_process_unsol_abts_req", + "not supported this kind frame"); + FCOET_RELE_XCHG(xch); + return (FCOE_FAILURE); + } + + cmd = (fct_cmd_t *)fct_alloc(FCT_STRUCT_CMD_RCVD_ABTS, 0, 0); + if (cmd == NULL) { + FCOET_LOG("fcoet_process_unsol_abts_req", + "can't alloc fct_cmd_t"); + FCOET_RELE_XCHG(xch); + return (FCOE_FAILURE); + } + + xch->xch_flags |= XCH_FLAG_INI_ASKED_ABORT; + cmd->cmd_fca_private = xch; + cmd->cmd_port = xch->xch_cmd->cmd_port; + cmd->cmd_rp_handle = xch->xch_cmd->cmd_rp_handle; + cmd->cmd_rportid = xch->xch_cmd->cmd_rportid; + cmd->cmd_lportid = xch->xch_cmd->cmd_lportid; + cmd->cmd_oxid = xch->xch_cmd->cmd_oxid; + cmd->cmd_rxid = xch->xch_cmd->cmd_rxid; + fct_post_rcvd_cmd(cmd, NULL); + FCOET_LOG("fcoet_process_unsol_abts_req", + "abts now: xch/%p, frm/%p - time/%p", + xch, frm, ddi_get_lbolt()); + + FCOET_RELE_XCHG(xch); + return (FCOE_SUCCESS); +} + +static int +fcoet_process_sol_abts_acc(fcoe_frame_t *frm) +{ + fcoet_exchange_t *xch = NULL; + uint16_t sol_oxid; + + sol_oxid = FRM_OXID(frm); + if (mod_hash_remove(FRM2SS(frm)->ss_sol_oxid_hash, + (mod_hash_key_t)(intptr_t)sol_oxid, + (mod_hash_val_t *)&xch) != 0) { + /* + * So far ABTS for FLOGI might be removed from ss_sol_oxid_hash + * in fcoet_watch_handle_sol_flogi, Will improve it later + */ + return (FCOE_SUCCESS); + } + + xch->xch_flags &= ~XCH_FLAG_IN_HASH_TABLE; + if (!FRM_IS_LAST_FRAME(frm)) { + FCOET_LOG("fcoet_process_sol_abts_acc", + "not supported this kind frame"); + FCOET_RELE_XCHG(xch); + return (FCOE_FAILURE); + } + FCOET_LOG("fcoet_process_sol_abts_acc", + "ABTS received but there is nothing to do"); + return (FCOE_SUCCESS); +} + +static int +fcoet_process_sol_abts_rjt(fcoe_frame_t *frm) +{ + fcoet_exchange_t *xch = NULL; + uint16_t sol_oxid; + + sol_oxid = FRM_OXID(frm); + if (mod_hash_remove(FRM2SS(frm)->ss_sol_oxid_hash, + (mod_hash_key_t)(intptr_t)sol_oxid, + (mod_hash_val_t *)&xch) != 0) { + /* + * So far ABTS for FLOGI might be removed from ss_sol_oxid_hash + * in fcoet_watch_handle_sol_flogi, Will improve it later + */ + return (FCOE_SUCCESS); + } + + xch->xch_flags &= ~XCH_FLAG_IN_HASH_TABLE; + + if (!FRM_IS_LAST_FRAME(frm)) { + FCOET_LOG("fcoet_process_sol_abts_rjt", + "not supported this kind frame"); + return (FCOE_FAILURE); + } + + FCOET_LOG("fcoet_process_sol_abts_rjt", + "ABTS_RJT received rjt reason %x but there is nothing to do", + frm->frm_payload[1]); + return (FCOE_SUCCESS); +} + +static int +fcoet_process_unsol_ct_req(fcoe_frame_t *frm) +{ + /* + * If you want to implement virtual name server, or FC/ETH + * gateway, you can do it here + */ + if (!FRM_IS_LAST_FRAME(frm)) { + FCOET_LOG("fcoet_process_unsol_ct_req", + "not supported this kind frame"); + return (FCOE_FAILURE); + } + + FCOET_LOG("fcoet_process_unsol_ct_req", + "No support for unsolicited CT request"); + return (FCOE_SUCCESS); +} + +static int +fcoet_process_sol_ct_rsp(fcoe_frame_t *frm) +{ + uint32_t actual_size; + fct_status_t fc_st; + uint32_t iof; + fct_sol_ct_t *ct = NULL; + fcoet_exchange_t *xch = NULL; + uint16_t sol_oxid; + + sol_oxid = FRM_OXID(frm); + + if (mod_hash_remove(FRM2SS(frm)->ss_sol_oxid_hash, + (mod_hash_key_t)(intptr_t)sol_oxid, + (mod_hash_val_t *)&xch) != 0) { + return (FCOE_SUCCESS); + } + + xch->xch_flags &= ~XCH_FLAG_IN_HASH_TABLE; + fcoet_init_tfm(frm, xch); + + ASSERT(FRM_IS_LAST_FRAME(frm)); + actual_size = CMD2ELS(xch->xch_cmd)->els_resp_size; + if (actual_size > frm->frm_payload_size) { + actual_size = frm->frm_payload_size; + } + ct = CMD2CT(xch->xch_cmd); + ct->ct_resp_size = (uint16_t)actual_size; + + bcopy(frm->frm_payload, + CMD2CT(xch->xch_cmd)->ct_resp_payload, actual_size); + + fc_st = FCT_SUCCESS; + iof = FCT_IOF_FCA_DONE; + fct_send_cmd_done(xch->xch_cmd, fc_st, iof); + + return (FCOE_SUCCESS); +} + +static int +fcoet_send_sol_fcp_data_done(fcoe_frame_t *frm) +{ + fcoet_exchange_t *xch = FRM2TFM(frm)->tfm_xch; + stmf_data_buf_t *dbuf; + int dbuf_index; + uint32_t iof; + + dbuf_index = FRM2TFM(frm)->tfm_buf_idx; + xch->xch_left_data_size -= frm->frm_payload_size; + dbuf = xch->xch_dbufs[dbuf_index]; + ASSERT((dbuf) && (dbuf->db_flags & DB_DIRECTION_TO_RPORT)); + + /* + * We decrease db_sglist_length only for READ-type commands. + * For INQUIRY, resid could be non-zero, then db_sglist_length will + * be useful. + */ + dbuf->db_sglist_length--; + if ((xch->xch_left_data_size <= 0) || (!dbuf->db_sglist_length)) { + iof = 0; + dbuf->db_xfer_status = FCT_SUCCESS; + dbuf->db_flags |= DB_DONT_REUSE; + if (dbuf->db_flags & DB_SEND_STATUS_GOOD) { + if (fcoet_send_status(xch->xch_cmd) != FCT_SUCCESS) { + return (FCOE_FAILURE); + } + } else { + fct_scsi_data_xfer_done(xch->xch_cmd, dbuf, iof); + } + } + FCOET_RELE_XCHG(xch); + return (FCOE_SUCCESS); +} + +static int +fcoet_send_fcp_status_done(fcoe_frame_t *frm) +{ + fcoet_exchange_t *xch = FRM2TFM(frm)->tfm_xch; + fct_status_t fc_st = FCT_SUCCESS; + uint32_t iof = FCT_IOF_FCA_DONE; + + if (xch->xch_flags & XCH_FLAG_FCT_CALLED_ABORT) { + FCOET_RELE_XCHG(xch); + return (FCOE_SUCCESS); + } + + if (fcoet_clear_unsol_exchange(xch) == FCOE_SUCCESS) { + FCOET_RELE_XCHG(xch); + fct_send_response_done(xch->xch_cmd, fc_st, iof); + } else { + /* Already cleared from hash table by abort */ + FCOET_RELE_XCHG(xch); + } + + return (FCOE_SUCCESS); +} + +/* + * Solicited frames callback area + */ +static int +fcoet_send_unsol_els_rsp_done(fcoe_frame_t *frm) +{ + fcoet_exchange_t *xch = FRM2TFM(frm)->tfm_xch; + fct_status_t fc_st; + uint32_t iof; + + FCOET_EXT_LOG("fcoet_send_unsol_els_rsp_done", + "frm/oxid/els: %p/%x/%x", + frm, FRM_OXID(frm), XCH2ELS(xch)->els_req_payload[0]); + if (xch->xch_flags & XCH_FLAG_FCT_CALLED_ABORT) { + FCOET_RELE_XCHG(xch); + return (FCOE_SUCCESS); + } + + if (fcoet_clear_unsol_exchange(xch) == FCOE_FAILURE) { + FCOET_RELE_XCHG(xch); + return (FCOE_SUCCESS); + } + + FCOET_RELE_XCHG(xch); + if (XCH2ELS(xch)->els_req_payload[0] != ELS_OP_FLOGI) { + fc_st = FCT_SUCCESS; + iof = FCT_IOF_FCA_DONE; + fct_send_response_done(xch->xch_cmd, fc_st, iof); + } else { + /* + * We need update ss_link_info and flags. + */ + mutex_enter(&xch->xch_ss->ss_watch_mutex); + xch->xch_ss->ss_link_info.portid = + xch->xch_cmd->cmd_lportid; + xch->xch_ss->ss_link_info.port_topology = + PORT_TOPOLOGY_PT_TO_PT; + if (frm->frm_eport->eport_link_speed == FCOE_PORT_SPEED_1G) { + xch->xch_ss->ss_link_info.port_speed = PORT_SPEED_1G; + } else if (frm->frm_eport->eport_link_speed == + FCOE_PORT_SPEED_10G) { + xch->xch_ss->ss_link_info.port_speed = PORT_SPEED_10G; + } + xch->xch_ss->ss_link_info.port_no_fct_flogi = 1; + xch->xch_ss->ss_link_info.port_fca_flogi_done = 1; + xch->xch_ss->ss_link_info.port_fct_flogi_done = 0; + bcopy(XCH2ELS(xch)->els_req_payload + 20, + xch->xch_ss->ss_link_info.port_rpwwn, 8); + bcopy(XCH2ELS(xch)->els_req_payload + 28, + xch->xch_ss->ss_link_info.port_rnwwn, 8); + atomic_or_32(&xch->xch_ss->ss_flags, + SS_FLAG_UNSOL_FLOGI_DONE); + atomic_or_32(&xch->xch_ss->ss_flags, + SS_FLAG_REPORT_TO_FCT); + + xch->xch_ss->ss_sol_flogi_state = SFS_FLOGI_ACC; + mutex_exit(&xch->xch_ss->ss_watch_mutex); + + fct_free(xch->xch_cmd); + } + return (FCOE_SUCCESS); +} + +/* ARGSUSED */ +static int +fcoet_send_sol_els_req_done(fcoe_frame_t *frm) +{ + return (FCOE_SUCCESS); +} + +/* + * FCT have released relevant fct_cmd_t and fcoet_exchange_t now, so it's not + * needed to notify FCT anything. Just do nothing. + */ +/* ARGSUSED */ +static int +fcoet_send_unsol_bls_acc_done(fcoe_frame_t *frm) +{ + FCOET_LOG("fcoet_send_unsol_bls_acc_done", + "Unsolicited BA_ACC sent out and released "); + + return (FCOE_SUCCESS); +} + +/* ARGSUSED */ +static int +fcoet_send_unsol_bls_rjt_done(fcoe_frame_t *frm) +{ + FCOET_LOG("fcoet_send_unsol_bls_rjt_done", + "Unsolicited BA_RJT sent out and released"); + return (FCOE_SUCCESS); +} + +/* ARGSUSED */ +static int +fcoet_send_sol_bls_req_done(fcoe_frame_t *frm) +{ + FCOET_LOG("fcoet_send_sol_bls_req_done", + "Soclited ABTS was sent out and released"); + return (FCOE_SUCCESS); +} + +/* ARGSUSED */ +static int +fcoet_send_sol_ct_req_done(fcoe_frame_t *frm) +{ + FCOET_LOG("fcoet_send_sol_ct_req_done", + "CT request was sent out and released"); + return (FCOE_SUCCESS); +} + +/* + * FCoET can only interpret solicited and unsolicited FLOGI, all the other + * ELS/CT/FCP should be passed up to FCT. + */ +static int +fcoet_process_unsol_flogi_req(fcoet_exchange_t *xch) +{ + fcoe_frame_t *frm; + + atomic_or_32(&xch->xch_ss->ss_flags, SS_FLAG_DELAY_PLOGI); + + /* + * In spec, common service parameter should indicate if it's from + * N-port or F-port, but the initial intel implementation is not + * spec-compliant, so we use eport_flags to workaround the problem + */ + if (!(xch->xch_ss->ss_eport->eport_flags & EPORT_FLAG_IS_DIRECT_P2P)) { + /* + * The topology is switch P2P, so there's no need to respond + * to this FLOGI + */ + FCOET_LOG("fcoet_process_unsol_flogi_req", + "skip FLOGI, since we are in switch topology"); + return (FCOE_SUCCESS); + } + + /* + * Send ACC according to the spec. + */ + frm = xch->xch_ss->ss_eport->eport_alloc_frame(xch->xch_ss->ss_eport, + FLOGI_ACC_PAYLOAD_SIZE + FCFH_SIZE, 0); + if (frm == NULL) { + ASSERT(0); + return (FCOE_FAILURE); + } else { + fcoet_init_tfm(frm, xch); + bzero(frm->frm_payload, frm->frm_payload_size); + } + + FFM_R_CTL(0x23, frm); + FRM2TFM(frm)->tfm_rctl = 0x23; + FFM_TYPE(0x01, frm); + FFM_F_CTL(0x980000, frm); + FFM_OXID(xch->xch_oxid, frm); + FFM_RXID(xch->xch_rxid, frm); + FFM_S_ID(0xFFFFFE, frm); + + /* + * ACC + */ + frm->frm_payload[0] = 0x02; + + /* + * Common Svc Parameters + */ + frm->frm_payload[4] = 0x20; + frm->frm_payload[5] = 0x20; + frm->frm_payload[7] = 0x0A; + frm->frm_payload[10] = 0x05; + frm->frm_payload[11] = 0xAC; + bcopy(xch->xch_ss->ss_eport->eport_portwwn, frm->frm_payload + 20, 8); + bcopy(xch->xch_ss->ss_eport->eport_nodewwn, frm->frm_payload + 28, 8); + + /* + * Class3 Svc Parameters + */ + frm->frm_payload[68] = 0x88; + + /* + * Send FLOGI ACC out + * After this, we should never use the exchange, because it could + * have been released. Please pay attention to other similiar cases. + */ + xch->xch_ss->ss_eport->eport_tx_frame(frm); + return (FCOE_SUCCESS); +} + +static int +fcoet_process_sol_flogi_rsp(fcoe_frame_t *frm) +{ + int ret = FCOE_SUCCESS; + fcoet_exchange_t *xch = FRM2TFM(frm)->tfm_xch; + fct_els_t *els = CMD2ELS(xch->xch_cmd); + + if (els->els_resp_payload[0] == ELS_OP_ACC) { + /* + * We need always update ss_link_info and flags for solicited + * FLOGI, because someone has assigned address for you. The + * initial intel implementation will always assign address for + * you even you are in back-to-back mode (direct P2P). + */ + mutex_enter(&xch->xch_ss->ss_watch_mutex); + if (xch->xch_flags & XCH_FLAG_NONFCP_REQ_SENT) { + xch->xch_cmd->cmd_lportid = FRM_D_ID(frm); + xch->xch_ss->ss_link_info.portid = + xch->xch_cmd->cmd_lportid; + /* + * Check the bit 28 in 3rd word of the payload + * in common service parameters to know the + * remote port is F_PORT or N_PORT + */ + if (els->els_resp_payload[8] & 0x10) { + uint8_t src_addr[ETHERADDRL]; + frm->frm_eport->eport_flags &= + ~EPORT_FLAG_IS_DIRECT_P2P; + FCOE_SET_DEFAULT_OUI(src_addr); + bcopy(frm->frm_hdr->hdr_d_id, src_addr + 3, 3); + bcopy((char *)frm->frm_hdr-22, + frm->frm_eport->eport_efh_dst, + ETHERADDRL); + frm->frm_eport->eport_set_mac_address( + frm->frm_eport, src_addr, B_TRUE); + xch->xch_ss->ss_link_info.port_topology = + PORT_TOPOLOGY_FABRIC_PT_TO_PT; + } else { + xch->xch_ss->ss_link_info.port_topology = + PORT_TOPOLOGY_PT_TO_PT; + } + + xch->xch_ss->ss_link_info.port_speed = PORT_SPEED_10G; + xch->xch_ss->ss_link_info.port_no_fct_flogi = 1; + xch->xch_ss->ss_link_info.port_fca_flogi_done = 1; + xch->xch_ss->ss_link_info.port_fct_flogi_done = 0; + xch->xch_ss->ss_sol_flogi_state = SFS_FLOGI_ACC; + cv_signal(&xch->xch_ss->ss_watch_cv); + FCOET_LOG("fcoet_process_sol_flogi_rsp", + "FLOGI is accecpted"); + } else { + FCOET_LOG("fcoet_process_sol_flogi_rsp", + "FLOGI xch_flags/%x", xch->xch_flags); + ret = FCOE_FAILURE; + } + mutex_exit(&xch->xch_ss->ss_watch_mutex); + } else { + FCOET_LOG("fcoet_process_sol_flogi_rsp", "FLOGI is rejected"); + ret = FCOE_FAILURE; + } + return (ret); +} diff --git a/usr/src/uts/common/io/comstar/port/fcoet/fcoet_eth.h b/usr/src/uts/common/io/comstar/port/fcoet/fcoet_eth.h new file mode 100644 index 0000000000..87a25296c5 --- /dev/null +++ b/usr/src/uts/common/io/comstar/port/fcoet/fcoet_eth.h @@ -0,0 +1,46 @@ +/* + * 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 _FCOET_ETH_H +#define _FCOET_ETH_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _KERNEL + +void fcoet_rx_frame(fcoe_frame_t *frame); +void fcoet_port_event(fcoe_port_t *eport, uint32_t event); +void fcoet_release_sol_frame(fcoe_frame_t *frame); +int fcoet_clear_unsol_exchange(fcoet_exchange_t *xch); +void fcoet_clear_sol_exchange(fcoet_exchange_t *xch); + +#endif /* _KERNEL */ + +#ifdef __cplusplus +} +#endif + +#endif /* _FCOET_ETH_H */ diff --git a/usr/src/uts/common/io/comstar/port/fcoet/fcoet_fc.c b/usr/src/uts/common/io/comstar/port/fcoet/fcoet_fc.c new file mode 100644 index 0000000000..86e97006ee --- /dev/null +++ b/usr/src/uts/common/io/comstar/port/fcoet/fcoet_fc.c @@ -0,0 +1,1053 @@ +/* + * 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. + */ + +/* + * This file defines interfaces between fcoe and fct driver. + */ + +/* + * Driver kernel header files + */ +#include <sys/conf.h> +#include <sys/ddi.h> +#include <sys/stat.h> +#include <sys/pci.h> +#include <sys/sunddi.h> +#include <sys/modctl.h> +#include <sys/file.h> +#include <sys/cred.h> +#include <sys/byteorder.h> +#include <sys/atomic.h> +#include <sys/modhash.h> +#include <sys/scsi/scsi.h> +#include <sys/ethernet.h> + +/* + * COMSTAR header files + */ +#include <sys/stmf_defines.h> +#include <sys/fct_defines.h> +#include <sys/stmf.h> +#include <sys/portif.h> +#include <sys/fct.h> + +/* + * FCoE hader files + */ +#include <sys/fcoe/fcoe_common.h> + +/* + * Driver's own header files + */ +#include <fcoet.h> +#include <fcoet_fc.h> +#include <fcoet_eth.h> + +/* + * function forward declaration + */ +static fct_status_t fcoet_fill_plogi_req(fct_local_port_t *port, + fct_remote_port_t *rp, fct_cmd_t *login); +static fct_status_t fcoet_fill_plogi_resp(fct_local_port_t *port, + fct_remote_port_t *rp, fct_cmd_t *login); +static fct_status_t fcoet_send_sol_els(fct_cmd_t *cmd); +static fct_status_t fcoet_send_sol_ct(fct_cmd_t *cmd); +static fct_status_t fcoet_send_good_status(fct_cmd_t *cmd); +static fct_status_t fcoet_send_els_response(fct_cmd_t *cmd); +static fct_status_t fcoet_send_abts_response(fct_cmd_t *cmd, uint32_t flags); +static fct_status_t fcoet_logo_fabric(fcoet_soft_state_t *ss); + +/* + * Return the lower link information + */ +fct_status_t +fcoet_get_link_info(fct_local_port_t *port, fct_link_info_t *li) +{ + bcopy(&PORT2SS(port)->ss_link_info, li, sizeof (fct_link_info_t)); + return (FCT_SUCCESS); +} + +/* + * FCT will call this, when it wants to send PLOGI or has received PLOGI. + */ +fct_status_t +fcoet_register_remote_port(fct_local_port_t *port, fct_remote_port_t *rp, + fct_cmd_t *login) +{ + uint16_t handle; + fct_status_t ret; + + switch (rp->rp_id) { + case 0xFFFFFC: + handle = 0x7FC; + break; + + case 0xFFFFFD: + handle = 0x7FD; + break; + + case 0xFFFFFE: + handle = 0x7FE; + break; + + case 0xFFFFFF: + handle = 0x7FF; + break; + + default: + /* + * For not well-known address, we let FCT to select one. + */ + handle = FCT_HANDLE_NONE; + break; + } + + rp->rp_handle = handle; + if (login->cmd_type == FCT_CMD_SOL_ELS) { + ret = fcoet_fill_plogi_req(port, rp, login); + } else { + ret = fcoet_fill_plogi_resp(port, rp, login); + } + + return (ret); +} + +/* + * FCT will call this to say "FCoET can release resources with this RP now." + */ +/* ARGSUSED */ +fct_status_t +fcoet_deregister_remote_port(fct_local_port_t *port, fct_remote_port_t *rp) +{ + fcoet_soft_state_t *this_ss = PORT2SS(port); + + this_ss->ss_rport_dereg_state = 0; + this_ss->ss_rportid_in_dereg = 0; + return (FCT_SUCCESS); +} + +fct_status_t +fcoet_send_cmd(fct_cmd_t *cmd) +{ + if (cmd->cmd_type == FCT_CMD_SOL_ELS) { + return (fcoet_send_sol_els(cmd)); + } else if (cmd->cmd_type == FCT_CMD_SOL_CT) { + return (fcoet_send_sol_ct(cmd)); + } + + return (FCT_FAILURE); +} + +/* + * SCSI response phase + * ELS_ACC/ELS_RJT + */ +fct_status_t +fcoet_send_cmd_response(fct_cmd_t *cmd, uint32_t ioflags) +{ + char info[160]; + + if (cmd->cmd_type == FCT_CMD_FCP_XCHG) { + if (ioflags & FCT_IOF_FORCE_FCA_DONE) { + goto send_cmd_rsp_error; + } else { + return (fcoet_send_status(cmd)); + } + } + + if (cmd->cmd_type == FCT_CMD_RCVD_ELS) { + if (ioflags & FCT_IOF_FORCE_FCA_DONE) { + goto send_cmd_rsp_error; + } else { + return (fcoet_send_els_response(cmd)); + } + } + + if (ioflags & FCT_IOF_FORCE_FCA_DONE) { + cmd->cmd_handle = 0; + } + + if (cmd->cmd_type == FCT_CMD_RCVD_ABTS) { + return (fcoet_send_abts_response(cmd, 0)); + } else { + ASSERT(0); + return (FCT_FAILURE); + } + +send_cmd_rsp_error: + (void) snprintf(info, 160, "fcoet_send_cmd_response: can not handle " + "FCT_IOF_FORCE_FCA_DONE for cmd %p, ioflags-%x", cmd, ioflags); + info[159] = 0; + (void) fct_port_shutdown(CMD2SS(cmd)->ss_port, + STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info); + return (FCT_FAILURE); +} + +/* + * It's for read/write (xfer_rdy) + */ +/* ARGSUSED */ +fct_status_t +fcoet_xfer_scsi_data(fct_cmd_t *cmd, stmf_data_buf_t *dbuf, uint32_t ioflags) +{ + fcoe_frame_t *frm; + int idx; + int frm_num; + int data_size; + int left_size; + int offset; + fcoet_exchange_t *xch = CMD2XCH(cmd); + + ASSERT(!xch->xch_dbufs[dbuf->db_relative_offset/FCOET_MAX_DBUF_LEN]); + xch->xch_dbufs[dbuf->db_relative_offset/FCOET_MAX_DBUF_LEN] = dbuf; + + left_size = (int)dbuf->db_data_size; + if (dbuf->db_relative_offset == 0) + xch->xch_left_data_size = + XCH2TASK(xch)->task_expected_xfer_length; + + if (dbuf->db_flags == DB_DIRECTION_FROM_RPORT) { + /* + * If it's write type command, we need send xfer_rdy now + * We may need to consider bidirectional command later + */ + frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame( + CMD2SS(cmd)->ss_eport, sizeof (fcoe_fcp_xfer_rdy_t) + + FCFH_SIZE, NULL); + if (frm == NULL) { + ASSERT(0); + return (FCT_FAILURE); + } else { + fcoet_init_tfm(frm, CMD2XCH(cmd)); + bzero(frm->frm_payload, frm->frm_payload_size); + } + + FFM_R_CTL(0x05, frm); + FRM2TFM(frm)->tfm_rctl = 0x05; + FFM_TYPE(0x08, frm); + FFM_F_CTL(0x890000, frm); + FFM_OXID(cmd->cmd_oxid, frm); + FFM_RXID(cmd->cmd_rxid, frm); + FFM_S_ID(cmd->cmd_lportid, frm); + FFM_D_ID(cmd->cmd_rportid, frm); + FCOE_V2B_4(dbuf->db_relative_offset, frm->frm_payload); + FCOE_V2B_4(dbuf->db_data_size, frm->frm_payload + 4); + CMD2SS(cmd)->ss_eport->eport_tx_frame(frm); + + return (FCT_SUCCESS); + } + + /* + * It's time to transfer READ data to remote side + */ + frm_num = (dbuf->db_data_size + CMD2SS(cmd)->ss_fcp_data_payload_size - + 1) / CMD2SS(cmd)->ss_fcp_data_payload_size; + offset = dbuf->db_relative_offset; + for (idx = 0; idx < frm_num; idx++) { + if (idx == (frm_num -1)) { + data_size = P2ROUNDUP(left_size, 4); + } else { + data_size = CMD2SS(cmd)->ss_fcp_data_payload_size; + } + + frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame( + CMD2SS(cmd)->ss_eport, data_size + FCFH_SIZE, + FCOET_GET_NETB(dbuf, idx)); + if (frm == NULL) { + ASSERT(0); + return (FCT_FAILURE); + } else { + fcoet_init_tfm(frm, CMD2XCH(cmd)); + /* + * lock the xchg to avoid being released (by abort) + * after sent out and before release + */ + FCOET_BUSY_XCHG(CMD2XCH(cmd)); + } + + FFM_R_CTL(0x01, frm); + FRM2TFM(frm)->tfm_rctl = 0x01; + FRM2TFM(frm)->tfm_buf_idx = + dbuf->db_relative_offset/FCOET_MAX_DBUF_LEN; + FFM_TYPE(0x08, frm); + if (idx != frm_num - 1) { + FFM_F_CTL(0x800008, frm); + } else { + FFM_F_CTL(0x880008, frm); + } + + FFM_OXID(cmd->cmd_oxid, frm); + FFM_RXID(cmd->cmd_rxid, frm); + FFM_S_ID(cmd->cmd_lportid, frm); + FFM_D_ID(cmd->cmd_rportid, frm); + FFM_SEQ_CNT(xch->xch_sequence_no, frm); + atomic_add_8(&xch->xch_sequence_no, 1); + FFM_PARAM(offset, frm); + offset += data_size; + left_size -= data_size; + + /* + * Disassociate netbs which will be freed by NIC driver + */ + FCOET_SET_NETB(dbuf, idx, NULL); + + CMD2SS(cmd)->ss_eport->eport_tx_frame(frm); + } + + return (FCT_SUCCESS); +} + +fct_status_t +fcoet_abort_cmd(struct fct_local_port *port, fct_cmd_t *cmd, uint32_t flags) +{ + fcoet_soft_state_t *this_ss = PORT2SS(port); + fct_status_t fct_ret = FCT_SUCCESS; + + FCOET_LOG("fcoet_abort_cmd", "cmd=%p, xch=%p, cmd_specific=%p", + cmd, cmd->cmd_fca_private, cmd->cmd_specific); + switch (cmd->cmd_type) { + case FCT_CMD_RCVD_ABTS: + /* + * Sometimes unsolicited ABTS request will be received twice + * and the first ABTS is not done yet, so the second ABTS + * will be passed down here, in this case we will do + * nothing and abts response is not needed to be sent + * fct_ret = fcoet_send_abts_response(cmd, 1); + */ + break; + case FCT_CMD_FCP_XCHG: + case FCT_CMD_RCVD_ELS: + if (CMD2XCH(cmd)->xch_flags & XCH_FLAG_FCT_CALLED_ABORT) { + break; + } + + CMD2XCH(cmd)->xch_flags |= XCH_FLAG_FCT_CALLED_ABORT; + (void) fcoet_clear_unsol_exchange(CMD2XCH(cmd)); + if (!(flags & FCT_IOF_FORCE_FCA_DONE)) { + mutex_enter(&this_ss->ss_watch_mutex); + CMD2XCH(cmd)->xch_start_time = ddi_get_lbolt(); + list_insert_tail(&this_ss->ss_abort_xchg_list, + CMD2XCH(cmd)); + cv_signal(&this_ss->ss_watch_cv); + mutex_exit(&this_ss->ss_watch_mutex); + } + break; + + case FCT_CMD_SOL_ELS: + case FCT_CMD_SOL_CT: + if (CMD2XCH(cmd)->xch_flags & XCH_FLAG_FCT_CALLED_ABORT) { + break; + } + + CMD2XCH(cmd)->xch_flags |= XCH_FLAG_FCT_CALLED_ABORT; + fcoet_clear_sol_exchange(CMD2XCH(cmd)); + + if (!(flags & FCT_IOF_FORCE_FCA_DONE)) { + mutex_enter(&this_ss->ss_watch_mutex); + CMD2XCH(cmd)->xch_start_time = ddi_get_lbolt(); + cv_signal(&this_ss->ss_watch_cv); + list_insert_tail(&this_ss->ss_abort_xchg_list, + CMD2XCH(cmd)); + mutex_exit(&this_ss->ss_watch_mutex); + } + + break; + + default: + ASSERT(0); + break; + } + + if ((flags & FCT_IOF_FORCE_FCA_DONE) && + (cmd->cmd_type != FCT_CMD_FCP_XCHG)) { + cmd->cmd_handle = 0; + } + + return (fct_ret); +} + +/* ARGSUSED */ +fct_status_t +fcoet_do_flogi(fct_local_port_t *port, fct_flogi_xchg_t *fx) +{ + cmn_err(CE_WARN, "FLOGI requested (not supported)"); + return (FCT_FAILURE); +} + +void +fcoet_send_sol_flogi(fcoet_soft_state_t *ss) +{ + fcoet_exchange_t *xch; + fct_cmd_t *cmd; + fct_els_t *els; + fcoe_frame_t *frm; + + /* + * FCT will initialize fct_cmd_t + * Initialize fcoet_exchange + */ + cmd = (fct_cmd_t *)fct_alloc(FCT_STRUCT_CMD_SOL_ELS, + sizeof (fcoet_exchange_t), 0); + xch = CMD2XCH(cmd); + els = CMD2ELS(cmd); + + xch->xch_oxid = atomic_add_16_nv(&ss->ss_next_sol_oxid, 1); + if (xch->xch_oxid == 0xFFFF) { + xch->xch_oxid = + atomic_add_16_nv(&ss->ss_next_sol_oxid, 1); + } + xch->xch_rxid = 0xFFFF; + xch->xch_flags = 0; + xch->xch_ss = ss; + xch->xch_cmd = cmd; + xch->xch_current_seq = NULL; + xch->xch_start_time = ddi_get_lbolt(); + + /* + * Keep it to compare with response + */ + ss->ss_sol_flogi = xch; + els->els_resp_alloc_size = 116; + els->els_resp_size = 116; + els->els_resp_payload = (uint8_t *) + kmem_zalloc(els->els_resp_size, KM_SLEEP); + (void) mod_hash_insert(xch->xch_ss->ss_sol_oxid_hash, + (mod_hash_key_t)(uintptr_t)xch->xch_oxid, (mod_hash_val_t)xch); + xch->xch_flags |= XCH_FLAG_IN_HASH_TABLE; + atomic_or_32(&ss->ss_flags, SS_FLAG_DELAY_PLOGI); + + /* + * FCoE will initialize fcoe_frame_t + */ + frm = ss->ss_eport->eport_alloc_frame(ss->ss_eport, + FLOGI_REQ_PAYLOAD_SIZE + FCFH_SIZE, NULL); + if (frm == NULL) { + ASSERT(0); + return; + } else { + fcoet_init_tfm(frm, xch); + bzero(frm->frm_payload, frm->frm_payload_size); + } + + FFM_R_CTL(0x22, frm); + FRM2TFM(frm)->tfm_rctl = 0x22; + FFM_TYPE(0x01, frm); + FFM_F_CTL(0x290000, frm); + FFM_OXID(xch->xch_oxid, frm); + FFM_RXID(xch->xch_rxid, frm); + FFM_D_ID(0xfffffe, frm); + frm->frm_payload[0] = ELS_OP_FLOGI; + /* Common Service Parameters */ + frm->frm_payload[4] = 0x20; + frm->frm_payload[5] = 0x08; + frm->frm_payload[6] = 0x0; + frm->frm_payload[7] = 0x03; + /* N_PORT */ + frm->frm_payload[8] = 0x88; + frm->frm_payload[9] = 0x00; + frm->frm_payload[10] = 0x08; + frm->frm_payload[11] = 0x0; + frm->frm_payload[12] = 0x0; + frm->frm_payload[13] = 0xff; + frm->frm_payload[14] = 0x0; + frm->frm_payload[15] = 0x03; + frm->frm_payload[16] = 0x0; + frm->frm_payload[17] = 0x0; + frm->frm_payload[18] = 0x07; + frm->frm_payload[19] = 0xd0; + /* PWWN and NWWN */ + frm->frm_payload[20] = 0x0; + bcopy(ss->ss_eport->eport_portwwn, frm->frm_payload+20, 8); + bcopy(ss->ss_eport->eport_nodewwn, frm->frm_payload+28, 8); + /* Class 3 Service Parameters */ + frm->frm_payload[68] = 0x88; + frm->frm_payload[74] = 0x08; + frm->frm_payload[77] = 0xff; + + ss->ss_eport->eport_tx_frame(frm); + xch->xch_flags |= XCH_FLAG_NONFCP_REQ_SENT; +} + +/* + * This is for solicited FLOGI only + */ +void +fcoet_send_sol_abts(fcoet_exchange_t *xch) +{ + fcoe_frame_t *frm; + fcoet_soft_state_t *ss = xch->xch_ss; + + /* + * FCoE will initialize fcoe_frame_t + * ABTS has no payload + */ + frm = ss->ss_eport->eport_alloc_frame(ss->ss_eport, + FCFH_SIZE, NULL); + if (frm == NULL) { + ASSERT(0); + return; + } else { + fcoet_init_tfm(frm, xch); + frm->frm_payload = NULL; + } + + FFM_R_CTL(0x81, frm); + FRM2TFM(frm)->tfm_rctl = 0x81; + FFM_F_CTL(0x090000, frm); + FFM_OXID(xch->xch_oxid, frm); + FFM_RXID(xch->xch_rxid, frm); + FFM_D_ID(0xfffffe, frm); + FFM_SEQ_CNT(xch->xch_sequence_no, frm); + xch->xch_start_time = ddi_get_lbolt(); + + ss->ss_eport->eport_tx_frame(frm); +} + +void +fcoet_ctl(struct fct_local_port *port, int cmd, void *arg) +{ + stmf_change_status_t st; + stmf_state_change_info_t *ssci = (stmf_state_change_info_t *)arg; + fcoet_soft_state_t *this_ss = PORT2SS(port); + + st.st_completion_status = FCT_SUCCESS; + st.st_additional_info = NULL; + + switch (cmd) { + case FCT_CMD_PORT_ONLINE: + if (this_ss->ss_state == FCT_STATE_ONLINE) + st.st_completion_status = STMF_ALREADY; + else if (this_ss->ss_state != FCT_STATE_OFFLINE) + st.st_completion_status = FCT_FAILURE; + if (st.st_completion_status == FCT_SUCCESS) { + this_ss->ss_state = FCT_STATE_ONLINING; + this_ss->ss_state_not_acked = 1; + st.st_completion_status = fcoet_enable_port(this_ss); + if (st.st_completion_status != STMF_SUCCESS) { + this_ss->ss_state = FCT_STATE_OFFLINE; + this_ss->ss_state_not_acked = 0; + } else { + this_ss->ss_state = FCT_STATE_ONLINE; + } + } + fct_ctl(port->port_lport, FCT_CMD_PORT_ONLINE_COMPLETE, &st); + this_ss->ss_change_state_flags = 0; + break; + + case FCT_CMD_PORT_OFFLINE: + if (this_ss->ss_state == FCT_STATE_OFFLINE) { + st.st_completion_status = STMF_ALREADY; + } else if (this_ss->ss_state != FCT_STATE_ONLINE) { + st.st_completion_status = FCT_FAILURE; + } + if (st.st_completion_status == FCT_SUCCESS) { + this_ss->ss_state = FCT_STATE_OFFLINING; + this_ss->ss_state_not_acked = 1; + this_ss->ss_change_state_flags = ssci->st_rflags; + st.st_completion_status = fcoet_disable_port(this_ss); + if (st.st_completion_status != STMF_SUCCESS) { + this_ss->ss_state = FCT_STATE_ONLINE; + this_ss->ss_state_not_acked = 0; + } else { + this_ss->ss_state = FCT_STATE_OFFLINE; + } + } + fct_ctl(port->port_lport, FCT_CMD_PORT_OFFLINE_COMPLETE, &st); + break; + + case FCT_ACK_PORT_ONLINE_COMPLETE: + this_ss->ss_state_not_acked = 0; + break; + + case FCT_ACK_PORT_OFFLINE_COMPLETE: + this_ss->ss_state_not_acked = 0; + if (this_ss->ss_change_state_flags & STMF_RFLAG_RESET) { + if (fct_port_initialize(port, + this_ss->ss_change_state_flags, + "fcoet_ctl FCT_ACK_PORT_OFFLINE_COMPLETE " + "with RLFLAG_RESET") != FCT_SUCCESS) { + cmn_err(CE_WARN, "fcoet_ctl: " + "fct_port_initialize %s failed", + this_ss->ss_alias); + FCOET_LOG("fcoet_ctl: fct_port_initialize " + "%s failed", this_ss->ss_alias); + } + } + break; + default: + FCOET_LOG("fcoet_ctl", "Unsupported cmd %x", cmd); + break; + } +} + +/* + * Filling the hba attributes + */ +/* ARGSUSED */ +void +fcoet_populate_hba_fru_details(struct fct_local_port *port, + struct fct_port_attrs *port_attrs) +{ + (void) snprintf(port_attrs->manufacturer, FCHBA_MANUFACTURER_LEN, + "Sun Microsystems, Inc."); + (void) snprintf(port_attrs->driver_name, FCHBA_DRIVER_NAME_LEN, + "%s", FCOET_NAME); + (void) snprintf(port_attrs->driver_version, FCHBA_DRIVER_VERSION_LEN, + "%s", FCOET_VERSION); + (void) strcpy(port_attrs->serial_number, "N/A"); + (void) strcpy(port_attrs->hardware_version, "N/A"); + (void) strcpy(port_attrs->model, "FCoE Virtual FC HBA"); + (void) strcpy(port_attrs->model_description, "N/A"); + (void) strcpy(port_attrs->firmware_version, "N/A"); + (void) strcpy(port_attrs->option_rom_version, "N/A"); + + port_attrs->vendor_specific_id = 0xFC0E; + port_attrs->max_frame_size = 2136; + port_attrs->supported_cos = 0x10000000; + /* Specified a fix speed here, need to change it in the future */ + port_attrs->supported_speed = PORT_SPEED_1G | PORT_SPEED_10G; +} + + +static fct_status_t +fcoet_send_sol_els(fct_cmd_t *cmd) +{ + fcoe_frame_t *frm; + fcoet_exchange_t *xch = NULL; + + xch = CMD2XCH(cmd); + xch->xch_flags = 0; + xch->xch_ss = CMD2SS(cmd); + xch->xch_cmd = cmd; + xch->xch_current_seq = NULL; + xch->xch_left_data_size = 0; + xch->xch_sequence_no = 0; + xch->xch_start_time = ddi_get_lbolt(); + xch->xch_rxid = 0xFFFF; + xch->xch_oxid = atomic_add_16_nv(&xch->xch_ss->ss_next_sol_oxid, 1); + if (xch->xch_oxid == 0xFFFF) { + xch->xch_oxid = + atomic_add_16_nv(&xch->xch_ss->ss_next_sol_oxid, 1); + } + + frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(CMD2SS(cmd)->ss_eport, + CMD2ELS(cmd)->els_req_size + FCFH_SIZE, NULL); + if (frm == NULL) { + ASSERT(0); + return (FCT_FAILURE); + } else { + fcoet_init_tfm(frm, CMD2XCH(cmd)); + bzero(frm->frm_payload, frm->frm_payload_size); + } + + (void) mod_hash_insert(FRM2SS(frm)->ss_sol_oxid_hash, + (mod_hash_key_t)(uintptr_t)xch->xch_oxid, (mod_hash_val_t)xch); + xch->xch_flags |= XCH_FLAG_IN_HASH_TABLE; + bcopy(CMD2ELS(cmd)->els_req_payload, frm->frm_payload, + frm->frm_payload_size); + FFM_R_CTL(0x22, frm); + FRM2TFM(frm)->tfm_rctl = 0x22; + FFM_TYPE(0x01, frm); + FFM_F_CTL(0x290000, frm); + FFM_OXID(xch->xch_oxid, frm); + FFM_RXID(xch->xch_rxid, frm); + FFM_S_ID(cmd->cmd_lportid, frm); + FFM_D_ID(cmd->cmd_rportid, frm); + CMD2SS(cmd)->ss_eport->eport_tx_frame(frm); + + return (FCT_SUCCESS); +} + +static fct_status_t +fcoet_send_sol_ct(fct_cmd_t *cmd) +{ + fcoe_frame_t *frm; + fcoet_exchange_t *xch; + + xch = CMD2XCH(cmd); + xch->xch_flags = 0; + xch->xch_ss = CMD2SS(cmd); + xch->xch_cmd = cmd; + xch->xch_current_seq = NULL; + xch->xch_left_data_size = 0; + xch->xch_sequence_no = 0; + xch->xch_start_time = ddi_get_lbolt(); + xch->xch_rxid = 0xFFFF; + xch->xch_oxid = atomic_add_16_nv(&xch->xch_ss->ss_next_sol_oxid, 1); + if (xch->xch_oxid == 0xFFFF) { + xch->xch_oxid = + atomic_add_16_nv(&xch->xch_ss->ss_next_sol_oxid, 1); + } + + frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(CMD2SS(cmd)->ss_eport, + CMD2ELS(cmd)->els_req_size + FCFH_SIZE, NULL); + if (frm == NULL) { + ASSERT(0); + return (FCT_FAILURE); + } else { + fcoet_init_tfm(frm, CMD2XCH(cmd)); + bzero(frm->frm_payload, frm->frm_payload_size); + } + + (void) mod_hash_insert(FRM2SS(frm)->ss_sol_oxid_hash, + (mod_hash_key_t)(uintptr_t)xch->xch_oxid, (mod_hash_val_t)xch); + xch->xch_flags |= XCH_FLAG_IN_HASH_TABLE; + bcopy(CMD2ELS(cmd)->els_req_payload, frm->frm_payload, + frm->frm_payload_size); + FFM_R_CTL(0x2, frm); + FRM2TFM(frm)->tfm_rctl = 0x2; + FFM_TYPE(0x20, frm); + FFM_F_CTL(0x290000, frm); + FFM_OXID(xch->xch_oxid, frm); + FFM_RXID(xch->xch_rxid, frm); + FFM_S_ID(cmd->cmd_lportid, frm); + FFM_D_ID(cmd->cmd_rportid, frm); + CMD2SS(cmd)->ss_eport->eport_tx_frame(frm); + + return (FCT_SUCCESS); +} + +fct_status_t +fcoet_send_status(fct_cmd_t *cmd) +{ + fcoe_frame_t *frm; + scsi_task_t *task = CMD2TASK(cmd); + fcoe_fcp_rsp_t *ffr; + int raw_frame_size; + + /* + * Fast channel for good status phase + */ + if (task->task_scsi_status == STATUS_GOOD && !task->task_resid) { + return (fcoet_send_good_status(cmd)); + } + + raw_frame_size = FCFH_SIZE + sizeof (fcoe_fcp_rsp_t); + if (task->task_scsi_status == STATUS_CHECK) { + raw_frame_size += task->task_sense_length; + } + raw_frame_size = P2ROUNDUP(raw_frame_size, 4); + + frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(CMD2SS(cmd)->ss_eport, + raw_frame_size, NULL); + if (frm == NULL) { + ASSERT(0); + return (FCT_FAILURE); + } else { + fcoet_init_tfm(frm, CMD2XCH(cmd)); + bzero(frm->frm_payload, frm->frm_payload_size); + /* + * lock the xchg to avoid being released (by abort) + * after sent out and before release + */ + FCOET_BUSY_XCHG(CMD2XCH(cmd)); + } + + /* + * If there's sense data, copy it first + */ + if ((task->task_scsi_status == STATUS_CHECK) && + task->task_sense_length) { + bcopy(task->task_sense_data, frm->frm_payload + + sizeof (fcoe_fcp_rsp_t), task->task_sense_length); + } + + /* + * Fill fcp_rsp + */ + ffr = (fcoe_fcp_rsp_t *)frm->frm_payload; + FCOE_V2B_4(0, ffr->ffr_retry_delay_timer); + FCOE_V2B_1(0, ffr->ffr_flags); + if (task->task_scsi_status == STATUS_CHECK || task->task_resid) { + if (task->task_scsi_status == STATUS_CHECK) { + ffr->ffr_flags[0] |= BIT_1; + } + if (task->task_status_ctrl == TASK_SCTRL_OVER) { + ffr->ffr_flags[0] |= BIT_2; + } else if (task->task_status_ctrl == TASK_SCTRL_UNDER) { + ffr->ffr_flags[0] |= BIT_3; + } + } + FCOE_V2B_1(task->task_scsi_status, ffr->ffr_scsi_status); + FCOE_V2B_4(task->task_resid, ffr->ffr_resid); + FCOE_V2B_4(task->task_sense_length, ffr->ffr_sns_len); + FCOE_V2B_4(0, ffr->ffr_rsp_len); + + /* + * Fill fc frame header + */ + FFM_R_CTL(0x07, frm); + FRM2TFM(frm)->tfm_rctl = 0x07; + FFM_TYPE(0x08, frm); + FFM_F_CTL(0x990000, frm); + FFM_OXID(cmd->cmd_oxid, frm); + FFM_RXID(cmd->cmd_rxid, frm); + FFM_S_ID(cmd->cmd_lportid, frm); + FFM_D_ID(cmd->cmd_rportid, frm); + FFM_SEQ_ID(0x01, frm); + CMD2SS(cmd)->ss_eport->eport_tx_frame(frm); + + return (FCT_SUCCESS); +} + +static fct_status_t +fcoet_send_els_response(fct_cmd_t *cmd) +{ + fcoe_frame_t *frm; + + frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(CMD2SS(cmd)->ss_eport, + CMD2ELS(cmd)->els_resp_size + FCFH_SIZE, NULL); + if (frm == NULL) { + ASSERT(0); + return (FCT_FAILURE); + } else { + fcoet_init_tfm(frm, CMD2XCH(cmd)); + bzero(frm->frm_payload, frm->frm_payload_size); + /* + * lock the xchg to avoid being released (by abort) + * after sent out and before release + */ + FCOET_BUSY_XCHG(CMD2XCH(cmd)); + } + + bcopy(CMD2ELS(cmd)->els_resp_payload, frm->frm_payload, + frm->frm_payload_size); + FFM_R_CTL(0x23, frm); + FRM2TFM(frm)->tfm_rctl = 0x23; + FFM_TYPE(0x01, frm); + FFM_F_CTL(0x980000, frm); + FFM_OXID(cmd->cmd_oxid, frm); + FFM_RXID(cmd->cmd_rxid, frm); + FFM_S_ID(cmd->cmd_lportid, frm); + FFM_D_ID(cmd->cmd_rportid, frm); + CMD2SS(cmd)->ss_eport->eport_tx_frame(frm); + + return (FCT_SUCCESS); +} + +/* ARGSUSED */ +static fct_status_t +fcoet_send_abts_response(fct_cmd_t *cmd, uint32_t flags) +{ + fcoe_frame_t *frm; + fct_rcvd_abts_t *abts = (fct_rcvd_abts_t *)cmd->cmd_specific; + + /* + * The relevant fcoet_exchange has been released + */ + cmd->cmd_fca_private = NULL; + frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(CMD2SS(cmd)->ss_eport, + 12 + FCFH_SIZE, NULL); + if (frm == NULL) { + ASSERT(0); + return (FCT_FAILURE); + } else { + fcoet_init_tfm(frm, NULL); + } + + bcopy(abts->abts_resp_payload, frm->frm_payload, + frm->frm_payload_size); + FFM_R_CTL(abts->abts_resp_rctl, frm); + FRM2TFM(frm)->tfm_rctl = abts->abts_resp_rctl; + FFM_TYPE(0x00, frm); + FFM_F_CTL(0x980000, frm); + FFM_OXID(cmd->cmd_oxid, frm); + FFM_RXID(cmd->cmd_rxid, frm); + FFM_S_ID(cmd->cmd_lportid, frm); + FFM_D_ID(cmd->cmd_rportid, frm); + CMD2SS(cmd)->ss_eport->eport_tx_frame(frm); + + return (FCT_SUCCESS); +} + +/* + * enable/disable port is simple compared to physical FC HBAs + */ +fct_status_t +fcoet_enable_port(fcoet_soft_state_t *ss) +{ + FCOET_EXT_LOG(ss->ss_alias, "port is being enabled-%p", ss); + /* Call fcoe function to online the port */ + if (ss->ss_eport->eport_ctl(ss->ss_eport, FCOE_CMD_PORT_ONLINE, 0) == + FCOE_FAILURE) { + return (FCT_FAILURE); + } + + if ((ss->ss_flags & SS_FLAG_PORT_DISABLED) == SS_FLAG_PORT_DISABLED) { + atomic_and_32(&ss->ss_flags, ~SS_FLAG_PORT_DISABLED); + } + + return (FCT_SUCCESS); +} + +fct_status_t +fcoet_disable_port(fcoet_soft_state_t *ss) +{ + fct_status_t status; + + FCOET_EXT_LOG(ss->ss_alias, "port is being disabled-%p", ss); + /* Call fcoe function to offline the port */ + status = fcoet_logo_fabric(ss); + ss->ss_eport->eport_ctl(ss->ss_eport, FCOE_CMD_PORT_OFFLINE, 0); + atomic_or_32(&ss->ss_flags, SS_FLAG_PORT_DISABLED); + return (status); +} + +static fct_status_t +fcoet_logo_fabric(fcoet_soft_state_t *ss) +{ + fcoe_frame_t *frm; + uint32_t req_payload_size = 16; + uint16_t xch_oxid, xch_rxid = 0xFFFF; + + frm = ss->ss_eport->eport_alloc_frame(ss->ss_eport, + req_payload_size + FCFH_SIZE, NULL); + if (frm == NULL) { + ASSERT(0); + return (FCT_FAILURE); + } else { + fcoet_init_tfm(frm, NULL); + bzero(frm->frm_payload, frm->frm_payload_size); + } + xch_oxid = atomic_add_16_nv(&ss->ss_next_sol_oxid, 1); + if (xch_oxid == 0xFFFF) { + xch_oxid = atomic_add_16_nv(&ss->ss_next_sol_oxid, 1); + } + FFM_R_CTL(0x22, frm); + FRM2TFM(frm)->tfm_rctl = 0x22; + FFM_TYPE(0x01, frm); + FFM_F_CTL(0x290000, frm); + FFM_OXID(xch_oxid, frm); + FFM_RXID(xch_rxid, frm); + FFM_S_ID(ss->ss_link_info.portid, frm); + FFM_D_ID(0xfffffe, frm); + + FCOE_V2B_1(0x5, frm->frm_payload); + FCOE_V2B_3(ss->ss_link_info.portid, frm->frm_payload + 5); + bcopy(ss->ss_eport->eport_portwwn, frm->frm_payload + 8, 8); + ss->ss_eport->eport_tx_frame(frm); + + return (FCT_SUCCESS); + +} + +/* + * Called by: fcoet_register_remote_port + */ +/* ARGSUSED */ +static fct_status_t +fcoet_fill_plogi_req(fct_local_port_t *port, fct_remote_port_t *rp, + fct_cmd_t *login) +{ + uint8_t *p; + + p = ((fct_els_t *)login->cmd_specific)->els_req_payload; + p[0] = ELS_OP_PLOGI; + p[4] = 0x20; + p[5] = 0x20; + p[7] = 3; + p[8] = 0x88; + p[10] = 8; + p[13] = 0xff; p[15] = 0x1f; + p[18] = 7; p[19] = 0xd0; + + bcopy(port->port_pwwn, p + 20, 8); + bcopy(port->port_nwwn, p + 28, 8); + + p[68] = 0x80; + p[74] = 8; + p[77] = 0xff; + p[81] = 1; + + return (FCT_SUCCESS); +} + +/* + * Called by: fcoet_register_remote_port + */ +/* ARGSUSED */ +static fct_status_t +fcoet_fill_plogi_resp(fct_local_port_t *port, fct_remote_port_t *rp, + fct_cmd_t *login) +{ + uint8_t *p; + /* + * ACC + */ + p = ((fct_els_t *)login->cmd_specific)->els_req_payload; + p[0] = ELS_OP_ACC; + p[4] = 0x20; + p[5] = 0x20; + p[7] = 0x0A; + p[10] = 0x05; + p[11] = 0xAC; + + bcopy(port->port_pwwn, p + 20, 8); + bcopy(port->port_nwwn, p + 28, 8); + + p[68] = 0x88; + return (FCT_SUCCESS); +} + +static fct_status_t +fcoet_send_good_status(fct_cmd_t *cmd) +{ + fcoe_frame_t *frm; + int raw_frame_size; + + raw_frame_size = FCFH_SIZE + sizeof (fcoe_fcp_rsp_t); + frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(CMD2SS(cmd)->ss_eport, + raw_frame_size, NULL); + if (frm == NULL) { + ASSERT(0); + return (FCT_FAILURE); + } else { + fcoet_init_tfm(frm, CMD2XCH(cmd)); + bzero(frm->frm_payload, frm->frm_payload_size); + /* + * lock the xchg to avoid being released (by abort) + * after sent out and before release + */ + FCOET_BUSY_XCHG(CMD2XCH(cmd)); + } + + /* + * Fill fc frame header + */ + FFM_R_CTL(0x07, frm); + FRM2TFM(frm)->tfm_rctl = 0x07; + FFM_TYPE(0x08, frm); + FFM_F_CTL(0x990000, frm); + FFM_OXID(cmd->cmd_oxid, frm); + FFM_RXID(cmd->cmd_rxid, frm); + FFM_S_ID(cmd->cmd_lportid, frm); + FFM_D_ID(cmd->cmd_rportid, frm); + FFM_SEQ_ID(0x01, frm); + + CMD2SS(cmd)->ss_eport->eport_tx_frame(frm); + + return (FCT_SUCCESS); +} diff --git a/usr/src/uts/common/io/comstar/port/fcoet/fcoet_fc.h b/usr/src/uts/common/io/comstar/port/fcoet/fcoet_fc.h new file mode 100644 index 0000000000..163d9ba9ac --- /dev/null +++ b/usr/src/uts/common/io/comstar/port/fcoet/fcoet_fc.h @@ -0,0 +1,65 @@ +/* + * 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 _FCOET_FC_H +#define _FCOET_FC_H + +#include <sys/stmf_defines.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _KERNEL + +fct_status_t +fcoet_get_link_info(fct_local_port_t *port, fct_link_info_t *li); +fct_status_t fcoet_register_remote_port(fct_local_port_t *port, + fct_remote_port_t *rp, fct_cmd_t *login); +fct_status_t +fcoet_deregister_remote_port(fct_local_port_t *port, fct_remote_port_t *rp); +fct_status_t fcoet_send_cmd(fct_cmd_t *cmd); +fct_status_t fcoet_send_cmd_response(fct_cmd_t *cmd, uint32_t ioflags); +fct_status_t +fcoet_xfer_scsi_data(fct_cmd_t *cmd, stmf_data_buf_t *dbuf, uint32_t ioflags); +fct_status_t +fcoet_abort_cmd(struct fct_local_port *port, fct_cmd_t *cmd, uint32_t flags); +fct_status_t +fcoet_do_flogi(fct_local_port_t *port, fct_flogi_xchg_t *fx); +void fcoet_send_sol_flogi(fcoet_soft_state_t *ss); +void fcoet_send_sol_abts(fcoet_exchange_t *xch); +void fcoet_ctl(struct fct_local_port *port, int cmd, void *arg); +void fcoet_populate_hba_fru_details(struct fct_local_port *port, + struct fct_port_attrs *port_attrs); +fct_status_t fcoet_enable_port(fcoet_soft_state_t *ss); +fct_status_t fcoet_disable_port(fcoet_soft_state_t *ss); +fcoet_exchange_t *fcoet_init_sol_exchange(fct_cmd_t *cmd); + +#endif /* _KERNEL */ + +#ifdef __cplusplus +} +#endif + +#endif /* _FCOET_FC_H */ diff --git a/usr/src/uts/common/io/comstar/port/fct/discovery.c b/usr/src/uts/common/io/comstar/port/fct/discovery.c index 80116f8866..9db1776f39 100644 --- a/usr/src/uts/common/io/comstar/port/fct/discovery.c +++ b/usr/src/uts/common/io/comstar/port/fct/discovery.c @@ -218,14 +218,18 @@ fct_li_to_txt(fct_link_info_t *li, char *topology, char *speed) (void) strcpy(topology, topologies[li->port_topology]); } - if ((s == 0) || ((s & 0xf0) != 0) || ((s & (s - 1)) != 0)) { + if ((s == 0) || ((s & 0xf00) != 0) || ((s & (s - 1)) != 0)) { speed[0] = '?'; + } else if (s == PORT_SPEED_10G) { + speed[0] = '1'; + speed[1] = '0'; + speed[2] = 'G'; + speed[3] = 0; } else { speed[0] = '0' + li->port_speed; + speed[1] = 'G'; + speed[2] = 0; } - - speed[1] = 'G'; - speed[2] = 0; } /* diff --git a/usr/src/uts/common/io/comstar/port/fct/fct.c b/usr/src/uts/common/io/comstar/port/fct/fct.c index a5c2e57395..0bc0285a0d 100644 --- a/usr/src/uts/common/io/comstar/port/fct/fct.c +++ b/usr/src/uts/common/io/comstar/port/fct/fct.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -479,6 +479,8 @@ fct_get_adapter_port_attr(fct_i_local_port_t *ilport, uint8_t *pwwn, port_attr->PortSupportedSpeed |= FC_HBA_PORTSPEED_4GBIT; if (attr->supported_speed & PORT_SPEED_8G) port_attr->PortSupportedSpeed |= FC_HBA_PORTSPEED_8GBIT; + if (attr->supported_speed & PORT_SPEED_10G) + port_attr->PortSupportedSpeed |= FC_HBA_PORTSPEED_10GBIT; switch (iport->iport_link_info.port_speed) { case PORT_SPEED_1G: port_attr->PortSpeed = FC_HBA_PORTSPEED_1GBIT; @@ -492,6 +494,9 @@ fct_get_adapter_port_attr(fct_i_local_port_t *ilport, uint8_t *pwwn, case PORT_SPEED_8G: port_attr->PortSpeed = FC_HBA_PORTSPEED_8GBIT; break; + case PORT_SPEED_10G: + port_attr->PortSpeed = FC_HBA_PORTSPEED_10GBIT; + break; default: port_attr->PortSpeed = FC_HBA_PORTSPEED_UNKNOWN; break; diff --git a/usr/src/uts/common/io/comstar/stmf/stmf.c b/usr/src/uts/common/io/comstar/stmf/stmf.c index 83b4943bbd..685c9b1194 100644 --- a/usr/src/uts/common/io/comstar/stmf/stmf.c +++ b/usr/src/uts/common/io/comstar/stmf/stmf.c @@ -1341,8 +1341,21 @@ stmf_alloc(stmf_struct_id_t struct_id, int additional_size, int flags) if (sh == NULL) return (NULL); - sh->fp = (__istmf_t *)GET_BYTE_OFFSET(sh, stmf_sizes[struct_id].shared); - sh->cp = GET_BYTE_OFFSET(sh->fp, stmf_sizes[struct_id].fw_private); + /* + * In principle, the implementation inside stmf_alloc should not + * be changed anyway. But the original order of framework private + * data and caller private data does not support sglist in the caller + * private data. + * To work around this, the memory segments of framework private + * data and caller private data are re-ordered here. + * A better solution is to provide a specific interface to allocate + * the sglist, then we will not need this workaround any more. + * But before the new interface is available, the memory segment + * ordering should be kept as is. + */ + sh->cp = GET_BYTE_OFFSET(sh, stmf_sizes[struct_id].shared); + sh->fp = (__istmf_t *)GET_BYTE_OFFSET(sh, + stmf_sizes[struct_id].shared + additional_size); sh->fp->bp = sh; /* Just store the total size instead of storing additional size */ diff --git a/usr/src/uts/common/io/fcoe/fcoe.c b/usr/src/uts/common/io/fcoe/fcoe.c new file mode 100644 index 0000000000..e2dbe02921 --- /dev/null +++ b/usr/src/uts/common/io/fcoe/fcoe.c @@ -0,0 +1,1286 @@ +/* + * 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. + */ + +/* + * The following notice accompanied the original version of this file: + * + * BSD LICENSE + * + * Copyright(c) 2007 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Common FCoE interface interacts with MAC and FCoE clients, managing + * FCoE ports, doing MAC address discovery/managment, and FC frame + * encapsulation/decapsulation + */ + +#include <sys/stat.h> +#include <sys/conf.h> +#include <sys/file.h> +#include <sys/cred.h> + +#include <sys/ddi.h> +#include <sys/sunddi.h> +#include <sys/sunndi.h> +#include <sys/byteorder.h> +#include <sys/atomic.h> +#include <sys/sysmacros.h> +#include <sys/cmn_err.h> +#include <sys/crc32.h> +#include <sys/strsubr.h> + +#include <sys/mac_client.h> + +/* + * FCoE header files + */ +#include <sys/fcoe/fcoeio.h> +#include <sys/fcoe/fcoe_common.h> + +/* + * Driver's own header files + */ +#include <fcoe.h> +#include <fcoe_fc.h> +#include <fcoe_eth.h> + +/* + * Function forward declaration + */ +static int fcoe_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); +static int fcoe_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); +static int fcoe_bus_ctl(dev_info_t *fca_dip, dev_info_t *rip, + ddi_ctl_enum_t op, void *arg, void *result); +static int fcoe_open(dev_t *devp, int flag, int otype, cred_t *credp); +static int fcoe_close(dev_t dev, int flag, int otype, cred_t *credp); +static int fcoe_ioctl(dev_t dev, int cmd, intptr_t data, int mode, + cred_t *credp, int *rval); +static int fcoe_copyin_iocdata(intptr_t data, int mode, fcoeio_t **fcoeio, + void **ibuf, void **abuf, void **obuf); +static int fcoe_copyout_iocdata(intptr_t data, int mode, fcoeio_t *fcoeio, + void *obuf); +static int fcoe_iocmd(fcoe_soft_state_t *ss, intptr_t data, int mode); +static int fcoe_attach_init(fcoe_soft_state_t *this_ss); +static int fcoe_detach_uninit(fcoe_soft_state_t *this_ss); +static int fcoe_initchild(dev_info_t *fcoe_dip, dev_info_t *client_dip); +static int fcoe_uninitchild(dev_info_t *fcoe_dip, dev_info_t *client_dip); +static void fcoe_init_wwn_from_mac(uint8_t *wwn, uint8_t *mac, + int is_pwwn, uint8_t idx); +static fcoe_mac_t *fcoe_create_mac_by_name(uint8_t *name); +static int fcoe_cmp_wwn(fcoe_mac_t *checkedmac); +static void fcoe_watchdog(void *arg); +static void fcoe_worker_init(); +static int fcoe_worker_fini(); +static void fcoe_worker_frame(); +static int fcoe_get_port_list(fcoe_port_instance_t *ports, int count); + +/* + * Driver identificaton stuff + */ +static struct cb_ops fcoe_cb_ops = { + fcoe_open, + fcoe_close, + nodev, + nodev, + nodev, + nodev, + nodev, + fcoe_ioctl, + nodev, + nodev, + nodev, + nochpoll, + ddi_prop_op, + 0, + D_MP | D_NEW | D_HOTPLUG, + CB_REV, + nodev, + nodev +}; + +static struct bus_ops fcoe_busops = { + BUSO_REV, + nullbusmap, /* bus_map */ + NULL, /* bus_get_intrspec */ + NULL, /* bus_add_intrspec */ + NULL, /* bus_remove_intrspec */ + i_ddi_map_fault, /* bus_map_fault */ + ddi_dma_map, /* bus_dma_map */ + ddi_dma_allochdl, /* bus_dma_allochdl */ + ddi_dma_freehdl, /* bus_dma_freehdl */ + ddi_dma_bindhdl, /* bus_dma_bindhdl */ + ddi_dma_unbindhdl, /* bus_unbindhdl */ + ddi_dma_flush, /* bus_dma_flush */ + ddi_dma_win, /* bus_dma_win */ + ddi_dma_mctl, /* bus_dma_ctl */ + fcoe_bus_ctl, /* bus_ctl */ + ddi_bus_prop_op, /* bus_prop_op */ + NULL, /* bus_get_eventcookie */ + NULL, /* bus_add_eventcall */ + NULL, /* bus_remove_event */ + NULL, /* bus_post_event */ + NULL, /* bus_intr_ctl */ + NULL, /* bus_config */ + NULL, /* bus_unconfig */ + NULL, /* bus_fm_init */ + NULL, /* bus_fm_fini */ + NULL, /* bus_fm_access_enter */ + NULL, /* bus_fm_access_exit */ + NULL, /* bus_power */ + NULL +}; + +static struct dev_ops fcoe_ops = { + DEVO_REV, + 0, + nodev, + nulldev, + nulldev, + fcoe_attach, + fcoe_detach, + nodev, + &fcoe_cb_ops, + &fcoe_busops, + ddi_power +}; + +#define FCOE_VERSION "20090311-1.00" +#define FCOE_NAME "FCoE Transport v" FCOE_VERSION +#define TASKQ_NAME_LEN 32 + +static struct modldrv modldrv = { + &mod_driverops, + FCOE_NAME, + &fcoe_ops, +}; + +static struct modlinkage modlinkage = { + MODREV_1, &modldrv, NULL +}; + +/* + * TRACE for all FCoE related modules + */ +static kmutex_t fcoe_trace_buf_lock; +static int fcoe_trace_buf_curndx = 0; +static int fcoe_trace_on = 1; +static caddr_t fcoe_trace_buf = NULL; +static clock_t fcoe_trace_start = 0; +static caddr_t ftb = NULL; +static int fcoe_trace_buf_size = (1 * 1024 * 1024); + +/* + * Driver's global variables + */ +static void *fcoe_state = NULL; +fcoe_soft_state_t *fcoe_global_ss = NULL; +int fcoe_use_ext_log = 1; + +static ddi_taskq_t *fcoe_worker_taskq; +static fcoe_worker_t *fcoe_workers; +static uint32_t fcoe_nworkers_running; + +const char *fcoe_workers_num = "workers-number"; +volatile int fcoe_nworkers; + +/* + * Common loadable module entry points _init, _fini, _info + */ + +int +_init(void) +{ + int ret; + + ret = ddi_soft_state_init(&fcoe_state, sizeof (fcoe_soft_state_t), 0); + if (ret == 0) { + ret = mod_install(&modlinkage); + if (ret != 0) { + ddi_soft_state_fini(&fcoe_state); + } else { + fcoe_trace_start = ddi_get_lbolt(); + ftb = kmem_zalloc(fcoe_trace_buf_size, + KM_SLEEP); + fcoe_trace_buf = ftb; + mutex_init(&fcoe_trace_buf_lock, NULL, MUTEX_DRIVER, 0); + } + } + + FCOE_LOG("fcoe", "exit _init with %x", ret); + + return (ret); +} + +int +_fini(void) +{ + int ret; + + ret = mod_remove(&modlinkage); + if (ret == 0) { + ddi_soft_state_fini(&fcoe_state); + } + + FCOE_LOG("fcoe", "exit _fini with %x", ret); + if (ret == 0) { + kmem_free(fcoe_trace_buf, fcoe_trace_buf_size); + mutex_destroy(&fcoe_trace_buf_lock); + } + + return (ret); +} + +int +_info(struct modinfo *modinfop) +{ + return (mod_info(&modlinkage, modinfop)); +} + +/* + * Autoconfiguration entry points: attach, detach, getinfo + */ + +static int +fcoe_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) +{ + int ret = DDI_FAILURE; + int fcoe_ret; + int instance; + fcoe_soft_state_t *ss; + + instance = ddi_get_instance(dip); + switch (cmd) { + case DDI_ATTACH: + ret = ddi_soft_state_zalloc(fcoe_state, instance); + if (ret == DDI_FAILURE) { + FCOE_LOG(0, "soft_state_zalloc-%x/%x", ret, instance); + return (ret); + } + + ss = ddi_get_soft_state(fcoe_state, instance); + ss->ss_dip = dip; + + ASSERT(fcoe_global_ss == NULL); + fcoe_global_ss = ss; + fcoe_ret = fcoe_attach_init(ss); + if (fcoe_ret == FCOE_SUCCESS) { + ret = DDI_SUCCESS; + } + + FCOE_LOG("fcoe", "fcoe_attach_init end with-%x", fcoe_ret); + break; + + case DDI_RESUME: + ret = DDI_SUCCESS; + break; + + default: + FCOE_LOG("fcoe", "unsupported attach cmd-%x", cmd); + break; + } + + return (ret); +} + +static int +fcoe_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) +{ + int ret = DDI_FAILURE; + int fcoe_ret; + int instance; + fcoe_soft_state_t *ss; + + instance = ddi_get_instance(dip); + ss = ddi_get_soft_state(fcoe_state, instance); + if (ss == NULL) { + return (ret); + } + + ASSERT(fcoe_global_ss != NULL); + ASSERT(dip == fcoe_global_ss->ss_dip); + switch (cmd) { + case DDI_DETACH: + fcoe_ret = fcoe_detach_uninit(ss); + if (fcoe_ret == FCOE_SUCCESS) { + ret = DDI_SUCCESS; + fcoe_global_ss = NULL; + } + + break; + + case DDI_SUSPEND: + ret = DDI_SUCCESS; + break; + + default: + FCOE_LOG(0, "unsupported detach cmd-%x", cmd); + break; + } + + return (ret); +} + +/* + * FCA driver's intercepted bus control operations. + */ +static int +fcoe_bus_ctl(dev_info_t *fcoe_dip, dev_info_t *rip, + ddi_ctl_enum_t op, void *clientarg, void *result) +{ + int ret; + switch (op) { + case DDI_CTLOPS_REPORTDEV: + case DDI_CTLOPS_IOMIN: + ret = DDI_SUCCESS; + break; + + case DDI_CTLOPS_INITCHILD: + ret = fcoe_initchild(fcoe_dip, (dev_info_t *)clientarg); + break; + + case DDI_CTLOPS_UNINITCHILD: + ret = fcoe_uninitchild(fcoe_dip, (dev_info_t *)clientarg); + break; + + default: + ret = ddi_ctlops(fcoe_dip, rip, op, clientarg, result); + break; + } + + return (ret); +} + +/* + * We need specify the dev address for client driver's instance, or we + * can't online client driver's instance. + */ +/* ARGSUSED */ +static int +fcoe_initchild(dev_info_t *fcoe_dip, dev_info_t *client_dip) +{ + char name[32]; + static int inicounter = 0; + static int tgtcounter = 0; + int *counter; + + if (strcmp(ddi_driver_name(client_dip), FCOET_DRIVER_NAME) == 0) { + counter = &tgtcounter; + tgtcounter++; + } else { + counter = &inicounter; + inicounter++; + } + + bzero(name, 32); + (void) sprintf((char *)name, "%x,0", *counter); + ddi_set_name_addr(client_dip, name); + + return (DDI_SUCCESS); +} + +/* ARGSUSED */ +static int +fcoe_uninitchild(dev_info_t *fcoe_dip, dev_info_t *client_dip) +{ + ddi_set_name_addr(client_dip, NULL); + return (DDI_SUCCESS); +} + +/* + * Device access entry points + */ +static int +fcoe_open(dev_t *devp, int flag, int otype, cred_t *credp) +{ + int instance; + fcoe_soft_state_t *ss; + + if (otype != OTYP_CHR) { + return (EINVAL); + } + + /* + * Since this is for debugging only, only allow root to issue ioctl now + */ + if (drv_priv(credp) != 0) { + return (EPERM); + } + + instance = (int)getminor(*devp); + ss = ddi_get_soft_state(fcoe_state, instance); + if (ss == NULL) { + return (ENXIO); + } + + mutex_enter(&ss->ss_ioctl_mutex); + if (ss->ss_ioctl_flags & FCOE_IOCTL_FLAG_EXCL) { + /* + * It is already open for exclusive access. + * So shut the door on this caller. + */ + mutex_exit(&ss->ss_ioctl_mutex); + return (EBUSY); + } + + if (flag & FEXCL) { + if (ss->ss_ioctl_flags & FCOE_IOCTL_FLAG_OPEN) { + /* + * Exclusive operation not possible + * as it is already opened + */ + mutex_exit(&ss->ss_ioctl_mutex); + return (EBUSY); + } + ss->ss_ioctl_flags |= FCOE_IOCTL_FLAG_EXCL; + } + + ss->ss_ioctl_flags |= FCOE_IOCTL_FLAG_OPEN; + mutex_exit(&ss->ss_ioctl_mutex); + + return (0); +} + +/* ARGSUSED */ +static int +fcoe_close(dev_t dev, int flag, int otype, cred_t *credp) +{ + int instance; + fcoe_soft_state_t *ss; + + if (otype != OTYP_CHR) { + return (EINVAL); + } + + instance = (int)getminor(dev); + ss = ddi_get_soft_state(fcoe_state, instance); + if (ss == NULL) { + return (ENXIO); + } + + mutex_enter(&ss->ss_ioctl_mutex); + if ((ss->ss_ioctl_flags & FCOE_IOCTL_FLAG_OPEN) == 0) { + mutex_exit(&ss->ss_ioctl_mutex); + return (ENODEV); + } + + ss->ss_ioctl_flags &= ~FCOE_IOCTL_FLAG_MASK; + mutex_exit(&ss->ss_ioctl_mutex); + + return (0); +} + +/* ARGSUSED */ +static int +fcoe_ioctl(dev_t dev, int cmd, intptr_t data, int mode, + cred_t *credp, int *rval) +{ + fcoe_soft_state_t *ss; + int ret = 0; + + if (drv_priv(credp) != 0) { + return (EPERM); + } + + ss = ddi_get_soft_state(fcoe_state, (int32_t)getminor(dev)); + if (ss == NULL) { + return (ENXIO); + } + + mutex_enter(&ss->ss_ioctl_mutex); + if ((ss->ss_ioctl_flags & FCOE_IOCTL_FLAG_OPEN) == 0) { + mutex_exit(&ss->ss_ioctl_mutex); + return (ENXIO); + } + mutex_exit(&ss->ss_ioctl_mutex); + + switch (cmd) { + case FCOEIO_CMD: + ret = fcoe_iocmd(ss, data, mode); + break; + default: + FCOE_LOG(0, "fcoe_ioctl: ioctl-0x%02X", cmd); + ret = ENOTTY; + break; + } + + return (ret); +} + +static int +fcoe_copyin_iocdata(intptr_t data, int mode, fcoeio_t **fcoeio, + void **ibuf, void **abuf, void **obuf) +{ + int ret = 0; + + *ibuf = NULL; + *abuf = NULL; + *obuf = NULL; + *fcoeio = kmem_zalloc(sizeof (fcoeio_t), KM_SLEEP); + if (ddi_copyin((void *)data, *fcoeio, sizeof (fcoeio_t), mode) != 0) { + ret = EFAULT; + goto copyin_iocdata_fail; + } + + if ((*fcoeio)->fcoeio_ilen > FCOEIO_MAX_BUF_LEN || + (*fcoeio)->fcoeio_alen > FCOEIO_MAX_BUF_LEN || + (*fcoeio)->fcoeio_olen > FCOEIO_MAX_BUF_LEN) { + ret = EFAULT; + goto copyin_iocdata_fail; + } + + if ((*fcoeio)->fcoeio_ilen) { + *ibuf = kmem_zalloc((*fcoeio)->fcoeio_ilen, KM_SLEEP); + if (ddi_copyin((void *)(unsigned long)(*fcoeio)->fcoeio_ibuf, + *ibuf, (*fcoeio)->fcoeio_ilen, mode) != 0) { + ret = EFAULT; + goto copyin_iocdata_fail; + } + } + + if ((*fcoeio)->fcoeio_alen) { + *abuf = kmem_zalloc((*fcoeio)->fcoeio_alen, KM_SLEEP); + if (ddi_copyin((void *)(unsigned long)(*fcoeio)->fcoeio_abuf, + *abuf, (*fcoeio)->fcoeio_alen, mode) != 0) { + ret = EFAULT; + goto copyin_iocdata_fail; + } + } + + if ((*fcoeio)->fcoeio_olen) { + *obuf = kmem_zalloc((*fcoeio)->fcoeio_olen, KM_SLEEP); + } + return (ret); + +copyin_iocdata_fail: + if (*abuf) { + kmem_free(*abuf, (*fcoeio)->fcoeio_alen); + *abuf = NULL; + } + + if (*ibuf) { + kmem_free(*ibuf, (*fcoeio)->fcoeio_ilen); + *ibuf = NULL; + } + + kmem_free(*fcoeio, sizeof (fcoeio_t)); + return (ret); +} + +static int +fcoe_copyout_iocdata(intptr_t data, int mode, fcoeio_t *fcoeio, void *obuf) +{ + if (fcoeio->fcoeio_olen) { + if (ddi_copyout(obuf, + (void *)(unsigned long)fcoeio->fcoeio_obuf, + fcoeio->fcoeio_olen, mode) != 0) { + return (EFAULT); + } + } + + if (ddi_copyout(fcoeio, (void *)data, sizeof (fcoeio_t), mode) != 0) { + return (EFAULT); + } + return (0); +} + +static int +fcoe_iocmd(fcoe_soft_state_t *ss, intptr_t data, int mode) +{ + int ret; + fcoe_mac_t *fcoe_mac; + void *ibuf = NULL; + void *obuf = NULL; + void *abuf = NULL; + fcoeio_t *fcoeio; + + ret = fcoe_copyin_iocdata(data, mode, &fcoeio, &ibuf, &abuf, &obuf); + if (ret != 0) { + goto fcoeiocmd_release_buf; + } + + /* + * If an exclusive open was demanded during open, ensure that + * only one thread can execute an ioctl at a time + */ + mutex_enter(&ss->ss_ioctl_mutex); + if (ss->ss_ioctl_flags & FCOE_IOCTL_FLAG_EXCL) { + if (ss->ss_ioctl_flags & FCOE_IOCTL_FLAG_EXCL_BUSY) { + mutex_exit(&ss->ss_ioctl_mutex); + fcoeio->fcoeio_status = FCOEIOE_BUSY; + ret = EBUSY; + goto fcoeiocmd_release_buf; + } + ss->ss_ioctl_flags |= FCOE_IOCTL_FLAG_EXCL_BUSY; + } + mutex_exit(&ss->ss_ioctl_mutex); + + fcoeio->fcoeio_status = 0; + + switch (fcoeio->fcoeio_cmd) { + case FCOEIO_CREATE_FCOE_PORT: { + fcoeio_create_port_param_t *param = + (fcoeio_create_port_param_t *)ibuf; + int cmpwwn = 0; + fcoe_port_t *eport; + + if (fcoeio->fcoeio_ilen != + sizeof (fcoeio_create_port_param_t) || + fcoeio->fcoeio_xfer != FCOEIO_XFER_WRITE) { + fcoeio->fcoeio_status = FCOEIOE_INVAL_ARG; + ret = EINVAL; + break; + } + + mutex_enter(&ss->ss_ioctl_mutex); + fcoe_mac = fcoe_create_mac_by_name(param->fcp_mac_name); + if (fcoe_mac == NULL) { + mutex_exit(&ss->ss_ioctl_mutex); + fcoeio->fcoeio_status = FCOEIOE_CREATE_MAC; + ret = EIO; + break; + } + + if (fcoe_mac->fm_flags & FCOE_MAC_FLAG_ENABLED) { + mutex_exit(&ss->ss_ioctl_mutex); + fcoeio->fcoeio_status = FCOEIOE_ALREADY; + ret = EALREADY; + break; + } else { + ret = fcoe_open_mac(fcoe_mac, param->fcp_force_promisc, + &fcoeio->fcoeio_status); + if (ret != 0) { + fcoe_destroy_mac(fcoe_mac); + mutex_exit(&ss->ss_ioctl_mutex); + if (fcoeio->fcoeio_status == 0) { + fcoeio->fcoeio_status = + FCOEIOE_OPEN_MAC; + } + ret = EIO; + break; + } else { + fcoe_mac->fm_flags |= FCOE_MAC_FLAG_ENABLED; + } + } + + /* + * Provide PWWN and NWWN based on mac address + */ + eport = &fcoe_mac->fm_eport; + if (!param->fcp_pwwn_provided) { + fcoe_init_wwn_from_mac(eport->eport_portwwn, + fcoe_mac->fm_current_addr, 1, 0); + } else { + (void) memcpy(eport->eport_portwwn, param->fcp_pwwn, 8); + } + + if (!param->fcp_nwwn_provided) { + fcoe_init_wwn_from_mac(eport->eport_nodewwn, + fcoe_mac->fm_current_addr, 0, 0); + } else { + (void) memcpy(eport->eport_nodewwn, param->fcp_nwwn, 8); + } + + cmpwwn = fcoe_cmp_wwn(fcoe_mac); + + if (cmpwwn != 0) { + if (cmpwwn == 1) { + fcoeio->fcoeio_status = FCOEIOE_PWWN_CONFLICTED; + } else if (cmpwwn == -1) { + fcoeio->fcoeio_status = FCOEIOE_NWWN_CONFLICTED; + } + (void) fcoe_close_mac(fcoe_mac); + fcoe_destroy_mac(fcoe_mac); + mutex_exit(&ss->ss_ioctl_mutex); + ret = ENOTUNIQ; + break; + } + + if (ret == 0) { + ret = fcoe_create_port(ss->ss_dip, + fcoe_mac, + (param->fcp_port_type == FCOE_CLIENT_TARGET)); + if (ret != 0) { + (void) fcoe_close_mac(fcoe_mac); + fcoe_destroy_mac(fcoe_mac); + fcoeio->fcoeio_status = FCOEIOE_CREATE_PORT; + ret = EIO; + } + } + mutex_exit(&ss->ss_ioctl_mutex); + + break; + } + + case FCOEIO_DELETE_FCOE_PORT: { + uint8_t *mac_name = (uint8_t *)ibuf; + + if (fcoeio->fcoeio_ilen > FCOE_MAX_MAC_NAME_LEN || + fcoeio->fcoeio_xfer != FCOEIO_XFER_WRITE) { + fcoeio->fcoeio_status = FCOEIOE_INVAL_ARG; + ret = EINVAL; + break; + } + + mutex_enter(&ss->ss_ioctl_mutex); + ret = fcoe_delete_port(ss->ss_dip, fcoeio, mac_name); + if (ret != 0) { + FCOE_LOG("fcoe", + "fcoe_delete_port failed: %d", ret); + } + mutex_exit(&ss->ss_ioctl_mutex); + break; + } + + case FCOEIO_GET_FCOE_PORT_LIST: { + fcoe_port_list_t *list = (fcoe_port_list_t *)obuf; + int count; + + if (fcoeio->fcoeio_xfer != FCOEIO_XFER_READ || + fcoeio->fcoeio_olen < sizeof (fcoe_port_list_t)) { + fcoeio->fcoeio_status = FCOEIOE_INVAL_ARG; + ret = EINVAL; + break; + } + mutex_enter(&ss->ss_ioctl_mutex); + + list->numPorts = 1 + (fcoeio->fcoeio_olen - + sizeof (fcoe_port_list_t))/sizeof (fcoe_port_instance_t); + + count = fcoe_get_port_list(list->ports, list->numPorts); + + if (count > list->numPorts) { + fcoeio->fcoeio_status = FCOEIOE_MORE_DATA; + ret = ENOSPC; + } + list->numPorts = count; + mutex_exit(&ss->ss_ioctl_mutex); + + break; + + } + + default: + return (ENOTTY); + } + + FCOE_LOG("fcoe", "fcoe_ioctl returned %d, fcoeio_status = %d", + ret, fcoeio->fcoeio_status); + +fcoeiocmd_release_buf: + if (ret == 0) { + ret = fcoe_copyout_iocdata(data, mode, fcoeio, obuf); + } else if (fcoeio->fcoeio_status) { + (void) fcoe_copyout_iocdata(data, mode, fcoeio, obuf); + } + + if (obuf != NULL) { + kmem_free(obuf, fcoeio->fcoeio_olen); + obuf = NULL; + } + if (abuf != NULL) { + kmem_free(abuf, fcoeio->fcoeio_alen); + abuf = NULL; + } + + if (ibuf != NULL) { + kmem_free(ibuf, fcoeio->fcoeio_ilen); + ibuf = NULL; + } + kmem_free(fcoeio, sizeof (fcoeio_t)); + + return (ret); +} + +/* + * Finish final initialization + */ +static int +fcoe_attach_init(fcoe_soft_state_t *ss) +{ + char taskq_name[TASKQ_NAME_LEN]; + + if (ddi_create_minor_node(ss->ss_dip, "admin", S_IFCHR, + ddi_get_instance(ss->ss_dip), DDI_PSEUDO, 0) != DDI_SUCCESS) { + FCOE_LOG("FCOE", "ddi_create_minor_node failed"); + return (FCOE_FAILURE); + } + + /* + * watchdog responsible for release frame and dispatch events + */ + (void) snprintf(taskq_name, sizeof (taskq_name), "fcoe_mac"); + taskq_name[TASKQ_NAME_LEN - 1] = 0; + if ((ss->ss_watchdog_taskq = ddi_taskq_create(NULL, + taskq_name, 2, TASKQ_DEFAULTPRI, 0)) == NULL) { + return (FCOE_FAILURE); + } + + ss->ss_ioctl_flags = 0; + mutex_init(&ss->ss_ioctl_mutex, NULL, MUTEX_DRIVER, NULL); + list_create(&ss->ss_mac_list, sizeof (fcoe_mac_t), + offsetof(fcoe_mac_t, fm_ss_node)); + list_create(&ss->ss_pfrm_list, sizeof (fcoe_i_frame_t), + offsetof(fcoe_i_frame_t, fmi_pending_node)); + + mutex_init(&ss->ss_watch_mutex, 0, MUTEX_DRIVER, 0); + cv_init(&ss->ss_watch_cv, NULL, CV_DRIVER, NULL); + ss->ss_flags &= ~SS_FLAG_TERMINATE_WATCHDOG; + (void) ddi_taskq_dispatch(ss->ss_watchdog_taskq, + fcoe_watchdog, ss, DDI_SLEEP); + while ((ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) == 0) { + delay(10); + } + fcoe_nworkers = ddi_prop_get_int(DDI_DEV_T_ANY, ss->ss_dip, + DDI_PROP_NOTPROM | DDI_PROP_DONTPASS, (char *)fcoe_workers_num, 4); + if (fcoe_nworkers < 1) { + fcoe_nworkers = 4; + } + fcoe_worker_init(); + + ddi_report_dev(ss->ss_dip); + return (FCOE_SUCCESS); +} + +/* + * Finish final uninitialization + */ +static int +fcoe_detach_uninit(fcoe_soft_state_t *ss) +{ + int ret; + if (!list_is_empty(&ss->ss_mac_list)) { + FCOE_LOG("fcoe", "ss_mac_list is not empty when detach"); + return (FCOE_FAILURE); + } + + if ((ret = fcoe_worker_fini()) != FCOE_SUCCESS) { + return (ret); + } + + /* + * Stop watchdog + */ + if (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) { + mutex_enter(&ss->ss_watch_mutex); + ss->ss_flags |= SS_FLAG_TERMINATE_WATCHDOG; + cv_broadcast(&ss->ss_watch_cv); + mutex_exit(&ss->ss_watch_mutex); + while (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) { + delay(10); + } + } + + ddi_taskq_destroy(ss->ss_watchdog_taskq); + mutex_destroy(&ss->ss_watch_mutex); + cv_destroy(&ss->ss_watch_cv); + + ddi_remove_minor_node(ss->ss_dip, NULL); + mutex_destroy(&ss->ss_ioctl_mutex); + list_destroy(&ss->ss_mac_list); + + return (FCOE_SUCCESS); +} + +/* + * Return mac instance if it exist, or else return NULL. + */ +fcoe_mac_t * +fcoe_lookup_mac_by_name(uint8_t *name) +{ + fcoe_mac_t *mac = NULL; + + ASSERT(mutex_owned(&fcoe_global_ss->ss_ioctl_mutex)); + for (mac = list_head(&fcoe_global_ss->ss_mac_list); mac; + mac = list_next(&fcoe_global_ss->ss_mac_list, mac)) { + if (strcmp((char *)name, mac->fm_link_name)) { + continue; + } + return (mac); + } + return (NULL); +} + +/* + * port wwn will start with 20:..., node wwn will start with 10:... + */ +static void +fcoe_init_wwn_from_mac(uint8_t *wwn, uint8_t *mac, int is_pwwn, uint8_t idx) +{ + ASSERT(wwn != NULL); + ASSERT(mac != NULL); + wwn[0] = (is_pwwn + 1) << 4; + wwn[1] = idx; + bcopy(mac, wwn + 2, ETHERADDRL); +} + +/* + * Return fcoe_mac if it exists, otherwise create a new one + */ +static fcoe_mac_t * +fcoe_create_mac_by_name(uint8_t *name) +{ + fcoe_mac_t *mac = NULL; + ASSERT(mutex_owned(&fcoe_global_ss->ss_ioctl_mutex)); + + mac = fcoe_lookup_mac_by_name(name); + if (mac != NULL) { + FCOE_LOG("fcoe", "fcoe_create_mac_by_name found one mac %s", + name); + return (mac); + } + + mac = kmem_zalloc(sizeof (fcoe_mac_t), KM_SLEEP); + bcopy(name, mac->fm_link_name, strlen((char *)name) + 1); + mac->fm_flags = 0; + mac->fm_ss = fcoe_global_ss; + list_insert_tail(&mac->fm_ss->ss_mac_list, mac); + FCOE_LOG("fcoe", "fcoe_create_mac_by_name created one mac %s", name); + return (mac); +} + +void +fcoe_destroy_mac(fcoe_mac_t *mac) +{ + ASSERT(mac != NULL); + list_remove(&mac->fm_ss->ss_mac_list, mac); + kmem_free(mac, sizeof (fcoe_mac_t)); +} + +/* + * raw frame layout: + * ethernet header + vlan header (optional) + FCoE header + + * FC frame + FCoE tailer + */ +/* ARGSUSED */ +mblk_t * +fcoe_get_mblk(fcoe_mac_t *mac, uint32_t raw_frame_size) +{ + mblk_t *mp; + int err; + + /* + * FCFH_SIZE + PADDING_SIZE + */ + ASSERT(raw_frame_size >= 60); + while ((mp = allocb((size_t)raw_frame_size, 0)) == NULL) { + if ((err = strwaitbuf((size_t)raw_frame_size, BPRI_LO)) != 0) { + FCOE_LOG("fcoe_get_mblk", "strwaitbuf return %d", err); + return (NULL); + } + } + mp->b_wptr = mp->b_rptr + raw_frame_size; + + /* + * We should always zero FC frame header + */ + bzero(mp->b_rptr + PADDING_HEADER_SIZE, + sizeof (fcoe_fc_frame_header_t)); + return (mp); +} + +static void +fcoe_watchdog(void *arg) +{ + fcoe_soft_state_t *ss = (fcoe_soft_state_t *)arg; + fcoe_i_frame_t *fmi; + fcoe_mac_t *mac = NULL; + + FCOE_LOG("fcoe", "fcoe_soft_state is %p", ss); + + mutex_enter(&ss->ss_watch_mutex); + ss->ss_flags |= SS_FLAG_WATCHDOG_RUNNING; + while ((ss->ss_flags & SS_FLAG_TERMINATE_WATCHDOG) == 0) { + while (fmi = (fcoe_i_frame_t *)list_head(&ss->ss_pfrm_list)) { + list_remove(&ss->ss_pfrm_list, fmi); + mutex_exit(&ss->ss_watch_mutex); + + mac = EPORT2MAC(fmi->fmi_frame->frm_eport); + mac->fm_client.ect_release_sol_frame(fmi->fmi_frame); + + mutex_enter(&ss->ss_watch_mutex); + mac->fm_frm_cnt--; + } + + ss->ss_flags |= SS_FLAG_DOG_WAITING; + (void) cv_wait(&ss->ss_watch_cv, &ss->ss_watch_mutex); + ss->ss_flags &= ~SS_FLAG_DOG_WAITING; + } + + ss->ss_flags &= ~SS_FLAG_WATCHDOG_RUNNING; + mutex_exit(&ss->ss_watch_mutex); +} + +static void +fcoe_worker_init() +{ + uint32_t i; + + fcoe_nworkers_running = 0; + fcoe_worker_taskq = ddi_taskq_create(0, "FCOE_WORKER_TASKQ", + fcoe_nworkers, TASKQ_DEFAULTPRI, 0); + fcoe_workers = (fcoe_worker_t *)kmem_zalloc(sizeof (fcoe_worker_t) * + fcoe_nworkers, KM_SLEEP); + for (i = 0; i < fcoe_nworkers; i++) { + fcoe_worker_t *w = &fcoe_workers[i]; + mutex_init(&w->worker_lock, NULL, MUTEX_DRIVER, NULL); + cv_init(&w->worker_cv, NULL, CV_DRIVER, NULL); + w->worker_flags &= ~FCOE_WORKER_TERMINATE; + list_create(&w->worker_frm_list, sizeof (fcoe_i_frame_t), + offsetof(fcoe_i_frame_t, fmi_pending_node)); + (void) ddi_taskq_dispatch(fcoe_worker_taskq, fcoe_worker_frame, + w, DDI_SLEEP); + } + while (fcoe_nworkers_running != fcoe_nworkers) { + delay(10); + } +} + +static int +fcoe_worker_fini() +{ + uint32_t i; + + for (i = 0; i < fcoe_nworkers; i++) { + fcoe_worker_t *w = &fcoe_workers[i]; + mutex_enter(&w->worker_lock); + if (w->worker_flags & FCOE_WORKER_STARTED) { + w->worker_flags |= FCOE_WORKER_TERMINATE; + cv_signal(&w->worker_cv); + } + mutex_exit(&w->worker_lock); + } + + while (fcoe_nworkers_running != 0) { + delay(drv_usectohz(10000)); + } + + ddi_taskq_destroy(fcoe_worker_taskq); + kmem_free(fcoe_workers, sizeof (fcoe_worker_t) * fcoe_nworkers); + fcoe_workers = NULL; + return (FCOE_SUCCESS); +} + +static int +fcoe_crc_verify(fcoe_frame_t *frm) +{ + uint32_t crc; + uint8_t *crc_array = FRM2FMI(frm)->fmi_fft->fft_crc; + uint32_t crc_from_frame = ~(crc_array[0] | (crc_array[1] << 8) | + (crc_array[2] << 16) | (crc_array[3] << 24)); + CRC32(crc, frm->frm_fc_frame, frm->frm_fc_frame_size, -1U, crc32_table); + return (crc == crc_from_frame ? FCOE_SUCCESS : FCOE_FAILURE); +} + +static void +fcoe_worker_frame(void *arg) +{ + fcoe_worker_t *w = (fcoe_worker_t *)arg; + fcoe_i_frame_t *fmi; + int ret; + + atomic_add_32(&fcoe_nworkers_running, 1); + mutex_enter(&w->worker_lock); + w->worker_flags |= FCOE_WORKER_STARTED | FCOE_WORKER_ACTIVE; + while ((w->worker_flags & FCOE_WORKER_TERMINATE) == 0) { + /* + * loop through the frames + */ + while (fmi = list_head(&w->worker_frm_list)) { + list_remove(&w->worker_frm_list, fmi); + mutex_exit(&w->worker_lock); + /* + * do the checksum + */ + ret = fcoe_crc_verify(fmi->fmi_frame); + if (ret == FCOE_SUCCESS) { + fmi->fmi_mac->fm_client.ect_rx_frame( + fmi->fmi_frame); + } else { + fcoe_release_frame(fmi->fmi_frame); + } + mutex_enter(&w->worker_lock); + w->worker_ntasks--; + } + w->worker_flags &= ~FCOE_WORKER_ACTIVE; + cv_wait(&w->worker_cv, &w->worker_lock); + w->worker_flags |= FCOE_WORKER_ACTIVE; + } + w->worker_flags &= ~(FCOE_WORKER_STARTED | FCOE_WORKER_ACTIVE); + mutex_exit(&w->worker_lock); + atomic_add_32(&fcoe_nworkers_running, -1); + list_destroy(&w->worker_frm_list); +} + +void +fcoe_post_frame(fcoe_frame_t *frm) +{ + fcoe_worker_t *w; + uint16_t oxid = FRM_OXID(frm); + + w = &fcoe_workers[oxid % fcoe_nworkers_running]; + mutex_enter(&w->worker_lock); + list_insert_tail(&w->worker_frm_list, frm->frm_fcoe_private); + w->worker_ntasks++; + if ((w->worker_flags & FCOE_WORKER_ACTIVE) == 0) { + cv_signal(&w->worker_cv); + } + mutex_exit(&w->worker_lock); +} + +/* + * The max length of every LOG is 158 + */ +void +fcoe_trace(caddr_t ident, const char *fmt, ...) +{ + va_list args; + char tbuf[160]; + int len; + clock_t curclock; + clock_t usec; + + if (fcoe_trace_on == 0) { + return; + } + + curclock = ddi_get_lbolt(); + usec = (curclock - fcoe_trace_start) * usec_per_tick; + len = snprintf(tbuf, 158, "%lu.%03lus 0t%lu %s ", (usec / + (1000 * 1000)), ((usec % (1000 * 1000)) / 1000), + curclock, (ident ? ident : "unknown")); + va_start(args, fmt); + len += vsnprintf(tbuf + len, 158 - len, fmt, args); + va_end(args); + + if (len > 158) { + len = 158; + } + tbuf[len++] = '\n'; + tbuf[len] = 0; + + mutex_enter(&fcoe_trace_buf_lock); + bcopy(tbuf, &fcoe_trace_buf[fcoe_trace_buf_curndx], len+1); + fcoe_trace_buf_curndx += len; + if (fcoe_trace_buf_curndx > (fcoe_trace_buf_size - 320)) { + fcoe_trace_buf_curndx = 0; + } + mutex_exit(&fcoe_trace_buf_lock); +} + +/* + * Check whether the pwwn or nwwn already exist or not + * Return value: + * 1: PWWN conflicted + * -1: NWWN conflicted + * 0: No conflict + */ +static int +fcoe_cmp_wwn(fcoe_mac_t *checkedmac) +{ + fcoe_mac_t *mac; + uint8_t *nwwn, *pwwn, *cnwwn, *cpwwn; + + cnwwn = checkedmac->fm_eport.eport_nodewwn; + cpwwn = checkedmac->fm_eport.eport_portwwn; + ASSERT(mutex_owned(&fcoe_global_ss->ss_ioctl_mutex)); + + for (mac = list_head(&fcoe_global_ss->ss_mac_list); mac; + mac = list_next(&fcoe_global_ss->ss_mac_list, mac)) { + if (mac == checkedmac) { + continue; + } + nwwn = mac->fm_eport.eport_nodewwn; + pwwn = mac->fm_eport.eport_portwwn; + + if (memcmp(nwwn, cnwwn, 8) == 0) { + return (-1); + } + + if (memcmp(pwwn, cpwwn, 8) == 0) { + return (1); + } + } + return (0); +} + +static int +fcoe_get_port_list(fcoe_port_instance_t *ports, int count) +{ + fcoe_mac_t *mac = NULL; + int i = 0; + + ASSERT(ports != NULL); + ASSERT(mutex_owned(&fcoe_global_ss->ss_ioctl_mutex)); + + for (mac = list_head(&fcoe_global_ss->ss_mac_list); mac; + mac = list_next(&fcoe_global_ss->ss_mac_list, mac)) { + if (i < count) { + bcopy(mac->fm_eport.eport_portwwn, + ports[i].fpi_pwwn, 8); + bcopy(mac->fm_link_name, + ports[i].fpi_mac_link_name, MAXLINKNAMELEN); + bcopy(mac->fm_current_addr, + ports[i].fpi_mac_current_addr, ETHERADDRL); + bcopy(mac->fm_primary_addr, + ports[i].fpi_mac_factory_addr, ETHERADDRL); + ports[i].fpi_port_type = + EPORT_CLT_TYPE(&mac->fm_eport); + ports[i].fpi_mtu_size = + mac->fm_eport.eport_mtu; + ports[i].fpi_mac_promisc = + mac->fm_promisc_handle != NULL ? 1 : 0; + } + i++; + } + return (i); +} diff --git a/usr/src/uts/common/io/fcoe/fcoe.conf b/usr/src/uts/common/io/fcoe/fcoe.conf new file mode 100644 index 0000000000..d2a6aa25f8 --- /dev/null +++ b/usr/src/uts/common/io/fcoe/fcoe.conf @@ -0,0 +1,35 @@ +# +# 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. +# + +# +# fcoe is nexus driver with children +# +name="fcoe" parent="/"; + +# +# number of workers to handle crc check +# +#workers-number=4; diff --git a/usr/src/uts/common/io/fcoe/fcoe.h b/usr/src/uts/common/io/fcoe/fcoe.h new file mode 100644 index 0000000000..222a29bf12 --- /dev/null +++ b/usr/src/uts/common/io/fcoe/fcoe.h @@ -0,0 +1,249 @@ +/* + * 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. + */ + +/* + * The following notice accompanied the original version of this file: + * + * BSD LICENSE + * + * Copyright(c) 2007 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _FCOE_H_ +#define _FCOE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _KERNEL + +extern int fcoe_use_ext_log; +extern struct fcoe_soft_state *fcoe_global_ss; + +/* + * Caution: 1) LOG will be available in debug/non-debug mode + * 2) Anything which can potentially flood the log should be under + * extended logging, and use FCOE_EXT_LOG. + * 3) Don't use FCOE_EXT_LOG in performance-critical code path, such + * as normal SCSI I/O code path. It could hurt system performance. + * 4) Use kmdb to change foce_use_ext_log in the fly to adjust + * tracing + */ +#define FCOE_EXT_LOG(log_ident, ...) \ + do { \ + if (fcoe_use_ext_log) { \ + fcoe_trace(log_ident, __VA_ARGS__); \ + } \ + } while (0) + +#define FCOE_LOG(log_ident, ...) \ + fcoe_trace(log_ident, __VA_ARGS__) + +/* + * There will be only one fcoe instance + */ +typedef struct fcoe_soft_state { + dev_info_t *ss_dip; + uint32_t ss_flags; + list_t ss_mac_list; + uint32_t ss_ioctl_flags; + kmutex_t ss_ioctl_mutex; + + /* + * watchdog stuff + */ + ddi_taskq_t *ss_watchdog_taskq; + kcondvar_t ss_watch_cv; + kmutex_t ss_watch_mutex; + list_t ss_pfrm_list; /* Pending frame */ +} fcoe_soft_state_t; + +#define SS_FLAG_TERMINATE_WATCHDOG 0x0020 +#define SS_FLAG_WATCHDOG_RUNNING 0x0040 +#define SS_FLAG_DOG_WAITING 0x0080 + +/* + * Driver name + */ +#define FCOEI_DRIVER_NAME "fcoei" +#define FCOET_DRIVER_NAME "fcoet" + +/* + * One for each ethernet port + */ +typedef struct fcoe_mac +{ + list_node_t fm_ss_node; + char fm_link_name[MAXLINKNAMELEN]; + uint32_t fm_flags; + + fcoe_soft_state_t *fm_ss; + fcoe_port_t fm_eport; + fcoe_client_t fm_client; + dev_info_t *fm_client_dev; + + mac_handle_t fm_handle; + mac_client_handle_t fm_cli_handle; + mac_promisc_handle_t fm_promisc_handle; + mac_notify_handle_t fm_notify_handle; + mac_unicast_handle_t fm_unicst_handle; + uint8_t fm_primary_addr[ETHERADDRL]; + uint8_t fm_current_addr[ETHERADDRL]; + uint32_t fm_running:1, + fm_force_promisc:1, + fm_rsvd:18, + fm_state:4, + fm_link_state:8; + uint32_t fm_frm_cnt; + kcondvar_t fm_tx_cv; + kmutex_t fm_mutex; +} fcoe_mac_t; + +#define FCOE_MAC_STATE_OFFLINE 0x0 +#define FCOE_MAC_STATE_ONLINE 0x1 + +#define FCOE_MAC_LINK_STATE_DOWN 0x00 +#define FCOE_MAC_LINK_STATE_UP 0x01 + +#define FCOE_MAC_FLAG_ENABLED 0x01 +#define FCOE_MAC_FLAG_BOUND 0x02 + +typedef struct fcoe_frame_header { + uint8_t ffh_ver[1]; /* version field - upper 4 bits */ + uint8_t ffh_resvd[12]; + uint8_t ffh_sof[1]; /* start of frame per RFC 3643 */ +} fcoe_frame_header_t; + +typedef struct fcoe_frame_tailer { + uint8_t fft_crc[4]; /* FC packet CRC */ + uint8_t fft_eof[1]; + uint8_t fft_resvd[3]; +} fcoe_frame_tailer_t; + +/* + * RAW frame structure + * It is used to describe the content of every mblk + */ +typedef struct fcoe_i_frame { + list_node_t fmi_pending_node; + + fcoe_frame_t *fmi_frame; /* to common struct */ + fcoe_mac_t *fmi_mac; /* to/from where */ + + /* + * FRAME structure + */ + struct ether_header *fmi_efh; /* 14 bytes eth header */ + fcoe_frame_header_t *fmi_ffh; /* 14 bytes FCOE hader */ + uint8_t *fmi_fc_frame; + fcoe_frame_tailer_t *fmi_fft; /* 8 bytes FCOE tailer */ +} fcoe_i_frame_t; + +typedef struct fcoe_worker { + list_t worker_frm_list; + kmutex_t worker_lock; + kcondvar_t worker_cv; + uint32_t worker_flags; + uint32_t worker_ntasks; +} fcoe_worker_t; + +#define FCOE_WORKER_TERMINATE 0x01 +#define FCOE_WORKER_STARTED 0x02 +#define FCOE_WORKER_ACTIVE 0x04 + +/* + * IOCTL supporting stuff + */ +#define FCOE_IOCTL_FLAG_MASK 0xFF +#define FCOE_IOCTL_FLAG_IDLE 0x00 +#define FCOE_IOCTL_FLAG_OPEN 0x01 +#define FCOE_IOCTL_FLAG_EXCL 0x02 +#define FCOE_IOCTL_FLAG_EXCL_BUSY 0x04 + +/* + * define common-used macros to simplify coding + */ +#define FCOE_FIP_TYPE 0x8914 +#define FCOE_802_1Q_TAG 0x8100 + +#define PADDING_HEADER_SIZE (sizeof (struct ether_header) + \ + sizeof (fcoe_frame_header_t)) +#define PADDING_SIZE (PADDING_HEADER_SIZE + sizeof (fcoe_frame_tailer_t)) + +#define EPORT2MAC(x_eport) ((fcoe_mac_t *)(x_eport)->eport_fcoe_private) + +#define FRM2MAC(x_frm) (EPORT2MAC((x_frm)->frm_eport)) +#define FRM2FMI(x_frm) ((fcoe_i_frame_t *)(x_frm)->frm_fcoe_private) +#define FRM2MBLK(x_frm) ((mblk_t *)(x_frm)->frm_netb) + +#define FCOE_VER 0 +#define FCOE_DECAPS_VER(x_ffh) ((x_ffh)->ffh_ver[0] >> 4) +#define FCOE_ENCAPS_VER(x_ffh, x_v) \ + { \ + (x_ffh)->ffh_ver[0] = ((x_v) << 4); \ + } + +/* + * fcoe driver common functions + */ +extern fcoe_mac_t *fcoe_lookup_mac_by_name(uint8_t *); +extern void fcoe_destroy_mac(fcoe_mac_t *); +extern mblk_t *fcoe_get_mblk(fcoe_mac_t *, uint32_t); +extern void fcoe_post_frame(fcoe_frame_t *); + +#endif /* _KERNEL */ + +#ifdef __cplusplus +} +#endif + +#endif /* _FCOE_H_ */ diff --git a/usr/src/uts/common/io/fcoe/fcoe_eth.c b/usr/src/uts/common/io/fcoe/fcoe_eth.c new file mode 100644 index 0000000000..91b4aa2032 --- /dev/null +++ b/usr/src/uts/common/io/fcoe/fcoe_eth.c @@ -0,0 +1,373 @@ +/* + * 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 <sys/stat.h> +#include <sys/types.h> +#include <netinet/in.h> +#include <sys/inttypes.h> +#include <sys/strsun.h> +#include <sys/mac_client.h> + +/* + * FCoE header files + */ +#include <sys/fcoe/fcoeio.h> +#include <sys/fcoe/fcoe_common.h> + +/* + * Driver's own header files + */ +#include <fcoe.h> +#include <fcoe_eth.h> +#include <fcoe_fc.h> + +static void fcoe_rx(void *arg, mac_resource_handle_t mrh, + mblk_t *mp, boolean_t loopback); +static void fcoe_mac_notify(void *arg, mac_notify_type_t type); + +/* + * Global variable definitions + */ + +/* + * Internal tunable, used to enable p2p mode + */ +volatile uint32_t fcoe_enable_p2pmode = 0; + +int +fcoe_open_mac(fcoe_mac_t *mac, int force_promisc, fcoeio_stat_t *err_detail) +{ + int ret; + int fcoe_ret; + char cli_name[MAXNAMELEN]; + mac_diag_t diag; + uint16_t fm_open_flag = 0; + + *err_detail = 0; + + /* + * Open MAC interface + */ + ret = mac_open_by_linkname(mac->fm_link_name, &mac->fm_handle); + if (ret != 0) { + cmn_err(CE_WARN, "Open network interface %s failed", + mac->fm_link_name); + FCOE_LOG("fcoe", "mac_open_by_linkname %s failed %x", + mac->fm_link_name, ret); + return (FCOE_FAILURE); + } + + if (mac_is_vnic(mac->fm_handle)) { + (void) mac_close(mac->fm_handle); + *err_detail = FCOEIOE_VNIC_UNSUPPORT; + return (FCOE_FAILURE); + } + + (void) sprintf(cli_name, "%s-%s", mac->fm_link_name, "fcoe"); + + ret = mac_client_open(mac->fm_handle, + &mac->fm_cli_handle, cli_name, fm_open_flag); + if (ret != 0) { + (void) fcoe_close_mac(mac); + return (FCOE_FAILURE); + } + /* + * Cache the pointer of the immutable MAC inforamtion and + * the current and primary MAC address + */ + mac_unicast_primary_get(mac->fm_handle, mac->fm_primary_addr); + bcopy(mac->fm_primary_addr, mac->fm_current_addr, + ETHERADDRL); + + if (mac_unicast_add(mac->fm_cli_handle, NULL, MAC_UNICAST_PRIMARY, + &mac->fm_unicst_handle, 0, &diag)) { + (void) fcoe_close_mac(mac); + return (FCOE_FAILURE); + } + + if (force_promisc) { + mac->fm_force_promisc = B_TRUE; + } + + /* Get mtu */ + mac_sdu_get(mac->fm_handle, NULL, &mac->fm_eport.eport_mtu); + if (mac->fm_eport.eport_mtu < FCOE_MIN_MTU_SIZE) { + if (!fcoe_enable_p2pmode || mac->fm_eport.eport_mtu < 1500) { + /* + * Fail open if fail to get mtu, or we are not + * using p2p, or we are using p2p, but + * the mtu is too small + */ + (void) fcoe_close_mac(mac); + *err_detail = FCOEIOE_NEED_JUMBO_FRAME; + return (FCOE_FAILURE); + } + } + + mac->fm_eport.eport_link_speed = + mac_client_stat_get(mac->fm_cli_handle, MAC_STAT_IFSPEED); + + cv_init(&mac->fm_tx_cv, NULL, CV_DRIVER, NULL); + mutex_init(&mac->fm_mutex, NULL, MUTEX_DRIVER, NULL); + mac->fm_running = B_TRUE; + + fcoe_ret = FCOE_SUCCESS; + return (fcoe_ret); +} + +int +fcoe_close_mac(fcoe_mac_t *mac) +{ + int ret; + + if (mac->fm_handle == NULL) { + return (FCOE_SUCCESS); + } + + if (mac->fm_running) { + cv_destroy(&mac->fm_tx_cv); + mutex_destroy(&mac->fm_mutex); + mac->fm_running = B_FALSE; + } + + if (mac->fm_promisc_handle != NULL) { + mac_promisc_remove(mac->fm_promisc_handle); + mac->fm_promisc_handle = NULL; + } else { + mac_rx_clear(mac->fm_cli_handle); + } + + if (mac->fm_notify_handle != NULL) { + ret = mac_notify_remove(mac->fm_notify_handle, B_TRUE); + ASSERT(ret == 0); + mac->fm_notify_handle = NULL; + } + + if (mac->fm_unicst_handle != NULL) { + (void) mac_unicast_remove(mac->fm_cli_handle, + mac->fm_unicst_handle); + mac->fm_unicst_handle = NULL; + } + + mac_client_close(mac->fm_cli_handle, 0); + mac->fm_cli_handle = NULL; + + (void) mac_close(mac->fm_handle); + mac->fm_handle = NULL; + + return (FCOE_SUCCESS); +} + +int +fcoe_enable_callback(fcoe_mac_t *mac) +{ + int ret; + + /* + * Set message callback + */ + if (mac->fm_force_promisc) { + ret = mac_promisc_add(mac->fm_cli_handle, + MAC_CLIENT_PROMISC_FILTERED, fcoe_rx, mac, + &mac->fm_promisc_handle, + MAC_PROMISC_FLAGS_NO_TX_LOOP); + if (ret != 0) { + cmn_err(CE_WARN, "Enable promisc mode on %s failed", + mac->fm_link_name); + FCOE_LOG("foce", "mac_promisc_add on %s failed %x", + mac->fm_link_name, ret); + return (FCOE_FAILURE); + } + } else { + mac_rx_set(mac->fm_cli_handle, fcoe_rx, mac); + } + + /* Get the link state, if it's up, we will need to notify client */ + mac->fm_link_state = + mac_stat_get(mac->fm_handle, MAC_STAT_LINK_UP)? + FCOE_MAC_LINK_STATE_UP:FCOE_MAC_LINK_STATE_DOWN; + + /* + * Add a notify function so that we get updates from MAC + */ + mac->fm_notify_handle = mac_notify_add(mac->fm_handle, + fcoe_mac_notify, (void *)mac); + return (FCOE_SUCCESS); +} + +int +fcoe_disable_callback(fcoe_mac_t *mac) +{ + int ret; + + if (mac->fm_promisc_handle) { + mac_promisc_remove(mac->fm_promisc_handle); + mac->fm_promisc_handle = NULL; + } else { + mac_rx_clear(mac->fm_cli_handle); + } + + if (mac->fm_notify_handle) { + ret = mac_notify_remove(mac->fm_notify_handle, B_TRUE); + ASSERT(ret == 0); + mac->fm_notify_handle = NULL; + } + + ret = fcoe_mac_set_address(&mac->fm_eport, + mac->fm_primary_addr, B_FALSE); + FCOE_SET_DEFAULT_FPORT_ADDR(mac->fm_eport.eport_efh_dst); + return (ret); +} + +/* ARGSUSED */ +static void +fcoe_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp, boolean_t loopback) +{ + fcoe_mac_t *mac = (fcoe_mac_t *)arg; + mblk_t *next; + fcoe_frame_t *frm; + uint32_t raw_frame_size, frame_size; + uint16_t frm_type; + + while (mp != NULL) { + next = mp->b_next; + mp->b_next = NULL; + frm_type = ntohs(*(uint16_t *)((uintptr_t)mp->b_rptr + 12)); + + if (frm_type != ETHERTYPE_FCOE) { + /* + * This mp is not allocated in FCoE, but we must free it + */ + freeb(mp); + mp = next; + continue; + } + + raw_frame_size = MBLKL(mp); + frame_size = raw_frame_size - PADDING_SIZE; + frm = fcoe_allocate_frame(&mac->fm_eport, frame_size, mp); + if (frm != NULL) { + fcoe_post_frame(frm); + } + + mp = next; + } +} + +static void +fcoe_mac_notify(void *arg, mac_notify_type_t type) +{ + fcoe_mac_t *mac = (fcoe_mac_t *)arg; + + /* + * We assume that the calls to this notification callback are serialized + * by MAC layer + */ + + switch (type) { + case MAC_NOTE_LINK: + /* + * This notification is sent every time the MAC driver + * updates the link state. + */ + if (mac_stat_get(mac->fm_handle, MAC_STAT_LINK_UP) != 0) { + if (mac->fm_link_state == FCOE_MAC_LINK_STATE_UP) { + break; + } + /* Get speed */ + mac->fm_eport.eport_link_speed = + mac_client_stat_get(mac->fm_cli_handle, + MAC_STAT_IFSPEED); + + (void) fcoe_mac_set_address(&mac->fm_eport, + mac->fm_primary_addr, B_FALSE); + + FCOE_SET_DEFAULT_FPORT_ADDR( + mac->fm_eport.eport_efh_dst); + + mac->fm_link_state = FCOE_MAC_LINK_STATE_UP; + FCOE_LOG(mac->fm_link_name, + "fcoe_mac_notify: arg/%p LINK up", arg, type); + fcoe_mac_notify_link_up(mac); + } else { + if (mac->fm_link_state == FCOE_MAC_LINK_STATE_DOWN) { + break; + } + mac->fm_link_state = FCOE_MAC_LINK_STATE_DOWN; + FCOE_LOG(mac->fm_link_name, + "fcoe_mac_notify: arg/%p LINK down", arg, type); + fcoe_mac_notify_link_down(mac); + } + break; + + case MAC_NOTE_TX: + /* + * MAC is not so busy now, then wake up fcoe_tx_frame to try + */ + mutex_enter(&mac->fm_mutex); + cv_broadcast(&mac->fm_tx_cv); + mutex_exit(&mac->fm_mutex); + + FCOE_LOG("fcoe_mac_notify", "wake up"); + break; + + default: + FCOE_LOG("fcoe_mac_notify", "not supported arg/%p, type/%d", + arg, type); + break; + } +} + +int +fcoe_mac_set_address(fcoe_port_t *eport, uint8_t *addr, boolean_t fc_assigned) +{ + fcoe_mac_t *mac = EPORT2MAC(eport); + int ret; + + if (bcmp(addr, mac->fm_current_addr, 6) == 0) { + return (FCOE_SUCCESS); + } + + mutex_enter(&mac->fm_mutex); + if (mac->fm_promisc_handle == NULL) { + ret = mac_unicast_primary_set(mac->fm_handle, addr); + if (ret != 0) { + mutex_exit(&mac->fm_mutex); + cmn_err(CE_WARN, "Set primary unicast address on %s " + "failed", mac->fm_link_name); + FCOE_LOG("fcoe", "mac_unicast_primary_set on %s " + "failed %x", mac->fm_link_name, ret); + return (FCOE_FAILURE); + } + } + if (fc_assigned) { + bcopy(addr, mac->fm_current_addr, ETHERADDRL); + } else { + bcopy(mac->fm_primary_addr, + mac->fm_current_addr, ETHERADDRL); + } + mutex_exit(&mac->fm_mutex); + return (FCOE_SUCCESS); +} diff --git a/usr/src/uts/common/io/fcoe/fcoe_eth.h b/usr/src/uts/common/io/fcoe/fcoe_eth.h new file mode 100644 index 0000000000..eff72c1345 --- /dev/null +++ b/usr/src/uts/common/io/fcoe/fcoe_eth.h @@ -0,0 +1,45 @@ +/* + * 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 _FCOE_ETH_H_ +#define _FCOE_ETH_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _KERNEL + +extern int fcoe_open_mac(fcoe_mac_t *, int, fcoeio_stat_t *); +extern int fcoe_close_mac(fcoe_mac_t *); +extern int fcoe_enable_callback(fcoe_mac_t *); +extern int fcoe_disable_callback(fcoe_mac_t *); +extern int fcoe_mac_set_address(fcoe_port_t *, uint8_t *, boolean_t); + +#endif /* _KERNEL */ +#ifdef __cplusplus +} +#endif + +#endif /* _FCOE_ETH_H_ */ diff --git a/usr/src/uts/common/io/fcoe/fcoe_fc.c b/usr/src/uts/common/io/fcoe/fcoe_fc.c new file mode 100644 index 0000000000..e1cb5e3bad --- /dev/null +++ b/usr/src/uts/common/io/fcoe/fcoe_fc.c @@ -0,0 +1,490 @@ +/* + * 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. + */ + +/* + * This file defines interfaces between fcoe and its clients (FCoEI/FCoET) + */ + +#include <sys/ddi.h> +#include <sys/sunddi.h> +#include <sys/sunndi.h> +#include <sys/byteorder.h> +#include <sys/atomic.h> +#include <sys/sysmacros.h> +#include <sys/cmn_err.h> +#include <sys/crc32.h> +#include <sys/fcntl.h> +#include <sys/unistd.h> +#include <sys/mac_client.h> + +/* + * FCoE header files + */ +#include <sys/fcoe/fcoeio.h> +#include <sys/fcoe/fcoe_common.h> + +/* + * Driver's own header files + */ +#include <fcoe.h> +#include <fcoe_fc.h> +#include <fcoe_eth.h> + +static void fcoe_fill_frame_headers(fcoe_frame_t *frm); +static void fcoe_fill_frame_tailers(fcoe_frame_t *frm); +static void fcoe_deregister_client(fcoe_port_t *eport); +static int fcoe_ctl(fcoe_port_t *eport, int cmd, void *arg); +static void fcoe_tx_frame(fcoe_frame_t *frm); +static void *fcoe_alloc_netb(fcoe_port_t *eport, + uint32_t fc_frame_size, uint8_t **ppfc); +static void fcoe_free_netb(void *netb); + +/* + * Only this function will be called explicitly by clients + * Register the specified client port (fcoei/fcoet) + */ +fcoe_port_t * +fcoe_register_client(fcoe_client_t *client) +{ + fcoe_mac_t *mac; + fcoe_port_t *eport; + + ASSERT(mutex_owned(&fcoe_global_ss->ss_ioctl_mutex)); + + /* + * We will not come here, when someone is changing ss_mac_list, + * so it's safe to go through ss_mac_list. + */ + for (mac = list_head(&fcoe_global_ss->ss_mac_list); mac; + mac = list_next(&fcoe_global_ss->ss_mac_list, mac)) { + if (strcmp(client->ect_channel_name, mac->fm_link_name) + == 0) { + break; + } + } + + if (mac == NULL) { + FCOE_LOG(0, "can't find the MAC you want to bind"); + return (NULL); + } + + if (mac->fm_flags & FCOE_MAC_FLAG_BOUND) { + FCOE_LOG(0, "the MAC you want to bind is bound already"); + return (NULL); + } + + atomic_or_32(&mac->fm_flags, FCOE_MAC_FLAG_BOUND); + bcopy(client, &mac->fm_client, sizeof (fcoe_client_t)); + + /* + * fcoe_port_t initialization + */ + eport = &mac->fm_eport; + eport->eport_flags = client->ect_eport_flags | EPORT_FLAG_MAC_IN_USE; + eport->eport_fcoe_private = mac; + eport->eport_client_private = client->ect_client_port_struct; + eport->eport_max_fc_frame_size = 2136; + eport->eport_tx_frame = fcoe_tx_frame; + eport->eport_alloc_frame = fcoe_allocate_frame; + eport->eport_release_frame = fcoe_release_frame; + eport->eport_alloc_netb = fcoe_alloc_netb; + eport->eport_free_netb = fcoe_free_netb; + eport->eport_deregister_client = fcoe_deregister_client; + eport->eport_ctl = fcoe_ctl; + eport->eport_set_mac_address = fcoe_mac_set_address; + + return (eport); +} + +/* + * The following routines will be called through vectors in fcoe_port_t + */ + +/* + * Deregister fcoet/fcoei modules, client should make sure the port is in + * offline status already + */ +static void +fcoe_deregister_client(fcoe_port_t *eport) +{ + fcoe_mac_t *mac = EPORT2MAC(eport); + + ASSERT(mutex_owned(&fcoe_global_ss->ss_ioctl_mutex)); + + /* + * Wait for all the related frame to be freed, this should be fast + * because before deregister fcoei/fcoet will make sure its port + * is already in offline status so no frame will be received or sent + * any more + */ + while (mac->fm_frm_cnt > 0) { + delay(10); + } + + atomic_and_32(&EPORT2MAC(eport)->fm_flags, ~FCOE_MAC_FLAG_BOUND); +} + +/* ARGSUSED */ +static int +fcoe_ctl(fcoe_port_t *eport, int cmd, void *arg) +{ + fcoe_mac_t *mac = EPORT2MAC(eport); + + switch (cmd) { + case FCOE_CMD_PORT_ONLINE: + /* + * client ask us to online, so it's safe to post event + * and data up + */ + if (fcoe_enable_callback(mac) == FCOE_FAILURE) { + return (FCOE_FAILURE); + } + mac->fm_state = FCOE_MAC_STATE_ONLINE; + if (mac->fm_link_state == FCOE_MAC_LINK_STATE_UP) + (void) ddi_taskq_dispatch( + fcoe_global_ss->ss_watchdog_taskq, + fcoe_mac_notify_link_up, mac, DDI_SLEEP); + break; + case FCOE_CMD_PORT_OFFLINE: + if (fcoe_disable_callback(mac) == FCOE_FAILURE) { + return (FCOE_FAILURE); + } + mac->fm_state = FCOE_MAC_STATE_OFFLINE; + // in case there are threads waiting + mutex_enter(&mac->fm_mutex); + cv_broadcast(&mac->fm_tx_cv); + mutex_exit(&mac->fm_mutex); + break; + default: + FCOE_LOG("fcoe", "fcoe_ctl, unsupported cmd %x", cmd); + break; + } + + return (FCOE_SUCCESS); +} + +/* + * Transmit the specified frame to the link + */ +static void +fcoe_tx_frame(fcoe_frame_t *frm) +{ + mblk_t *ret_mblk = NULL; + fcoe_mac_t *mac = FRM2MAC(frm); + mac_tx_cookie_t ret_cookie; + + fcoe_fill_frame_headers(frm); + fcoe_fill_frame_tailers(frm); + +tx_frame: + ret_cookie = mac_tx(mac->fm_cli_handle, FRM2MBLK(frm), 0, + MAC_TX_NO_ENQUEUE, &ret_mblk); + if (ret_cookie != NULL) { + mutex_enter(&mac->fm_mutex); + (void) cv_timedwait(&mac->fm_tx_cv, &mac->fm_mutex, + ddi_get_lbolt() + drv_usectohz(100000)); + mutex_exit(&mac->fm_mutex); + + if (mac->fm_state == FCOE_MAC_STATE_OFFLINE) { + /* + * we are doing offline, so just tell the upper that + * this is finished, the cmd will be aborted soon. + */ + fcoe_free_netb(ret_mblk); + } else { + goto tx_frame; + } + } + + /* + * MAC driver will release the mblk of the frame + * We need only release the frame itself + */ + mutex_enter(&FRM2MAC(frm)->fm_ss->ss_watch_mutex); + list_insert_tail(&FRM2MAC(frm)->fm_ss->ss_pfrm_list, + FRM2FMI(frm)); + mac->fm_frm_cnt ++; + if (FRM2MAC(frm)->fm_ss->ss_flags & SS_FLAG_DOG_WAITING) { + cv_signal(&FRM2MAC(frm)->fm_ss->ss_watch_cv); + } + mutex_exit(&FRM2MAC(frm)->fm_ss->ss_watch_mutex); +} + +/* + * Consider cache allocation in the future + */ +void +fcoe_release_frame(fcoe_frame_t *frame) +{ + kmem_free(frame, frame->frm_alloc_size); +} + +static void * +fcoe_alloc_netb(fcoe_port_t *eport, uint32_t fc_frame_size, uint8_t **ppfc) +{ + mblk_t *mp; + + mp = fcoe_get_mblk(eport->eport_fcoe_private, + fc_frame_size + PADDING_SIZE); + if (mp != NULL) { + *ppfc = mp->b_rptr + PADDING_HEADER_SIZE; + } + + return (mp); +} + +static void +fcoe_free_netb(void *netb) +{ + freeb((mblk_t *)netb); +} + +fcoe_frame_t * +fcoe_allocate_frame(fcoe_port_t *eport, uint32_t fc_frame_size, void *xmp) +{ + fcoe_frame_t *frm; + fcoe_i_frame_t *fmi; + mblk_t *mp = xmp; + uint32_t alloc_size; + uint32_t raw_frame_size; + + if (fc_frame_size > 2136) { + FCOE_LOG("fcoe", "fcoe_allocate_frame %d > 2136", + fc_frame_size); + return (NULL); + } + + if (mp == NULL) { + /* + * We are allocating solicited frame now + */ + raw_frame_size = PADDING_SIZE + fc_frame_size; + mp = fcoe_get_mblk(EPORT2MAC(eport), raw_frame_size); + if (mp == NULL) { + return (NULL); + } + } + + alloc_size = sizeof (fcoe_frame_t) + sizeof (fcoe_i_frame_t) + + EPORT2MAC(eport)->fm_client.ect_private_frame_struct_size; + + /* + * fcoe_frame_t initialization + */ + frm = (fcoe_frame_t *)kmem_alloc(alloc_size, KM_SLEEP); + frm->frm_alloc_size = alloc_size; + frm->frm_fc_frame_size = fc_frame_size; + frm->frm_payload_size = fc_frame_size - + sizeof (fcoe_fc_frame_header_t); + frm->frm_fcoe_private = sizeof (fcoe_frame_t) + (uint8_t *)frm; + frm->frm_client_private = sizeof (fcoe_i_frame_t) + + (uint8_t *)frm->frm_fcoe_private; + frm->frm_flags = 0; + frm->frm_eport = eport; + frm->frm_netb = mp; + + /* + * fcoe_i_frame_t initialization + */ + fmi = FRM2FMI(frm); + fmi->fmi_frame = frm; + fmi->fmi_mac = EPORT2MAC(eport); + fmi->fmi_efh = (void *)mp->b_rptr; + + fmi->fmi_ffh = (fcoe_frame_header_t *) + (sizeof (struct ether_header) + (uint8_t *)fmi->fmi_efh); + + fmi->fmi_fc_frame = sizeof (fcoe_frame_header_t) + + (uint8_t *)fmi->fmi_ffh; + fmi->fmi_fft = (fcoe_frame_tailer_t *) + (fc_frame_size + (uint8_t *)fmi->fmi_fc_frame); + + /* + * Continue to initialize fcoe_frame_t + */ + frm->frm_hdr = (fcoe_fc_frame_header_t *)fmi->fmi_fc_frame; + frm->frm_ofh1 = NULL; + frm->frm_ofh2 = NULL; + frm->frm_fc_frame = (uint8_t *)frm->frm_hdr; + frm->frm_payload = sizeof (fcoe_fc_frame_header_t) + + (uint8_t *)frm->frm_fc_frame; + return (frm); +} + +/* + * Sub routines called by interface functions + */ + +/* + * According to spec, fill EthernetII frame header, FCoE frame header + * VLAN (not included for now) + */ +static void +fcoe_fill_frame_headers(fcoe_frame_t *frm) +{ + fcoe_i_frame_t *fmi = FRM2FMI(frm); + + /* + * Initialize ethernet frame header + */ + bcopy(FRM2MAC(frm)->fm_current_addr, &fmi->fmi_efh->ether_shost, + ETHERADDRL); + bcopy(frm->frm_eport->eport_efh_dst, + &fmi->fmi_efh->ether_dhost, ETHERADDRL); + fmi->fmi_efh->ether_type = htons(ETHERTYPE_FCOE); + + /* + * Initialize FCoE frame header + */ + bzero(fmi->fmi_ffh, sizeof (fcoe_frame_header_t)); + FCOE_ENCAPS_VER(fmi->fmi_ffh, FCOE_VER); + /* set to SOFi3 for the first frame of a sequence */ + if (FRM_SEQ_CNT(frm) == 0) { + FCOE_V2B_1(0x2E, fmi->fmi_ffh->ffh_sof); + } else { + FCOE_V2B_1(0x36, fmi->fmi_ffh->ffh_sof); + } +} + +/* + * According to spec, fill FCOE frame tailer including CRC + * VLAN (not included for now) + */ +static void +fcoe_fill_frame_tailers(fcoe_frame_t *frm) +{ + uint32_t crc; + + /* + * Initialize FCoE frame tailer + * CRC is not big endian, can't use macro V2B + */ + CRC32(crc, frm->frm_fc_frame, frm->frm_fc_frame_size, + (uint32_t)~0, crc32_table); + FRM2FMI(frm)->fmi_fft->fft_crc[0] = 0xFF & (~crc); + FRM2FMI(frm)->fmi_fft->fft_crc[1] = 0xFF & (~crc >> 8); + FRM2FMI(frm)->fmi_fft->fft_crc[2] = 0xFF & (~crc >> 16); + FRM2FMI(frm)->fmi_fft->fft_crc[3] = 0xFF & (~crc >> 24); + if (FRM_F_CTL(frm) & 0x080000) { + FCOE_V2B_1(0x42, FRM2FMI(frm)->fmi_fft->fft_eof); + } else { + FCOE_V2B_1(0x41, FRM2FMI(frm)->fmi_fft->fft_eof); + } + + FRM2FMI(frm)->fmi_fft->fft_resvd[0] = 0; + FRM2FMI(frm)->fmi_fft->fft_resvd[1] = 0; + FRM2FMI(frm)->fmi_fft->fft_resvd[2] = 0; +} + +void +fcoe_mac_notify_link_up(void *arg) +{ + fcoe_mac_t *mac = (fcoe_mac_t *)arg; + + ASSERT(mac->fm_flags & FCOE_MAC_FLAG_BOUND); + + mac->fm_client.ect_port_event(&mac->fm_eport, + FCOE_NOTIFY_EPORT_LINK_UP); +} +void +fcoe_mac_notify_link_down(void *arg) +{ + fcoe_mac_t *mac = (fcoe_mac_t *)arg; + + if (mac->fm_flags & FCOE_MAC_FLAG_BOUND) { + mac->fm_client.ect_port_event(&mac->fm_eport, + FCOE_NOTIFY_EPORT_LINK_DOWN); + } +} + +int +fcoe_create_port(dev_info_t *parent, fcoe_mac_t *mac, int is_target) +{ + int rval = 0; + dev_info_t *child = NULL; + char *mac_name = mac->fm_link_name; + char *devname = is_target ? FCOET_DRIVER_NAME : FCOEI_DRIVER_NAME; + + ndi_devi_alloc_sleep(parent, devname, DEVI_PSEUDO_NODEID, &child); + if (child == NULL) { + FCOE_LOG("fcoe", "fail to create new devinfo"); + return (NDI_FAILURE); + } + + if (ddi_prop_update_string(DDI_DEV_T_NONE, child, + "mac_name", mac_name) != DDI_PROP_SUCCESS) { + FCOE_LOG("fcoe", + "fcoe%d: prop_update port mac name failed for mac %s", + ddi_get_instance(parent), mac_name); + (void) ndi_devi_free(child); + return (NDI_FAILURE); + } + + rval = ndi_devi_online(child, NDI_ONLINE_ATTACH); + if (rval != NDI_SUCCESS) { + FCOE_LOG("fcoe", "fcoe%d: online_driver failed for mac %s", + ddi_get_instance(parent), mac->fm_link_name); + return (NDI_FAILURE); + } + mac->fm_client_dev = child; + + return (rval); +} + +int +fcoe_delete_port(dev_info_t *parent, fcoeio_t *fcoeio, uint8_t *mac_name) +{ + int rval = 0; + fcoe_mac_t *mac; + + mac = fcoe_lookup_mac_by_name(mac_name); + if (mac == NULL) { + fcoeio->fcoeio_status = FCOEIOE_MAC_NOT_FOUND; + return (EINVAL); + } + + if ((mac->fm_flags & FCOE_MAC_FLAG_ENABLED) != FCOE_MAC_FLAG_ENABLED) { + fcoeio->fcoeio_status = FCOEIOE_ALREADY; + return (EALREADY); + } + + atomic_and_32(&mac->fm_eport.eport_flags, ~EPORT_FLAG_MAC_IN_USE); + + rval = ndi_devi_offline(mac->fm_client_dev, NDI_DEVI_REMOVE); + if (rval != NDI_SUCCESS) { + FCOE_LOG("fcoe", "fcoe%d: offline_driver %s failed", + ddi_get_instance(parent), + ddi_get_name(mac->fm_client_dev)); + atomic_or_32(&mac->fm_eport.eport_flags, + EPORT_FLAG_MAC_IN_USE); + + fcoeio->fcoeio_status = FCOEIOE_OFFLINE_FAILURE; + return (EBUSY); + } + (void) fcoe_close_mac(mac); + fcoe_destroy_mac(mac); + return (0); +} diff --git a/usr/src/uts/common/io/fcoe/fcoe_fc.h b/usr/src/uts/common/io/fcoe/fcoe_fc.h new file mode 100644 index 0000000000..8fbbe52936 --- /dev/null +++ b/usr/src/uts/common/io/fcoe/fcoe_fc.h @@ -0,0 +1,47 @@ +/* + * 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 _FCOE_FC_H_ +#define _FCOE_FC_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _KERNEL + +extern void fcoe_release_frame(fcoe_frame_t *); +extern fcoe_frame_t *fcoe_allocate_frame(fcoe_port_t *, uint32_t, void *); +extern void fcoe_mac_notify_link_up(void *); +extern void fcoe_mac_notify_link_down(void *); +extern int fcoe_create_port(dev_info_t *, fcoe_mac_t *, int); +extern int fcoe_delete_port(dev_info_t *, fcoeio_t *, uint8_t *); + +#endif /* _KERNEL */ + +#ifdef __cplusplus +} +#endif + +#endif /* _FCOE_FC_H_ */ diff --git a/usr/src/uts/common/sys/ethernet.h b/usr/src/uts/common/sys/ethernet.h index 97531e917c..eb1b686540 100644 --- a/usr/src/uts/common/sys/ethernet.h +++ b/usr/src/uts/common/sys/ethernet.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -30,8 +30,6 @@ #ifndef _SYS_ETHERNET_H #define _SYS_ETHERNET_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif @@ -94,6 +92,7 @@ struct ether_vlan_extinfo { #define ETHERTYPE_PPPOES (0x8864) /* PPPoE Session Stage */ #define ETHERTYPE_EAPOL (0x888e) /* EAPOL protocol */ #define ETHERTYPE_RSN_PREAUTH (0x88c7) /* RSN PRE-Authentication */ +#define ETHERTYPE_FCOE (0x8906) /* FCoE */ #define ETHERTYPE_MAX (0xffff) /* Max valid ethernet type */ /* diff --git a/usr/src/uts/common/sys/fcoe/fcoe_common.h b/usr/src/uts/common/sys/fcoe/fcoe_common.h new file mode 100644 index 0000000000..bad3c5a133 --- /dev/null +++ b/usr/src/uts/common/sys/fcoe/fcoe_common.h @@ -0,0 +1,349 @@ +/* + * 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 _FCOE_COMMON_H_ +#define _FCOE_COMMON_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _KERNEL + +/* + * Interface return value + */ +#define FCOE_SUCCESS 0 +#define FCOE_FAILURE -1 +#define FCOE_BUSY -2 +#define FCOE_NOT_SUPPORTED -3 +#define FCOE_BAD_FRAME -4 + +/* + * FCOE port speed + */ +#define FCOE_PORT_SPEED_1G 1000000000 +#define FCOE_PORT_SPEED_10G 10000000000 + +/* + * FC Frame header size: 24 bytes + */ +#define FCFH_SIZE (sizeof (fcoe_fc_frame_header_t)) + +/* + * FLOGI + */ +#define FLOGI_REQ_PAYLOAD_SIZE 116 +#define FLOGI_ACC_PAYLOAD_SIZE 116 + +/* + * Minimum MTU size + */ +#define FCOE_MIN_MTU_SIZE 2500 + +/* + * 24 byte FC frame header + * For all data structures that have endian problems, we will use only + * one type: uint8_t. We need associate the data structure pointer with + * one buffer directly. + */ +typedef struct fcoe_fc_frame_header { + uint8_t hdr_r_ctl[1]; + uint8_t hdr_d_id[3]; + + uint8_t hdr_cs_ctl[1]; + uint8_t hdr_s_id[3]; + + uint8_t hdr_type[1]; + uint8_t hdr_f_ctl[3]; + + uint8_t hdr_seq_id[1]; + uint8_t hdr_df_ctl[1]; + uint8_t hdr_seq_cnt[2]; + + uint8_t hdr_oxid[2]; + uint8_t hdr_rxid[2]; + + uint8_t hdr_param[4]; +} fcoe_fc_frame_header_t; + +/* + * Solicited frame: allocted by FCOET/FOCEI, free-ed by FCOE + * Unsolicited frame: allocated by FCOE, free-ed by FCOET/FCOEI + */ +struct fcoe_port; +typedef struct fcoe_frame { + uint32_t frm_flags; + void *frm_netb; + fcoe_fc_frame_header_t *frm_hdr; + uint8_t *frm_ofh1; + uint8_t *frm_ofh2; + uint8_t *frm_fc_frame; + uint8_t *frm_payload; + uint32_t frm_fc_frame_size; + uint32_t frm_payload_size; + uint32_t frm_alloc_size; + struct fcoe_port *frm_eport; + void *frm_fcoe_private; + void *frm_client_private; +} fcoe_frame_t; + +/* + * FCOE HBA + */ +typedef struct fcoe_port { + uint32_t eport_flags; + void *eport_fcoe_private; + void *eport_client_private; + uint8_t eport_portwwn[8]; + uint8_t eport_nodewwn[8]; + uint32_t eport_max_fc_frame_size; + uint32_t eport_mtu; + uint64_t eport_link_speed; + uint8_t eport_efh_dst[ETHERADDRL]; + void (*eport_tx_frame)(fcoe_frame_t *frame); + fcoe_frame_t *(*eport_alloc_frame)(struct fcoe_port *eport, + uint32_t this_fc_frame_size, void *netb); + void (*eport_release_frame)(fcoe_frame_t *frame); + void *(*eport_alloc_netb)(struct fcoe_port *eport, + uint32_t this_fc_frame_size, uint8_t **ppfc); + void (*eport_free_netb)(void *netb); + void (*eport_deregister_client)(struct fcoe_port *eport); + int (*eport_ctl)(struct fcoe_port *eport, + int cmd, void *arg); + int (*eport_set_mac_address)(struct fcoe_port *eport, + uint8_t *addr, boolean_t fc_assigned); +} fcoe_port_t; + +/* + * FCOE only supports two kinds of topology: direct P2P, fabric P2P. + */ +#define EPORT_FLAG_IS_DIRECT_P2P 0x01 +#define EPORT_FLAG_TGT_MODE 0x02 +#define EPORT_FLAG_INI_MODE 0x04 +#define EPORT_FLAG_MAC_IN_USE 0x08 + +#define FCOE_NOTIFY_EPORT_LINK_UP 0x01 +#define FCOE_NOTIFY_EPORT_LINK_DOWN 0x02 +#define FCOE_NOTIFY_EPORT_ADDR_CHG 0x03 + +#define FCOE_PORT_CTL_CMDS 0x3000 +#define FCOE_CMD_PORT_ONLINE (FCOE_PORT_CTL_CMDS | 0x01) +#define FCOE_CMD_PORT_OFFLINE (FCOE_PORT_CTL_CMDS | 0x02) + +typedef struct fcoe_client { + uint32_t ect_eport_flags; + uint32_t ect_max_fc_frame_size; + uint32_t ect_private_frame_struct_size; + char ect_channel_name[32]; + void *ect_client_port_struct; + void (*ect_rx_frame)(fcoe_frame_t *frame); + void (*ect_port_event)(fcoe_port_t *eport, uint32_t event); + void (*ect_release_sol_frame)(fcoe_frame_t *frame); +} fcoe_client_t; + +/* + * Define common-used conversion or calculation macros + */ +#define FCOE_V2B_1(x_v, x_b) \ + { \ + ((uint8_t *)(x_b))[0] = 0xFF & (x_v); \ + } + +#define FCOE_V2B_2(x_v, x_b) \ + { \ + ((uint8_t *)(x_b))[1] = 0xFF & (x_v); \ + ((uint8_t *)(x_b))[0] = 0xFF & ((x_v) >> 8); \ + } + +#define FCOE_V2B_3(x_v, x_b) \ + { \ + ((uint8_t *)(x_b))[2] = 0xFF & (x_v); \ + ((uint8_t *)(x_b))[1] = 0xFF & ((x_v) >> 8); \ + ((uint8_t *)(x_b))[0] = 0xFF & ((x_v) >> 16); \ + } + +#define FCOE_V2B_4(x_v, x_b) \ + { \ + ((uint8_t *)(x_b))[3] = 0xFF & (x_v); \ + ((uint8_t *)(x_b))[2] = 0xFF & ((x_v) >> 8); \ + ((uint8_t *)(x_b))[1] = 0xFF & ((x_v) >> 16); \ + ((uint8_t *)(x_b))[0] = 0xFF & ((x_v) >> 24); \ + } + +#define FCOE_V2B_8(x_v, x_b) \ + { \ + ((uint8_t *)(x_b))[7] = 0xFF & (x_v); \ + ((uint8_t *)(x_b))[6] = 0xFF & ((x_v) >> 8); \ + ((uint8_t *)(x_b))[5] = 0xFF & ((x_v) >> 16); \ + ((uint8_t *)(x_b))[4] = 0xFF & ((x_v) >> 24); \ + ((uint8_t *)(x_b))[3] = 0xFF & ((x_v) >> 32); \ + ((uint8_t *)(x_b))[2] = 0xFF & ((x_v) >> 40); \ + ((uint8_t *)(x_b))[1] = 0xFF & ((x_v) >> 48); \ + ((uint8_t *)(x_b))[0] = 0xFF & ((x_v) >> 56); \ + } + +#define FCOE_B2V_1(x_b) \ + ((((uint8_t *)(x_b))[0]) & 0xFF) + +#define FCOE_B2V_2(x_b) \ + ((((uint8_t *)(x_b))[1] | ((uint8_t *)(x_b))[0] << 8) & 0xFFFF) + +#define FCOE_B2V_3(x_b) \ + ((((uint8_t *)(x_b))[2] | ((uint8_t *)(x_b))[1] << 8 | \ + ((uint8_t *)(x_b))[0] << 16) & 0xFFFFFF) + +#define FCOE_B2V_4(x_b) \ + ((((uint8_t *)(x_b))[3] | ((uint8_t *)(x_b))[2] << 8 | \ + ((uint8_t *)(x_b))[1] << 16 | \ + ((uint8_t *)(x_b))[0] << 24) & 0xFFFFFFFF) + +#define FCOE_B2V_8(x_b) \ + ((((uint8_t *)(x_b))[7] | ((uint8_t *)(x_b))[6] << 8 | \ + ((uint8_t *)(x_b))[5] << 16 | \ + ((uint8_t *)(x_b))[4] << 24 | \ + ((uint8_t *)(x_b))[3] << 32 | \ + ((uint8_t *)(x_b))[2] << 40 | \ + ((uint8_t *)(x_b))[1] << 48 | \ + ((uint8_t *)(x_b))[0] << 56) & 0xFFFFFFFFFFFFFFFF) + +/* + * Get FC frame header's element + */ +#define FRM_R_CTL(x_frm) (FCOE_B2V_1((x_frm)->frm_hdr->hdr_r_ctl)) +#define FRM_D_ID(x_frm) (FCOE_B2V_3((x_frm)->frm_hdr->hdr_d_id)) +#define FRM_S_ID(x_frm) (FCOE_B2V_3((x_frm)->frm_hdr->hdr_s_id)) +#define FRM_TYPE(x_frm) (FCOE_B2V_1((x_frm)->frm_hdr->hdr_type)) +#define FRM_F_CTL(x_frm) (FCOE_B2V_3((x_frm)->frm_hdr->hdr_f_ctl)) +#define FRM_SEQ_ID(x_frm) (FCOE_B2V_1((x_frm)->frm_hdr->hdr_seq_id)) +#define FRM_DF_CTL(x_frm) (FCOE_B2V_1((x_frm)->frm_hdr->hdr_df_ctl)) +#define FRM_SEQ_CNT(x_frm) (FCOE_B2V_2((x_frm)->frm_hdr->hdr_seq_cnt)) +#define FRM_OXID(x_frm) (FCOE_B2V_2((x_frm)->frm_hdr->hdr_oxid)) +#define FRM_RXID(x_frm) (FCOE_B2V_2((x_frm)->frm_hdr->hdr_rxid)) +#define FRM_PARAM(x_frm) (FCOE_B2V_4((x_frm)->frm_hdr->hdr_param)) + +/* + * Set FC frame header's element + */ +#define FFM_R_CTL(x_v, x_frm) FCOE_V2B_1((x_v), (x_frm)->frm_hdr->hdr_r_ctl) +#define FFM_D_ID(x_v, x_frm) FCOE_V2B_3((x_v), (x_frm)->frm_hdr->hdr_d_id) +#define FFM_S_ID(x_v, x_frm) FCOE_V2B_3((x_v), (x_frm)->frm_hdr->hdr_s_id) +#define FFM_TYPE(x_v, x_frm) FCOE_V2B_1((x_v), (x_frm)->frm_hdr->hdr_type) +#define FFM_F_CTL(x_v, x_frm) FCOE_V2B_3((x_v), (x_frm)->frm_hdr->hdr_f_ctl) +#define FFM_SEQ_ID(x_v, x_frm) FCOE_V2B_1((x_v), (x_frm)->frm_hdr->hdr_seq_id) +#define FFM_DF_CTL(x_v, x_frm) FCOE_V2B_1((x_v), (x_frm)->frm_hdr->hdr_df_ctl) +#define FFM_SEQ_CNT(x_v, x_frm) FCOE_V2B_2((x_v), (x_frm)->frm_hdr->hdr_seq_cnt) +#define FFM_OXID(x_v, x_frm) FCOE_V2B_2((x_v), (x_frm)->frm_hdr->hdr_oxid) +#define FFM_RXID(x_v, x_frm) FCOE_V2B_2((x_v), (x_frm)->frm_hdr->hdr_rxid) +#define FFM_PARAM(x_v, x_frm) FCOE_V2B_4((x_v), (x_frm)->frm_hdr->hdr_param) + +/* + * frame header checking + */ +#define FRM_IS_LAST_FRAME(x_frm) (FRM_F_CTL(x_frm) & (1 << 19)) + +/* + * FCOET/FCOEI will only call this fcoe function explicitly, all others + * should be called through vectors in struct fcoe_port. + * FCOE client call this to register one port to FCOE, FCOE need initialize + * and return the corresponding fcoe_port. + */ +extern fcoe_port_t *fcoe_register_client(fcoe_client_t *client); + +#define EPORT_CLT_TYPE(eport) \ + (((eport)->eport_flags & EPORT_FLAG_INI_MODE) ? \ + FCOE_CLIENT_INITIATOR : FCOE_CLIENT_TARGET) + +#define FCOE_SET_DEFAULT_OUI(x_oui) \ + (x_oui)[0] = 0x0e; (x_oui)[1] = 0xfc; (x_oui)[2] = 0x00; +#define FCOE_SET_DEFAULT_FPORT_ADDR(x_addr) \ + FCOE_SET_DEFAULT_OUI(x_addr) \ + (x_addr)[3] = 0xff; (x_addr)[4] = 0xff; (x_addr)[5] = 0xfe; + +/* + * FC payload size + */ +#define FCOE_DEFAULT_FCP_DATA_PAYLOAD_SIZE 2048 +#define FCOE_MIN_FCP_DATA_PAYLOAD_SIZE 1024 + +typedef struct fcoe_fcp_cmnd { + uint8_t ffc_lun[8]; + uint8_t ffc_ref_num[1]; + + /* + * least 3 bits + */ + uint8_t ffc_attribute[1]; + + /* + * Magnagement flags + */ + uint8_t ffc_management_flags[1]; + + /* + * additional cdb len and read/write flag + */ + uint8_t ffc_addlen_rdwr[1]; + + uint8_t ffc_cdb[16]; + uint8_t ffc_fcp_dl[4]; +} fcoe_fcp_cmnd_t; + +typedef struct fcoe_fcp_rsp { + uint8_t ffr_rsvd[8]; + + /* + * see SAM-4 + */ + uint8_t ffr_retry_delay_timer[2]; + uint8_t ffr_flags[1]; + uint8_t ffr_scsi_status[1]; + uint8_t ffr_resid[4]; + uint8_t ffr_sns_len[4]; + uint8_t ffr_rsp_len[4]; + /* + * Followed by sense data when available + */ +} fcoe_fcp_rsp_t; + +typedef struct fcoe_fcp_xfer_rdy { + uint8_t fxr_data_ro[4]; + uint8_t fxr_burst_len[4]; + uint8_t fxr_rsvd[4]; +} fcoe_fcp_xfer_rdy_t; + +/* + * FCOE project global functions + */ +#define FCOE_SEC2TICK(x_sec) (drv_usectohz((x_sec) * 1000000)) +typedef void (*TQ_FUNC_P)(void *); +extern void fcoe_trace(caddr_t ident, const char *fmt, ...); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _FCOE_COMMON_H_ */ diff --git a/usr/src/uts/common/sys/fcoe/fcoeio.h b/usr/src/uts/common/sys/fcoe/fcoeio.h new file mode 100644 index 0000000000..6d24a2673f --- /dev/null +++ b/usr/src/uts/common/sys/fcoe/fcoeio.h @@ -0,0 +1,144 @@ +/* + * 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 _FCOEIO_H_ +#define _FCOEIO_H_ + +#include <sys/ethernet.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * ioctl cmd definitions + */ +#define FCOEIO_CMD ('G'<< 8 | 2009) +#define FCOEIO_SUB_CMD ('X' << 8) + +/* + * fcoe ioctl sub-command + */ +#define FCOEIO_CREATE_FCOE_PORT (FCOEIO_SUB_CMD + 0x01) +#define FCOEIO_DELETE_FCOE_PORT (FCOEIO_SUB_CMD + 0x02) +#define FCOEIO_GET_FCOE_PORT_LIST (FCOEIO_SUB_CMD + 0x03) + +/* + * define common-used constants + */ +#define FCOE_MAX_MAC_NAME_LEN 32 + +/* + * fcoeio_xfer definitions + */ +#define FCOEIO_XFER_NONE 0x00 +#define FCOEIO_XFER_READ 0x01 +#define FCOEIO_XFER_WRITE 0x02 +#define FCOEIO_XFER_RW (FCOEIO_XFER_READ | FCOEIO_XFER_WRITE) + +/* + * fcoeio_errno definitions + */ +typedef enum { + FCOEIOE_INVAL_ARG = 5, + FCOEIOE_BUSY, + FCOEIOE_ALREADY, + FCOEIOE_PWWN_CONFLICTED, + FCOEIOE_NWWN_CONFLICTED, + FCOEIOE_CREATE_MAC, + FCOEIOE_OPEN_MAC, + FCOEIOE_CREATE_PORT, + FCOEIOE_NEED_JUMBO_FRAME, + FCOEIOE_MAC_NOT_FOUND, + FCOEIOE_OFFLINE_FAILURE, + FCOEIOE_MORE_DATA, + FCOEIOE_VNIC_UNSUPPORT +} fcoeio_stat_t; + +/* Biggest buffer length, can hold up to 1024 port instances */ +#define FCOEIO_MAX_BUF_LEN 0x10000 + +typedef struct fcoeio { + uint16_t fcoeio_xfer; /* direction */ + uint16_t fcoeio_cmd; /* sub command */ + uint16_t fcoeio_flags; /* flags */ + uint16_t fcoeio_cmd_flags; /* command specific flags */ + uint32_t fcoeio_ilen; /* Input buffer length */ + uint32_t fcoeio_olen; /* Output buffer length */ + uint32_t fcoeio_alen; /* Auxillary buffer length */ + fcoeio_stat_t fcoeio_status; /* FC internal error status */ + uint64_t fcoeio_ibuf; /* Input buffer */ + uint64_t fcoeio_obuf; /* Output buffer */ + uint64_t fcoeio_abuf; /* Auxillary buffer */ +} fcoeio_t; + +/* + * Client port type + */ +typedef enum { + FCOE_CLIENT_INITIATOR = 0, + FCOE_CLIENT_TARGET +} fcoe_cli_type_t; + +/* + * Command for FCOEIO_CREATE_FCOET_PORT + */ +#define FCOE_WWN_SIZE 8 +typedef struct fcoeio_create_port_param { + uchar_t fcp_pwwn[FCOE_WWN_SIZE]; + uchar_t fcp_nwwn[FCOE_WWN_SIZE]; + uint32_t fcp_nwwn_provided; + uint32_t fcp_pwwn_provided; + uint32_t fcp_force_promisc; + fcoe_cli_type_t fcp_port_type; + uchar_t fcp_mac_name[MAXLINKNAMELEN]; +} fcoeio_create_port_param_t; + +/* + * FCOE port instance + */ +typedef struct fcoe_port_instance { + uchar_t fpi_pwwn[FCOE_WWN_SIZE]; + uchar_t fpi_mac_link_name[MAXLINKNAMELEN]; + uint8_t fpi_mac_factory_addr[ETHERADDRL]; + uint16_t fpi_mac_promisc; + uint8_t fpi_mac_current_addr[ETHERADDRL]; + uint16_t fpi_rsvd1; + fcoe_cli_type_t fpi_port_type; + uint32_t fpi_mtu_size; +} fcoe_port_instance_t; + +/* + * FCOE port instance list + */ +typedef struct fcoe_port_list { + uint64_t numPorts; + fcoe_port_instance_t ports[1]; +} fcoe_port_list_t; + +#ifdef __cplusplus +} +#endif + +#endif /* _FCOEIO_H_ */ diff --git a/usr/src/uts/common/sys/fct.h b/usr/src/uts/common/sys/fct.h index 1808038963..514535afba 100644 --- a/usr/src/uts/common/sys/fct.h +++ b/usr/src/uts/common/sys/fct.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _FCT_H @@ -294,6 +294,7 @@ typedef struct fct_link_info { #define PORT_SPEED_2G 2 #define PORT_SPEED_4G 4 #define PORT_SPEED_8G 8 +#define PORT_SPEED_10G 16 /* * Abort commands diff --git a/usr/src/uts/common/sys/stmf.h b/usr/src/uts/common/sys/stmf.h index 940545b255..1159cc13b1 100644 --- a/usr/src/uts/common/sys/stmf.h +++ b/usr/src/uts/common/sys/stmf.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _STMF_H @@ -87,6 +87,7 @@ typedef struct stmf_data_buf { #define DB_SEND_STATUS_GOOD 0x0004 #define DB_STATUS_GOOD_SENT 0x0008 #define DB_DONT_CACHE 0x0010 +#define DB_DONT_REUSE 0x0020 typedef struct scsi_task { void *task_stmf_private; diff --git a/usr/src/uts/intel/Makefile.intel.shared b/usr/src/uts/intel/Makefile.intel.shared index 734bfd007c..8dc5f05120 100644 --- a/usr/src/uts/intel/Makefile.intel.shared +++ b/usr/src/uts/intel/Makefile.intel.shared @@ -333,6 +333,8 @@ DRV_KMODS += zyd DRV_KMODS += stmf DRV_KMODS += stmf_sbd DRV_KMODS += fct +DRV_KMODS += fcoe +DRV_KMODS += fcoet DRV_KMODS += qlt DRV_KMODS += iscsit DRV_KMODS += ncall nsctl sdbc nskern sv diff --git a/usr/src/uts/intel/fcoe/Makefile b/usr/src/uts/intel/fcoe/Makefile new file mode 100644 index 0000000000..3fda0d67d2 --- /dev/null +++ b/usr/src/uts/intel/fcoe/Makefile @@ -0,0 +1,85 @@ +# +# 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. +# +# This makefile drives the production of the fcoe driver + +# +# Path to the base of the uts directory tree (usually /usr/src/uts) +# +UTSBASE = ../.. +ARCHDIR:sh = cd ..; basename `pwd` + +# +# Define the module and object file sets +# +MODULE = fcoe +OBJECTS = $(FCOE_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(FCOE_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_DRV_DIR)/$(MODULE) +CONF_SRCDIR = $(UTSBASE)/common/io/fcoe + +# +# Include common rules. +# +include ../Makefile.$(ARCHDIR) + +# +# Define targets +# +ALL_TARGET = $(BINARY) $(SRC_CONFILE) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) + +# +# Overrides and depends_on +# +MODSTUBS_DIR = $(OBJS_DIR) +LDFLAGS += -dy -Ndrv/mac +INC_PATH += -I$(UTSBASE)/common/io/fcoe + +# +# Default build targets. +# +.KEEP_STATE: + +def: $(DEF_DEPS) + +all: $(ALL_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +lint: $(LINT_DEPS) + +modlintlib: $(MODLINTLIB_DEPS) + +clean.lint: $(CLEAN_LINT_DEPS) + +install: $(INSTALL_DEPS) + +# +# Include common targets +# +include ../Makefile.targ diff --git a/usr/src/uts/intel/fcoet/Makefile b/usr/src/uts/intel/fcoet/Makefile new file mode 100644 index 0000000000..ca049c7c3a --- /dev/null +++ b/usr/src/uts/intel/fcoet/Makefile @@ -0,0 +1,86 @@ +# +# 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 +# +# uts/intel/fcoet/Makefile +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# This makefile drives the production of the fcoet driver for COMSTAR. +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../.. +ARCHDIR:sh = cd ..; basename `pwd` + +# +# Define the module and object file sets. +# +MODULE = fcoet +OBJECTS = $(FCOET_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(FCOET_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_DRV_DIR)/$(MODULE) + +# +# Include common rules. +# +include ../Makefile.$(ARCHDIR) + +# +# Define targets +# +ALL_TARGET = $(BINARY) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) + +# +# Overrides and depends_on +# +MODSTUBS_DIR = $(OBJS_DIR) +LDFLAGS += -dy -Ndrv/stmf -Ndrv/fct -Ndrv/fcoe +INC_PATH += -I$(UTSBASE)/common/io/comstar/port/fcoet + +# +# Default build targets. +# +.KEEP_STATE: + +def: $(DEF_DEPS) + +all: $(ALL_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +lint: $(LINT_DEPS) + +modlintlib: $(MODLINTLIB_DEPS) + +clean.lint: $(CLEAN_LINT_DEPS) + +install: $(INSTALL_DEPS) + +# +# Include common targets. +# +include ../Makefile.targ diff --git a/usr/src/uts/sparc/Makefile.sparc.shared b/usr/src/uts/sparc/Makefile.sparc.shared index f226ccda05..df11c813cc 100644 --- a/usr/src/uts/sparc/Makefile.sparc.shared +++ b/usr/src/uts/sparc/Makefile.sparc.shared @@ -295,6 +295,8 @@ DRV_KMODS += dmd DRV_KMODS += stmf DRV_KMODS += stmf_sbd DRV_KMODS += fct +DRV_KMODS += fcoe +DRV_KMODS += fcoet DRV_KMODS += qlt DRV_KMODS += iscsit DRV_KMODS += ncall nsctl sdbc nskern sv diff --git a/usr/src/uts/sparc/fcoe/Makefile b/usr/src/uts/sparc/fcoe/Makefile new file mode 100644 index 0000000000..72e55c644e --- /dev/null +++ b/usr/src/uts/sparc/fcoe/Makefile @@ -0,0 +1,85 @@ +# +# 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. +# +# This makefile drives the production of the fcoe driver. + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../.. +ARCHDIR:sh = cd ..; basename `pwd` + +# +# Define the module and object file sets. +# +MODULE = fcoe +OBJECTS = $(FCOE_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(FCOE_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_DRV_DIR)/$(MODULE) +CONF_SRCDIR = $(UTSBASE)/common/io/fcoe + +# +# Include common rules. +# +include ../Makefile.$(ARCHDIR) + +# +# Define targets +# +ALL_TARGET = $(BINARY) $(SRC_CONFILE) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) + +# +# Overrides and depends_on +# +MODSTUBS_DIR = $(OBJS_DIR) +LDFLAGS += -dy -Ndrv/mac +INC_PATH += -I$(UTSBASE)/common/io/fcoe + +# +# Default build targets. +# +.KEEP_STATE: + +def: $(DEF_DEPS) + +all: $(ALL_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +lint: $(LINT_DEPS) + +modlintlib: $(MODLINTLIB_DEPS) + +clean.lint: $(CLEAN_LINT_DEPS) + +install: $(INSTALL_DEPS) + +# +# Include common targets. +# +include ../Makefile.targ diff --git a/usr/src/uts/sparc/fcoet/Makefile b/usr/src/uts/sparc/fcoet/Makefile new file mode 100644 index 0000000000..049893b085 --- /dev/null +++ b/usr/src/uts/sparc/fcoet/Makefile @@ -0,0 +1,85 @@ +# +# 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 +# +# uts/sparc/fcoet/Makefile +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# This makefile drives the production of the fcoet driver for COMSTAR. +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../.. +ARCHDIR:sh = cd ..; basename `pwd` + +# +# Define the module and object file sets. +# +MODULE = fcoet +OBJECTS = $(FCOET_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(FCOET_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_DRV_DIR)/$(MODULE) + +# +# Include common rules. +# +include ../Makefile.$(ARCHDIR) + +# +# Define targets +# +ALL_TARGET = $(BINARY) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) + +# +# Overrides and depends_on +# +MODSTUBS_DIR = $(OBJS_DIR) +LDFLAGS += -dy -Ndrv/stmf -Ndrv/fct -Ndrv/fcoe +INC_PATH += -I$(UTSBASE)/common/io/comstar/port/fcoet + +# Default build targets. +# +.KEEP_STATE: + +def: $(DEF_DEPS) + +all: $(ALL_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +lint: $(LINT_DEPS) + +modlintlib: $(MODLINTLIB_DEPS) + +clean.lint: $(CLEAN_LINT_DEPS) + +install: $(INSTALL_DEPS) + +# +# Include common targets. +# +include ../Makefile.targ |