changeset 10822:2a6b5dc1374c

PSARC 2008/427 iSCSI Boot PSARC 2009/480 Add bootpath into Solaris Sparc BootArchive for iSCSI boot 6714847 iSCSI boot,sparc part
author Jack Meng <Jack.Meng@Sun.COM>
date Wed, 21 Oct 2009 11:28:57 +0800
parents 77dbb4cf3365
children 8e74955a6eca
files usr/src/uts/common/fs/vfs.c usr/src/uts/common/fs/zfs/spa.c usr/src/uts/common/io/idm/idm_so.c usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_login.c usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_net.c usr/src/uts/common/io/strplumb.c usr/src/uts/common/os/devcfg.c usr/src/uts/common/os/iscsiboot_prop.c usr/src/uts/common/os/swapgeneric.c usr/src/uts/common/sys/bootprops.h usr/src/uts/common/sys/idm/idm.h usr/src/uts/i86pc/os/ibft.c usr/src/uts/sparc/os/iscsi_boot.c
diffstat 13 files changed, 849 insertions(+), 53 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/fs/vfs.c	Wed Oct 21 10:55:51 2009 +0800
+++ b/usr/src/uts/common/fs/vfs.c	Wed Oct 21 11:28:57 2009 +0800
@@ -4491,7 +4491,6 @@
 #endif /* __x86 */
 
 extern ib_boot_prop_t *iscsiboot_prop;
-extern void iscsi_boot_prop_free();
 
 int
 rootconf()
@@ -4544,8 +4543,13 @@
 		return (EINVAL);
 	}
 
-	if (netboot || iscsiboot_prop)
+	if (netboot || iscsiboot_prop) {
 		ret = strplumb();
+		if (ret != 0) {
+			cmn_err(CE_WARN, "Cannot plumb network device %d", ret);
+			return (EFAULT);
+		}
+	}
 
 	if ((ret == 0) && iscsiboot_prop) {
 		ret = modload("drv", "iscsi");
--- a/usr/src/uts/common/fs/zfs/spa.c	Wed Oct 21 10:55:51 2009 +0800
+++ b/usr/src/uts/common/fs/zfs/spa.c	Wed Oct 21 11:28:57 2009 +0800
@@ -64,6 +64,7 @@
 
 #ifdef	_KERNEL
 #include <sys/zone.h>
+#include <sys/bootprops.h>
 #endif	/* _KERNEL */
 
 #include "zfs_prop.h"
@@ -2420,7 +2421,17 @@
 	/*
 	 * Read the label from the boot device and generate a configuration.
 	 */
-	if ((config = spa_generate_rootconf(devpath, devid, &guid)) == NULL) {
+	config = spa_generate_rootconf(devpath, devid, &guid);
+#if defined(_OBP) && defined(_KERNEL)
+	if (config == NULL) {
+		if (strstr(devpath, "/iscsi/ssd") != NULL) {
+			/* iscsi boot */
+			get_iscsi_bootpath_phy(devpath);
+			config = spa_generate_rootconf(devpath, devid, &guid);
+		}
+	}
+#endif
+	if (config == NULL) {
 		cmn_err(CE_NOTE, "Can not read the pool label from '%s'",
 		    devpath);
 		return (EIO);
--- a/usr/src/uts/common/io/idm/idm_so.c	Wed Oct 21 10:55:51 2009 +0800
+++ b/usr/src/uts/common/io/idm/idm_so.c	Wed Oct 21 11:28:57 2009 +0800
@@ -68,7 +68,8 @@
 static void idm_so_conn_destroy_common(idm_conn_t *ic);
 static void idm_so_conn_connect_common(idm_conn_t *ic);
 
-static void idm_set_ini_preconnect_options(idm_so_conn_t *sc);
+static void idm_set_ini_preconnect_options(idm_so_conn_t *sc,
+    boolean_t boot_conn);
 static void idm_set_ini_postconnect_options(idm_so_conn_t *sc);
 static void idm_set_tgt_connect_options(ksocket_t so);
 static idm_status_t idm_i_so_tx(idm_pdu_t *pdu);
@@ -685,7 +686,7 @@
 }
 
 static void
-idm_set_ini_preconnect_options(idm_so_conn_t *sc)
+idm_set_ini_preconnect_options(idm_so_conn_t *sc, boolean_t boot_conn)
 {
 	int	conn_abort = 10000;
 	int	conn_notify = 2000;
@@ -695,11 +696,14 @@
 	(void) ksocket_setsockopt(sc->ic_so, IPPROTO_TCP,
 	    TCP_CONN_NOTIFY_THRESHOLD, (char *)&conn_notify, sizeof (int),
 	    CRED());
-	(void) ksocket_setsockopt(sc->ic_so, IPPROTO_TCP,
-	    TCP_CONN_ABORT_THRESHOLD, (char *)&conn_abort, sizeof (int),
-	    CRED());
-	(void) ksocket_setsockopt(sc->ic_so, IPPROTO_TCP, TCP_ABORT_THRESHOLD,
-	    (char *)&abort, sizeof (int), CRED());
+	if (boot_conn == B_FALSE) {
+		(void) ksocket_setsockopt(sc->ic_so, IPPROTO_TCP,
+		    TCP_CONN_ABORT_THRESHOLD, (char *)&conn_abort, sizeof (int),
+		    CRED());
+		(void) ksocket_setsockopt(sc->ic_so, IPPROTO_TCP,
+		    TCP_ABORT_THRESHOLD,
+		    (char *)&abort, sizeof (int), CRED());
+	}
 }
 
 static void
@@ -866,7 +870,7 @@
 
 	so_conn = ic->ic_transport_private;
 	/* Set up socket options */
-	idm_set_ini_preconnect_options(so_conn);
+	idm_set_ini_preconnect_options(so_conn, cr->cr_boot_conn);
 
 	return (IDM_STATUS_SUCCESS);
 }
--- a/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_login.c	Wed Oct 21 10:55:51 2009 +0800
+++ b/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_login.c	Wed Oct 21 11:28:57 2009 +0800
@@ -2150,6 +2150,11 @@
 	    sizeof (cr.cr_ini_dst_addr));
 	bcopy(&icp->conn_bound_addr, &cr.cr_bound_addr,
 	    sizeof (cr.cr_bound_addr));
