summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/cmd-inet/sbin/dhcpagent/agent.c40
-rw-r--r--usr/src/cmd/iscsiadm/iscsiadm_main.c211
-rw-r--r--usr/src/cmd/iscsiadm/sun_ima.c149
-rw-r--r--usr/src/cmd/iscsiadm/sun_ima.h9
-rw-r--r--usr/src/cmd/svc/milestone/local-fs.xml14
-rw-r--r--usr/src/pkgdefs/SUNWiscsir/postinstall5
-rw-r--r--usr/src/uts/common/Makefile.files3
-rw-r--r--usr/src/uts/common/Makefile.rules7
-rw-r--r--usr/src/uts/common/fs/sockfs/socksubr.c15
-rw-r--r--usr/src/uts/common/fs/vfs.c34
-rw-r--r--usr/src/uts/common/inet/kifconf/kifconf.c238
-rw-r--r--usr/src/uts/common/io/scsi/adapters/iscsi/iscsi.c172
-rw-r--r--usr/src/uts/common/io/scsi/adapters/iscsi/iscsi.h12
-rw-r--r--usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_conn.c46
-rw-r--r--usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_ioctl.c32
-rw-r--r--usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_lun.c48
-rw-r--r--usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_net.c250
-rw-r--r--usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_sess.c237
-rw-r--r--usr/src/uts/common/io/scsi/adapters/iscsi/iscsid.c867
-rw-r--r--usr/src/uts/common/io/scsi/adapters/iscsi/nvfile.c19
-rw-r--r--usr/src/uts/common/io/strplumb.c45
-rw-r--r--usr/src/uts/common/os/iscsiboot_prop.c269
-rw-r--r--usr/src/uts/common/os/main.c10
-rw-r--r--usr/src/uts/common/os/space.c10
-rw-r--r--usr/src/uts/common/sys/bootprops.h84
-rw-r--r--usr/src/uts/common/sys/scsi/adapters/iscsi_if.h23
-rw-r--r--usr/src/uts/i86pc/Makefile.files1
-rw-r--r--usr/src/uts/i86pc/os/ibft.c757
-rw-r--r--usr/src/uts/i86xpv/Makefile.files1
-rw-r--r--usr/src/uts/sparc/os/iscsi_boot.c35
-rw-r--r--usr/src/uts/sun4u/Makefile.files1
-rw-r--r--usr/src/uts/sun4v/Makefile.files1
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