diff options
Diffstat (limited to 'usr/src')
32 files changed, 3390 insertions, 255 deletions
diff --git a/usr/src/cmd/cmd-inet/sbin/dhcpagent/agent.c b/usr/src/cmd/cmd-inet/sbin/dhcpagent/agent.c index 807bc8269b..34bb772632 100644 --- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/agent.c +++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/agent.c @@ -23,8 +23,6 @@ * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/types.h> #include <stdlib.h> #include <errno.h> @@ -41,6 +39,10 @@ #include <netinet/dhcp.h> #include <net/route.h> #include <sys/sockio.h> +#include <sys/stat.h> +#include <stropts.h> +#include <fcntl.h> +#include <sys/scsi/adapters/iscsi_if.h> #include "async.h" #include "agent.h" @@ -121,6 +123,9 @@ static uint_t ipc_cmd_flags[DHCP_NIPC] = { /* DHCP_GET_TAG */ CMD_BOOTP|CMD_IMMED }; +static boolean_t +is_iscsi_active(void); + int main(int argc, char **argv) { @@ -367,8 +372,16 @@ drain_script(iu_eh_t *ehp, void *arg) { if (shutdown_started == B_FALSE) { shutdown_started = B_TRUE; - if (do_adopt == B_FALSE) /* see 4291141 */ + /* + * Check if the system is diskless client and/or + * there are active iSCSI sessions + * + * Do not drop the lease, or the system will be + * unable to sync(dump) through nfs/iSCSI driver + */ + if (!do_adopt && !is_iscsi_active()) { nuke_smach_list(); + } } return (script_count == 0); } @@ -1468,3 +1481,24 @@ check_cmd_allowed(DHCPSTATE state, dhcp_ipc_type_t cmd) { return (ipc_cmd_allowed[state][cmd] != 0); } + +static boolean_t +is_iscsi_active(void) +{ + int fd; + int active; + + if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) { + return (B_FALSE); + } + + if ((ioctl(fd, ISCSI_IS_ACTIVE, &active)) != 0) { + active = 0; + } + (void) close(fd); + if (active) { + return (B_TRUE); + } else { + return (B_FALSE); + } +} diff --git a/usr/src/cmd/iscsiadm/iscsiadm_main.c b/usr/src/cmd/iscsiadm/iscsiadm_main.c index 99ac43e7a2..3613c7493c 100644 --- a/usr/src/cmd/iscsiadm/iscsiadm_main.c +++ b/usr/src/cmd/iscsiadm/iscsiadm_main.c @@ -3586,9 +3586,24 @@ modifyNode(cmdOptions_t *options, int *funcRet) IMA_OID sharedNodeOid; int i; int lowerCase; + IMA_BOOL iscsiBoot = IMA_FALSE; + IMA_BOOL mpxioEnabled = IMA_FALSE; assert(funcRet != NULL); + /* Get boot session's info */ + (void) SUN_IMA_GetBootIscsi(&iscsiBoot); + if (iscsiBoot == IMA_TRUE) { + status = SUN_IMA_GetBootMpxio(&mpxioEnabled); + if (!IMA_SUCCESS(status)) { + (void) fprintf(stderr, "%s: %s\n", + cmdName, gettext("unable to get MPxIO info" + " of root disk")); + *funcRet = 1; + return (1); + } + } + /* Find Sun initiator */ ret = sunInitiatorFind(&oid); if (ret > 0) { @@ -3643,6 +3658,13 @@ modifyNode(cmdOptions_t *options, int *funcRet) * return (INF_ERROR); * } */ + if (iscsiBoot == IMA_TRUE) { + (void) fprintf(stderr, "%s: %s\n", + cmdName, gettext("iscsi boot, not" + " allowed to change" + " initiator's name")); + return (1); + } oid.objectType = IMA_OBJECT_TYPE_NODE; status = IMA_SetNodeName(oid, nodeName); if (!IMA_SUCCESS(status)) { @@ -3653,6 +3675,13 @@ modifyNode(cmdOptions_t *options, int *funcRet) break; case 'A': + if (iscsiBoot == IMA_TRUE) { + (void) fprintf(stderr, "%s: %s\n", + cmdName, gettext("iscsi boot, not" + " allowed to change" + " initiator's alias")); + return (1); + } /* Take the first operand as node alias. */ if (strlen(optionList->optarg) >= MAX_ISCSI_NAME_LEN) { @@ -3690,6 +3719,13 @@ modifyNode(cmdOptions_t *options, int *funcRet) break; case 'a': + if (iscsiBoot == IMA_TRUE) { + (void) fprintf(stderr, "%s: %s\n", + cmdName, gettext("iscsi boot, not" + " allowed to change authentication" + " method")); + return (1); + } if (modifyNodeAuthMethod(oid, options->optarg, funcRet) != 0) { return (1); @@ -3718,6 +3754,12 @@ modifyNode(cmdOptions_t *options, int *funcRet) break; case 'C': + if (iscsiBoot == IMA_TRUE) { + (void) fprintf(stderr, "%s: %s\n", + cmdName, gettext("iscsi boot, not" + " allowed to change CHAP secret")); + return (1); + } if (modifyNodeAuthParam(oid, AUTH_PASSWORD, NULL, funcRet) != 0) { return (1); @@ -3725,20 +3767,61 @@ modifyNode(cmdOptions_t *options, int *funcRet) break; case 'c': + if (iscsiBoot == IMA_TRUE) { + if (mpxioEnabled == IMA_FALSE) { + (void) fprintf(stderr, + "%s: %s\n", cmdName, + gettext("iscsi" + " boot and MPxIO" + " is disabled, not allowed" + " to change number of" + " sessions to be" + " configured")); + return (1); + } + } if (modifyConfiguredSessions(oid, optionList->optarg) != 0) { + if (iscsiBoot == IMA_TRUE) { + (void) fprintf(stderr, + "%s: %s\n", cmdName, + gettext("iscsi boot," + " fail to set configured" + " session")); + } return (1); } break; + case 'H': + if (iscsiBoot == IMA_TRUE) { + (void) fprintf(stderr, "%s: %s\n", + cmdName, gettext("iscsi boot, not" + " allowed to change CHAP name")); + return (1); + } if (modifyNodeAuthParam(oid, AUTH_NAME, optionList->optarg, funcRet) != 0) { return (1); } break; + case 'd': + if (iscsiBoot == IMA_TRUE) { + if (mpxioEnabled == IMA_FALSE) { + (void) fprintf(stderr, + "%s: %s\n", cmdName, + gettext("iscsi" + " boot and MPxIO" + " is disabled, not" + " allowed to" + " change initiator's" + " login params")); + return (1); + } + } if (setLoginParameter(oid, DATA_DIGEST, optionList->optarg) != 0) { return (1); @@ -3746,6 +3829,19 @@ modifyNode(cmdOptions_t *options, int *funcRet) break; case 'h': + if (iscsiBoot == IMA_TRUE) { + if (mpxioEnabled == IMA_FALSE) { + (void) fprintf(stderr, + "%s: %s\n", cmdName, + gettext("iscsi" + " boot and MPxIO" + " is disabled, not" + " allowed to" + " change initiator's" + " login params")); + return (1); + } + } if (setLoginParameter(oid, HEADER_DIGEST, optionList->optarg) != 0) { return (1); @@ -3786,6 +3882,11 @@ modifyTargetParam(cmdOptions_t *options, char *targetName, int *funcRet) IMA_UINT16 port = 0; IMA_UINT16 tpgt = 0; + IMA_NODE_NAME bootTargetName; + IMA_INITIATOR_AUTHPARMS bootTargetCHAP; + IMA_BOOL iscsiBoot; + IMA_BOOL mpxioEnabled; + cmdOptions_t *optionList = options; assert(funcRet != NULL); @@ -3828,6 +3929,34 @@ modifyTargetParam(cmdOptions_t *options, char *targetName, int *funcRet) return (0); } + (void) SUN_IMA_GetBootIscsi(&iscsiBoot); + if (iscsiBoot == IMA_TRUE) { + status = SUN_IMA_GetBootMpxio(&mpxioEnabled); + if (!IMA_SUCCESS(status)) { + (void) fprintf(stderr, "%s: %s\n", + cmdName, gettext("unable to get MPxIO info" + " of root disk")); + *funcRet = 1; + return (ret); + } + status = SUN_IMA_GetBootTargetName(bootTargetName); + if (!IMA_SUCCESS(status)) { + (void) fprintf(stderr, "%s: %s\n", + cmdName, gettext("unable to get boot target's" + " name")); + *funcRet = 1; + return (ret); + } + status = SUN_IMA_GetBootTargetAuthParams(&bootTargetCHAP); + if (!IMA_SUCCESS(status)) { + (void) fprintf(stderr, "%s: %s\n", + cmdName, gettext("unable to get boot target's" + " auth param")); + *funcRet = 1; + return (ret); + } + } + /* find target oid */ for (found = B_FALSE, i = 0; i < targetList->oidCount; i++) { status = SUN_IMA_GetTargetProperties(targetList->oids[i], @@ -3852,6 +3981,43 @@ modifyTargetParam(cmdOptions_t *options, char *targetName, int *funcRet) */ found = B_TRUE; targetOid = targetList->oids[i]; + + if ((targetNamesEqual(bootTargetName, wcInputObject) + == B_TRUE) && (iscsiBoot == IMA_TRUE)) { + /* + * iscsi booting, need changed target param is + * booting target, for auth param, not allow + * to change, for others dependent on mpxio + */ + + if ((optionList->optval == 'C') || + (optionList->optval == 'H') || + (optionList->optval == 'B') || + (optionList->optval == 'a')) { + /* + * -C CHAP secret set + * -H CHAP name set + * -a authentication + * -B bi-directional-authentication + */ + (void) fprintf(stderr, "%s: %s\n", + cmdName, gettext("iscsi boot," + " not allowed to modify" + " authentication parameters" + " of boot target")); + return (1); + } + if (mpxioEnabled == IMA_FALSE) { + (void) fprintf(stderr, "%s: %s\n", + cmdName, gettext("iscsi boot and" + " MPxIO is disabled, not allowed" + " to modify boot target's" + " parameters")); + return (1); + } + + } + if (modifyIndividualTargetParam(optionList, targetOid, funcRet) != 0) { return (ret); @@ -4326,6 +4492,30 @@ removeTargetParam(int operandLen, char *operand[], int *funcRet) int ret; boolean_t found; int i, j; + IMA_NODE_NAME bootTargetName; + IMA_BOOL iscsiBoot = IMA_FALSE; + IMA_BOOL mpxioEnabled = IMA_FALSE; + + /* Get boot session's info */ + (void) SUN_IMA_GetBootIscsi(&iscsiBoot); + if (iscsiBoot == IMA_TRUE) { + status = SUN_IMA_GetBootMpxio(&mpxioEnabled); + if (!IMA_SUCCESS(status)) { + (void) fprintf(stderr, "%s: %s\n", + cmdName, gettext("unable to get MPxIO info of" + " root disk")); + *funcRet = 1; + return (1); + } + status = SUN_IMA_GetBootTargetName(bootTargetName); + if (!IMA_SUCCESS(status)) { + (void) fprintf(stderr, "%s: %s\n", + cmdName, gettext("unable to get boot" + " target's name")); + *funcRet = 1; + return (1); + } + } assert(funcRet != NULL); @@ -4381,6 +4571,27 @@ removeTargetParam(int operandLen, char *operand[], int *funcRet) if (targetNamesEqual(targetProps.imaProps.name, wcInputObject) == B_TRUE) { found = B_TRUE; + if ((targetNamesEqual(bootTargetName, + wcInputObject) == B_TRUE) && + (iscsiBoot == IMA_TRUE)) { + /* + * iscsi booting, need changed target + * param is booting target, booting + * session mpxio disabled, not + * allow to update + */ + if (mpxioEnabled == IMA_FALSE) { + (void) fprintf(stderr, + "%s: %s\n", cmdName, + gettext("iscsi boot" + " with MPxIO disabled," + " not allowed to remove" + " boot sess param")); + continue; + } + + } + status = SUN_IMA_RemoveTargetParam( targetList->oids[j]); if (!IMA_SUCCESS(status)) { diff --git a/usr/src/cmd/iscsiadm/sun_ima.c b/usr/src/cmd/iscsiadm/sun_ima.c index d41e4b94c4..1893cbe8ef 100644 --- a/usr/src/cmd/iscsiadm/sun_ima.c +++ b/usr/src/cmd/iscsiadm/sun_ima.c @@ -50,6 +50,7 @@ #define LIBRARY_PROPERTY_VENDOR L"Sun Microsystems, Inc." #define DEFAULT_NODE_NAME_FORMAT "iqn.2003-13.com.ima.%s" #define PLUGIN_OWNER 1 +#define MAX_CHAP_SECRET_LEN 16 /* LINTED E_STATIC_UNUSED */ static IMA_INT32 number_of_plugins = -1; @@ -2992,3 +2993,151 @@ IMA_API IMA_STATUS SUN_IMA_GetTargetAuthParms( return (IMA_STATUS_SUCCESS); } + +IMA_API IMA_STATUS SUN_IMA_GetBootTargetName( + IMA_NODE_NAME tgtName +) +{ + int fd; + IMA_STATUS rtn; + iscsi_boot_property_t bootProp; + + bootProp.tgt_name.n_name[0] = '\0'; + bootProp.tgt_chap.c_user[0] = '\0'; + tgtName[0] = L'\0'; + rtn = IMA_ERROR_UNEXPECTED_OS_ERROR; + if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) { + syslog(LOG_USER|LOG_DEBUG, "Unable to open %s (%d)", + ISCSI_DRIVER_DEVCTL, errno); + return (IMA_ERROR_UNEXPECTED_OS_ERROR); + } + + if (ioctl(fd, ISCSI_BOOTPROP_GET, &bootProp) != 0) { + syslog(LOG_USER|LOG_DEBUG, + "ISCSI_BOOTPROP_GET ioctl failed, errno: %d", + errno); + (void) close(fd); + return (IMA_ERROR_UNEXPECTED_OS_ERROR); + } + + if ((bootProp.tgt_name.n_name[0] != '\0') && (tgtName != NULL)) { + if (mbstowcs(tgtName, (const char *)bootProp.tgt_name.n_name, + IMA_NODE_NAME_LEN) == (size_t)-1) { + syslog(LOG_USER|LOG_DEBUG, + "ISCSI Target name covert to WCHAR fail"); + return (IMA_ERROR_UNEXPECTED_OS_ERROR); + } else { + rtn = IMA_STATUS_SUCCESS; + } + } + + return (rtn); +} + +IMA_API IMA_STATUS SUN_IMA_GetBootTargetAuthParams( + IMA_INITIATOR_AUTHPARMS *pTgtCHAP +) +{ + int fd; + IMA_STATUS rtn; + iscsi_boot_property_t bootProp; + + bootProp.tgt_name.n_name[0] = '\0'; + bootProp.tgt_chap.c_user[0] = '\0'; + bootProp.tgt_chap.c_secret[0] = '\0'; + rtn = IMA_ERROR_UNEXPECTED_OS_ERROR; + if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) { + syslog(LOG_USER|LOG_DEBUG, "Unable to open %s (%d)", + ISCSI_DRIVER_DEVCTL, errno); + return (IMA_ERROR_UNEXPECTED_OS_ERROR); + } + + if (ioctl(fd, ISCSI_BOOTPROP_GET, &bootProp) != 0) { + syslog(LOG_USER|LOG_DEBUG, + "ISCSI_BOOTPROP_GET ioctl failed, errno: %d", + errno); + (void) close(fd); + return (IMA_ERROR_UNEXPECTED_OS_ERROR); + } + + if (pTgtCHAP != NULL) { + if (bootProp.tgt_chap.c_user[0] != '\0') { + (void) memcpy(pTgtCHAP->chapParms.name, + bootProp.tgt_chap.c_user, ISCSI_MAX_NAME_LEN); + } else { + pTgtCHAP->chapParms.name[0] = '\0'; + } + if (bootProp.tgt_chap.c_secret[0] != '\0') { + (void) memcpy(pTgtCHAP->chapParms.challengeSecret, + bootProp.tgt_chap.c_secret, MAX_CHAP_SECRET_LEN); + } else { + pTgtCHAP->chapParms.challengeSecret[0] = '\0'; + } + rtn = IMA_STATUS_SUCCESS; + } + return (rtn); +} + +IMA_STATUS SUN_IMA_GetBootMpxio( + IMA_BOOL *pMpxioEnabled +) +{ + int fd; + iscsi_boot_property_t bootProp; + + bootProp.hba_mpxio_enabled = B_FALSE; + *pMpxioEnabled = IMA_UNKNOWN; + + if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) { + syslog(LOG_USER|LOG_DEBUG, "Unable to open %s (%d)", + ISCSI_DRIVER_DEVCTL, errno); + return (IMA_ERROR_UNEXPECTED_OS_ERROR); + } + + if (ioctl(fd, ISCSI_BOOTPROP_GET, &bootProp) != 0) { + syslog(LOG_USER|LOG_DEBUG, + "ISCSI_BOOTPROP_GET ioctl failed, errno: %d", + errno); + (void) close(fd); + return (IMA_ERROR_UNEXPECTED_OS_ERROR); + } + + if (bootProp.hba_mpxio_enabled) { + *pMpxioEnabled = IMA_TRUE; + } else { + *pMpxioEnabled = IMA_FALSE; + } + + (void) close(fd); + return (IMA_STATUS_SUCCESS); +} + +IMA_STATUS SUN_IMA_GetBootIscsi( + IMA_BOOL *pIscsiBoot +) +{ + int fd; + iscsi_boot_property_t bootProp; + + bootProp.iscsiboot = 0; + *pIscsiBoot = 0; + + if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) { + syslog(LOG_USER|LOG_DEBUG, "Unable to open %s (%d)", + ISCSI_DRIVER_DEVCTL, errno); + return (IMA_ERROR_UNEXPECTED_OS_ERROR); + } + + if (ioctl(fd, ISCSI_BOOTPROP_GET, &bootProp) != 0) { + syslog(LOG_USER|LOG_DEBUG, + "ISCSI_BOOTPROP_GET ioctl failed, errno: %d", + errno); + (void) close(fd); + return (IMA_ERROR_UNEXPECTED_OS_ERROR); + } + + *pIscsiBoot = bootProp.iscsiboot; + + (void) close(fd); + return (IMA_STATUS_SUCCESS); +} diff --git a/usr/src/cmd/iscsiadm/sun_ima.h b/usr/src/cmd/iscsiadm/sun_ima.h index a4d3ac4de1..2d40f9503c 100644 --- a/usr/src/cmd/iscsiadm/sun_ima.h +++ b/usr/src/cmd/iscsiadm/sun_ima.h @@ -135,7 +135,14 @@ IMA_API IMA_STATUS SUN_IMA_GetTargetAuthParms( IMA_OID oid, IMA_AUTHMETHOD method, IMA_INITIATOR_AUTHPARMS *pParms); - +IMA_STATUS SUN_IMA_GetBootTargetName( + IMA_NODE_NAME tgtName); +IMA_STATUS SUN_IMA_GetBootTargetAuthParams( + IMA_INITIATOR_AUTHPARMS *pTgtCHAP); +IMA_STATUS SUN_IMA_GetBootMpxio( + IMA_BOOL *pMpxioEnabled); +IMA_STATUS SUN_IMA_GetBootIscsi( + IMA_BOOL *pIscsiBoot); #ifdef __cplusplus } diff --git a/usr/src/cmd/svc/milestone/local-fs.xml b/usr/src/cmd/svc/milestone/local-fs.xml index a523a63b06..71349b5e58 100644 --- a/usr/src/cmd/svc/milestone/local-fs.xml +++ b/usr/src/cmd/svc/milestone/local-fs.xml @@ -1,15 +1,14 @@ <?xml version="1.0"?> <!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1"> <!-- - Copyright 2005 Sun Microsystems, Inc. All rights reserved. + Copyright 2008 Sun Microsystems, Inc. All rights reserved. Use is subject to license terms. CDDL HEADER START The contents of this file are subject to the terms of the - Common Development and Distribution License, Version 1.0 only - (the "License"). You may not use this file except in compliance - with the License. + 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. @@ -24,8 +23,6 @@ CDDL HEADER END - ident "%Z%%M% %I% %E% SMI" - NOTE: This service manifest is not editable; its contents will be overwritten by package or patch operations, including operating system upgrade. Make customizations in a different @@ -51,12 +48,17 @@ <service_fmri value='svc:/milestone/single-user' /> </dependency> + <!-- + With the introduction of iSCSI Boot, local filesystem + needs basic network setup (DHCP/IP and so on) to mount + --> <dependency name='root' grouping='require_all' restart_on='none' type='service'> <service_fmri value='svc:/system/filesystem/minimal' /> + <service_fmri value='svc:/network/physical' /> </dependency> <!-- diff --git a/usr/src/pkgdefs/SUNWiscsir/postinstall b/usr/src/pkgdefs/SUNWiscsir/postinstall index 683cc73732..07b773fcd9 100644 --- a/usr/src/pkgdefs/SUNWiscsir/postinstall +++ b/usr/src/pkgdefs/SUNWiscsir/postinstall @@ -29,11 +29,12 @@ PATH="/usr/bin:/usr/sbin:${PATH}"; export PATH # Driver definitions DRVR_NAME=iscsi; export DRVR_NAME DRVR_PERM='* 0600 root sys'; export DRVR_PERM +DRVR_CLS=scsi-self-identify; export DRVR_CLS if [ "${BASEDIR}" = "/" ]; then - add_drv -m "${DRVR_PERM}" ${DRVR_NAME} + add_drv -m "${DRVR_PERM}" -c ${DRVR_CLS} ${DRVR_NAME} else - add_drv -b "${BASEDIR}" -m "${DRVR_PERM}" ${DRVR_NAME} + add_drv -b "${BASEDIR}" -m "${DRVR_PERM}" -c ${DRVR_CLS} ${DRVR_NAME} fi exit 0 diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files index 1d28772d6d..ca6ce67df3 100644 --- a/usr/src/uts/common/Makefile.files +++ b/usr/src/uts/common/Makefile.files @@ -47,6 +47,7 @@ COMMON_CORE_OBJS += \ disp.o \ group.o \ kstat_fr.o \ + iscsiboot_prop.o \ lgrp.o \ lgrp_topo.o \ mutex.o \ @@ -1797,7 +1798,7 @@ ISCSI_INITIATOR_OBJS = chap.o iscsi_io.o iscsi_thread.o \ iscsi_queue.o persistent.o iscsi_conn.o \ iscsi_sess.o radius_auth.o iscsi_crc.o \ iscsi_stats.o radius_packet.o iscsi_doorclt.o \ - iscsi_targetparam.o utils.o + iscsi_targetparam.o utils.o kifconf.o # # ntxn 10Gb/1Gb NIC driver module diff --git a/usr/src/uts/common/Makefile.rules b/usr/src/uts/common/Makefile.rules index d1678f46cb..0035b502b9 100644 --- a/usr/src/uts/common/Makefile.rules +++ b/usr/src/uts/common/Makefile.rules @@ -1109,6 +1109,10 @@ $(OBJS_DIR)/%.o: $(COMMONBASE)/iscsi/%.c $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) +$(OBJS_DIR)/%.o: $(UTSBASE)/common/inet/kifconf/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + # # krtld must refer to its own bzero/bcopy until the kernel is fully linked # @@ -2118,6 +2122,9 @@ $(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/scsi/adapters/iscsi/%.c $(LINTS_DIR)/%.ln: $(COMMONBASE)/iscsi/%.c @($(LHEAD) $(LINT.c) $< $(LTAIL)) +$(LINTS_DIR)/%.ln: $(UTSBASE)/common/inet/kifconf/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + ZMODLINTFLAGS = -erroff=E_CONSTANT_CONDITION $(LINTS_DIR)/%.ln: $(UTSBASE)/common/zmod/%.c diff --git a/usr/src/uts/common/fs/sockfs/socksubr.c b/usr/src/uts/common/fs/sockfs/socksubr.c index d8b69aef5e..33a6841f16 100644 --- a/usr/src/uts/common/fs/sockfs/socksubr.c +++ b/usr/src/uts/common/fs/sockfs/socksubr.c @@ -92,7 +92,7 @@ static struct kmem_cache *socktpi_cache, *socktpi_unix_cache; struct kmem_cache *socktpi_sod_cache; dev_t sockdev; /* For fsid in getattr */ - +int sockfs_defer_nl7c_init = 0; struct sockparams *sphead; krwlock_t splist_lock; @@ -107,6 +107,8 @@ extern void nl7c_init(void); extern int sostr_init(); +extern int modrootloaded; + #define ADRSTRLEN (2 * sizeof (void *) + 1) /* * kernel structure for passing the sockinfo data back up to the user. @@ -195,6 +197,11 @@ soconfig(int domain, int type, int protocol, dprint(0, ("soconfig(%d,%d,%d,%s,%d)\n", domain, type, protocol, devpath, devpathlen)); + if (sockfs_defer_nl7c_init) { + nl7c_init(); + sockfs_defer_nl7c_init = 0; + } + /* * Look for an existing match. */ @@ -769,7 +776,11 @@ sockinit(int fstype, char *name) mutex_init(&socklist.sl_lock, NULL, MUTEX_DEFAULT, NULL); sendfile_init(); - nl7c_init(); + if (!modrootloaded) { + sockfs_defer_nl7c_init = 1; + } else { + nl7c_init(); + } return (0); diff --git a/usr/src/uts/common/fs/vfs.c b/usr/src/uts/common/fs/vfs.c index 30e9cf7430..bf9d325048 100644 --- a/usr/src/uts/common/fs/vfs.c +++ b/usr/src/uts/common/fs/vfs.c @@ -36,7 +36,6 @@ * contributors. */ - #include <sys/types.h> #include <sys/t_lock.h> #include <sys/param.h> @@ -84,11 +83,11 @@ #include <sys/attr.h> #include <sys/spa.h> #include <sys/lofi.h> +#include <sys/bootprops.h> #include <vm/page.h> #include <fs/fs_subr.h> - /* Private interfaces to create vopstats-related data structures */ extern void initialize_vopstats(vopstats_t *); extern vopstats_t *get_fstype_vopstats(struct vfs *, struct vfssw *); @@ -4489,6 +4488,9 @@ vfs_root_redev(vfs_t *vfsp, dev_t ndev, int fstype) extern int hvmboot_rootconf(); #endif /* __x86 */ +extern ib_boot_prop_t *iscsiboot_prop; +extern void iscsi_boot_prop_free(); + int rootconf() { @@ -4496,6 +4498,7 @@ rootconf() struct vfssw *vsw; extern void pm_init(); char *fstyp, *fsmod; + int ret = -1; getrootfs(&fstyp, &fsmod); @@ -4533,8 +4536,31 @@ rootconf() pm_init(); - if (netboot) - (void) strplumb(); + if (netboot && iscsiboot_prop) { + cmn_err(CE_WARN, "NFS boot and iSCSI boot" + " shouldn't happen in the same time"); + return (EINVAL); + } + + if (netboot || iscsiboot_prop) + ret = strplumb(); + + if ((ret == 0) && iscsiboot_prop) { + ret = modload("drv", "iscsi"); + /* -1 indicates fail */ + if (ret == -1) { + cmn_err(CE_WARN, "Failed to load iscsi module"); + iscsi_boot_prop_free(); + return (EINVAL); + } else { + if (!i_ddi_attach_pseudo_node("iscsi")) { + cmn_err(CE_WARN, + "Failed to attach iscsi driver"); + iscsi_boot_prop_free(); + return (ENODEV); + } + } + } error = VFS_MOUNTROOT(rootvfs, ROOT_INIT); vfs_unrefvfssw(vsw); diff --git a/usr/src/uts/common/inet/kifconf/kifconf.c b/usr/src/uts/common/inet/kifconf/kifconf.c new file mode 100644 index 0000000000..90c0ebdcd5 --- /dev/null +++ b/usr/src/uts/common/inet/kifconf/kifconf.c @@ -0,0 +1,238 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#include <sys/t_kuser.h> +#include <sys/netconfig.h> +#include <netinet/in.h> +#include <net/route.h> +#include <net/if.h> +#include <sys/kstr.h> +#include <rpc/clnt.h> +#include <sys/stropts.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <sys/bootprops.h> + +static int +kivoid_to_sock(int af, void *source, void *dest) +{ + struct sockaddr_in *sin = NULL; + struct sockaddr_in6 *sin6 = NULL; + + if (source == NULL || dest == NULL) { + return (-1); + } + if (af == AF_INET) { + sin = (struct sockaddr_in *)dest; + (void) bcopy(source, &sin->sin_addr, + sizeof (struct in_addr)); + sin->sin_family = af; + } else if (af == AF_INET6) { + sin6 = (struct sockaddr_in6 *)dest; + (void) bcopy(source, &sin6->sin6_addr, + sizeof (struct in6_addr)); + sin6->sin6_family = af; + } else { + return (-1); + } + return (0); +} + +int +kdlifconfig(TIUSER *tiptr, int af, void *myIPaddr, void *mymask, + struct in_addr *mybraddr, struct in_addr *gateway, char *ifname) +{ + int rc; + struct netbuf sbuf; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + struct rtentry route; + struct sockaddr_in *rt_sin; + + if (myIPaddr == NULL || mymask == NULL) { + return (-1); + } + + if (af == AF_INET) { + rc = kivoid_to_sock(af, mymask, &sin); + if (rc != 0) { + return (rc); + } + sbuf.buf = (caddr_t)&sin; + sbuf.maxlen = sbuf.len = sizeof (sin); + } else { + rc = kivoid_to_sock(af, mymask, &sin6); + if (rc != 0) { + return (rc); + } + sbuf.buf = (caddr_t)&sin6; + sbuf.maxlen = sbuf.len = sizeof (sin6); + } + if (rc = kifioctl(tiptr, SIOCSLIFNETMASK, &sbuf, ifname)) { + return (rc); + } + + if (af == AF_INET) { + rc = kivoid_to_sock(af, myIPaddr, &sin); + if (rc != 0) { + return (rc); + } + sbuf.buf = (caddr_t)&sin; + sbuf.maxlen = sbuf.len = sizeof (sin); + } else { + rc = kivoid_to_sock(af, myIPaddr, &sin6); + if (rc != 0) { + return (rc); + } + sbuf.buf = (caddr_t)&sin6; + sbuf.maxlen = sbuf.len = sizeof (sin6); + } + + if (rc = kifioctl(tiptr, SIOCSLIFADDR, &sbuf, ifname)) { + return (rc); + } + /* + * Only IPv4 has brocadcast address. + */ + if (af == AF_INET && mybraddr != NULL) { + if (mybraddr->s_addr != INADDR_BROADCAST) { + rc = kivoid_to_sock(af, mybraddr, &sin); + if (rc != 0) { + return (rc); + } + sbuf.buf = (caddr_t)&sin; + sbuf.maxlen = sbuf.len = sizeof (sin); + if (rc = kifioctl(tiptr, SIOCSLIFBRDADDR, &sbuf, + ifname)) { + return (rc); + } + } + } + + /* + * Now turn on the interface. + */ + if (rc = ksetifflags(tiptr, IFF_UP, ifname)) { + return (rc); + } + + /* + * Set the default gateway. + */ + if (af == AF_INET && gateway != NULL) { + (void) memset(&route, 0, sizeof (route)); + rt_sin = (struct sockaddr_in *)&route.rt_dst; + rt_sin->sin_family = AF_INET; + + rt_sin = (struct sockaddr_in *)&route.rt_gateway; + rt_sin->sin_addr.s_addr = gateway->s_addr; + route.rt_flags = RTF_GATEWAY | RTF_UP; + sbuf.buf = (caddr_t)&route; + sbuf.maxlen = sbuf.len = sizeof (route); + if (rc = kifioctl(tiptr, SIOCADDRT, &sbuf, ifname)) { + return (rc); + } + } + return (0); +} + +int +kifioctl(TIUSER *tiptr, int cmd, struct netbuf *nbuf, char *ifname) +{ + struct strioctl iocb; + struct lifreq lifr; + vnode_t *vp = NULL; + char *buf = NULL; + int rc = 0; + + (void) memset(&lifr, 0, sizeof (lifr)); + /* + * Now do the one requested. + */ + if (nbuf->len) { + if (nbuf->len == sizeof (struct rtentry)) { + if (cmd != SIOCADDRT) { + return (-1); + } + /* + * Set up gateway parameters. + */ + iocb.ic_len = nbuf->len; + iocb.ic_dp = nbuf->buf; + } else { + if (nbuf->len != sizeof (struct sockaddr_in) && + nbuf->len != sizeof (struct sockaddr_in6)) { + return (-1); + } + buf = (char *)&lifr.lifr_addr; + bcopy(nbuf->buf, buf, nbuf->len); + iocb.ic_len = sizeof (lifr); + iocb.ic_dp = (caddr_t)&lifr; + } + } else { + iocb.ic_len = sizeof (lifr); + iocb.ic_dp = (caddr_t)&lifr; + } + (void) strncpy((caddr_t)&lifr.lifr_name, ifname, + sizeof (lifr.lifr_name)); + iocb.ic_cmd = cmd; + iocb.ic_timout = 0; + + vp = tiptr->fp->f_vnode; + rc = kstr_ioctl(vp, I_STR, (intptr_t)&iocb); + if (rc) { + return (rc); + } + + return (0); +} + +int +ksetifflags(TIUSER *tiptr, uint_t value, char *ifname) +{ + int rc; + struct strioctl iocb; + struct lifreq lifr; + + if (ifname == NULL) { + return (-1); + } + + (void) memset(&lifr, 0, sizeof (lifr)); + + (void) strncpy((caddr_t)&lifr.lifr_name, ifname, + sizeof (lifr.lifr_name)); + iocb.ic_cmd = SIOCGLIFFLAGS; + iocb.ic_timout = 0; + iocb.ic_len = sizeof (lifr); + iocb.ic_dp = (caddr_t)&lifr; + if (rc = kstr_ioctl(tiptr->fp->f_vnode, I_STR, (intptr_t)&iocb)) + return (rc); + + lifr.lifr_flags |= value; + iocb.ic_cmd = SIOCSLIFFLAGS; + return (kstr_ioctl(tiptr->fp->f_vnode, I_STR, (intptr_t)&iocb)); +} diff --git a/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi.c b/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi.c index 0bef2b1892..d638c24459 100644 --- a/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi.c +++ b/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi.c @@ -41,6 +41,7 @@ #include <sys/utsname.h> #include "isns_client.h" #include "isns_protocol.h" +#include <sys/bootprops.h> #define ISCSI_NAME_VERSION "iSCSI Initiator v-1.55" @@ -60,6 +61,8 @@ int iscsi_nop_delay = ISCSI_DEFAULT_NOP_DELAY; int iscsi_rx_window = ISCSI_DEFAULT_RX_WINDOW; int iscsi_rx_max_window = ISCSI_DEFAULT_RX_MAX_WINDOW; +extern ib_boot_prop_t *iscsiboot_prop; + /* * +--------------------------------------------------------------------+ * | iscsi.c prototypes | @@ -140,6 +143,7 @@ static int iscsi_i_commoncap(struct scsi_address *ap, char *cap, int val, int lunonly, int doset); static void iscsi_get_name_to_iqn(char *name, int name_max_len); static void iscsi_get_name_from_iqn(char *name, int name_max_len); +static boolean_t iscsi_cmp_boot_sess_oid(iscsi_hba_t *ihp, uint32_t oid); /* struct helpers prototypes */ @@ -530,6 +534,7 @@ iscsi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) * initialize the discovery processes and * persistent store. */ + ihp->persistent_loaded = B_FALSE; if (iscsid_init(ihp, B_FALSE) == B_FALSE) { goto iscsi_attach_failed0; } @@ -1410,6 +1415,7 @@ iscsi_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, boolean_t rval; char init_port_name[MAX_NAME_PROP_SIZE]; iscsi_sockaddr_t addr_dsc; + iscsi_boot_property_t *bootProp; instance = getminor(dev); ihp = (iscsi_hba_t *)ddi_get_soft_state(iscsi_state, instance); @@ -1747,6 +1753,20 @@ iscsi_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, break; } rtn = iscsi_set_params(ils, ihp, B_TRUE); + if (iscsiboot_prop) { + if (iscsi_cmp_boot_sess_oid(ihp, ils->s_oid)) { + /* + * found active session for this object + * or this is initiator's object + * with mpxio enabled + */ + if (!iscsi_reconfig_boot_sess(ihp)) { + rtn = EINVAL; + kmem_free(ils, sizeof (*ils)); + break; + } + } + } kmem_free(ils, sizeof (*ils)); break; @@ -1874,7 +1894,14 @@ iscsi_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, hba_params), &(isp->sess_params), sizeof (isp->sess_params)); - + if (iscsiboot_prop && + isp->sess_boot) { + /* + * reconfig boot + * session later + */ + continue; + } /* * Notify the session that the * login parameters have @@ -1892,6 +1919,19 @@ iscsi_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, kmem_free(ics, sizeof (*ics)); kmem_free(name, ISCSI_MAX_NAME_LEN); rw_exit(&ihp->hba_sess_list_rwlock); + if (iscsiboot_prop) { + if (iscsi_cmp_boot_sess_oid(ihp, e.e_oid)) { + /* + * found active session for this object + * or this is initiator object + * with mpxio enabled + */ + if (!iscsi_reconfig_boot_sess(ihp)) { + rtn = EINVAL; + break; + } + } + } } break; @@ -3936,9 +3976,109 @@ iscsi_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, } else { /* set */ rtn = iscsi_ioctl_set_config_sess(ihp, ics); + if (iscsiboot_prop) { + if (iscsi_cmp_boot_sess_oid(ihp, + ics->ics_oid)) { + /* + * found active session for this object + * or this is initiator object + * with mpxio enabled + */ + if (!iscsi_reconfig_boot_sess(ihp)) { + rtn = EINVAL; + break; + } + } + } } break; + case ISCSI_IS_ACTIVE: + /* + * dhcpagent calls here to check if there are + * active iSCSI sessions + */ + instance = 0; + if (iscsiboot_prop) { + instance = 1; + } + if (!instance) { + rw_enter(&ihp->hba_sess_list_rwlock, + RW_READER); + for (isp = ihp->hba_sess_list; isp; + isp = isp->sess_next) { + if ((isp->sess_state == + ISCSI_SESS_STATE_LOGGED_IN) && + (isp->sess_lun_list != + NULL)) { + instance = 1; + break; + } + } + rw_exit(&ihp->hba_sess_list_rwlock); + } + size = sizeof (instance); + if (ddi_copyout(&instance, (caddr_t)arg, size, + mode) != 0) { + rtn = EFAULT; + } + break; + + case ISCSI_BOOTPROP_GET: + size = sizeof (*bootProp); + bootProp = iscsi_ioctl_copyin((caddr_t)arg, mode, size); + if (bootProp == NULL) { + rtn = EFAULT; + break; + } + bootProp->hba_mpxio_enabled = + iscsi_chk_bootlun_mpxio(ihp); + if (iscsiboot_prop == NULL) { + bootProp->iscsiboot = 0; + rtn = iscsi_ioctl_copyout(bootProp, size, + (caddr_t)arg, mode); + break; + } else { + bootProp->iscsiboot = 1; + } + + if (iscsiboot_prop->boot_init.ini_name != NULL) { + (void) strncpy((char *)bootProp->ini_name.n_name, + (char *)iscsiboot_prop->boot_init.ini_name, + ISCSI_MAX_NAME_LEN); + } + if (iscsiboot_prop->boot_init.ini_chap_name != NULL) { + bootProp->auth.a_auth_method = authMethodCHAP; + (void) strncpy((char *)bootProp->ini_chap.c_user, + (char *)iscsiboot_prop->boot_init.ini_chap_name, + ISCSI_MAX_NAME_LEN); + (void) strncpy((char *)bootProp->ini_chap.c_secret, + (char *)iscsiboot_prop->boot_init.ini_chap_sec, + ISCSI_CHAP_SECRET_LEN); + if (iscsiboot_prop->boot_tgt.tgt_chap_name != + NULL) { + bootProp->auth.a_bi_auth = B_TRUE; + } else { + bootProp->auth.a_bi_auth = B_FALSE; + } + } + if (iscsiboot_prop->boot_tgt.tgt_name != NULL) { + (void) strncpy((char *)bootProp->tgt_name.n_name, + (char *)iscsiboot_prop->boot_tgt.tgt_name, + ISCSI_MAX_NAME_LEN); + } + if (iscsiboot_prop->boot_tgt.tgt_chap_name != NULL) { + (void) strncpy((char *)bootProp->tgt_chap.c_user, + (char *)iscsiboot_prop->boot_tgt.tgt_chap_name, + ISCSI_MAX_NAME_LEN); + (void) strncpy((char *)bootProp->tgt_chap.c_secret, + (char *)iscsiboot_prop->boot_tgt.tgt_chap_sec, + ISCSI_CHAP_SECRET_LEN); + } + + rtn = iscsi_ioctl_copyout(bootProp, size, (caddr_t)arg, mode); + break; + default: rtn = ENOTTY; cmn_err(CE_NOTE, "unrecognized ioctl 0x%x", cmd); @@ -4726,3 +4866,33 @@ iscsi_override_target_default(iscsi_hba_t *ihp, iscsi_param_get_t *ipg) } kmem_free(pp, sizeof (*pp)); } + +static boolean_t +iscsi_cmp_boot_sess_oid(iscsi_hba_t *ihp, uint32_t oid) +{ + iscsi_sess_t *isp = NULL; + + if (iscsi_chk_bootlun_mpxio(ihp)) { + for (isp = ihp->hba_sess_list; isp; isp = isp->sess_next) { + if ((isp->sess_oid == oid) && isp->sess_boot) { + /* oid is session object */ + break; + } + if ((isp->sess_target_oid == oid) && isp->sess_boot) { + /* + * oid is target object while + * this session is boot session + */ + break; + } + } + if (oid == ihp->hba_oid) { + /* oid is initiator object id */ + return (B_TRUE); + } else if ((isp != NULL) && (isp->sess_boot)) { + /* oid is boot session object id */ + return (B_TRUE); + } + } + return (B_FALSE); +} diff --git a/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi.h b/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi.h index 5c7ef0719f..6258ff9d5b 100644 --- a/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi.h +++ b/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi.h @@ -228,6 +228,12 @@ extern int iscsi_rx_window; extern int iscsi_rx_max_window; /* + * During iscsi boot, if the boot session has been created, the + * initiator hasn't changed the boot lun to be online, we will wait + * 180s here for lun online by default. + */ +#define ISCSI_BOOT_DEFAULT_MAX_DELAY 180 /* seconds */ +/* * +--------------------------------------------------------------------+ * | iSCSI Driver Structures | * +--------------------------------------------------------------------+ @@ -812,6 +818,7 @@ typedef struct iscsi_sess { iscsi_thread_t *sess_ic_thread; boolean_t sess_window_open; + boolean_t sess_boot; iscsi_sess_type_t sess_type; boolean_t sess_enum_in_progress; @@ -914,6 +921,7 @@ typedef struct iscsi_hba { boolean_t hba_discovery_in_progress; boolean_t hba_mpxio_enabled; /* mpxio-enabled */ + boolean_t persistent_loaded; /* persistent_loaded */ /* * Ensures only one SendTargets operation occurs at a time @@ -1084,6 +1092,10 @@ boolean_t iscsid_login_tgt(iscsi_hba_t *ihp, char *target_name, iSCSIDiscoveryMethod_t method, struct sockaddr *addr_dsc); void iscsid_addr_to_sockaddr(int src_insize, void *src_addr, int src_port, struct sockaddr *dst_addr); +boolean_t iscsi_reconfig_boot_sess(iscsi_hba_t *ihp); +boolean_t iscsi_chk_bootlun_mpxio(iscsi_hba_t *ihp); +boolean_t iscsi_cmp_boot_ini_name(char *name); +boolean_t iscsi_cmp_boot_tgt_name(char *name); extern void bcopy(const void *s1, void *s2, size_t n); extern void bzero(void *s, size_t n); diff --git a/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_conn.c b/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_conn.c index 5e26452da5..c1d8a3f6c2 100644 --- a/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_conn.c +++ b/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_conn.c @@ -27,6 +27,9 @@ #include "iscsi.h" #include "persistent.h" +#include <sys/bootprops.h> + +extern ib_boot_prop_t *iscsiboot_prop; /* interface connection interfaces */ static iscsi_status_t iscsi_conn_state_free(iscsi_conn_t *icp, @@ -51,6 +54,7 @@ static void iscsi_conn_retry(iscsi_sess_t *isp, #define SHUTDOWN_TIMEOUT 180 /* seconds */ +extern int modrootloaded; /* * +--------------------------------------------------------------------+ * | External Connection Interfaces | @@ -543,9 +547,22 @@ iscsi_conn_sync_params(iscsi_conn_t *icp) (void) persistent_param_get((char *)isp->sess_name, &pp); for (param_id = 0; param_id < ISCSI_NUM_LOGIN_PARAM; param_id++) { + if (iscsiboot_prop && modrootloaded && + !iscsi_chk_bootlun_mpxio(ihp) && isp->sess_boot) { + /* + * iscsi boot with mpxio disabled + * while iscsi booting target's parameter overriden + * do no update target's parameters. + */ + if (pp.p_bitmap) { + cmn_err(CE_NOTE, "Adopting " + " default login parameters in" + " boot session as MPxIO is disabled"); + } + break; + } if (pp.p_bitmap & (1 << param_id)) { - - switch (param_id) { + switch (param_id) { /* * Boolean parameters */ @@ -644,13 +661,38 @@ iscsi_conn_sync_params(iscsi_conn_t *icp) } } + if (iscsiboot_prop && (ics->ics_out > 1) && isp->sess_boot && + !iscsi_chk_bootlun_mpxio(ihp)) { + /* + * iscsi booting session with mpxio disabled, + * no need set multiple sessions for booting session + */ + ics->ics_out = 1; + ics->ics_bound = B_FALSE; + cmn_err(CE_NOTE, "MPxIO is disabled," + " no need to configure multiple boot sessions"); + } + /* * Check to make sure this session is still a configured * session. The user might have decreased the session * count. (NOTE: byte 5 of the sess_isid is the session * count (via MS/T). This counter starts at 0.) */ + + idx = isp->sess_isid[5]; + + if (iscsiboot_prop && (idx == ISCSI_MAX_CONFIG_SESSIONS)) { + /* + * This is temporary session for boot session propose + * no need to bound IP for this session + */ + icp->conn_bound = B_FALSE; + kmem_free(ics, sizeof (iscsi_config_sess_t)); + return (ISCSI_STATUS_SUCCESS); + } + if (ics->ics_out <= idx) { /* * No longer a configured session. Return a diff --git a/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_ioctl.c b/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_ioctl.c index 7ef9c9f0f8..e5967dab8c 100644 --- a/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_ioctl.c +++ b/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_ioctl.c @@ -37,6 +37,9 @@ #include "iscsi_targetparam.h" #include <sys/strsubr.h> #include <sys/socketvar.h> +#include <sys/bootprops.h> + +extern ib_boot_prop_t *iscsiboot_prop; static iscsi_status_t iscsi_create_sendtgts_list(iscsi_conn_t *icp, char *data, int data_len, iscsi_sendtgts_list_t *stl); @@ -869,14 +872,26 @@ iscsi_set_params(iscsi_param_set_t *ils, iscsi_hba_t *ihp, boolean_t persist) } /* - * We may have multiple sessions with different - * tpgt values. So we need to loop through + * Here may have multiple sessions with different + * tpgt values. So it is needed to loop through * the sessions and update all sessions. */ if (rtn == 0) { rw_enter(&ihp->hba_sess_list_rwlock, RW_READER); for (isp = ihp->hba_sess_list; isp; isp = isp->sess_next) { + if (iscsiboot_prop && + isp->sess_boot && + iscsi_chk_bootlun_mpxio(ihp)) { + /* + * MPxIO is enabled so capable + * of changing. All changes + * will be applied later, + * after this function + */ + continue; + } + if (strncmp((char *)isp->sess_name, (char *)name, ISCSI_MAX_NAME_LEN) == 0) { @@ -917,16 +932,25 @@ mutex_exit(&isp->sess_state_mutex); rw_enter(&ihp->hba_sess_list_rwlock, RW_READER); for (isp = ihp->hba_sess_list; isp; isp = isp->sess_next) { - ilg->g_param = ils->s_param; params = &isp->sess_params; if (iscsi_get_persisted_param( isp->sess_name, ilg, params) != 0) { - rtn = iscsi_set_param(params, ils); if (rtn != 0) { break; } + if (iscsiboot_prop && + isp->sess_boot && + iscsi_chk_bootlun_mpxio(ihp)) { + /* + * MPxIO is enabled so capable + * of changing. Changes will + * be applied later, right + * after this function + */ + continue; + } /* * Notify the session that diff --git a/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_lun.c b/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_lun.c index 6a89c238c4..a757790ef0 100644 --- a/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_lun.c +++ b/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_lun.c @@ -27,6 +27,7 @@ #include "iscsi.h" #include <sys/fs/dv_node.h> /* devfs_clean */ +#include <sys/bootprops.h> /* tpgt bytes in string form */ #define TPGT_EXT_SIZE 5 @@ -47,6 +48,7 @@ static iscsi_status_t iscsi_lun_phys_create(iscsi_sess_t *isp, uint16_t lun_num, iscsi_lun_t *ilp, struct scsi_inquiry *inq); extern dev_info_t *scsi_vhci_dip; +extern ib_boot_prop_t *iscsiboot_prop; /* * +--------------------------------------------------------------------+ @@ -69,6 +71,8 @@ iscsi_lun_create(iscsi_sess_t *isp, uint16_t lun_num, uint8_t lun_addr_type, iscsi_lun_t *ilp = NULL; iscsi_lun_t *ilp_tmp = NULL; char *addr = NULL; + uint16_t boot_lun_num = 0; + uint64_t *lun_num_ptr = NULL; ASSERT(isp != NULL); ihp = isp->sess_hba; @@ -81,7 +85,7 @@ iscsi_lun_create(iscsi_sess_t *isp, uint16_t lun_num, uint8_t lun_addr_type, ADDR_EXT_SIZE + 1), "%02X%02X%s%04X,%d", isp->sess_isid[4], isp->sess_isid[5], isp->sess_name, - isp->sess_tpgt_conf & 0xFFFF, lun_num); + isp->sess_tpgt_nego & 0xFFFF, lun_num); /* allocate space for lun struct */ ilp = kmem_zalloc(sizeof (iscsi_lun_t), KM_SLEEP); @@ -168,13 +172,27 @@ iscsi_lun_create(iscsi_sess_t *isp, uint16_t lun_num, uint8_t lun_addr_type, } else { ilp->lun_state = ISCSI_LUN_STATE_ONLINE; ilp->lun_time_online = ddi_get_time(); + + /* Check whether this is the required LUN for iscsi boot */ + if (iscsiboot_prop != NULL && isp->sess_boot == B_TRUE && + iscsiboot_prop->boot_tgt.lun_online == 0) { + lun_num_ptr = + (uint64_t *)iscsiboot_prop->boot_tgt.tgt_boot_lun; + boot_lun_num = (uint16_t)(*lun_num_ptr); + if (boot_lun_num == ilp->lun_num) { + /* + * During iscsi boot, the boot lun has been + * online, we should set the "online flag". + */ + iscsiboot_prop->boot_tgt.lun_online = 1; + } + } } rw_exit(&isp->sess_lun_list_rwlock); return (rtn); } - /* * iscsi_lun_destroy - offline and remove lun * @@ -490,13 +508,15 @@ phys_create_done: void iscsi_lun_online(iscsi_hba_t *ihp, iscsi_lun_t *ilp) { - int circ = 0; - int rval; + int circ = 0; + int rval = 0; + uint64_t *lun_num_ptr = NULL; + uint16_t boot_lun_num = 0; + iscsi_sess_t *isp = NULL; ASSERT(ilp != NULL); ASSERT((ilp->lun_pip != NULL) || (ilp->lun_dip != NULL)); - if (ilp->lun_pip != NULL) { ndi_devi_enter(scsi_vhci_dip, &circ); rval = mdi_pi_online(ilp->lun_pip, 0); @@ -515,6 +535,24 @@ iscsi_lun_online(iscsi_hba_t *ihp, iscsi_lun_t *ilp) ilp->lun_time_online = ddi_get_time(); } } + + /* Check whether this is the required LUN for iscsi boot */ + if (iscsiboot_prop != NULL && + iscsiboot_prop->boot_tgt.lun_online == 0) { + isp = ilp->lun_sess; + if (isp->sess_boot == B_TRUE) { + lun_num_ptr = + (uint64_t *)iscsiboot_prop->boot_tgt.tgt_boot_lun; + boot_lun_num = (uint16_t)(*lun_num_ptr); + if (boot_lun_num == ilp->lun_num) { + /* + * During iscsi boot, the boot lun has been + * online, we should set the "online flag". + */ + iscsiboot_prop->boot_tgt.lun_online = 1; + } + } + } } /* diff --git a/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_net.c b/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_net.c index d02c8efc1a..23e64684a1 100644 --- a/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_net.c +++ b/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_net.c @@ -32,7 +32,9 @@ #include <sys/pathname.h> /* declares: lookupname */ #include <sys/fs/snode.h> /* defines: VTOS */ #include <sys/fs/dv_node.h> /* declares: devfs_lookupname */ -#include <netinet/in.h> +#include <sys/bootconf.h> +#include <sys/bootprops.h> + #include "iscsi.h" /* @@ -142,8 +144,27 @@ const int is_incoming_opcode_invalid[256] = { /* 0xEX */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xFX */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, }; +/* + * Define macros to manipulate snode, vnode, and open device flags + */ +#define VTYP_VALID(i) (((i) == VCHR) || ((i) == VBLK)) +#define STYP_VALID(i) (((i) == S_IFCHR) || ((i) == S_IFBLK)) +#define STYP_TO_VTYP(i) (((i) == S_IFCHR) ? VCHR : VBLK) + +#define IP_4_BITS 32 +#define IP_6_BITS 128 + +extern int modrootloaded; +extern ib_boot_prop_t *iscsiboot_prop; /* prototypes */ + +/* for iSCSI boot */ +static int net_up = 0; +static iscsi_status_t iscsi_net_interface(); +static int iscsi_ldi_vp_from_name(char *path, vnode_t **vpp); +/* boot prototypes end */ + static void * iscsi_net_socket(int domain, int type, int protocol); static int iscsi_net_bind(void *socket, struct sockaddr * name, int name_len, int backlog, int flags); @@ -282,6 +303,11 @@ iscsi_net_socket(int domain, int type, int protocol) int err = 0; major_t maj; + if (!modrootloaded && !net_up && iscsiboot_prop) { + if (iscsi_net_interface() == ISCSI_STATUS_SUCCESS) + net_up = 1; + } + /* ---- solookup: start ---- */ if ((vp = solookup(domain, type, protocol, NULL, &err)) == NULL) { @@ -291,10 +317,16 @@ iscsi_net_socket(int domain, int type, int protocol) * to use USERSPACE and declared static we'll do the * work here instead. */ - err = lookupname(type == SOCK_STREAM ? "/dev/tcp" : "/dev/udp", - UIO_SYSSPACE, FOLLOW, NULLVPP, &vp); - if (err) + if (!modrootloaded) { + err = iscsi_ldi_vp_from_name("/devices/pseudo/tcp@0:" + "tcp", &vp); + } else { + err = lookupname(type == SOCK_STREAM ? "/dev/tcp" : + "/dev/udp", UIO_SYSSPACE, FOLLOW, NULLVPP, &vp); + } + if (err) { return (NULL); + } /* ---- check that it is the correct vnode ---- */ if (vp->v_type != VCHR) { @@ -905,3 +937,213 @@ iscsi_net_recvdata(void *socket, iscsi_hdr_t *ihp, char *data, } return (ISCSI_STATUS_SUCCESS); } + +/* + * Convert a prefix length to a mask. + */ +static iscsi_status_t +iscsi_prefixlentomask(int prefixlen, int maxlen, uchar_t *mask) +{ + if (prefixlen < 0 || prefixlen > maxlen || mask == NULL) { + return (ISCSI_STATUS_INTERNAL_ERROR); + } + + while (prefixlen > 0) { + if (prefixlen >= 8) { + *mask = 0xff; + mask++; + prefixlen = prefixlen - 8; + continue; + } + *mask = *mask | (1 << (8 - prefixlen)); + prefixlen--; + } + return (ISCSI_STATUS_SUCCESS); +} + +static iscsi_status_t +iscsi_net_interface() +{ + struct in_addr braddr; + struct in_addr subnet; + struct in_addr myaddr; + struct in_addr defgateway; + struct in6_addr myaddr6; + struct in6_addr subnet6; + uchar_t mask_prefix = 0; + int mask_bits = 1; + TIUSER *tiptr; + TIUSER *tiptr6; + char ifname[16] = {0}; + iscsi_status_t status; + + struct knetconfig dl_udp_netconf = { + NC_TPI_CLTS, + NC_INET, + NC_UDP, + 0, }; + struct knetconfig dl_udp6_netconf = { + NC_TPI_CLTS, + NC_INET6, + NC_UDP, + 0, }; + + (void) strlcpy(ifname, rootfs.bo_ifname, sizeof (ifname)); + + if (iscsiboot_prop->boot_nic.sin_family == AF_INET) { + /* + * Assumes only one linkage array element. + */ + dl_udp_netconf.knc_rdev = + makedevice(clone_major, ddi_name_to_major("udp")); + + myaddr.s_addr = + iscsiboot_prop->boot_nic.nic_ip_u.u_in4.s_addr; + + mask_prefix = iscsiboot_prop->boot_nic.sub_mask_prefix; + (void) memset(&subnet.s_addr, 0, sizeof (subnet)); + status = iscsi_prefixlentomask(mask_prefix, IP_4_BITS, + (uchar_t *)&subnet.s_addr); + if (status != ISCSI_STATUS_SUCCESS) { + return (status); + } + + mask_bits = mask_bits << (IP_4_BITS - mask_prefix); + mask_bits = mask_bits - 1; + /* + * Set the last mask bits of the ip address with 1, then + * we can get the broadcast address. + */ + braddr.s_addr = myaddr.s_addr | mask_bits; + + defgateway.s_addr = + iscsiboot_prop->boot_nic.nic_gw_u.u_in4.s_addr; + + /* initialize interface */ + if (t_kopen((file_t *)NULL, dl_udp_netconf.knc_rdev, + FREAD|FWRITE, &tiptr, CRED()) == 0) { + if (kdlifconfig(tiptr, AF_INET, &myaddr, &subnet, + &braddr, &defgateway, ifname)) { + cmn_err(CE_WARN, "Failed to configure" + " iSCSI boot nic"); + (void) t_kclose(tiptr, 0); + return (ISCSI_STATUS_INTERNAL_ERROR); + } + } else { + cmn_err(CE_WARN, "Failed to configure" + " iSCSI boot nic"); + return (ISCSI_STATUS_INTERNAL_ERROR); + } + return (ISCSI_STATUS_SUCCESS); + } else { + dl_udp6_netconf.knc_rdev = + makedevice(clone_major, ddi_name_to_major("udp6")); + + bcopy(&iscsiboot_prop->boot_nic.nic_ip_u.u_in6.s6_addr, + &myaddr6.s6_addr, 16); + + (void) memset(&subnet6, 0, sizeof (subnet6)); + mask_prefix = iscsiboot_prop->boot_nic.sub_mask_prefix; + status = iscsi_prefixlentomask(mask_prefix, IP_6_BITS, + (uchar_t *)&subnet6.s6_addr); + if (status != ISCSI_STATUS_SUCCESS) { + return (status); + } + + if (t_kopen((file_t *)NULL, dl_udp6_netconf.knc_rdev, + FREAD|FWRITE, &tiptr6, CRED()) == 0) { + if (kdlifconfig(tiptr6, AF_INET6, &myaddr6, + &subnet6, NULL, NULL, ifname)) { + cmn_err(CE_WARN, "Failed to configure" + " iSCSI boot nic"); + (void) t_kclose(tiptr, 0); + return (ISCSI_STATUS_INTERNAL_ERROR); + } + } else { + cmn_err(CE_WARN, "Failed to configure" + " iSCSI boot nic"); + return (ISCSI_STATUS_INTERNAL_ERROR); + } + return (ISCSI_STATUS_SUCCESS); + } +} + +/* + * vp is needed to create the socket for the time being. + */ +static int +iscsi_ldi_vp_from_name(char *path, vnode_t **vpp) +{ + vnode_t *vp = NULL; + int ret; + + /* sanity check required input parameters */ + if ((path == NULL) || (vpp == NULL)) + return (EINVAL); + + if (modrootloaded) { + cred_t *saved_cred = curthread->t_cred; + + /* we don't want lookupname to fail because of credentials */ + curthread->t_cred = kcred; + + /* + * all lookups should be done in the global zone. but + * lookupnameat() won't actually do this if an absolute + * path is passed in. since the ldi interfaces require an + * absolute path we pass lookupnameat() a pointer to + * the character after the leading '/' and tell it to + * start searching at the current system root directory. + */ + ASSERT(*path == '/'); + ret = lookupnameat(path + 1, UIO_SYSSPACE, FOLLOW, NULLVPP, + &vp, rootdir); + + /* restore this threads credentials */ + curthread->t_cred = saved_cred; + + if (ret == 0) { + if (!vn_matchops(vp, spec_getvnodeops()) || + !VTYP_VALID(vp->v_type)) { + VN_RELE(vp); + return (ENXIO); + } + } + } + + if (vp == NULL) { + dev_info_t *dip; + dev_t dev; + int spec_type; + + /* + * Root is not mounted, the minor node is not specified, + * or an OBP path has been specified. + */ + + /* + * Determine if path can be pruned to produce an + * OBP or devfs path for resolve_pathname. + */ + if (strncmp(path, "/devices/", 9) == 0) + path += strlen("/devices"); + + /* + * if no minor node was specified the DEFAULT minor node + * will be returned. if there is no DEFAULT minor node + * one will be fabricated of type S_IFCHR with the minor + * number equal to the instance number. + */ + ret = resolve_pathname(path, &dip, &dev, &spec_type); + if (ret != 0) + return (ENODEV); + + ASSERT(STYP_VALID(spec_type)); + vp = makespecvp(dev, STYP_TO_VTYP(spec_type)); + spec_assoc_vp_with_devi(vp, dip); + ddi_release_devi(dip); + } + + *vpp = vp; + return (0); +} diff --git a/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_sess.c b/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_sess.c index c69239272f..a1b2dcd92f 100644 --- a/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_sess.c +++ b/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_sess.c @@ -25,6 +25,7 @@ * iSCSI session interfaces */ +#include <sys/bootprops.h> #include "iscsi.h" #include "persistent.h" #include "iscsi_targetparam.h" @@ -140,7 +141,16 @@ iscsi_sess_create(iscsi_hba_t *ihp, iSCSIDiscoveryMethod_t method, (uchar_t *)target_name); } + if (method & iSCSIDiscoveryMethodBoot) { + /* This is boot session. */ + isp->sess_boot = B_TRUE; + } else { + isp->sess_boot = B_FALSE; + } + /* Associate session with this discovery method */ + method = method & ~(iSCSIDiscoveryMethodBoot); + isp->sess_discovered_by = method; if (addr_dsc == NULL) { bzero(&isp->sess_discovered_addr, @@ -530,6 +540,7 @@ iscsi_sess_destroy(iscsi_sess_t *isp) return (rval); } +extern ib_boot_prop_t *iscsiboot_prop; /* * static iscsi_sess_set_auth - * @@ -540,6 +551,7 @@ iscsi_sess_set_auth(iscsi_sess_t *isp) char *init_name; iscsi_chap_props_t *chap = NULL; iscsi_auth_props_t *auth = NULL; + uchar_t *tmp = NULL; if (isp == (iscsi_sess_t *)NULL) { return (B_FALSE); @@ -549,100 +561,175 @@ iscsi_sess_set_auth(iscsi_sess_t *isp) if (isp->sess_hba == (iscsi_hba_t *)NULL) { return (B_FALSE); } + init_name = (char *)isp->sess_hba->hba_name; - auth = (iscsi_auth_props_t *)kmem_zalloc - (sizeof (iscsi_auth_props_t), KM_SLEEP); - /* Obtain target's authentication settings. */ - if (persistent_auth_get((char *)isp->sess_name, auth) != B_TRUE) { - /* - * If no target authentication settings found, try to obtain - * system wide configuration (from the initiator). - */ - bzero(auth, sizeof (*auth)); - if (persistent_auth_get(init_name, auth) != B_TRUE) { + /* Zero out the session authentication structure */ + bzero(&isp->sess_auth, sizeof (iscsi_auth_t)); + + if (isp->sess_boot == B_FALSE) { + + auth = (iscsi_auth_props_t *)kmem_zalloc + (sizeof (iscsi_auth_props_t), KM_SLEEP); + /* Obtain target's authentication settings. */ + if (persistent_auth_get((char *)isp->sess_name, auth) + != B_TRUE) { + /* + * If no target authentication settings found, + * try to obtain system wide configuration + * (from the initiator). + */ bzero(auth, sizeof (*auth)); - auth->a_auth_method = authMethodNone; - } + if (persistent_auth_get(init_name, auth) != B_TRUE) { + bzero(auth, sizeof (*auth)); + auth->a_auth_method = authMethodNone; + } - /* We do not support system wide bi-directional auth flag. */ - auth->a_bi_auth = B_FALSE; - } + /* + * We do not support system wide bi-directional + * auth flag. + */ + auth->a_bi_auth = B_FALSE; + } - /* Zero out the session authentication structure */ - bzero(&isp->sess_auth, sizeof (iscsi_auth_t)); + chap = (iscsi_chap_props_t *)kmem_zalloc + (sizeof (iscsi_chap_props_t), KM_SLEEP); - chap = (iscsi_chap_props_t *)kmem_zalloc - (sizeof (iscsi_chap_props_t), KM_SLEEP); + /* + * Initialize the target-side chap name to the session name + * if no chap settings have been saved for the current session. + */ + if (persistent_chap_get((char *)isp->sess_name, chap) + == B_FALSE) { + int name_len = strlen((char *)isp->sess_name); + bcopy((char *)isp->sess_name, chap->c_user, name_len); + chap->c_user_len = name_len; + (void) (persistent_chap_set((char *)isp->sess_name, + chap)); + bzero(chap, sizeof (*chap)); + } - /* - * Initialize the target-side chap name to the session name if no chap - * settings have been saved for the current session. - */ - if (persistent_chap_get((char *)isp->sess_name, chap) == B_FALSE) { - int name_len = strlen((char *)isp->sess_name); - bcopy((char *)isp->sess_name, chap->c_user, name_len); - chap->c_user_len = name_len; - (void) (persistent_chap_set((char *)isp->sess_name, chap)); - bzero(chap, sizeof (*chap)); - } + if (auth->a_auth_method & authMethodCHAP) { + /* Obtain initiator's CHAP settings. */ + if (persistent_chap_get(init_name, chap) == B_FALSE) { + /* No initiator secret defined. */ + kmem_free(chap, sizeof (iscsi_chap_props_t)); + /* Set authentication method to NONE */ + isp->sess_auth.password_length = 0; + kmem_free(auth, sizeof (iscsi_auth_props_t)); + return (B_FALSE); + } - if (auth->a_auth_method & authMethodCHAP) { - /* Obtain initiator's CHAP settings. */ - if (persistent_chap_get(init_name, chap) == B_FALSE) { - /* No initiator secret defined. */ - kmem_free(chap, sizeof (iscsi_chap_props_t)); + bcopy(chap->c_user, isp->sess_auth.username, + sizeof (chap->c_user)); + bcopy(chap->c_secret, isp->sess_auth.password, + sizeof (chap->c_secret)); + isp->sess_auth.password_length = chap->c_secret_len; + } else { /* Set authentication method to NONE */ isp->sess_auth.password_length = 0; + } + + /* + * Consider enabling bidirectional authentication only if + * authentication method is not NONE. + */ + if (auth->a_auth_method & authMethodCHAP && + auth->a_bi_auth == B_TRUE) { + /* Enable bi-directional authentication. */ + isp->sess_auth.bidirectional_auth = 1; + + bzero(chap, sizeof (*chap)); + /* Obtain target's CHAP settings. */ + if (persistent_chap_get((char *)isp->sess_name, chap) + == B_TRUE) { + bcopy(chap->c_secret, + isp->sess_auth.password_in, + sizeof (chap->c_secret)); + bcopy(chap->c_user, isp->sess_auth.username_in, + strlen((char *)chap->c_user)); + isp->sess_auth.password_length_in = + chap->c_secret_len; + } else { + /* + * No target secret defined. + * RADIUS server should have been enabled. + */ + /* EMPTY */ + } + } else { + /* Disable bi-directional authentication */ + isp->sess_auth.bidirectional_auth = 0; + } + + if (auth != NULL) { kmem_free(auth, sizeof (iscsi_auth_props_t)); + } + if (chap != NULL) { + kmem_free(chap, sizeof (iscsi_chap_props_t)); + } + } else { + /* + * This session is boot session. We will use the CHAP and + * the user name got from the boot property structure instead + * of persistent sotre. + */ + if (iscsiboot_prop == NULL) { return (B_FALSE); } - bcopy(chap->c_user, isp->sess_auth.username, - sizeof (chap->c_user)); - bcopy(chap->c_secret, isp->sess_auth.password, - sizeof (chap->c_secret)); - isp->sess_auth.password_length = chap->c_secret_len; - } else { - /* Set authentication method to NONE */ - isp->sess_auth.password_length = 0; - } + if (iscsiboot_prop->boot_init.ini_chap_sec == NULL) { + return (B_FALSE); + } - /* - * Consider enabling bidirectional authentication only if - * authentication method is not NONE. - */ - if (auth->a_auth_method & authMethodCHAP && - auth->a_bi_auth == B_TRUE) { - /* Enable bi-directional authentication. */ - isp->sess_auth.bidirectional_auth = 1; - - bzero(chap, sizeof (*chap)); - /* Obtain target's CHAP settings. */ - if (persistent_chap_get((char *)isp->sess_name, chap) == - B_TRUE) { - bcopy(chap->c_secret, isp->sess_auth.password_in, - sizeof (chap->c_secret)); - bcopy(chap->c_user, isp->sess_auth.username_in, - strlen((char *)chap->c_user)); - isp->sess_auth.password_length_in = chap->c_secret_len; + /* CHAP secret */ + (void) bcopy(iscsiboot_prop->boot_init.ini_chap_sec, + isp->sess_auth.password, + strlen((char *)iscsiboot_prop->boot_init.ini_chap_sec)); + + /* + * If chap name is not set, + * we will use initiator name instead. + */ + if (iscsiboot_prop->boot_init.ini_chap_name == NULL) { + (void) bcopy(init_name, isp->sess_auth.username, + strlen(init_name)); } else { + tmp = iscsiboot_prop->boot_init.ini_chap_name; + (void) bcopy(tmp, + isp->sess_auth.username, strlen((char *)tmp)); + } + + isp->sess_auth.password_length = + strlen((char *)iscsiboot_prop->boot_init.ini_chap_sec); + + if (iscsiboot_prop->boot_tgt.tgt_chap_sec != NULL) { /* - * No target secret defined. - * RADIUS server should have been enabled. + * Bidirectional authentication is required. */ - /* EMPTY */ - } - } else { - /* Disable bi-directional authentication */ - isp->sess_auth.bidirectional_auth = 0; - } + tmp = iscsiboot_prop->boot_tgt.tgt_chap_sec; + (void) bcopy(tmp, + isp->sess_auth.password_in, strlen((char *)tmp)); - if (auth != NULL) { - kmem_free(auth, sizeof (iscsi_auth_props_t)); - } - if (chap != NULL) { - kmem_free(chap, sizeof (iscsi_chap_props_t)); + /* + * If the target's chap name is not set, we will use + * session name instead. + */ + if (iscsiboot_prop->boot_tgt.tgt_chap_name == NULL) { + (void) bcopy(isp->sess_name, + isp->sess_auth.username_in, + isp->sess_name_length); + } else { + tmp = iscsiboot_prop->boot_tgt.tgt_chap_name; + (void) bcopy(tmp, + isp->sess_auth.username_in, + strlen((char *)tmp)); + } + tmp = iscsiboot_prop->boot_tgt.tgt_chap_sec; + isp->sess_auth.password_length_in = + strlen((char *)tmp); + isp->sess_auth.bidirectional_auth = 1; + } } /* Set up authentication buffers only if configured */ diff --git a/usr/src/uts/common/io/scsi/adapters/iscsi/iscsid.c b/usr/src/uts/common/io/scsi/adapters/iscsi/iscsid.c index dc89313b96..b7b0db9205 100644 --- a/usr/src/uts/common/io/scsi/adapters/iscsi/iscsid.c +++ b/usr/src/uts/common/io/scsi/adapters/iscsi/iscsid.c @@ -41,6 +41,7 @@ #include "persistent.h" #include "iscsi.h" #include <sys/ethernet.h> +#include <sys/bootprops.h> /* * local function prototypes @@ -51,6 +52,7 @@ static void iscsid_thread_static(iscsi_thread_t *thread, void *p); static void iscsid_thread_sendtgts(iscsi_thread_t *thread, void *p); static void iscsid_thread_isns(iscsi_thread_t *thread, void *p); static void iscsid_thread_slp(iscsi_thread_t *thread, void *p); +static void iscsid_thread_boot_wd(iscsi_thread_t *thread, void *p); static void iscsid_threads_create(iscsi_hba_t *ihp); static void iscsid_threads_destroy(void); static int iscsid_copyto_param_set(uint32_t param_id, @@ -62,11 +64,19 @@ static void iscsid_remove_target_param(char *name); static boolean_t iscsid_add(iscsi_hba_t *ihp, iSCSIDiscoveryMethod_t method, struct sockaddr *addr_dsc, char *target_name, int tpgt, struct sockaddr *addr_tgt); - static void iscsi_discovery_event(iscsi_hba_t *ihp, iSCSIDiscoveryMethod_t m, boolean_t start); static void iscsi_send_sysevent(iscsi_hba_t *ihp, char *subclass, nvlist_t *np); +static boolean_t iscsid_boot_init_config(iscsi_hba_t *ihp); +static iscsi_sess_t *iscsi_add_boot_sess(iscsi_hba_t *ihp, int isid); +static boolean_t iscsid_make_entry(ib_boot_prop_t *boot_prop_entry, + entry_t *entry); + +extern int modrootloaded; +int iscsi_configroot_retry = 20; +static boolean_t iscsi_configroot_printed = FALSE; +extern ib_boot_prop_t *iscsiboot_prop; /* * iSCSI target discovery thread table @@ -96,7 +106,6 @@ static iscsid_thr_table iscsid_thr[] = { NULL } }; - /* * discovery method event table */ @@ -109,13 +118,130 @@ iSCSIDiscoveryMethod_t for_failure[] = { }; /* + * The following private tunable, set in /etc/system, e.g., + * set iscsi:iscsi_boot_max_delay = 360 + * , provides with customer a max wait time in + * seconds to wait for boot lun online during iscsi boot. + * Defaults to 180s. + */ +int iscsi_boot_max_delay = ISCSI_BOOT_DEFAULT_MAX_DELAY; + +/* * discovery configuration semaphore */ ksema_t iscsid_config_semaphore; +static iscsi_thread_t *iscsi_boot_wd_handle = NULL; + #define CHECK_METHOD(v) ((dm & v) ? B_TRUE : B_FALSE) /* + * Check if IP is valid + */ +static boolean_t +iscsid_ip_check(char *ip) +{ + int i = 0; + + if (!ip) + return (B_FALSE); + for (; (ip[i] == 0) && (i < IB_IP_BUFLEN); i++) {} + if (i == IB_IP_BUFLEN) { + /* invalid IP address */ + return (B_FALSE); + } + return (B_TRUE); +} + +/* + * Make an entry for the boot target. + * return B_TRUE upon success + * B_FALSE if fail + */ +static boolean_t +iscsid_make_entry(ib_boot_prop_t *boot_prop_entry, entry_t *entry) +{ + if (entry == NULL || boot_prop_entry == NULL) { + return (B_FALSE); + } + + if (!iscsid_ip_check( + (char *)&boot_prop_entry->boot_tgt.tgt_ip_u)) + return (B_FALSE); + + if (boot_prop_entry->boot_tgt.sin_family != AF_INET && + boot_prop_entry->boot_tgt.sin_family != AF_INET6) + return (B_FALSE); + + entry->e_vers = ISCSI_INTERFACE_VERSION; + + mutex_enter(&iscsi_oid_mutex); + entry->e_oid = iscsi_oid++; + mutex_exit(&iscsi_oid_mutex); + + entry->e_tpgt = ISCSI_DEFAULT_TPGT; + + if (boot_prop_entry->boot_tgt.sin_family == AF_INET) { + entry->e_u.u_in4.s_addr = + boot_prop_entry->boot_tgt.tgt_ip_u.u_in4.s_addr; + entry->e_insize = sizeof (struct in_addr); + } else { + (void) bcopy( + &boot_prop_entry->boot_tgt.tgt_ip_u.u_in6.s6_addr, + entry->e_u.u_in6.s6_addr, 16); + entry->e_insize = sizeof (struct in6_addr); + } + + entry->e_port = boot_prop_entry->boot_tgt.tgt_port; + entry->e_boot = B_TRUE; + return (B_TRUE); +} + +/* + * Create the boot session + */ +static void +iscsi_boot_session_create(iscsi_hba_t *ihp, + ib_boot_prop_t *boot_prop_table) +{ + iSCSIDiscoveryMethod_t dm; + entry_t e; + iscsi_sockaddr_t addr_dsc; + + if (ihp == NULL || boot_prop_table == NULL) { + return; + } + + if (!iscsid_ip_check( + (char *)&boot_prop_table->boot_tgt.tgt_ip_u)) { + return; + } + + if (boot_prop_table->boot_tgt.tgt_name != NULL) { + dm = iSCSIDiscoveryMethodStatic | + iSCSIDiscoveryMethodBoot; + if (!iscsid_make_entry(boot_prop_table, &e)) + return; + iscsid_addr_to_sockaddr(e.e_insize, &e.e_u, + e.e_port, &addr_dsc.sin); + + (void) iscsid_add(ihp, dm, &addr_dsc.sin, + (char *)boot_prop_table->boot_tgt.tgt_name, + e.e_tpgt, &addr_dsc.sin); + } else { + dm = iSCSIDiscoveryMethodSendTargets | + iSCSIDiscoveryMethodBoot; + if (!iscsid_make_entry(boot_prop_table, &e)) + return; + iscsid_addr_to_sockaddr(e.e_insize, &e.e_u, + e.e_port, &addr_dsc.sin); + iscsid_do_sendtgts(&e); + (void) iscsid_login_tgt(ihp, NULL, dm, + &addr_dsc.sin); + } +} + +/* * iscsid_init -- load data from persistent storage and start discovery threads * * If restart is B_TRUE than someone has issued an ISCSI_DB_RELOAD ioctl. @@ -132,40 +258,74 @@ iscsid_init(iscsi_hba_t *ihp, boolean_t restart) sema_init(&iscsid_config_semaphore, 1, NULL, SEMA_DRIVER, NULL); - rval = persistent_init(restart); - if (rval == B_TRUE) { - rval = iscsid_init_config(ihp); - if (rval == B_TRUE) { - rval = iscsid_init_targets(ihp); + if (iscsiboot_prop) { + if (ihp->persistent_loaded) { + rval = persistent_init(B_TRUE); + } else { + rval = persistent_init(B_FALSE); + if (rval) + ihp->persistent_loaded = B_TRUE; } - } - - if (rval == B_TRUE) { + } else { + rval = persistent_init(restart); if (restart == B_FALSE) { - iscsid_threads_create(ihp); + ihp->persistent_loaded = B_TRUE; } + } - dm = persistent_disc_meth_get(); - rval = iscsid_enable_discovery(ihp, dm, B_FALSE); + if ((modrootloaded == 0) && (iscsiboot_prop != NULL) && rval) { + if (!iscsid_boot_init_config(ihp)) { + rval = B_FALSE; + } else { + iscsi_boot_session_create(ihp, iscsiboot_prop); + iscsi_boot_wd_handle = + iscsi_thread_create(ihp->hba_dip, + "BootWD", iscsid_thread_boot_wd, ihp); + if (iscsi_boot_wd_handle) { + rval = iscsi_thread_start( + iscsi_boot_wd_handle); + } else { + rval = B_FALSE; + } + } + if (!rval) { + cmn_err(CE_NOTE, "Initializaton of iscsi initiator" + " partially failed"); + } + } else { if (rval == B_TRUE) { - rval = iscsid_disable_discovery(ihp, ~dm); + rval = iscsid_init_config(ihp); + if (rval == B_TRUE) { + rval = iscsid_init_targets(ihp); + } } - } - if (rval == B_FALSE) { - /* - * In case of failure the events still need to be sent - * because the door daemon will pause until all these - * events have occurred. - */ - for (fdm = &for_failure[0]; *fdm != iSCSIDiscoveryMethodUnknown; - fdm++) { - /* ---- Send both start and end events ---- */ - iscsi_discovery_event(ihp, *fdm, B_TRUE); - iscsi_discovery_event(ihp, *fdm, B_FALSE); + if (rval == B_TRUE) { + if (restart == B_FALSE) { + iscsid_threads_create(ihp); + } + + dm = persistent_disc_meth_get(); + rval = iscsid_enable_discovery(ihp, dm, B_FALSE); + if (rval == B_TRUE) { + rval = iscsid_disable_discovery(ihp, ~dm); + } + + } + if (rval == B_FALSE) { + /* + * In case of failure the events still need to be sent + * because the door daemon will pause until all these + * events have occurred. + */ + for (fdm = &for_failure[0]; *fdm != + iSCSIDiscoveryMethodUnknown; fdm++) { + /* ---- Send both start and end events ---- */ + iscsi_discovery_event(ihp, *fdm, B_TRUE); + iscsi_discovery_event(ihp, *fdm, B_FALSE); + } } } - return (rval); } @@ -177,6 +337,10 @@ void iscsid_fini() { iscsid_threads_destroy(); + if (iscsi_boot_wd_handle != NULL) { + iscsi_thread_destroy(iscsi_boot_wd_handle); + iscsi_boot_wd_handle = NULL; + } persistent_fini(); sema_destroy(&iscsid_config_semaphore); } @@ -369,7 +533,8 @@ iscsid_do_sendtgts(entry_t *disc_addr) const char *ip; int ctr; int rc; - iscsi_hba_t *ihp; + iscsi_hba_t *ihp; + iSCSIDiscoveryMethod_t dm = iSCSIDiscoveryMethodSendTargets; /* allocate and initialize sendtargets list header */ stl_sz = sizeof (*stl_hdr) + ((stl_num_tgts - 1) * @@ -436,8 +601,10 @@ retry_sendtgts: &(stl_hdr->stl_list[ctr].ste_ipaddr.a_addr.i_addr), stl_hdr->stl_list[ctr].ste_ipaddr.a_port, &addr_tgt.sin); - - (void) iscsid_add(ihp, iSCSIDiscoveryMethodSendTargets, + if (disc_addr->e_boot == B_TRUE) { + dm = dm | iSCSIDiscoveryMethodBoot; + } + (void) iscsid_add(ihp, dm, &addr_dsc.sin, (char *)stl_hdr->stl_list[ctr].ste_name, stl_hdr->stl_list[ctr].ste_tpgt, &addr_tgt.sin); @@ -528,29 +695,73 @@ iscsid_do_isns_query(iscsi_hba_t *ihp) void iscsid_config_one(iscsi_hba_t *ihp, char *name, boolean_t protect) { - boolean_t rc; - - rc = iscsid_login_tgt(ihp, name, - iSCSIDiscoveryMethodUnknown, NULL); - /* - * If we didn't login to the device we might have - * to update our discovery information and attempt - * the login again. - */ - if (rc == B_FALSE) { + boolean_t rc = B_FALSE; + int retry = 0; + int lun_online = 0; + int cur_sec = 0; + + if (!modrootloaded && (iscsiboot_prop != NULL)) { + if (!iscsi_configroot_printed) { + cmn_err(CE_NOTE, "Configuring" + " iSCSI boot session..."); + iscsi_configroot_printed = B_TRUE; + } + while (rc == B_FALSE && retry < + iscsi_configroot_retry) { + rc = iscsid_login_tgt(ihp, name, + iSCSIDiscoveryMethodBoot, NULL); + if (rc == B_FALSE) { + /* + * create boot session + */ + iscsi_boot_session_create(ihp, + iscsiboot_prop); + } else { + /* + * The boot session has been created, if + * the target lun has not been online, + * we should wait here for a while + */ + do { + lun_online = + iscsiboot_prop->boot_tgt.lun_online; + if (lun_online == 0) { + delay(SEC_TO_TICK(1)); + cur_sec++; + } + } while ((lun_online == 0) && + (cur_sec < iscsi_boot_max_delay)); + } + retry++; + } + if (!rc) { + cmn_err(CE_WARN, "Failed to configure iSCSI" + " boot session"); + } + } else { + rc = iscsid_login_tgt(ihp, name, iSCSIDiscoveryMethodUnknown, + NULL); /* - * Stale /dev links can cause us to get floods - * of config requests. Prevent these repeated - * requests from causing unneeded discovery updates - * if ISCSI_CONFIG_STORM_PROTECT is set. + * If we didn't login to the device we might have + * to update our discovery information and attempt + * the login again. */ - if ((protect == B_FALSE) || - (ddi_get_lbolt() > ihp->hba_config_lbolt + - SEC_TO_TICK(ihp->hba_config_storm_delay))) { - ihp->hba_config_lbolt = ddi_get_lbolt(); - iscsid_poke_discovery(ihp, iSCSIDiscoveryMethodUnknown); - (void) iscsid_login_tgt(ihp, name, - iSCSIDiscoveryMethodUnknown, NULL); + if (rc == B_FALSE) { + /* + * Stale /dev links can cause us to get floods + * of config requests. Prevent these repeated + * requests from causing unneeded discovery updates + * if ISCSI_CONFIG_STORM_PROTECT is set. + */ + if ((protect == B_FALSE) || + (ddi_get_lbolt() > ihp->hba_config_lbolt + + SEC_TO_TICK(ihp->hba_config_storm_delay))) { + ihp->hba_config_lbolt = ddi_get_lbolt(); + iscsid_poke_discovery(ihp, + iSCSIDiscoveryMethodUnknown); + (void) iscsid_login_tgt(ihp, name, + iSCSIDiscoveryMethodUnknown, NULL); + } } } } @@ -565,20 +776,68 @@ iscsid_config_one(iscsi_hba_t *ihp, char *name, boolean_t protect) void iscsid_config_all(iscsi_hba_t *ihp, boolean_t protect) { - /* - * Stale /dev links can cause us to get floods - * of config requests. Prevent these repeated - * requests from causing unneeded discovery updates - * if ISCSI_CONFIG_STORM_PROTECT is set. - */ - if ((protect == B_FALSE) || - (ddi_get_lbolt() > ihp->hba_config_lbolt + - SEC_TO_TICK(ihp->hba_config_storm_delay))) { - ihp->hba_config_lbolt = ddi_get_lbolt(); - iscsid_poke_discovery(ihp, iSCSIDiscoveryMethodUnknown); - } - (void) iscsid_login_tgt(ihp, NULL, - iSCSIDiscoveryMethodUnknown, NULL); + boolean_t rc = B_FALSE; + int retry = 0; + int lun_online = 0; + int cur_sec = 0; + + if (!modrootloaded && iscsiboot_prop != NULL) { + if (!iscsi_configroot_printed) { + cmn_err(CE_NOTE, "Configuring" + " iSCSI boot session..."); + iscsi_configroot_printed = B_TRUE; + } + while (rc == B_FALSE && retry < + iscsi_configroot_retry) { + rc = iscsid_login_tgt(ihp, NULL, + iSCSIDiscoveryMethodBoot, NULL); + if (rc == B_FALSE) { + /* + * No boot session has been created. + * We would like to create the boot + * Session first. + */ + iscsi_boot_session_create(ihp, + iscsiboot_prop); + } else { + /* + * The boot session has been created, if + * the target lun has not been online, + * we should wait here for a while + */ + do { + lun_online = + iscsiboot_prop->boot_tgt.lun_online; + if (lun_online == 0) { + delay(SEC_TO_TICK(1)); + cur_sec++; + } + } while ((lun_online == 0) && + (cur_sec < iscsi_boot_max_delay)); + } + retry++; + } + if (!rc) { + cmn_err(CE_WARN, "Failed to configure" + " boot session"); + } + } else { + /* + * Stale /dev links can cause us to get floods + * of config requests. Prevent these repeated + * requests from causing unneeded discovery updates + * if ISCSI_CONFIG_STORM_PROTECT is set. + */ + if ((protect == B_FALSE) || + (ddi_get_lbolt() > ihp->hba_config_lbolt + + SEC_TO_TICK(ihp->hba_config_storm_delay))) { + ihp->hba_config_lbolt = ddi_get_lbolt(); + iscsid_poke_discovery(ihp, + iSCSIDiscoveryMethodUnknown); + } + (void) iscsid_login_tgt(ihp, NULL, + iSCSIDiscoveryMethodUnknown, NULL); + } } /* @@ -754,6 +1013,19 @@ iscsid_add(iscsi_hba_t *ihp, iSCSIDiscoveryMethod_t method, } } + if (iscsiboot_prop && (ics->ics_out > 1) && + !iscsi_chk_bootlun_mpxio(ihp)) { + /* + * iscsi boot with mpxio disabled + * no need to search configured boot session + */ + + if (iscsi_cmp_boot_ini_name(tmp) || + iscsi_cmp_boot_tgt_name(tmp)) { + ics->ics_out = 1; + ics->ics_bound = B_FALSE; + } + } /* Check to see if we need to get more information */ if (ics->ics_out > 1) { /* record new size and free last buffer */ @@ -866,7 +1138,8 @@ iscsid_del(iscsi_hba_t *ihp, char *target_name, try_destroy = B_TRUE; } - if (try_destroy == B_TRUE) { + if (try_destroy == B_TRUE && + isp->sess_boot == B_FALSE) { (void) strcpy(name, (char *)isp->sess_name); status = iscsi_sess_destroy(isp); if (ISCSI_SUCCESS(status)) { @@ -914,44 +1187,58 @@ iscsid_login_tgt(iscsi_hba_t *ihp, char *target_name, isp = ihp->hba_sess_list; while (isp != NULL) { boolean_t try_online; - - if (target_name == NULL) { - if (method == iSCSIDiscoveryMethodUnknown) { - /* unknown method mean login to all */ - try_online = B_TRUE; - } else if (isp->sess_discovered_by & method) { - if ((method == iSCSIDiscoveryMethodISNS) || - (method == - iSCSIDiscoveryMethodSendTargets)) { - if ((addr_dsc == NULL) || - (bcmp(&isp->sess_discovered_addr, - addr_dsc, SIZEOF_SOCKADDR( - &isp->sess_discovered_addr.sin)) - == 0)) { - /* - * iSNS or sendtarget - * discovery and discovery - * address is NULL or match - */ - try_online = B_TRUE; - } else { + if (!(method & iSCSIDiscoveryMethodBoot)) { + if (target_name == NULL) { + if (method == iSCSIDiscoveryMethodUnknown) { + /* unknown method mean login to all */ + try_online = B_TRUE; + } else if (isp->sess_discovered_by & method) { + if ((method == + iSCSIDiscoveryMethodISNS) || + (method == + iSCSIDiscoveryMethodSendTargets)) { +#define SESS_DISC_ADDR isp->sess_discovered_addr.sin + if ((addr_dsc == NULL) || + (bcmp( + &isp->sess_discovered_addr, + addr_dsc, SIZEOF_SOCKADDR( + &SESS_DISC_ADDR)) + == 0)) { + /* + * iSNS or sendtarget + * discovery and + * discovery address + * is NULL or match + */ + try_online = B_TRUE; + } else { /* addr_dsc not a match */ - try_online = B_FALSE; + try_online = B_FALSE; + } +#undef SESS_DISC_ADDR + } else { + /* static configuration */ + try_online = B_TRUE; } } else { - /* static configuration */ - try_online = B_TRUE; + /* method not a match */ + try_online = B_FALSE; } + } else if (strcmp(target_name, + (char *)isp->sess_name) == 0) { + /* target_name match */ + try_online = B_TRUE; } else { - /* method not a match */ + /* target_name not a match */ try_online = B_FALSE; } - } else if (strcmp(target_name, (char *)isp->sess_name) == 0) { - /* target_name match */ - try_online = B_TRUE; } else { - /* target_name not a match */ - try_online = B_FALSE; + /* + * online the boot session. + */ + if (isp->sess_boot == B_TRUE) { + try_online = B_TRUE; + } } if (try_online == B_TRUE) { @@ -993,22 +1280,36 @@ iscsid_init_config(iscsi_hba_t *ihp) bzero(&ips, sizeof (ips)); if (persistent_initiator_name_get(initiatorName, ISCSI_MAX_NAME_LEN) == B_TRUE) { - (void) strncpy((char *)ips.s_value.v_name, initiatorName, - sizeof (ips.s_value.v_name)); - ips.s_vers = ISCSI_INTERFACE_VERSION; ips.s_param = ISCSI_LOGIN_PARAM_INITIATOR_NAME; - (void) iscsi_set_params(&ips, ihp, B_FALSE); + if (iscsiboot_prop && !iscsi_cmp_boot_ini_name(initiatorName)) { + (void) strncpy(initiatorName, + (const char *)iscsiboot_prop->boot_init.ini_name, + ISCSI_MAX_NAME_LEN); + (void) strncpy((char *)ips.s_value.v_name, + (const char *)iscsiboot_prop->boot_init.ini_name, + sizeof (ips.s_value.v_name)); + (void) iscsi_set_params(&ips, ihp, B_TRUE); + cmn_err(CE_NOTE, "Set initiator's name" + " from firmware"); + } else { + (void) strncpy((char *)ips.s_value.v_name, + initiatorName, sizeof (ips.s_value.v_name)); + + (void) iscsi_set_params(&ips, ihp, B_FALSE); + } } else { /* - * if we don't have an initiator-node name it's most - * likely because this is a fresh install (or we - * couldn't read the persistent store properly). Set - * a default initiator name so the initiator can + * if no initiator-node name available it is most + * likely due to a fresh install, or the persistent + * store is not working correctly. Set + * a default initiator name so that the initiator can * be brought up properly. */ iscsid_set_default_initiator_node_settings(ihp); + (void) strncpy(initiatorName, (const char *)ihp->hba_name, + ISCSI_MAX_NAME_LEN); } /* @@ -1052,6 +1353,10 @@ iscsid_init_config(iscsi_hba_t *ihp) } } } /* END for() */ + if (iscsiboot_prop && + iscsi_chk_bootlun_mpxio(ihp)) { + (void) iscsi_reconfig_boot_sess(ihp); + } break; } } /* END while() */ @@ -1114,6 +1419,15 @@ iscsid_init_targets(iscsi_hba_t *ihp) continue; } + if (iscsiboot_prop && iscsi_cmp_boot_tgt_name(name) && + !iscsi_chk_bootlun_mpxio(ihp)) { + /* + * boot target is not mpxio enabled + * simply ignore these overriden parameters + */ + continue; + } + ips.s_oid = iscsi_targetparam_get_oid((unsigned char *)name); for (param_id = 0; param_id < ISCSI_NUM_LOGIN_PARAM; @@ -1133,6 +1447,10 @@ iscsid_init_targets(iscsi_hba_t *ihp) } } } /* END for() */ + if (iscsiboot_prop && iscsi_cmp_boot_tgt_name(name) && + iscsi_chk_bootlun_mpxio(ihp)) { + (void) iscsi_reconfig_boot_sess(ihp); + } } /* END while() */ persistent_param_unlock(); @@ -1463,28 +1781,37 @@ iscsid_set_default_initiator_node_settings(iscsi_hba_t *ihp) iscsi_chap_props_t *chap = NULL; /* Set default initiator-node name */ - (void) snprintf((char *)ihp->hba_name, - ISCSI_MAX_NAME_LEN, - "iqn.1986-03.com.sun:01:"); - - (void) localetheraddr(NULL, &eaddr); - for (i = 0; i < ETHERADDRL; i++) { - (void) snprintf(val, sizeof (val), "%02x", - eaddr.ether_addr_octet[i]); + if (iscsiboot_prop && iscsiboot_prop->boot_init.ini_name != NULL) { + (void) strncpy((char *)ihp->hba_name, + (const char *)iscsiboot_prop->boot_init.ini_name, + ISCSI_MAX_NAME_LEN); + } else { + (void) snprintf((char *)ihp->hba_name, + ISCSI_MAX_NAME_LEN, + "iqn.1986-03.com.sun:01:"); + + (void) localetheraddr(NULL, &eaddr); + for (i = 0; i < ETHERADDRL; i++) { + (void) snprintf(val, sizeof (val), "%02x", + eaddr.ether_addr_octet[i]); + (void) strncat((char *)ihp->hba_name, val, + ISCSI_MAX_NAME_LEN); + } + + /* Set default initiator-node alias */ + x = ddi_get_time(); + (void) snprintf(val, sizeof (val), ".%lx", x); (void) strncat((char *)ihp->hba_name, val, ISCSI_MAX_NAME_LEN); - } - /* Set default initiator-node alias */ - x = ddi_get_time(); - (void) snprintf(val, sizeof (val), ".%lx", x); - (void) strncat((char *)ihp->hba_name, val, ISCSI_MAX_NAME_LEN); - (void) persistent_initiator_name_set((char *)ihp->hba_name); - if (ihp->hba_alias[0] == '\0') { - (void) strncpy((char *)ihp->hba_alias, - utsname.nodename, ISCSI_MAX_NAME_LEN); - ihp->hba_alias_length = strlen((char *)ihp->hba_alias); - (void) persistent_alias_name_set((char *)ihp->hba_alias); + if (ihp->hba_alias[0] == '\0') { + (void) strncpy((char *)ihp->hba_alias, + utsname.nodename, ISCSI_MAX_NAME_LEN); + ihp->hba_alias_length = strlen((char *)ihp->hba_alias); + (void) persistent_alias_name_set( + (char *)ihp->hba_alias); + } } + (void) persistent_initiator_name_set((char *)ihp->hba_name); /* Set default initiator-node CHAP settings */ if (persistent_initiator_name_get((char *)ihp->hba_name, @@ -1633,3 +1960,297 @@ iscsi_send_sysevent(iscsi_hba_t *ihp, char *subclass, nvlist_t *np) (void) ddi_log_sysevent(ihp->hba_dip, DDI_VENDOR_SUNW, EC_ISCSI, subclass, np, NULL, DDI_SLEEP); } + +static boolean_t +iscsid_boot_init_config(iscsi_hba_t *ihp) +{ + if (strlen((const char *)iscsiboot_prop->boot_init.ini_name) != 0) { + bcopy(iscsiboot_prop->boot_init.ini_name, + ihp->hba_name, + strlen((const char *)iscsiboot_prop->boot_init.ini_name)); + } + /* or using default login param for boot session */ + return (B_TRUE); +} + +boolean_t +iscsi_reconfig_boot_sess(iscsi_hba_t *ihp) +{ + iscsi_config_sess_t *ics; + int idx; + iscsi_sess_t *isp, *t_isp; + int isid, size; + char *name; + boolean_t rtn = B_TRUE; + + if (iscsiboot_prop == NULL) { + return (B_FALSE); + } + size = sizeof (*ics); + ics = kmem_zalloc(size, KM_SLEEP); + ics->ics_in = 1; + + /* get information of number of sessions to be configured */ + name = (char *)iscsiboot_prop->boot_tgt.tgt_name; + if (persistent_get_config_session(name, ics) == B_FALSE) { + /* + * No target information available to check + * initiator information. Assume one session + * by default. + */ + name = (char *)iscsiboot_prop->boot_init.ini_name; + if (persistent_get_config_session(name, ics) == B_FALSE) { + ics->ics_out = 1; + ics->ics_bound = B_TRUE; + } + } + + /* get necessary information */ + if (ics->ics_out > 1) { + idx = ics->ics_out; + size = ISCSI_SESSION_CONFIG_SIZE(ics->ics_out); + kmem_free(ics, sizeof (*ics)); + + ics = kmem_zalloc(size, KM_SLEEP); + ics->ics_in = idx; + + /* get configured sessions information */ + if (persistent_get_config_session((char *)name, + ics) != B_TRUE) { + cmn_err(CE_NOTE, "session(%s) - " + "failed to setup multiple sessions", + name); + kmem_free(ics, size); + return (B_FALSE); + } + } + + /* create a temporary session to keep boot session connective */ + t_isp = iscsi_add_boot_sess(ihp, ISCSI_MAX_CONFIG_SESSIONS); + if (t_isp == NULL) { + cmn_err(CE_NOTE, "session(%s) - " + "failed to setup multiple sessions", name); + rw_exit(&ihp->hba_sess_list_rwlock); + kmem_free(ics, size); + return (B_FALSE); + } + + /* destroy all old boot sessions */ + rw_enter(&ihp->hba_sess_list_rwlock, RW_WRITER); + isp = ihp->hba_sess_list; + while (isp != NULL) { + if (iscsi_chk_bootlun_mpxio(ihp) && isp->sess_boot) { + if (isp->sess_isid[5] != ISCSI_MAX_CONFIG_SESSIONS) { + /* + * destroy all stale sessions + * except temporary boot session + */ + if (ISCSI_SUCCESS(iscsi_sess_destroy( + isp))) { + isp = ihp->hba_sess_list; + } else { + /* + * couldn't destroy stale sessions + * at least poke it to disconnect + */ + mutex_enter(&isp->sess_state_mutex); + iscsi_sess_state_machine(isp, + ISCSI_SESS_EVENT_N7); + mutex_exit(&isp->sess_state_mutex); + isp = isp->sess_next; + cmn_err(CE_NOTE, "session(%s) - " + "failed to setup multiple" + " sessions", name); + } + } else { + isp = isp->sess_next; + } + } else { + isp = isp->sess_next; + } + } + rw_exit(&ihp->hba_sess_list_rwlock); + + for (isid = 0; isid < ics->ics_out; isid++) { + isp = iscsi_add_boot_sess(ihp, isid); + if (isp == NULL) { + cmn_err(CE_NOTE, "session(%s) - failed to setup" + " multiple sessions", name); + rtn = B_FALSE; + break; + } + } + if (!rtn && (isid == 0)) { + /* + * fail to create any new boot session + * so only the temporary session is alive + * quit without destroying it + */ + kmem_free(ics, size); + return (rtn); + } + + rw_enter(&ihp->hba_sess_list_rwlock, RW_WRITER); + if (!ISCSI_SUCCESS(iscsi_sess_destroy(t_isp))) { + /* couldn't destroy temp boot session */ + cmn_err(CE_NOTE, "session(%s) - " + "failed to setup multiple sessions", name); + rw_exit(&ihp->hba_sess_list_rwlock); + rtn = B_FALSE; + } + rw_exit(&ihp->hba_sess_list_rwlock); + + kmem_free(ics, size); + return (rtn); +} + +static iscsi_sess_t * +iscsi_add_boot_sess(iscsi_hba_t *ihp, int isid) +{ + iscsi_sess_t *isp; + iscsi_conn_t *icp; + uint_t oid; + + iscsi_sockaddr_t addr_dst; + + addr_dst.sin.sa_family = iscsiboot_prop->boot_tgt.sin_family; + if (addr_dst.sin.sa_family == AF_INET) { + bcopy(&iscsiboot_prop->boot_tgt.tgt_ip_u.u_in4.s_addr, + &addr_dst.sin4.sin_addr.s_addr, sizeof (struct in_addr)); + addr_dst.sin4.sin_port = + htons(iscsiboot_prop->boot_tgt.tgt_port); + } else { + bcopy(&iscsiboot_prop->boot_tgt.tgt_ip_u.u_in6.s6_addr, + &addr_dst.sin6.sin6_addr.s6_addr, + sizeof (struct in6_addr)); + addr_dst.sin6.sin6_port = + htons(iscsiboot_prop->boot_tgt.tgt_port); + } + + rw_enter(&ihp->hba_sess_list_rwlock, RW_WRITER); + isp = iscsi_sess_create(ihp, + iSCSIDiscoveryMethodBoot|iSCSIDiscoveryMethodStatic, + (struct sockaddr *)&addr_dst, + (char *)iscsiboot_prop->boot_tgt.tgt_name, + ISCSI_DEFAULT_TPGT, isid, ISCSI_SESS_TYPE_NORMAL, &oid); + if (isp == NULL) { + /* create temp booting session failed */ + rw_exit(&ihp->hba_sess_list_rwlock); + return (NULL); + } + isp->sess_boot = B_TRUE; + + if (!ISCSI_SUCCESS(iscsi_conn_create((struct sockaddr *)&addr_dst, + isp, &icp))) { + rw_exit(&ihp->hba_sess_list_rwlock); + return (NULL); + } + + rw_exit(&ihp->hba_sess_list_rwlock); + /* now online created session */ + if (iscsid_login_tgt(ihp, (char *)iscsiboot_prop->boot_tgt.tgt_name, + iSCSIDiscoveryMethodBoot|iSCSIDiscoveryMethodStatic, + (struct sockaddr *)&addr_dst) == B_FALSE) { + return (NULL); + } + + return (isp); +} + +static void +iscsid_thread_boot_wd(iscsi_thread_t *thread, void *p) +{ + int rc = 1; + iscsi_hba_t *ihp = (iscsi_hba_t *)p; + + while (rc != 0) { + if (iscsiboot_prop && (modrootloaded == 1) && + (ihp->persistent_loaded == B_TRUE)) { + (void) iscsid_init(ihp, B_FALSE); + (void) iscsi_reconfig_boot_sess(ihp); + iscsid_poke_discovery(ihp, iSCSIDiscoveryMethodUnknown); + (void) iscsid_login_tgt(ihp, NULL, + iSCSIDiscoveryMethodUnknown, NULL); + break; + } + rc = iscsi_thread_wait(thread, SEC_TO_TICK(1)); + } +} + +boolean_t +iscsi_cmp_boot_tgt_name(char *name) +{ + if (iscsiboot_prop && (strncmp((const char *)name, + (const char *)iscsiboot_prop->boot_tgt.tgt_name, + ISCSI_MAX_NAME_LEN) == 0)) { + return (B_TRUE); + } else { + return (B_FALSE); + } +} + +boolean_t +iscsi_cmp_boot_ini_name(char *name) +{ + if (iscsiboot_prop && (strncmp((const char *)name, + (const char *)iscsiboot_prop->boot_init.ini_name, + ISCSI_MAX_NAME_LEN) == 0)) { + return (B_TRUE); + } else { + return (B_FALSE); + } +} + +boolean_t +iscsi_chk_bootlun_mpxio(iscsi_hba_t *ihp) +{ + iscsi_sess_t *isp; + iscsi_lun_t *ilp; + isp = ihp->hba_sess_list; + boolean_t tgt_mpxio_enabled = B_FALSE; + boolean_t bootlun_found = B_FALSE; + uint16_t lun_num; + + if (iscsiboot_prop == NULL) { + return (B_FALSE); + } + + if (!ihp->hba_mpxio_enabled) { + return (B_FALSE); + } + + lun_num = *((uint64_t *)(iscsiboot_prop->boot_tgt.tgt_boot_lun)); + + while (isp != NULL) { + if ((strncmp((char *)isp->sess_name, + (const char *)iscsiboot_prop->boot_tgt.tgt_name, + ISCSI_MAX_NAME_LEN) == 0) && + (isp->sess_boot == B_TRUE)) { + /* + * found boot session. + * check its mdi path info is null or not + */ + ilp = isp->sess_lun_list; + while (ilp != NULL) { + if (lun_num == ilp->lun_num) { + if (ilp->lun_pip) { + tgt_mpxio_enabled = B_TRUE; + } + bootlun_found = B_TRUE; + } + ilp = ilp->lun_next; + } + } + isp = isp->sess_next; + } + if (bootlun_found) { + return (tgt_mpxio_enabled); + } else { + /* + * iscsiboot_prop not NULL while no boot lun found + * in most cases this is none iscsi boot while iscsiboot_prop + * is not NULL, in this scenario return iscsi HBA's mpxio config + */ + return (ihp->hba_mpxio_enabled); + } +} diff --git a/usr/src/uts/common/io/scsi/adapters/iscsi/nvfile.c b/usr/src/uts/common/io/scsi/adapters/iscsi/nvfile.c index 0ff155693d..f7d6028783 100644 --- a/usr/src/uts/common/io/scsi/adapters/iscsi/nvfile.c +++ b/usr/src/uts/common/io/scsi/adapters/iscsi/nvfile.c @@ -26,10 +26,12 @@ #include "iscsi.h" #include "nvfile.h" #include <sys/file.h> /* defines: FKIOCTL */ +#include <sys/kobj.h> #define NVF_GETF 16 static kmutex_t nvf_getf_lock; static file_t *nvf_fd[NVF_GETF]; +extern int modrootloaded; /* * file names @@ -208,7 +210,12 @@ nvf_load(void) /* * try to load current file */ - rval = nvf_parse(nvf_curr_filename); + if (!modrootloaded) { + mutex_exit(&nvf_lock); + return (B_TRUE); + } else { + rval = nvf_parse(nvf_curr_filename); + } if (rval == B_TRUE) { mutex_exit(&nvf_lock); return (rval); @@ -224,7 +231,13 @@ nvf_load(void) /* * try to load previous file */ - rval = nvf_parse(nvf_prev_filename); + if (!modrootloaded) { + mutex_exit(&nvf_lock); + return (B_TRUE); + } else { + rval = nvf_parse(nvf_curr_filename); + } + if (rval == B_TRUE) { mutex_exit(&nvf_lock); return (rval); @@ -837,7 +850,7 @@ nvf_thread(void *arg) /* * check whether its time to write to file. If not, reschedule self */ - if (nticks > NVF_RESCHED_MIN_TICKS) { + if ((nticks > NVF_RESCHED_MIN_TICKS) || !modrootloaded) { if (NVF_IS_ACTIVE(nvf_flags)) { mutex_exit(&nvf_lock); nvf_thread_id = timeout(nvf_thread, NULL, nticks); diff --git a/usr/src/uts/common/io/strplumb.c b/usr/src/uts/common/io/strplumb.c index 4eaf8e20ac..ffb7753e09 100644 --- a/usr/src/uts/common/io/strplumb.c +++ b/usr/src/uts/common/io/strplumb.c @@ -23,8 +23,6 @@ * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/param.h> #include <sys/types.h> #include <sys/user.h> @@ -78,6 +76,8 @@ */ int strplumbdebug = 0; +extern ib_boot_prop_t *iscsiboot_prop; + #define DBG0(_f) \ if (strplumbdebug != 0) \ printf("strplumb: " _f) @@ -143,6 +143,7 @@ _info(struct modinfo *modinfop) #define UDPDEV "/devices/pseudo/udp@0:udp" #define TCP6DEV "/devices/pseudo/tcp6@0:tcp6" +#define UDP6DEV "/devices/pseudo/udp6@0:udp6" #define SCTP6DEV "/devices/pseudo/sctp6@0:sctp6" #define IP6DEV "/devices/pseudo/ip6@0:ip6" @@ -424,6 +425,8 @@ setifname(ldi_handle_t lh, struct lifreq *lifrp) return (ldi_ioctl(lh, I_STR, (intptr_t)&iocb, FKIOCTL, CRED(), &rval)); } +extern ib_boot_prop_t *iscsiboot_prop; + static int strplumb_dev(ldi_ident_t li) { @@ -433,10 +436,16 @@ strplumb_dev(ldi_ident_t li) struct lifreq lifr; struct ifreq ifr; int rval; + int af = 0; + char *name = NULL; bzero(&lifr, sizeof (struct lifreq)); bzero(&ifr, sizeof (ifr)); + if (iscsiboot_prop != NULL) { + af = iscsiboot_prop->boot_nic.sin_family; + } + /* * Now set up the links. Ultimately, we should have two streams * permanently linked underneath UDP (which is actually IP with UDP @@ -474,9 +483,18 @@ strplumb_dev(ldi_ident_t li) if ((err = getifflags(lh, &lifr)) != 0) goto done; - lifr.lifr_flags |= IFF_IPV4; - lifr.lifr_flags &= ~IFF_IPV6; - + if (af == 0 || af == AF_INET) { + lifr.lifr_flags |= IFF_IPV4; + lifr.lifr_flags &= ~IFF_IPV6; + name = UDPDEV; + } else { + /* + * iscsi boot is used with ipv6 enabled + */ + lifr.lifr_flags |= IFF_IPV6; + lifr.lifr_flags &= ~IFF_IPV4; + name = UDP6DEV; + } if ((err = ldi_ioctl(lh, I_PUSH, (intptr_t)ARP, FKIOCTL, CRED(), &rval)) != 0) { printf("strplumb: push ARP failed: %d\n", err); @@ -498,7 +516,7 @@ strplumb_dev(ldi_ident_t li) } /* Pop out ARP if not needed */ - if (lifr.lifr_flags & IFF_NOARP) { + if (lifr.lifr_flags & (IFF_NOARP | IFF_IPV6)) { err = ldi_ioctl(lh, I_POP, (intptr_t)0, FKIOCTL, CRED(), &rval); if (err != 0) { @@ -507,9 +525,9 @@ strplumb_dev(ldi_ident_t li) } } - if ((err = ldi_open_by_name(UDPDEV, FREAD|FWRITE, CRED(), &mux_lh, + if ((err = ldi_open_by_name(name, FREAD|FWRITE, CRED(), &mux_lh, li)) != 0) { - printf("strplumb: open of UDPDEV failed: %d\n", err); + printf("strplumb: open of %s failed: %d\n", name, err); goto done; } @@ -521,6 +539,10 @@ strplumb_dev(ldi_ident_t li) goto done; } + if (af == AF_INET6) { + goto done; + } + DBG2("UDP-ARP-IP-%s muxid: %d\n", rootfs.bo_ifname, ifr.ifr_ip_muxid); (void) ldi_close(lh, FREAD|FWRITE, CRED()); @@ -681,8 +703,13 @@ strplumb_get_netdev_path(void) dhcacklen = bootp_len; ddi_prop_free(bootp); - } else + } else if (iscsiboot_prop != NULL) { + bcopy(iscsiboot_prop->boot_nic.nic_mac, + boot_macaddr, IB_BOOT_MACLEN); + boot_maclen = IB_BOOT_MACLEN; + } else { return (NULL); + } ddi_walk_devs(ddi_root_node(), matchmac, (void *)&devpath); return (devpath); diff --git a/usr/src/uts/common/os/iscsiboot_prop.c b/usr/src/uts/common/os/iscsiboot_prop.c new file mode 100644 index 0000000000..28b0566d34 --- /dev/null +++ b/usr/src/uts/common/os/iscsiboot_prop.c @@ -0,0 +1,269 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * Commmon routines, handling iscsi boot props + */ + +#include <sys/types.h> +#include <sys/bootprops.h> +#include <sys/cmn_err.h> +#include <sys/socket.h> +#include <sys/kmem.h> +#include <netinet/in.h> + +extern void *memset(void *s, int c, size_t n); +extern int memcmp(const void *s1, const void *s2, size_t n); +extern void bcopy(const void *s1, void *s2, size_t n); +extern size_t strlen(const char *s); +static void kinet_ntoa(char *buf, void *in, int af); +extern ib_boot_prop_t *iscsiboot_prop; + +int iscsi_print_bootprop = 0; + +#define ISCSI_BOOTPROP_BUFLEN 256 + +#ifndef NULL +#define NULL 0 +#endif + +static void +iscsi_bootprop_print(int level, char *str) +{ + if (str == NULL) { + return; + } + if (iscsi_print_bootprop == 1) { + cmn_err(level, "%s", str); + } +} + +static void +iscsi_print_initiator_property(ib_ini_prop_t *ibinitp) +{ + char outbuf[ISCSI_BOOTPROP_BUFLEN] = {0}; + + if (ibinitp == NULL) { + return; + } + + if (ibinitp->ini_name != NULL) { + (void) sprintf(outbuf, + "Initiator Name : %s\n", + ibinitp->ini_name); + iscsi_bootprop_print(CE_CONT, outbuf); + } + + if (ibinitp->ini_chap_name != NULL) { + (void) memset(outbuf, 0, ISCSI_BOOTPROP_BUFLEN); + (void) sprintf(outbuf, + "Initiator CHAP Name : %s\n", + ibinitp->ini_chap_name); + + iscsi_bootprop_print(CE_CONT, outbuf); + } +} + +static void +iscsi_print_nic_property(ib_nic_prop_t *nicp) +{ + char outbuf[ISCSI_BOOTPROP_BUFLEN] = {0}; + char ipaddr[50] = {0}; + int n = 0; + + if (nicp == NULL) { + return; + } + + kinet_ntoa(ipaddr, &nicp->nic_ip_u, nicp->sin_family); + n = snprintf(outbuf, ISCSI_BOOTPROP_BUFLEN, + "Local IP addr : %s\n", ipaddr); + + (void) memset(ipaddr, 0, 50); + kinet_ntoa(ipaddr, &nicp->nic_gw_u, nicp->sin_family); + n = n + snprintf(outbuf + n, ISCSI_BOOTPROP_BUFLEN - n, + "Local gateway : %s\n", ipaddr); + + (void) memset(ipaddr, 0, 50); + kinet_ntoa(ipaddr, &nicp->nic_dhcp_u, nicp->sin_family); + n = n + snprintf(outbuf + n, ISCSI_BOOTPROP_BUFLEN - n, + "Local DHCP : %s\n", ipaddr); + + (void) snprintf(outbuf + n, ISCSI_BOOTPROP_BUFLEN - n, + "Local MAC : %02x:%02x:%02x:%02x:%02x:%02x\n", + nicp->nic_mac[0], + nicp->nic_mac[1], + nicp->nic_mac[2], + nicp->nic_mac[3], + nicp->nic_mac[4], + nicp->nic_mac[5]); + + iscsi_bootprop_print(CE_CONT, outbuf); +} + +static void +iscsi_print_tgt_property(ib_tgt_prop_t *itgtp) +{ + char outbuf[ISCSI_BOOTPROP_BUFLEN] = {0}; + char ipaddr[50] = {0}; + + if (itgtp == NULL) { + return; + } + + if (itgtp->tgt_name != NULL) { + (void) memset(outbuf, 0, ISCSI_BOOTPROP_BUFLEN); + (void) sprintf(outbuf, + "Target Name : %s\n", + itgtp->tgt_name); + iscsi_bootprop_print(CE_CONT, outbuf); + } + + kinet_ntoa(ipaddr, &itgtp->tgt_ip_u, itgtp->sin_family); + (void) sprintf(outbuf, + "Target IP : %s\n" + "Target Port : %d\n" + "Boot LUN : %02x%02x-%02x%02x-%02x%02x-%02x%02x\n", + ipaddr, + itgtp->tgt_port, + itgtp->tgt_boot_lun[0], + itgtp->tgt_boot_lun[1], + itgtp->tgt_boot_lun[2], + itgtp->tgt_boot_lun[3], + itgtp->tgt_boot_lun[4], + itgtp->tgt_boot_lun[5], + itgtp->tgt_boot_lun[6], + itgtp->tgt_boot_lun[7]); + iscsi_bootprop_print(CE_CONT, outbuf); + + if (itgtp->tgt_chap_name != NULL) { + (void) memset(outbuf, 0, ISCSI_BOOTPROP_BUFLEN); + (void) sprintf(outbuf, + "CHAP Name : %s\n", + itgtp->tgt_chap_name); + iscsi_bootprop_print(CE_CONT, outbuf); + } +} + +void +iscsi_print_boot_property() +{ + if (iscsiboot_prop == NULL) { + return; + } + + iscsi_print_initiator_property( + &iscsiboot_prop->boot_init); + + iscsi_print_nic_property(&iscsiboot_prop->boot_nic); + + iscsi_print_tgt_property(&iscsiboot_prop->boot_tgt); +} + +void +iscsi_boot_free_ini(ib_ini_prop_t *init) +{ + if (init == NULL) { + return; + } + + if (init->ini_name != NULL) { + kmem_free(init->ini_name, strlen((char *)init->ini_name) + 1); + init->ini_name = NULL; + } + if (init->ini_chap_name != NULL) { + kmem_free(init->ini_chap_name, + strlen((char *)init->ini_chap_name) + 1); + init->ini_chap_name = NULL; + } + if (init->ini_chap_sec != NULL) { + kmem_free(init->ini_chap_sec, + strlen((char *)init->ini_chap_sec) + 1); + init->ini_chap_sec = NULL; + } +} + +void +iscsi_boot_free_tgt(ib_tgt_prop_t *target) +{ + if (target == NULL) { + return; + } + + if (target->tgt_name != NULL) { + kmem_free(target->tgt_name, + strlen((char *)target->tgt_name) + 1); + target->tgt_name = NULL; + } + if (target->tgt_chap_name != NULL) { + kmem_free(target->tgt_chap_name, + strlen((char *)target->tgt_chap_name) + 1); + target->tgt_chap_name = NULL; + } + if (target->tgt_chap_sec != NULL) { + kmem_free(target->tgt_chap_sec, + strlen((char *)target->tgt_chap_sec) + 1); + target->tgt_chap_sec = NULL; + } +} + +/* + * Free the memory used by boot property. + */ +void +iscsi_boot_prop_free() +{ + ib_boot_prop_t *tmp; + + if (iscsiboot_prop == NULL) { + return; + } + tmp = iscsiboot_prop; + iscsiboot_prop = NULL; + iscsi_boot_free_ini(&(tmp->boot_init)); + iscsi_boot_free_tgt(&(tmp->boot_tgt)); +} + +static void +kinet_ntoa(char *buf, void *in, int af) +{ + unsigned char *p = NULL; + int i = 0; + + if (buf == NULL || in == NULL) { + return; + } + p = (unsigned char *)in; + if (af == AF_INET) { + (void) sprintf(buf, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); + } else { + for (i = 0; i < 14; i = i + 2) { + (void) sprintf(buf, "%02x%02x:", p[i], p[i+1]); + buf = buf + 5; + } + (void) sprintf(buf, "%02x%02x", p[i], p[i+1]); + } +} diff --git a/usr/src/uts/common/os/main.c b/usr/src/uts/common/os/main.c index 5b3d8d5d03..7d0cf27d8e 100644 --- a/usr/src/uts/common/os/main.c +++ b/usr/src/uts/common/os/main.c @@ -26,7 +26,6 @@ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ - #include <sys/types.h> #include <sys/param.h> #include <sys/sysmacros.h> @@ -76,6 +75,7 @@ #include <sys/dc_ki.h> #include <c2/audit.h> +#include <sys/bootprops.h> /* well known processes */ proc_t *proc_sched; /* memory scheduler */ @@ -361,6 +361,7 @@ main(void) extern id_t syscid, defaultcid; extern int swaploaded; extern int netboot; + extern ib_boot_prop_t *iscsiboot_prop; extern void vm_init(void); extern void cbe_init_pre(void); extern void cbe_init(void); @@ -429,7 +430,10 @@ main(void) */ for (initptr = &init_tbl[0]; *initptr; initptr++) (**initptr)(); - + /* + * Load iSCSI boot properties + */ + ld_ib_prop(); /* * initialize vm related stuff. */ @@ -474,7 +478,7 @@ main(void) * Plumb the protocol modules and drivers only if we are not * networked booted, in this case we already did it in rootconf(). */ - if (netboot == 0) + if (netboot == 0 && iscsiboot_prop == NULL) (void) strplumb(); gethrestime(&PTOU(curproc)->u_start); diff --git a/usr/src/uts/common/os/space.c b/usr/src/uts/common/os/space.c index 08384fab47..6edebecdfe 100644 --- a/usr/src/uts/common/os/space.c +++ b/usr/src/uts/common/os/space.c @@ -20,12 +20,10 @@ */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* * The intent of this file is to contain any data that must remain * resident in the kernel. @@ -61,6 +59,7 @@ #include <sys/kbio.h> #include <sys/consdev.h> #include <sys/wscons.h> +#include <sys/bootprops.h> struct buf bfreelist; /* Head of the free list of buffers */ @@ -377,3 +376,8 @@ uint_t ip_threads_per_cpu = NUMBER_OF_THREADS_PER_CPU; /* Global flag to enable/disable soft ring facility */ boolean_t ip_squeue_soft_ring = B_FALSE; + +/* + * Global iscsi boot prop + */ +ib_boot_prop_t *iscsiboot_prop = NULL; diff --git a/usr/src/uts/common/sys/bootprops.h b/usr/src/uts/common/sys/bootprops.h index f337777172..ed6dd8bd7a 100644 --- a/usr/src/uts/common/sys/bootprops.h +++ b/usr/src/uts/common/sys/bootprops.h @@ -19,16 +19,16 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _BOOTPROPS_H #define _BOOTPROPS_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/types.h> +#include <netinet/in.h> +#include <sys/t_kuser.h> #ifdef __cplusplus extern "C" { @@ -48,6 +48,84 @@ extern "C" { #define BP_BOOTP_RESPONSE "bootp-response" #define BP_NETWORK_INTERFACE "network-interface" +/* + * kifconf prototypes + */ +int +kdlifconfig(TIUSER *tiptr, int af, void *myIPaddr, void *mymask, + struct in_addr *mybraddr, struct in_addr *gateway, char *ifname); +int +ksetifflags(TIUSER *tiptr, uint_t value, char *ifname); +int +kifioctl(TIUSER *tiptr, int cmd, struct netbuf *nbuf, char *ifname); + +/* + * Boot properties related to iscsi boot: + */ +#define IB_BOOT_MACLEN 6 +#define IB_IP_BUFLEN 16 + +/* + * iSCSI boot initiator's properties + */ +typedef struct _ib_ini_prop { + uchar_t *ini_name; + uchar_t *ini_chap_name; + uchar_t *ini_chap_sec; +} ib_ini_prop_t; + +/* + * iSCSI boot nic's properties + */ +typedef struct _ib_nic_prop { + uchar_t nic_mac[6]; + uchar_t nic_vlan[2]; + union { + struct in_addr u_in4; + struct in6_addr u_in6; + } nic_ip_u; + union { + struct in_addr u_in4; + struct in6_addr u_in6; + } nic_gw_u; + union { + struct in_addr u_in4; + struct in6_addr u_in6; + } nic_dhcp_u; + int sin_family; + uchar_t sub_mask_prefix; + +} ib_nic_prop_t; + +/* + * iSCSI boot target's properties + */ +typedef struct _ib_tgt_prop { + union { + struct in_addr u_in4; + struct in6_addr u_in6; + }tgt_ip_u; + int sin_family; + uint32_t tgt_port; + uchar_t tgt_boot_lun[8]; + uchar_t *tgt_name; + uchar_t *tgt_chap_name; + uchar_t *tgt_chap_sec; + int lun_online; +} ib_tgt_prop_t; + +/* + * iSCSI boot properties + */ +typedef struct _ib_boot_prop { + ib_ini_prop_t boot_init; + ib_nic_prop_t boot_nic; + ib_tgt_prop_t boot_tgt; +} ib_boot_prop_t; + +void +ld_ib_prop(); + #ifdef __cplusplus } #endif diff --git a/usr/src/uts/common/sys/scsi/adapters/iscsi_if.h b/usr/src/uts/common/sys/scsi/adapters/iscsi_if.h index f56e67fd76..dd5f72a5c0 100644 --- a/usr/src/uts/common/sys/scsi/adapters/iscsi_if.h +++ b/usr/src/uts/common/sys/scsi/adapters/iscsi_if.h @@ -145,6 +145,8 @@ extern "C" { #define ISCSI_GET_CONFIG_SESSIONS (ISCSI_IOCTL | 44) #define ISCSI_SET_CONFIG_SESSIONS (ISCSI_IOCTL | 45) #define ISCSI_INIT_NODE_NAME_SET (ISCSI_IOCTL | 46) +#define ISCSI_IS_ACTIVE (ISCSI_IOCTL | 47) +#define ISCSI_BOOTPROP_GET (ISCSI_IOCTL | 48) #define ISCSI_DB_DUMP (ISCSI_IOCTL | 100) /* DBG */ /* @@ -180,7 +182,13 @@ typedef enum iSCSIDiscoveryMethod { iSCSIDiscoveryMethodStatic = 1, iSCSIDiscoveryMethodSLP = 2, iSCSIDiscoveryMethodISNS = 4, - iSCSIDiscoveryMethodSendTargets = 8 + iSCSIDiscoveryMethodSendTargets = 8, + /* + * Since there is no specification about boot discovery method, + * we should leave a value gap in case of other discovery + * methods added. + */ + iSCSIDiscoveryMethodBoot = 128 } iSCSIDiscoveryMethod_t; #define ISCSI_ALL_DISCOVERY_METHODS (iSCSIDiscoveryMethodStatic | \ iSCSIDiscoveryMethodSLP | \ @@ -246,6 +254,8 @@ typedef struct entry { int e_insize; int e_port; int e_tpgt; + /* e_boot should be true if a boot session is created. */ + boolean_t e_boot; } entry_t; /* @@ -601,6 +611,17 @@ typedef struct iscsi_config_sess { iscsi_ipaddr_t ics_bindings[1]; } iscsi_config_sess_t; +/* iscsi booting prop */ +typedef struct _iSCSIBootProperties { + node_name_t ini_name; + node_name_t tgt_name; + iscsi_auth_props_t auth; + iscsi_chap_props_t ini_chap; + iscsi_chap_props_t tgt_chap; + int iscsiboot; + boolean_t hba_mpxio_enabled; +} iscsi_boot_property_t; + #define ISCSI_SESSION_CONFIG_SIZE(SIZE) \ (sizeof (iscsi_config_sess_t) + \ ((SIZE - 1) * sizeof (iscsi_ipaddr_t))) diff --git a/usr/src/uts/i86pc/Makefile.files b/usr/src/uts/i86pc/Makefile.files index 8c91132364..d656d8db55 100644 --- a/usr/src/uts/i86pc/Makefile.files +++ b/usr/src/uts/i86pc/Makefile.files @@ -60,6 +60,7 @@ CORE_OBJS += \ hrtimers.o \ htable.o \ i86_mmu.o \ + ibft.o \ instr_size.o \ intr.o \ kboot_mmu.o \ diff --git a/usr/src/uts/i86pc/os/ibft.c b/usr/src/uts/i86pc/os/ibft.c new file mode 100644 index 0000000000..141b837988 --- /dev/null +++ b/usr/src/uts/i86pc/os/ibft.c @@ -0,0 +1,757 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * This is the place to implement ld_ib_props() + * For x86 it is to load iBFT and costruct the global ib props + */ + +#include <sys/types.h> +#include <sys/cmn_err.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <sys/mman.h> +#include <sys/bootprops.h> +#include <sys/kmem.h> +#include <sys/psm.h> + +#ifndef NULL +#define NULL 0 +#endif + +typedef enum ibft_structure_type { + Reserved = 0, + Control = 1, + Initiator = 2, + Nic = 3, + Target = 4, + Extensions = 5, + Type_End +}ibft_struct_type; + +typedef enum _chap_type { + NO_CHAP = 0, + CHAP = 1, + Mutual_CHAP = 2, + TYPE_UNKNOWN +}chap_type; + +typedef struct ibft_entry { + int af; + int e_port; + char target_name[224]; + char target_addr[INET6_ADDRSTRLEN]; +}ibft_entry_t; + +typedef struct iSCSI_ibft_tbl_hdr { + char Signature[4]; + int Length; + char Revision; + char Checksum; + char oem_id[6]; + char oem_table_id[8]; + char Reserved[24]; +}iscsi_ibft_tbl_hdr_t; + +typedef struct iSCSI_ibft_hdr { + char Structure_id; + char Version; + ushort_t Length; + char Index; + char Flags; +}iscsi_ibft_hdr_t; + +typedef struct iSCSI_ibft_control { + iscsi_ibft_hdr_t header; + ushort_t Extensions; + ushort_t Initiator_offset; + ushort_t Nic0_offset; + ushort_t Target0_offset; + ushort_t Nic1_offset; + ushort_t Target1_offset; +}iscsi_ibft_ctl_t; + +typedef struct iSCSI_ibft_initiator { + iscsi_ibft_hdr_t header; + uchar_t iSNS_Server[16]; + uchar_t SLP_Server[16]; + uchar_t Pri_Radius_Server[16]; + uchar_t Sec_Radius_Server[16]; + ushort_t ini_name_len; + ushort_t ini_name_offset; +}iscsi_ibft_initiator_t; + +typedef struct iSCSI_ibft_nic { + iscsi_ibft_hdr_t header; + uchar_t ip_addr[16]; + char Subnet_Mask_Prefix; + char Origin; + uchar_t Gateway[16]; + uchar_t Primary_dns[16]; + uchar_t Secondary_dns[16]; + uchar_t dhcp[16]; + ushort_t vlan; + char mac[6]; + ushort_t pci_BDF; + ushort_t Hostname_len; + ushort_t Hostname_offset; +}iscsi_ibft_nic_t; + +typedef struct iSCSI_ibft_target { + iscsi_ibft_hdr_t header; + uchar_t ip_addr[16]; + ushort_t port; + uchar_t boot_lun[8]; + uchar_t chap_type; + uchar_t nic_association; + ushort_t target_name_len; + ushort_t target_name_offset; + ushort_t chap_name_len; + ushort_t chap_name_offset; + ushort_t chap_secret_len; + ushort_t chap_secret_offset; + ushort_t rev_chap_name_len; + ushort_t rev_chap_name_offset; + ushort_t rev_chap_secret_len; + ushort_t rev_chap_secret_offset; +}iscsi_ibft_tgt_t; + +#define ISCSI_IBFT_LOWER_ADDR 0x80000 /* 512K */ +#define ISCSI_IBFT_HIGHER_ADDR 0x100000 /* 1024K */ +#define ISCSI_IBFT_SIGNATRUE "iBFT" +#define ISCSI_IBFT_SIGNATURE_LEN 4 +#define ISCSI_IBFT_TBL_BUF_LEN 1024 +#define ISCSI_IBFT_ALIGNED 16 +#define ISCSI_IBFT_CTL_OFFSET 48 + +#define IBFT_BLOCK_VALID_YES 0x01 /* bit 0 */ +#define IBFT_FIRMWARE_BOOT_SELECTED 0x02 /* bit 1 */ +#define IBFT_USE_RADIUS_CHAP 0x04 /* bit 2 */ +#define IBFT_USE_GLOBLE 0x04 /* NIC structure */ +#define IBFT_USE_RADIUS_RHCAP 0x08 /* bit 3 */ + +/* + * Currently, we only support initiator offset, NIC0 offset, Target0 offset, + * NIC1 offset and Target1 offset. So the length is 5. If we want to support + * extensions, we should change this number. + */ +#define IBFT_OFFSET_BUF_LEN 5 +#define IPV4_OFFSET 12 + +#define IBFT_INVALID_MSG "Invalid iBFT table 0x%x" + +typedef enum ibft_status { + IBFT_STATUS_OK = 0, + /* General error */ + IBFT_STATUS_ERR, + /* Bad header */ + IBFT_STATUS_BADHDR, + /* Bad control ID */ + IBFT_STATUS_BADCID, + /* Bad ip addr */ + IBFT_STATUS_BADIP, + /* Bad af */ + IBFT_STATUS_BADAF, + /* Bad chap name */ + IBFT_STATUS_BADCHAPNAME, + /* Bad chap secret */ + IBFT_STATUS_BADCHAPSEC, + /* Bad checksum */ + IBFT_STATUS_BADCHECKSUM, + /* Low memory */ + IBFT_STATUS_LOWMEM, + /* No table */ + IBFT_STATUS_NOTABLE +} ibft_status_t; + +extern void *memset(void *s, int c, size_t n); +extern int memcmp(const void *s1, const void *s2, size_t n); +extern void bcopy(const void *s1, void *s2, size_t n); +extern void iscsi_print_boot_property(); + +ib_boot_prop_t boot_property; /* static allocated */ +extern ib_boot_prop_t *iscsiboot_prop; /* to be filled */ + +static ibft_status_t iscsi_parse_ibft_control(iscsi_ibft_ctl_t *ctl_hdr, + ushort_t *iscsi_offset_buf); + +static ibft_status_t iscsi_parse_ibft_initiator(char *begin_of_ibft, + iscsi_ibft_initiator_t *initiator); + +static ibft_status_t iscsi_parse_ibft_NIC(iscsi_ibft_nic_t *nicp); + +static ibft_status_t iscsi_parse_ibft_target(char *begin_of_ibft, + iscsi_ibft_tgt_t *tgtp); + + +/* + * Return value: + * Success: IBFT_STATUS_OK + * Fail: IBFT_STATUS_BADCHECKSUM + */ +static ibft_status_t +iscsi_ibft_hdr_checksum(iscsi_ibft_tbl_hdr_t *tbl_hdr) +{ + uchar_t checksum = 0; + uchar_t *start = NULL; + int length = 0; + int i = 0; + + if (tbl_hdr == NULL) { + return (IBFT_STATUS_BADHDR); + } + + length = tbl_hdr->Length; + start = (uchar_t *)tbl_hdr; + + for (i = 0; i < length; i++) { + checksum = checksum + start[i]; + } + + if (!checksum) + return (IBFT_STATUS_OK); + else + return (IBFT_STATUS_BADCHECKSUM); +} + +/* + * Now we only support one control structure in the IBFT. + * So there is no Control ID here. + */ +static ibft_status_t +iscsi_parse_ibft_structure(char *begin_of_ibft, char *buf) +{ + iscsi_ibft_hdr_t *hdr = NULL; + ibft_status_t ret = IBFT_STATUS_OK; + + if (buf == NULL) { + return (IBFT_STATUS_ERR); + } + + hdr = (iscsi_ibft_hdr_t *)buf; + switch (hdr->Structure_id) { + case Initiator: + ret = iscsi_parse_ibft_initiator( + begin_of_ibft, + (iscsi_ibft_initiator_t *)buf); + break; + case Nic: + ret = iscsi_parse_ibft_NIC( + (iscsi_ibft_nic_t *)buf); + break; + case Target: + ret = iscsi_parse_ibft_target( + begin_of_ibft, + (iscsi_ibft_tgt_t *)buf); + break; + default: + ret = IBFT_STATUS_BADHDR; + break; + } + + return (ret); +} + +/* + * Parse the iBFT table + * return IBFT_STATUS_OK upon sucess + */ +static ibft_status_t +iscsi_parse_ibft_tbl(iscsi_ibft_tbl_hdr_t *tbl_hdr) +{ + char *outbuf = NULL; + int i = 0; + ibft_status_t ret = IBFT_STATUS_OK; + ushort_t iscsi_offset_buf[IBFT_OFFSET_BUF_LEN] = {0}; + + if (tbl_hdr == NULL) { + return (IBFT_STATUS_ERR); + } + + if (iscsi_ibft_hdr_checksum(tbl_hdr) != IBFT_STATUS_OK) { + return (IBFT_STATUS_BADCHECKSUM); + } + + outbuf = (char *)tbl_hdr; + + ret = iscsi_parse_ibft_control( + (iscsi_ibft_ctl_t *)&outbuf[ISCSI_IBFT_CTL_OFFSET], + iscsi_offset_buf); + + if (ret == IBFT_STATUS_OK) { + ret = IBFT_STATUS_ERR; + for (i = 0; i < IBFT_OFFSET_BUF_LEN; i++) { + if (iscsi_offset_buf[i] != 0) { + ret = iscsi_parse_ibft_structure( + (char *)tbl_hdr, + (char *)tbl_hdr + + iscsi_offset_buf[i]); + if (ret != IBFT_STATUS_OK) { + return (ret); + } + } + } + } + + return (ret); +} + +static ibft_status_t +iscsi_parse_ibft_control(iscsi_ibft_ctl_t *ctl_hdr, + ushort_t *iscsi_offset_buf) +{ + int i = 0; + ushort_t *offsetp = NULL; + + if (ctl_hdr == NULL) { + return (IBFT_STATUS_BADHDR); + } + + if (ctl_hdr->header.Structure_id != Control) { + return (IBFT_STATUS_BADCID); + } + + /* + * Copy the offsets to offset buffer. + */ + for (offsetp = &(ctl_hdr->Initiator_offset); i < IBFT_OFFSET_BUF_LEN; + offsetp++) { + iscsi_offset_buf[i++] = *offsetp; + } + + return (IBFT_STATUS_OK); +} + +/* + * We only copy the "Firmare Boot Selseted" and valid initiator + * to the boot property. + */ +static ibft_status_t +iscsi_parse_ibft_initiator(char *begin_of_ibft, + iscsi_ibft_initiator_t *initiator) +{ + if (initiator == NULL) { + return (IBFT_STATUS_ERR); + } + + if (initiator->header.Structure_id != Initiator) { + return (IBFT_STATUS_BADHDR); + } + + if ((initiator->header.Flags & IBFT_FIRMWARE_BOOT_SELECTED) && + (initiator->header.Flags & IBFT_BLOCK_VALID_YES)) { + /* + * If the initiator name exists, we will copy it to our own + * property structure + */ + if (initiator->ini_name_len != 0) { + boot_property.boot_init.ini_name = + (uchar_t *)kmem_zalloc( + initiator->ini_name_len + 1, KM_SLEEP); + (void) snprintf( + (char *)boot_property.boot_init.ini_name, + initiator->ini_name_len + 1, "%s", + begin_of_ibft + initiator->ini_name_offset); + } + } + return (IBFT_STATUS_OK); +} + +static ibft_status_t +iscsi_parse_ipaddr(uchar_t *source, char *dest, int *af) +{ + int i = 0; + + if (source == NULL) { + return (IBFT_STATUS_ERR); + } + + if (source[0] == 0x00 && source[1] == 0x00 && + source[2] == 0x00 && source[3] == 0x00 && + source[4] == 0x00 && source[5] == 0x00 && + source[6] == 0x00 && source[7] == 0x00 && + source[8] == 0x00 && source[9] == 0x00 && + (source[10] == 0xff) && (source[11] == 0xff)) { + /* + * IPv4 address + */ + if (dest != NULL) { + (void) sprintf(dest, "%d.%d.%d.%d", + source[12], source[13], source[14], source[15]); + } + if (af != NULL) { + *af = AF_INET; + } + } else { + if (dest != NULL) { + for (i = 0; i < 14; i = i + 2) { + (void) sprintf(dest, "%02x%02x:", source[i], + source[i+1]); + dest = dest + 5; + } + (void) sprintf(dest, "%02x%02x", + source[i], source[i+1]); + } + if (af != NULL) { + *af = AF_INET6; + } + } + + return (IBFT_STATUS_OK); +} + +/* + * Copy the ip address from ibft. If IPv4 is used, we should copy + * the address from 12th byte. + */ +static ibft_status_t +iscsi_copy_ibft_ipaddr(uchar_t *source, void *dest, int *af) +{ + ibft_status_t ret = IBFT_STATUS_OK; + int sin_family = 0; + + if (source == NULL || dest == NULL) { + return (IBFT_STATUS_ERR); + } + ret = iscsi_parse_ipaddr(source, NULL, &sin_family); + if (ret != 0) { + return (IBFT_STATUS_BADIP); + } + + if (sin_family == AF_INET) { + bcopy(source+IPV4_OFFSET, dest, sizeof (struct in_addr)); + } else if (sin_family == AF_INET6) { + bcopy(source, dest, sizeof (struct in6_addr)); + } else { + return (IBFT_STATUS_BADAF); + } + + if (af != NULL) { + *af = sin_family; + } + return (IBFT_STATUS_OK); +} + +/* + * Maybe there are multiply NICs are available. We only copy the + * "Firmare Boot Selseted" and valid one to the boot property. + */ +static ibft_status_t +iscsi_parse_ibft_NIC(iscsi_ibft_nic_t *nicp) +{ + ibft_status_t ret = IBFT_STATUS_OK; + int af = 0; + + if (nicp == NULL) { + return (IBFT_STATUS_ERR); + } + + if (nicp->header.Structure_id != Nic) { + return (IBFT_STATUS_ERR); + } + + if ((nicp->header.Flags & IBFT_FIRMWARE_BOOT_SELECTED) && + (nicp->header.Flags & IBFT_BLOCK_VALID_YES)) { + ret = iscsi_copy_ibft_ipaddr(nicp->ip_addr, + &boot_property.boot_nic.nic_ip_u, &af); + if (ret != IBFT_STATUS_OK) { + return (ret); + } + + boot_property.boot_nic.sin_family = af; + + ret = iscsi_copy_ibft_ipaddr(nicp->Gateway, + &boot_property.boot_nic.nic_gw_u, NULL); + if (ret != IBFT_STATUS_OK) { + return (ret); + } + + ret = iscsi_copy_ibft_ipaddr(nicp->dhcp, + &boot_property.boot_nic.nic_dhcp_u, NULL); + if (ret != IBFT_STATUS_OK) { + return (ret); + } + + bcopy(nicp->mac, boot_property.boot_nic.nic_mac, 6); + boot_property.boot_nic.sub_mask_prefix = + nicp->Subnet_Mask_Prefix; + } + + return (IBFT_STATUS_OK); +} + +/* + * Maybe there are multiply targets are available. We only copy the + * "Firmare Boot Selseted" and valid one to the boot property. + */ +static ibft_status_t +iscsi_parse_ibft_target(char *begin_of_ibft, iscsi_ibft_tgt_t *tgtp) +{ + char *tmp = NULL; + int af = 0; + ibft_status_t ret = IBFT_STATUS_OK; + + if (tgtp == NULL) { + return (IBFT_STATUS_ERR); + } + + if (tgtp->header.Structure_id != Target) { + return (IBFT_STATUS_BADHDR); + } + + if ((tgtp->header.Flags & IBFT_FIRMWARE_BOOT_SELECTED) && + (tgtp->header.Flags & IBFT_BLOCK_VALID_YES)) { + /* + * Get Target Address + */ + ret = iscsi_copy_ibft_ipaddr(tgtp->ip_addr, + &boot_property.boot_tgt.tgt_ip_u, &af); + if (ret != IBFT_STATUS_OK) { + return (ret); + } + boot_property.boot_tgt.sin_family = af; + /* + * Get Target Name + */ + if (tgtp->target_name_len != 0) { + boot_property.boot_tgt.tgt_name = + (uchar_t *)kmem_zalloc(tgtp->target_name_len + 1, + KM_SLEEP); + (void) snprintf( + (char *)boot_property.boot_tgt.tgt_name, + tgtp->target_name_len + 1, "%s", + begin_of_ibft + tgtp->target_name_offset); + } else { + boot_property.boot_tgt.tgt_name = NULL; + } + + /* Get Dest Port */ + boot_property.boot_tgt.tgt_port = tgtp->port; + + boot_property.boot_tgt.lun_online = 0; + + /* + * Get CHAP secret and name. + */ + if (tgtp->chap_type != NO_CHAP) { + if (tgtp->chap_name_len != 0) { + boot_property.boot_init.ini_chap_name = + (uchar_t *)kmem_zalloc( + tgtp->chap_name_len + 1, + KM_SLEEP); + tmp = (char *) + boot_property.boot_init.ini_chap_name; + (void) snprintf( + tmp, + tgtp->chap_name_len + 1, "%s", + begin_of_ibft + tgtp->chap_name_offset); + } else { + /* + * Just set NULL, initiator is able to deal + * with this + */ + boot_property.boot_init.ini_chap_name = NULL; + } + + if (tgtp->chap_secret_len != 0) { + boot_property.boot_init.ini_chap_sec = + (uchar_t *)kmem_zalloc( + tgtp->chap_secret_len + 1, + KM_SLEEP); + bcopy(begin_of_ibft + + tgtp->chap_secret_offset, + boot_property.boot_init.ini_chap_sec, + tgtp->chap_secret_len); + } else { + boot_property.boot_init.ini_chap_sec = NULL; + return (IBFT_STATUS_ERR); + } + + if (tgtp->chap_type == Mutual_CHAP) { + if (tgtp->rev_chap_name_len != 0) { + boot_property.boot_tgt.tgt_chap_name = + (uchar_t *)kmem_zalloc( + tgtp->chap_name_len + 1, + KM_SLEEP); +#define TGT_CHAP_NAME boot_property.boot_tgt.tgt_chap_name + tmp = (char *)TGT_CHAP_NAME; +#undef TGT_CHAP_NAME + (void) snprintf( + tmp, + tgtp->chap_name_len + 1, + "%s", + begin_of_ibft + + tgtp->rev_chap_name_offset); + } else { + /* + * Just set NULL, initiator is able + * to deal with this + */ + boot_property.boot_tgt.tgt_chap_name = + NULL; + } + + if (tgtp->rev_chap_secret_len != 0) { + boot_property.boot_tgt.tgt_chap_sec = + (uchar_t *)kmem_zalloc( + tgtp->rev_chap_secret_len + 1, + KM_SLEEP); + tmp = (char *) + boot_property.boot_tgt.tgt_chap_sec; + (void) snprintf( + tmp, + tgtp->rev_chap_secret_len + 1, + "%s", + begin_of_ibft + + tgtp->chap_secret_offset); + } else { + boot_property.boot_tgt.tgt_chap_sec = + NULL; + return (IBFT_STATUS_BADCHAPSEC); + } + } + } else { + boot_property.boot_init.ini_chap_name = NULL; + boot_property.boot_init.ini_chap_sec = NULL; + } + + /* + * Get Boot LUN + */ + (void) bcopy(tgtp->boot_lun, + boot_property.boot_tgt.tgt_boot_lun, 8); + } + + return (IBFT_STATUS_OK); +} + +/* + * This function is used for scanning iBFT from the physical memory. + * Return Value: + * IBFT_STATUS_OK + * IBFT_STATUS_ERR + */ +static ibft_status_t +iscsi_scan_ibft_tbl(char *ibft_tbl_buf) +{ + int start; + void *va = NULL; + int *len = NULL; + ibft_status_t ret = IBFT_STATUS_NOTABLE; + + for (start = ISCSI_IBFT_LOWER_ADDR; start < ISCSI_IBFT_HIGHER_ADDR; + start = start + ISCSI_IBFT_ALIGNED) { + va = (void *)psm_map((paddr_t)(start&0xffffffff), + ISCSI_IBFT_SIGNATURE_LEN, + PROT_READ); + + if (va == NULL) { + continue; + } + if (memcmp(va, ISCSI_IBFT_SIGNATRUE, + ISCSI_IBFT_SIGNATURE_LEN) == 0) { + ret = IBFT_STATUS_ERR; + /* Acquire table length */ + len = (int *)psm_map( + (paddr_t)((start+\ + ISCSI_IBFT_SIGNATURE_LEN)&0xffffffff), + ISCSI_IBFT_SIGNATURE_LEN, PROT_READ); + if (len == NULL) { + psm_unmap((caddr_t)va, + ISCSI_IBFT_SIGNATURE_LEN); + continue; + } + if (ISCSI_IBFT_LOWER_ADDR + *len < + ISCSI_IBFT_HIGHER_ADDR - 1) { + psm_unmap(va, + ISCSI_IBFT_SIGNATURE_LEN); + va = psm_map((paddr_t)(start&0xffffffff), + *len, + PROT_READ); + if (va != NULL) { + /* + * Copy data to our own buffer + */ + bcopy(va, ibft_tbl_buf, *len); + ret = IBFT_STATUS_OK; + } + psm_unmap((caddr_t)va, *len); + psm_unmap((caddr_t)len, + ISCSI_IBFT_SIGNATURE_LEN); + break; + } else { + psm_unmap((caddr_t)va, + ISCSI_IBFT_SIGNATURE_LEN); + psm_unmap((caddr_t)len, + ISCSI_IBFT_SIGNATURE_LEN); + } + } else { + psm_unmap((caddr_t)va, ISCSI_IBFT_SIGNATURE_LEN); + } + } + + return (ret); +} + +/* + * Scan the ibft table and store the iSCSI boot properties + * If there is a valid table then set the iscsiboot_prop + * iBF should be off if the host is not intended + * to be booted from iSCSI disk + */ +void +ld_ib_prop() +{ + ibft_status_t ret = IBFT_STATUS_OK; + char *ibft_tbl_buf; + + ibft_tbl_buf = (char *)kmem_zalloc(ISCSI_IBFT_TBL_BUF_LEN, + KM_SLEEP); + + if (!ibft_tbl_buf) { + /* Unlikely to happen */ + cmn_err(CE_NOTE, IBFT_INVALID_MSG, + IBFT_STATUS_LOWMEM); + return; + } + + (void) memset(&boot_property, 0, sizeof (boot_property)); + if ((ret = iscsi_scan_ibft_tbl(ibft_tbl_buf)) == + IBFT_STATUS_OK) { + ret = iscsi_parse_ibft_tbl( + (iscsi_ibft_tbl_hdr_t *)ibft_tbl_buf); + if (ret == IBFT_STATUS_OK) { + iscsiboot_prop = &boot_property; + iscsi_print_boot_property(); + } else { + cmn_err(CE_NOTE, IBFT_INVALID_MSG, ret); + } + } else if (ret != IBFT_STATUS_NOTABLE) { + cmn_err(CE_NOTE, IBFT_INVALID_MSG, ret); + } + + kmem_free(ibft_tbl_buf, ISCSI_IBFT_TBL_BUF_LEN); +} diff --git a/usr/src/uts/i86xpv/Makefile.files b/usr/src/uts/i86xpv/Makefile.files index 1e7d3a354a..546549e603 100644 --- a/usr/src/uts/i86xpv/Makefile.files +++ b/usr/src/uts/i86xpv/Makefile.files @@ -61,6 +61,7 @@ CORE_OBJS += \ hrtimers.o \ htable.o \ i86_mmu.o \ + ibft.o \ instr_size.o \ intr.o \ kboot_mmu.o \ diff --git a/usr/src/uts/sparc/os/iscsi_boot.c b/usr/src/uts/sparc/os/iscsi_boot.c new file mode 100644 index 0000000000..4a928c6a0e --- /dev/null +++ b/usr/src/uts/sparc/os/iscsi_boot.c @@ -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 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#include <sys/bootprops.h> + +extern ib_boot_prop_t *iscsiboot_prop; + +void +ld_ib_prop() { + /* + * For sparc, do nothing now + */ +} diff --git a/usr/src/uts/sun4u/Makefile.files b/usr/src/uts/sun4u/Makefile.files index 1d7d978a4f..2e05b61c1e 100644 --- a/usr/src/uts/sun4u/Makefile.files +++ b/usr/src/uts/sun4u/Makefile.files @@ -44,6 +44,7 @@ CORE_OBJS += forthdebug.o CORE_OBJS += hardclk.o CORE_OBJS += hat_sfmmu.o CORE_OBJS += hat_kdi.o +CORE_OBJS += iscsi_boot.o CORE_OBJS += mach_copy.o CORE_OBJS += mach_kpm.o CORE_OBJS += mach_mp_startup.o diff --git a/usr/src/uts/sun4v/Makefile.files b/usr/src/uts/sun4v/Makefile.files index c37e69a272..49bfb35ef3 100644 --- a/usr/src/uts/sun4v/Makefile.files +++ b/usr/src/uts/sun4v/Makefile.files @@ -42,6 +42,7 @@ CORE_OBJS += hardclk.o CORE_OBJS += hat_sfmmu.o CORE_OBJS += hat_kdi.o CORE_OBJS += hsvc.o +CORE_OBJS += iscsi_boot.o CORE_OBJS += lpad.o CORE_OBJS += mach_cpu_states.o CORE_OBJS += mach_ddi_impl.o |