+	if (isp->sess_boot == B_TRUE) {
+		cr.cr_boot_conn = B_TRUE;
+	} else {
+		cr.cr_boot_conn = B_FALSE;
+	}
 
 	/*
 	 * Allocate IDM connection context
--- a/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_net.c	Wed Oct 21 10:55:51 2009 +0800
+++ b/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_net.c	Wed Oct 21 11:28:57 2009 +0800
@@ -910,8 +910,16 @@
 		/* 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)) {
+			int	ret	= 0;
+			if (defgateway.s_addr == 0) {
+				/* No default gate way specified */
+				ret = kdlifconfig(tiptr, AF_INET, &myaddr,
+				    &subnet, &braddr, NULL, ifname);
+			} else {
+				ret = kdlifconfig(tiptr, AF_INET, &myaddr,
+				    &subnet, &braddr, &defgateway, ifname);
+			}
+			if (ret != 0) {
 				cmn_err(CE_WARN, "Failed to configure"
 				    " iSCSI boot nic");
 				(void) t_kclose(tiptr, 0);
--- a/usr/src/uts/common/io/strplumb.c	Wed Oct 21 10:55:51 2009 +0800
+++ b/usr/src/uts/common/io/strplumb.c	Wed Oct 21 11:28:57 2009 +0800
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -426,8 +426,6 @@
 	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)
 {
@@ -659,15 +657,32 @@
 strplumb_get_netdev_path(void)
 {
 #ifdef	_OBP
-	char fstype[OBP_MAXPROPNAME];
+	char		fstype[OBP_MAXPROPNAME];
+	static char	iscsi_network_path[BO_MAXOBJNAME]	= {0};
+	int		proplen;
+	char		*p	= NULL;
 
 	if (bop_getprop("fstype", fstype) == -1)
 		return (NULL);
 
 	if (strncmp(fstype, "nfs", 3) == 0)
 		return (prom_bootpath());
-	else
-		return (NULL);
+	else if (iscsiboot_prop != NULL) {
+		proplen =  BOP_GETPROPLEN(bootops,
+		    BP_ISCSI_NETWORK_BOOTPATH);
+		if (proplen > 0) {
+			if (BOP_GETPROP(bootops,
+			    BP_ISCSI_NETWORK_BOOTPATH,
+			    iscsi_network_path) > 0) {
+				p = strchr(iscsi_network_path, ':');
+				if (p != NULL) {
+					*p = '\0';
+				}
+				return (iscsi_network_path);
+			}
+		}
+	}
+	return (NULL);
 #else
 
 	char *macstr, *devpath = NULL;
--- a/usr/src/uts/common/os/devcfg.c	Wed Oct 21 10:55:51 2009 +0800
+++ b/usr/src/uts/common/os/devcfg.c	Wed Oct 21 11:28:57 2009 +0800
@@ -55,6 +55,8 @@
 #include <sys/fs/sdev_impl.h>
 #include <sys/sunldi.h>
 #include <sys/sunldi_impl.h>
+#include <sys/bootprops.h>
+
 
 #if defined(__i386) || defined(__amd64)
 #if !defined(__xpv)
@@ -3607,6 +3609,38 @@
 	return (info.dip);
 }
 
+extern ib_boot_prop_t *iscsiboot_prop;
+static void
+i_ddi_parse_iscsi_name(char *name, char **nodename, char **addrname,
+    char **minorname)
+{
+	char *cp, *colon;
+	static char nulladdrname[] = "";
+
+	/* default values */
+	if (nodename)
+		*nodename = name;
+	if (addrname)
+		*addrname = nulladdrname;
+	if (minorname)
+		*minorname = NULL;
+
+	cp = colon = name;
+	while (*cp != '\0') {
+		if (addrname && *cp == '@') {
+			*addrname = cp + 1;
+			*cp = '\0';
+		} else if (minorname && *cp == ':') {
+			*minorname = cp + 1;
+			colon = cp;
+		}
+		++cp;
+	}
+	if (colon != name) {
+		*colon = '\0';
+	}
+}
+
 /*
  * Parse for name, addr, and minor names. Some args may be NULL.
  */
@@ -3779,8 +3813,13 @@
 
 		/* Get component and chop off minorname */
 		(void) pn_getcomponent(&pn, component);
-		i_ddi_parse_name(component, NULL, NULL, &minorname);
-
+		if ((iscsiboot_prop != NULL) &&
+		    (strcmp((DEVI(parent)->devi_node_name), "iscsi") == 0)) {
+			i_ddi_parse_iscsi_name(component, NULL, NULL,
+			    &minorname);
+		} else {
+			i_ddi_parse_name(component, NULL, NULL, &minorname);
+		}
 		if (prev_minor == NULL) {
 			(void) snprintf(config_name, MAXNAMELEN, "%s",
 			    component);
--- a/usr/src/uts/common/os/iscsiboot_prop.c	Wed Oct 21 10:55:51 2009 +0800
+++ b/usr/src/uts/common/os/iscsiboot_prop.c	Wed Oct 21 11:28:57 2009 +0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -50,6 +50,8 @@
 #define	NULL	0
 #endif
 
+static int replace_sp_c(unsigned char *dst, unsigned char *source, size_t n);
+
 static void
 iscsi_bootprop_print(int level, char *str)
 {
@@ -191,18 +193,21 @@
 	}
 
 	if (init->ini_name != NULL) {
-		kmem_free(init->ini_name, strlen((char *)init->ini_name) + 1);
+		kmem_free(init->ini_name, init->ini_name_len);
 		init->ini_name = NULL;
+		init->ini_name_len = 0;
 	}
 	if (init->ini_chap_name != NULL) {
 		kmem_free(init->ini_chap_name,
-		    strlen((char *)init->ini_chap_name) + 1);
+		    init->ini_chap_name_len);
 		init->ini_chap_name = NULL;
+		init->ini_chap_name_len = 0;
 	}
 	if (init->ini_chap_sec != NULL) {
 		kmem_free(init->ini_chap_sec,
-		    strlen((char *)init->ini_chap_sec) + 1);
+		    init->ini_chap_sec_len);
 		init->ini_chap_sec = NULL;
+		init->ini_chap_sec_len = 0;
 	}
 }
 
