diff options
author | Jack Meng <Jack.Meng@Sun.COM> | 2008-11-22 07:33:57 +0800 |
---|---|---|
committer | Jack Meng <Jack.Meng@Sun.COM> | 2008-11-22 07:33:57 +0800 |
commit | 6cefaae1e90a413ba01560575bb3998e1a3df40e (patch) | |
tree | c749b753f1ee011412736e0a48381d6e5bb58a34 | |
parent | 7bc22e45a20f905cdd06bb98c98a5c8be7fd25c0 (diff) | |
download | illumos-joyent-6cefaae1e90a413ba01560575bb3998e1a3df40e.tar.gz |
PSARC 2008/427 iSCSI Boot
PSARC 2008/640 iSCSI With DHCP
6701045 iSCSI boot on x86
6713364 iscsi needs to support PSARC 2008/337 scsi-self-identifying
6422549 delay nl7c_init() call until after the root is mounted
6751246 dhcp release the lease before sync is committed on iSCSI disk
6763891 device name of the same lun is different by different discovery mode, non MPxIO
6768382 Add dependency on netowrk/physical in local-fs service
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 |