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