@@ -215,18 +220,27 @@
 
 	if (target->tgt_name != NULL) {
 		kmem_free(target->tgt_name,
-		    strlen((char *)target->tgt_name) + 1);
+		    target->tgt_name_len);
 		target->tgt_name = NULL;
+		target->tgt_name_len = 0;
 	}
 	if (target->tgt_chap_name != NULL) {
 		kmem_free(target->tgt_chap_name,
-		    strlen((char *)target->tgt_chap_name) + 1);
+		    target->tgt_chap_name_len);
 		target->tgt_chap_name = NULL;
+		target->tgt_chap_name_len = 0;
 	}
 	if (target->tgt_chap_sec != NULL) {
 		kmem_free(target->tgt_chap_sec,
-		    strlen((char *)target->tgt_chap_sec) + 1);
+		    target->tgt_chap_sec_len);
 		target->tgt_chap_sec = NULL;
+		target->tgt_chap_sec_len = 0;
+	}
+	if (target->tgt_boot_par != NULL) {
+		kmem_free(target->tgt_boot_par,
+		    target->tgt_boot_par_len);
+		target->tgt_boot_par = NULL;
+		target->tgt_boot_par_len = 0;
 	}
 }
 
@@ -267,3 +281,111 @@
 		(void) sprintf(buf, "%02x%02x", p[i], p[i+1]);
 	}
 }
+
+#ifndef	BO_MAXOBJNAME
+#define	BO_MAXOBJNAME	256
+#endif
+
+#ifndef ISCSI_BOOT_ISID
+#define	ISCSI_BOOT_ISID	"0000"
+#endif
+
+/*
+ * Generate the 'ssd' bootpath of an iSCSI boot device
+ * The caller is responsible to alloc the buf with BO_MAXOBJNAME length
+ */
+void
+get_iscsi_bootpath_vhci(char *bootpath)
+{
+	uint16_t	*lun_num;
+
+	if (iscsiboot_prop == NULL)
+		ld_ib_prop();
+	if (iscsiboot_prop == NULL)
+		return;
+	lun_num = (uint16_t *)(&iscsiboot_prop->boot_tgt.tgt_boot_lun[0]);
+	(void) snprintf(bootpath, BO_MAXOBJNAME, "/iscsi/ssd@%s%s%04X,%d:%s",
+	    ISCSI_BOOT_ISID, iscsiboot_prop->boot_tgt.tgt_name,
+	    iscsiboot_prop->boot_tgt.tgt_tpgt, lun_num[0],
+	    iscsiboot_prop->boot_tgt.tgt_boot_par);
+}
+
+/*
+ * Generate the 'disk' bootpath of an iSCSI boot device
+ * The caller is responsible to alloc the buf with BO_MAXOBJNAME length
+ */
+void
+get_iscsi_bootpath_phy(char *bootpath)
+{
+	uint16_t	lun_num		= 0;
+	uchar_t		replaced_name[BO_MAXOBJNAME] = {0};
+
+	if (iscsiboot_prop == NULL)
+		ld_ib_prop();
+	if (iscsiboot_prop == NULL)
+		return;
+	if (replace_sp_c(replaced_name, iscsiboot_prop->boot_tgt.tgt_name,
+	    iscsiboot_prop->boot_tgt.tgt_name_len) != 0) {
+		return;
+	}
+	lun_num = *(uint16_t *)(&iscsiboot_prop->boot_tgt.tgt_boot_lun[0]);
+	(void) snprintf(bootpath, BO_MAXOBJNAME, "/iscsi/disk@%s%s%04X,%d:%s",
+	    ISCSI_BOOT_ISID, replaced_name, iscsiboot_prop->boot_tgt.tgt_tpgt,
+	    lun_num, iscsiboot_prop->boot_tgt.tgt_boot_par);
+}
+
+static int replace_sp_c(unsigned char *dst, unsigned char *source, size_t n)
+{
+	unsigned char	*p	= NULL;
+	int		i	= 0;
+
+	if (source == NULL || dst == NULL || n == 0) {
+		return (-1);
+	}
+
+	for (p = source; *p != '\0'; p++, i++) {
+		if (i >= n) {
+			return (-1);
+		}
+		switch (*p) {
+		case ':':
+			*dst = '%';
+			dst++;
+			*dst = '3';
+			dst++;
+			*dst = 'A';
+			dst++;
+			break;
+		case ' ':
+			*dst = '%';
+			dst++;
+			*dst = '2';
+			dst++;
+			*dst = '0';
+			dst++;
+			break;
+		case '@':
+			*dst = '%';
+			dst++;
+			*dst = '4';
+			dst++;
+			*dst = '0';
+			dst++;
+			break;
+		case '/':
+			*dst = '%';
+			dst++;
+			*dst = '2';
+			dst++;
+			*dst = 'F';
+			dst++;
+			break;
+		default:
+			*dst = *p;
+			dst++;
+		}
+	}
+	*dst = '\0';
+
+	return (0);
+}
--- a/usr/src/uts/common/os/swapgeneric.c	Wed Oct 21 10:55:51 2009 +0800
+++ b/usr/src/uts/common/os/swapgeneric.c	Wed Oct 21 11:28:57 2009 +0800
@@ -20,7 +20,7 @@
  */
 /* ONC_PLUS EXTRACT START */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 /* ONC_PLUS EXTRACT END */
@@ -70,7 +70,7 @@
 #include <sys/hwconf.h>
 #include <sys/dc_ki.h>
 #include <sys/promif.h>
-
+#include <sys/bootprops.h>
 
 /*
  * Local routines
@@ -83,7 +83,7 @@
 static int load_boot_platform_modules(char *drv);
 static dev_info_t *path_to_devinfo(char *path);
 static boolean_t netboot_over_ib(char *bootpath);
-
+static boolean_t netboot_over_iscsi(void);
 
 /*
  * Module linkage information for the kernel.
@@ -114,16 +114,17 @@
 	return (mod_info(&modlinkage, modinfop));
 }
 
+extern ib_boot_prop_t *iscsiboot_prop;
 /*
  * Configure root file system.
  */
 int
 rootconf(void)
 {
-	int error;
-	struct vfssw *vsw;
+	int		error;
+	struct vfssw	*vsw;
 	extern void pm_init(void);
-
+	int ret = -1;
 	BMDPRINTF(("rootconf: fstype %s\n", rootfs.bo_fstype));
 	BMDPRINTF(("rootconf: name %s\n", rootfs.bo_name));
 	BMDPRINTF(("rootconf: flags 0x%x\n", rootfs.bo_flags));
@@ -186,10 +187,34 @@
 	 */
 	pm_init();
 
-	if (netboot) {
-		if ((error = strplumb()) != 0) {
-			cmn_err(CE_CONT, "Cannot plumb network device\n");
-			return (error);
+	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) {
+			cmn_err(CE_WARN, "Cannot plumb network device %d", ret);
+			return (EFAULT);
+		}
+	}
+
+	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);
+			}
 		}
 	}
 
@@ -263,7 +288,13 @@
 {
 	dev_t	d;
 
-	if ((d = ddi_pathname_to_dev_t(rootfs.bo_name)) == NODEV)
+	d = ddi_pathname_to_dev_t(rootfs.bo_name);
+	if ((d == NODEV) && (iscsiboot_prop != NULL)) {
+		/* Give it another try with the 'disk' path */
+		get_iscsi_bootpath_phy(rootfs.bo_name);
+		d = ddi_pathname_to_dev_t(rootfs.bo_name);
+	}
+	if (d == NODEV)
 		cmn_err(CE_CONT, "Cannot assemble drivers for root %s\n",
 		    rootfs.bo_name);
 	return (d);
@@ -378,7 +409,6 @@
 
 loop:
 	(void) getphysdev("root", rootfs.bo_name, BO_MAXOBJNAME);
-
 	/*
 	 * Given a physical pathname, load the correct set of driver
 	 * modules into memory, including all possible parents.
@@ -508,7 +538,40 @@
 			goto out;
 		}
 	}
-
+	if (netboot_over_iscsi() == B_TRUE) {
+		/* iscsi boot */
+		if ((err = modloadonly("dacf", "net_dacf")) < 0) {
+			cmn_err(CE_CONT, "Cannot load dacf/net_dacf\n");
+			goto out;
+		}
+		if ((err = modload("misc", "tlimod")) < 0) {
+			cmn_err(CE_CONT, "Cannot load misc/tlimod\n");
+			goto out;
+		}
+		if ((err = modload("mac", "mac_ether")) < 0) {
+			cmn_err(CE_CONT, "Cannot load mac/mac_ether\n");
+			goto out;
+		}
+		if ((err = modloadonly("drv", "iscsi")) < 0) {
+			cmn_err(CE_CONT, "Cannot load drv/iscsi\n");
+			goto out;
+		}
+		if ((err = modloadonly("drv", "ssd")) < 0) {
+			cmn_err(CE_CONT, "Cannot load drv/ssd\n");
+			goto out;
+		}
+		if ((err = modloadonly("drv", "sd")) < 0) {
+			cmn_err(CE_CONT, "Cannot load drv/sd\n");
+			goto out;
+		}
+		if ((err = modload("misc", "strplumb")) < 0) {
+			cmn_err(CE_CONT, "Cannot load misc/strplumb\n");
+			goto out;
+		}
+		if ((err = strplumb_load()) < 0) {
+			goto out;
+		}
+	}
 	/*
 	 * Preload modules needed for booting as a cluster.
 	 */
@@ -540,6 +603,11 @@
 			    "boot-path", bootpath) == -1)
 				return (-1);
 		}
+		if (memcmp(bootpath, BP_ISCSI_DISK,
+		    strlen(BP_ISCSI_DISK)) == 0) {
+			/* iscsi boot */
+			get_iscsi_bootpath_vhci(bootpath);
+		}
 	}
 	return (0);
 }
@@ -837,15 +905,43 @@
 	int		pathcopy_len;
 	int		rval;
 	char		*p;
+	int		proplen;
+	char		iscsi_network_path[BO_MAXOBJNAME];
 
 	if (bootpath == NULL || *bootpath == 0)
 		return (-1);
 
 	BMDPRINTF(("load_bootpath_drivers: %s\n", bootpath));
-
-	pathcopy = i_ddi_strdup(bootpath, KM_SLEEP);
-	pathcopy_len = strlen(pathcopy) + 1;
-
+#ifdef _OBP
+	if (netboot_over_iscsi()) {
+		/* iscsi boot */
+		if (root_is_ramdisk) {
+			modloadonly("drv", "ramdisk");
+		}
+		proplen = BOP_GETPROPLEN(bootops, BP_ISCSI_NETWORK_BOOTPATH);
+		if (proplen > 0) {
+			if (BOP_GETPROP(bootops, BP_ISCSI_NETWORK_BOOTPATH,
+			    iscsi_network_path) > 0) {
+				p = strchr(iscsi_network_path, ':');
+				if (p != NULL) {
+					*p = '\0';
+				}
+				pathcopy = i_ddi_strdup(iscsi_network_path,
+				    KM_SLEEP);
+				pathcopy_len = strlen(pathcopy) + 1;
+			} else {
+				return (-1);
+			}
+		} else {
+			return (-1);
+		}
+	} else {
+#endif
+		pathcopy = i_ddi_strdup(bootpath, KM_SLEEP);
+		pathcopy_len = strlen(pathcopy) + 1;
+#ifdef _OBP
+	}
+#endif
 	dip = path_to_devinfo(pathcopy);
 
 #if defined(__i386) || defined(__amd64)
@@ -1079,6 +1175,9 @@
 	char		devicetype[OBP_MAXDRVNAME];
 
 	/* Is this IB node ? */
+	if (node == OBP_BADNODE || node == OBP_NONODE) {
+		return (B_FALSE);
+	}
 	len = prom_getproplen(node, OBP_DEVICETYPE);
 	if (len <= 1 || len >= OBP_MAXDRVNAME)
 		return (B_FALSE);
@@ -1097,3 +1196,22 @@
 	}
 	return (ret);
 }
+
+static boolean_t
+netboot_over_iscsi(void)
+{
+	int proplen;
+	boolean_t	ret = B_FALSE;
+	char	bootpath[OBP_MAXPATHLEN];
+
+	proplen = BOP_GETPROPLEN(bootops, BP_BOOTPATH);
+	if (proplen > 0) {
+		if (BOP_GETPROP(bootops, BP_BOOTPATH, bootpath) > 0) {
+			if (memcmp(bootpath, BP_ISCSI_DISK,
+			    strlen(BP_ISCSI_DISK)) == 0) {
+				ret = B_TRUE;
+			}
+		}
+	}
+	return (ret);
+}
--- a/usr/src/uts/common/sys/bootprops.h	Wed Oct 21 10:55:51 2009 +0800
+++ b/usr/src/uts/common/sys/bootprops.h	Wed Oct 21 11:28:57 2009 +0800
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -46,7 +46,24 @@
 #define	BP_SERVER_PATH			"server-path"
 #define	BP_SERVER_ROOTOPTS		"server-rootopts"
 #define	BP_BOOTP_RESPONSE		"bootp-response"
+
+/*
+ * Boot properties related to iscsiboot:
+ */
 #define	BP_NETWORK_INTERFACE		"network-interface"
+#define	BP_ISCSI_TARGET_NAME		"iscsi-target-name"
+#define	BP_ISCSI_TARGET_IP		"iscsi-target-ip"
+#define	BP_ISCSI_INITIATOR_ID		"iscsi-initiator-id"
+#define	BP_ISCSI_PORT			"iscsi-port"
+#define	BP_ISCSI_TPGT			"iscsi-tpgt"
+#define	BP_ISCSI_LUN			"iscsi-lun"
+#define	BP_ISCSI_PAR			"iscsi-partition"
+#define	BP_ISCSI_NETWORK_BOOTPATH	"iscsi-network-bootpath"
+#define	BP_ISCSI_DISK			"/iscsi-hba/disk"
+#define	BP_BOOTPATH			"bootpath"
+#define	BP_CHAP_USER			"chap-user"
+#define	BP_CHAP_PASSWORD		"chap-password"
+#define	BP_LOCAL_MAC_ADDRESS		"local-mac-address"
 
 /*
  * kifconf prototypes
@@ -70,8 +87,11 @@
  */
 typedef struct _ib_ini_prop {
 	uchar_t		*ini_name;
+	size_t		ini_name_len;
 	uchar_t		*ini_chap_name;
+	size_t		ini_chap_name_len;
 	uchar_t		*ini_chap_sec;
+	size_t		ini_chap_sec_len;
 } ib_ini_prop_t;
 
 /*
@@ -109,9 +129,15 @@
 	uint32_t	tgt_port;
 	uchar_t		tgt_boot_lun[8];
 	uchar_t		*tgt_name;
+	size_t		tgt_name_len;
 	uchar_t		*tgt_chap_name;
+	size_t		tgt_chap_name_len;
 	uchar_t		*tgt_chap_sec;
+	size_t		tgt_chap_sec_len;
 	int		lun_online;
+	uchar_t		*tgt_boot_par;
+	size_t		tgt_boot_par_len;
+	uint16_t	tgt_tpgt;
 } ib_tgt_prop_t;
 
 /*
@@ -126,6 +152,15 @@
 void
 ld_ib_prop();
 
+void
+iscsi_boot_prop_free();
+
+void
+get_iscsi_bootpath_vhci(char *bootpath);
+
+void
+get_iscsi_bootpath_phy(char *bootpath);
+
 #ifdef	__cplusplus
 }
 #endif
--- a/usr/src/uts/common/sys/idm/idm.h	Wed Oct 21 10:55:51 2009 +0800
+++ b/usr/src/uts/common/sys/idm/idm.h	Wed Oct 21 11:28:57 2009 +0800
@@ -181,6 +181,7 @@
 	idm_sockaddr_t		cr_ini_dst_addr;
 	ldi_ident_t		cr_li;
 	idm_conn_ops_t		icr_conn_ops;
+	boolean_t		cr_boot_conn;
 } idm_conn_req_t;
 
 typedef struct {
--- a/usr/src/uts/i86pc/os/ibft.c	Wed Oct 21 10:55:51 2009 +0800
+++ b/usr/src/uts/i86pc/os/ibft.c	Wed Oct 21 11:28:57 2009 +0800
@@ -374,6 +374,8 @@
 			boot_property.boot_init.ini_name =
 			    (uchar_t *)kmem_zalloc(
 			    initiator->ini_name_len + 1, KM_SLEEP);
+			boot_property.boot_init.ini_name_len =
+			    initiator->ini_name_len + 1;
 			(void) snprintf(
 			    (char *)boot_property.boot_init.ini_name,
 			    initiator->ini_name_len + 1, "%s",
@@ -543,6 +545,8 @@
 			boot_property.boot_tgt.tgt_name =
 			    (uchar_t *)kmem_zalloc(tgtp->target_name_len + 1,
 			    KM_SLEEP);
+			boot_property.boot_tgt.tgt_name_len =
+			    tgtp->target_name_len + 1;
 			(void) snprintf(
 			    (char *)boot_property.boot_tgt.tgt_name,
 			    tgtp->target_name_len + 1, "%s",
@@ -565,6 +569,8 @@
 				    (uchar_t *)kmem_zalloc(
 				    tgtp->chap_name_len + 1,
 				    KM_SLEEP);
+				boot_property.boot_init.ini_chap_name_len =
+				    tgtp->chap_name_len + 1;
 				tmp = (char *)
 				    boot_property.boot_init.ini_chap_name;
 				(void) snprintf(
@@ -584,6 +590,8 @@
 				    (uchar_t *)kmem_zalloc(
 				    tgtp->chap_secret_len + 1,
 				    KM_SLEEP);
+				boot_property.boot_init.ini_chap_sec_len =
+				    tgtp->chap_secret_len + 1;
 				bcopy(begin_of_ibft +
 				    tgtp->chap_secret_offset,
 				    boot_property.boot_init.ini_chap_sec,
@@ -597,14 +605,16 @@
 				if (tgtp->rev_chap_name_len != 0) {
 					boot_property.boot_tgt.tgt_chap_name =
 					    (uchar_t *)kmem_zalloc(
-					    tgtp->chap_name_len + 1,
+					    tgtp->rev_chap_name_len + 1,
 					    KM_SLEEP);
+					boot_property.boot_tgt.tgt_chap_name_len
+					    = tgtp->rev_chap_name_len + 1;
 #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,
+					    tgtp->rev_chap_name_len + 1,
 					    "%s",
 					    begin_of_ibft +
 					    tgtp->rev_chap_name_offset);
@@ -622,6 +632,8 @@
 					    (uchar_t *)kmem_zalloc(
 					    tgtp->rev_chap_secret_len + 1,
 					    KM_SLEEP);
+					boot_property.boot_tgt.tgt_chap_sec_len
+					    = tgtp->rev_chap_secret_len + 1;
 					tmp = (char *)
 					    boot_property.boot_tgt.tgt_chap_sec;
 					(void) snprintf(
--- a/usr/src/uts/sparc/os/iscsi_boot.c	Wed Oct 21 10:55:51 2009 +0800
+++ b/usr/src/uts/sparc/os/iscsi_boot.c	Wed Oct 21 11:28:57 2009 +0800
@@ -19,17 +19,439 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #include <sys/bootprops.h>
+#include <sys/bootconf.h>
+#include <sys/modctl.h>
+#include <sys/mman.h>
+#include <sys/kmem.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/types.h>
+#include <sys/obpdefs.h>
+#include <sys/promif.h>
+#include <sys/iscsi_protocol.h>
 
+#define	ISCSI_OBP_MAX_CHAP_USER_LEN	16
+#define	ISCSI_OBP_MIN_CHAP_LEN		12
+#define	ISCSI_OBP_MAX_CHAP_LEN		16
+
+#define	OBP_GET_KEY_STATUS_OK		0
+#define	OBP_GET_KEY_STATUS_NOT_EXIST	-3
+
+ib_boot_prop_t boot_property;
 extern ib_boot_prop_t *iscsiboot_prop;
+static int inet_aton(char *ipstr, uchar_t *ip);
+static boolean_t parse_lun_num(uchar_t *str_num, uchar_t *hex_num);
+static void generate_iscsi_initiator_id(void);
 
+static int
+isdigit(int ch)
+{
+	return (ch >= '0' && ch <= '9');
+}
+
+static boolean_t
+iscsiboot_tgt_prop_read(void)
+{
+	int		proplen;
+	boolean_t	set		= B_FALSE;
+	char		iscsi_target_ip[INET6_ADDRSTRLEN];
+	uchar_t		iscsi_target_name[ISCSI_MAX_NAME_LEN];
+	uchar_t		iscsi_par[8];
+	char		chap_user[ISCSI_OBP_MAX_CHAP_USER_LEN]	= {0};
+	char		chap_password[ISCSI_OBP_MAX_CHAP_LEN]	= {0};
+	uchar_t		iscsi_port[8];
+	uchar_t		iscsi_lun[8];
+	uchar_t		iscsi_tpgt[8];
+	long		iscsi_tpgtl;
+	long		port;
+	int		ret		= 0;
+	int		status		= 0;
+	int		chap_user_len	= 0;
+	int		chap_pwd_len	= 0;
+
+	/* Get iscsi target IP address */
+	proplen = BOP_GETPROPLEN(bootops, BP_ISCSI_TARGET_IP);
+	if (proplen > 0) {
+		if (BOP_GETPROP(bootops, BP_ISCSI_TARGET_IP,
+		    iscsi_target_ip) > 0) {
+			if (inet_aton(iscsi_target_ip,
+			    (uchar_t *)&boot_property.boot_tgt.tgt_ip_u) ==
+			    0) {
+				boot_property.boot_tgt.sin_family = AF_INET;
+				set = B_TRUE;
+			}
+		}
+	}
+	if (set != B_TRUE) {
+		return (B_FALSE);
+	}
+
+	/* Get iscsi target port number */
+	set = B_FALSE;
+	proplen = BOP_GETPROPLEN(bootops, BP_ISCSI_PORT);
+	if (proplen > 0) {
+		if (BOP_GETPROP(bootops, BP_ISCSI_PORT,
+		    iscsi_port) > 0) {
+			if (ddi_strtol((const char *)iscsi_port, NULL,
+			    10, &port) == 0) {
+				boot_property.boot_tgt.tgt_port =
+				    (unsigned int)port;
+				set = B_TRUE;
+			}
+		}
+	}
+	if (set != B_TRUE) {
+		boot_property.boot_tgt.tgt_port = 3260;
+	}
+
+	/* Get iscsi target LUN number */
+	set = B_FALSE;
+	proplen = BOP_GETPROPLEN(bootops, BP_ISCSI_LUN);
+	if (proplen > 0) {
+		if (BOP_GETPROP(bootops, BP_ISCSI_LUN,
+		    iscsi_lun) > 0) {
+			if (parse_lun_num(iscsi_lun,
+			    (uchar_t *)
+			    (&boot_property.boot_tgt.tgt_boot_lun[0]))
+			    == B_TRUE) {
+				set = B_TRUE;
+			}
+		}
+	}
+	if (set != B_TRUE) {
+		bzero((void *)boot_property.boot_tgt.tgt_boot_lun, 8);
+	}
+
+	/* Get iscsi target portal group tag */
+	set = B_FALSE;
+	proplen = BOP_GETPROPLEN(bootops, BP_ISCSI_TPGT);
+	if (proplen > 0) {
+		if (BOP_GETPROP(bootops, BP_ISCSI_TPGT,
+		    iscsi_tpgt) > 0) {
+			if (ddi_strtol((const char *)iscsi_tpgt, NULL, 10,
+			    &iscsi_tpgtl) == 0) {
+				boot_property.boot_tgt.tgt_tpgt =
+				    (uint16_t)iscsi_tpgtl;
+				set = B_TRUE;
+			}
+		}
+	}
+	if (set != B_TRUE) {
+		boot_property.boot_tgt.tgt_tpgt = 1;
+	}
+
+	/* Get iscsi target node name */
+	set = B_FALSE;
+	boot_property.boot_tgt.tgt_name = NULL;
+	proplen = BOP_GETPROPLEN(bootops, BP_ISCSI_TARGET_NAME);
+	if (proplen > 0) {
+		if (BOP_GETPROP(bootops, BP_ISCSI_TARGET_NAME,
+		    iscsi_target_name) > 0) {
+			boot_property.boot_tgt.tgt_name =
+			    (uchar_t *)kmem_zalloc(proplen + 1, KM_SLEEP);
+			boot_property.boot_tgt.tgt_name_len = proplen + 1;
+			(void) snprintf((char *)boot_property.boot_tgt.tgt_name,
+			    proplen + 1, "%s", iscsi_target_name);
+			set = B_TRUE;
+		}
+	}
+	if (set != B_TRUE) {
+		if (boot_property.boot_tgt.tgt_name != NULL) {
+			kmem_free(boot_property.boot_tgt.tgt_name,
+			    boot_property.boot_tgt.tgt_name_len);
+			boot_property.boot_tgt.tgt_name = NULL;
+			boot_property.boot_tgt.tgt_name_len = 0;
+		}
+		return (B_FALSE);
+	}
+
+	/* Get iscsi target boot partition */
+	set = B_FALSE;
+	boot_property.boot_tgt.tgt_boot_par = NULL;
+	boot_property.boot_tgt.tgt_boot_par_len = 0;
+	proplen = BOP_GETPROPLEN(bootops, BP_ISCSI_PAR);
+	if (proplen > 0) {
+		if (BOP_GETPROP(bootops, BP_ISCSI_PAR, iscsi_par) > 0) {
+			boot_property.boot_tgt.tgt_boot_par =
+			    (uchar_t *)kmem_zalloc(proplen + 1, KM_SLEEP);
+			boot_property.boot_tgt.tgt_boot_par_len = proplen + 1;
+			(void) snprintf(
+			    (char *)boot_property.boot_tgt.tgt_boot_par,
+			    proplen + 1, "%s", iscsi_par);
+			set = B_TRUE;
+		}
+	}
+	if (set != B_TRUE) {
+		boot_property.boot_tgt.tgt_boot_par =
+		    (uchar_t *)kmem_zalloc(2, KM_SLEEP);
+		boot_property.boot_tgt.tgt_boot_par_len = 2;
+		boot_property.boot_tgt.tgt_boot_par[0] = 'a';
+	}
+
+	/* Get CHAP name and secret */
+	ret = prom_get_security_key(BP_CHAP_USER, chap_user,
+	    ISCSI_OBP_MAX_CHAP_USER_LEN, &chap_user_len, &status);
+	if (ret != 0) {
+		return (B_FALSE);
+	}
+	if (status == OBP_GET_KEY_STATUS_NOT_EXIST) {
+		/* No chap name */
+		return (B_TRUE);
+	}
+	if (status != OBP_GET_KEY_STATUS_OK ||
+	    chap_user_len > ISCSI_OBP_MAX_CHAP_USER_LEN ||
+	    chap_user_len <= 0) {
+		return (B_FALSE);
+	}
+
+	ret = prom_get_security_key(BP_CHAP_PASSWORD, chap_password,
+	    ISCSI_OBP_MAX_CHAP_LEN, &chap_pwd_len, &status);
+	if (ret != 0) {
+		return (B_FALSE);
+	}
+
+	if (status == OBP_GET_KEY_STATUS_NOT_EXIST) {
+		/* No chap secret */
+		return (B_TRUE);
+	}
+	if (status != OBP_GET_KEY_STATUS_OK ||
+	    chap_pwd_len > ISCSI_OBP_MAX_CHAP_LEN ||
+	    chap_pwd_len <= 0) {
+		return (B_FALSE);
+	}
+
+	boot_property.boot_init.ini_chap_name =
+	    (uchar_t *)kmem_zalloc(chap_user_len + 1, KM_SLEEP);
+	boot_property.boot_init.ini_chap_name_len = chap_user_len + 1;
+	(void) memcpy(boot_property.boot_init.ini_chap_name, chap_user,
+	    chap_user_len);
+
+	boot_property.boot_init.ini_chap_sec =
+	    (uchar_t *)kmem_zalloc(chap_pwd_len + 1, KM_SLEEP);
+	boot_property.boot_init.ini_chap_sec_len = chap_pwd_len + 1;
+	(void) memcpy(boot_property.boot_init.ini_chap_sec, chap_password,
+	    chap_pwd_len);
+
+	return (B_TRUE);
+}
+
+static boolean_t
+iscsiboot_init_prop_read(void)
+{
+	int	proplen;
+	uchar_t	iscsi_initiator_id[ISCSI_MAX_NAME_LEN];
+	boolean_t	set = B_FALSE;
+
+	/* Get initiator node name */
+	proplen = BOP_GETPROPLEN(bootops, BP_ISCSI_INITIATOR_ID);
+	if (proplen > 0) {
+		if (BOP_GETPROP(bootops, BP_ISCSI_INITIATOR_ID,
+		    iscsi_initiator_id) > 0) {
+			boot_property.boot_init.ini_name =
+			    (uchar_t *)kmem_zalloc(proplen + 1, KM_SLEEP);
+			boot_property.boot_init.ini_name_len = proplen + 1;
+			(void) snprintf(
+			    (char *)boot_property.boot_init.ini_name,
+			    proplen + 1, "%s", iscsi_initiator_id);
+			set = B_TRUE;
+		}
+	}
+	if (set != B_TRUE) {
+		generate_iscsi_initiator_id();
+	}
+	return (B_TRUE);
+}
+
+static boolean_t
+iscsiboot_nic_prop_read(void)
+{
+	int	proplen;
+	char	host_ip[INET6_ADDRSTRLEN];
+	char	router_ip[INET6_ADDRSTRLEN];
+	char	subnet_mask[INET6_ADDRSTRLEN];
+	uchar_t	iscsi_network_path[MAXPATHLEN];
+	char	host_mac[6];
+	uchar_t	hex_netmask[4];
+	pnode_t	nodeid;
+	boolean_t	set = B_FALSE;
+
+	/* Get host IP address */
+	proplen = BOP_GETPROPLEN(bootops, BP_HOST_IP);
+	if (proplen > 0) {
+		if (BOP_GETPROP(bootops, BP_HOST_IP,
+		    host_ip) > 0) {
+			if (inet_aton(host_ip,
+			    (uchar_t *)&boot_property.boot_nic.nic_ip_u) ==
+			    0) {
+				boot_property.boot_nic.sin_family = AF_INET;
+				set = B_TRUE;
+			}
+		}
+	}
+	if (set != B_TRUE) {
+		return (B_FALSE);
+	}
+
+	/* Get router IP address */
+	proplen = BOP_GETPROPLEN(bootops, BP_ROUTER_IP);
+	if (proplen > 0) {
+		if (BOP_GETPROP(bootops, BP_ROUTER_IP,
+		    router_ip) > 0) {
+			(void) inet_aton(router_ip,
+			    (uchar_t *)&boot_property.boot_nic.nic_gw_u);
+		}
+	}
+
+	/* Get host netmask */
+	set = B_FALSE;
+	proplen = BOP_GETPROPLEN(bootops, BP_SUBNET_MASK);
+	if (proplen > 0) {
+		if (BOP_GETPROP(bootops, BP_SUBNET_MASK,
+		    subnet_mask) > 0) {
+			if (inet_aton(subnet_mask, hex_netmask) == 0) {
+				int i = 0;
+				uint32_t tmp = *((uint32_t *)hex_netmask);
+				while (tmp) {
+					i ++;
+					tmp = tmp << 1;
+				}
+				boot_property.boot_nic.sub_mask_prefix = i;
+				set = B_TRUE;
+			}
+		}
+	}
+	if (set != B_TRUE) {
+		boot_property.boot_nic.sub_mask_prefix = 24;
+	}
+
+	/* Get iscsi boot NIC path in OBP */
+	set = B_FALSE;
+	proplen = BOP_GETPROPLEN(bootops, BP_ISCSI_NETWORK_BOOTPATH);
+	if (proplen > 0) {
+		if (BOP_GETPROP(bootops, BP_ISCSI_NETWORK_BOOTPATH,
+		    iscsi_network_path) > 0) {
+			nodeid = prom_finddevice((char *)iscsi_network_path);
+			proplen = prom_getproplen(nodeid, BP_LOCAL_MAC_ADDRESS);
+			if (proplen > 0) {
+				if (prom_getprop(nodeid, BP_LOCAL_MAC_ADDRESS,
+				    host_mac) > 0) {
+					(void) memcpy(
+					    boot_property.boot_nic.nic_mac,
+					    host_mac, 6);
+					set = B_TRUE;
+				}
+			}
+		}
+	}
+	if (set != B_TRUE) {
+		return (B_FALSE);
+	}
+
+	return (B_TRUE);
+}
+
+/*
+ * Manully construct iscsiboot_prop table based on
+ * OBP '/chosen' properties related to iscsi boot
+ */
 void
-ld_ib_prop() {
-	/*
-	 * For sparc, do nothing now
-	 */
+ld_ib_prop()
+{
+	if (iscsiboot_prop != NULL)
+		return;
+
+	if ((iscsiboot_tgt_prop_read() == B_TRUE) &&
+	    (iscsiboot_init_prop_read() == B_TRUE) &&
+	    (iscsiboot_nic_prop_read() == B_TRUE)) {
+		iscsiboot_prop = &boot_property;
+	} else {
+		iscsi_boot_prop_free();
+	}
+}
+
+static boolean_t
+parse_lun_num(uchar_t *str_num, uchar_t *hex_num)
+{
+	char *p, *buf;
+	uint16_t *conv_num = (uint16_t *)hex_num;
+	long tmp;
+	int i = 0;
+
+	if ((str_num == NULL) || (hex_num == NULL)) {
+		return (B_FALSE);
+	}
+	bzero((void *)hex_num, 8);
+	buf = (char *)str_num;
+
+	for (i = 0; i < 4; i++) {
+		p = NULL;
+		p = strchr((const char *)buf, '-');
+		if (p != NULL) {
+			*p = '\0';
+		}
+		if (ddi_strtol((const char *)buf, NULL, 16, &tmp) != 0) {
+			return (B_FALSE);
+		}
+		conv_num[i] = (uint16_t)tmp;
+		if (p != NULL) {
+			buf = p + 1;
+		} else {
+			break;
+		}
+	}
+
+	return (B_TRUE);
 }
+
+static void
+generate_iscsi_initiator_id(void)
+{
+	boot_property.boot_init.ini_name_len = 38;
+	boot_property.boot_init.ini_name =
+	    (uchar_t *)kmem_zalloc(boot_property.boot_init.ini_name_len,
+	    KM_SLEEP);
+	(void) snprintf((char *)boot_property.boot_init.ini_name,
+	    38, "iqn.1986-03.com.sun:boot.%02x%02x%02x%02x%02x%02x",
+	    boot_property.boot_nic.nic_mac[0],
+	    boot_property.boot_nic.nic_mac[1],
+	    boot_property.boot_nic.nic_mac[2],
+	    boot_property.boot_nic.nic_mac[3],
+	    boot_property.boot_nic.nic_mac[4],
+	    boot_property.boot_nic.nic_mac[5]);
+}
+
+
+/* We only deal with a.b.c.d decimal format. ip points to 4 byte storage */
+static int
+inet_aton(char *ipstr, uchar_t *ip)
+{
+	int i = 0;
+	uchar_t val[4] = {0};
+	char c = *ipstr;
+
+	for (;;) {
+		if (!isdigit(c))
+			return (-1);
+		for (;;) {
+			if (!isdigit(c))
+				break;
+			val[i] = val[i] * 10 + (c - '0');
+			c = *++ipstr;
+		}
+		i++;
+		if (i == 4)
+			break;
+		if (c != '.')
+			return (-1);
+		c = *++ipstr;
+	}
+	if (c != 0)
+		return (-1);
+	bcopy(val, ip, 4);
+	return (0);
+}