diff options
author | Jack Meng <Jack.Meng@Sun.COM> | 2009-10-21 11:28:57 +0800 |
---|---|---|
committer | Jack Meng <Jack.Meng@Sun.COM> | 2009-10-21 11:28:57 +0800 |
commit | dedec472759b1a1a25044d504201ef59ccbffb56 (patch) | |
tree | c2b74ed12b9e160d396751f8d912f5631a3e5b0c /usr/src | |
parent | 89e1f902f752842a275fadd3481dd907e0a1a82a (diff) | |
download | illumos-gate-dedec472759b1a1a25044d504201ef59ccbffb56.tar.gz |
PSARC 2008/427 iSCSI Boot
PSARC 2009/480 Add bootpath into Solaris Sparc BootArchive for iSCSI boot
6714847 iSCSI boot,sparc part
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/uts/common/fs/vfs.c | 8 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/spa.c | 13 | ||||
-rw-r--r-- | usr/src/uts/common/io/idm/idm_so.c | 20 | ||||
-rw-r--r-- | usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_login.c | 5 | ||||
-rw-r--r-- | usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_net.c | 12 | ||||
-rw-r--r-- | usr/src/uts/common/io/strplumb.c | 27 | ||||
-rw-r--r-- | usr/src/uts/common/os/devcfg.c | 43 | ||||
-rw-r--r-- | usr/src/uts/common/os/iscsiboot_prop.c | 136 | ||||
-rw-r--r-- | usr/src/uts/common/os/swapgeneric.c | 152 | ||||
-rw-r--r-- | usr/src/uts/common/sys/bootprops.h | 37 | ||||
-rw-r--r-- | usr/src/uts/common/sys/idm/idm.h | 1 | ||||
-rw-r--r-- | usr/src/uts/i86pc/os/ibft.c | 16 | ||||
-rw-r--r-- | usr/src/uts/sparc/os/iscsi_boot.c | 432 |
13 files changed, 849 insertions, 53 deletions
diff --git a/usr/src/uts/common/fs/vfs.c b/usr/src/uts/common/fs/vfs.c index 0d750e00ed..6d494c7516 100644 --- a/usr/src/uts/common/fs/vfs.c +++ b/usr/src/uts/common/fs/vfs.c @@ -4491,7 +4491,6 @@ extern int hvmboot_rootconf(); #endif /* __x86 */ extern ib_boot_prop_t *iscsiboot_prop; -extern void iscsi_boot_prop_free(); int rootconf() @@ -4544,8 +4543,13 @@ rootconf() 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"); diff --git a/usr/src/uts/common/fs/zfs/spa.c b/usr/src/uts/common/fs/zfs/spa.c index e242926b5a..4c44d3d76a 100644 --- a/usr/src/uts/common/fs/zfs/spa.c +++ b/usr/src/uts/common/fs/zfs/spa.c @@ -64,6 +64,7 @@ #ifdef _KERNEL #include <sys/zone.h> +#include <sys/bootprops.h> #endif /* _KERNEL */ #include "zfs_prop.h" @@ -2420,7 +2421,17 @@ spa_import_rootpool(char *devpath, char *devid) /* * 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); diff --git a/usr/src/uts/common/io/idm/idm_so.c b/usr/src/uts/common/io/idm/idm_so.c index ecb2b427f4..fce503b97d 100644 --- a/usr/src/uts/common/io/idm/idm_so.c +++ b/usr/src/uts/common/io/idm/idm_so.c @@ -68,7 +68,8 @@ static idm_status_t idm_so_conn_create_common(idm_conn_t *ic, ksocket_t new_so); 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 @@ idm_iov_sorecv(ksocket_t so, iovec_t *iop, int iovlen, size_t total_len) } 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 @@ idm_set_ini_preconnect_options(idm_so_conn_t *sc) (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 @@ idm_so_ini_conn_create(idm_conn_req_t *cr, idm_conn_t *ic) 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); } diff --git a/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_login.c b/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_login.c index 3ebee23692..5f821deb95 100644 --- a/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_login.c +++ b/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_login.c @@ -2150,6 +2150,11 @@ iscsi_login_connect(iscsi_conn_t *icp) 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 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 7a5d0b3133..94481fe9cc 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 @@ -910,8 +910,16 @@ iscsi_net_interface() /* 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); diff --git a/usr/src/uts/common/io/strplumb.c b/usr/src/uts/common/io/strplumb.c index 33406bea05..f43648fd7f 100644 --- a/usr/src/uts/common/io/strplumb.c +++ b/usr/src/uts/common/io/strplumb.c @@ -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 @@ 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) { @@ -659,15 +657,32 @@ char * 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; diff --git a/usr/src/uts/common/os/devcfg.c b/usr/src/uts/common/os/devcfg.c index 0c35c932ba..f1fc739b97 100644 --- a/usr/src/uts/common/os/devcfg.c +++ b/usr/src/uts/common/os/devcfg.c @@ -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 @@ ddi_find_devinfo(char *nodename, int instance, int attached) 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 @@ resolve_pathname(char *pathname, /* 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); diff --git a/usr/src/uts/common/os/iscsiboot_prop.c b/usr/src/uts/common/os/iscsiboot_prop.c index 28b0566d34..e803fefc0f 100644 --- a/usr/src/uts/common/os/iscsiboot_prop.c +++ b/usr/src/uts/common/os/iscsiboot_prop.c @@ -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 @@ int iscsi_print_bootprop = 0; #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 @@ iscsi_boot_free_ini(ib_ini_prop_t *init) } 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 @@ iscsi_boot_free_tgt(ib_tgt_prop_t *target) 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 @@ kinet_ntoa(char *buf, void *in, int af) (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); +} diff --git a/usr/src/uts/common/os/swapgeneric.c b/usr/src/uts/common/os/swapgeneric.c index 65254506e4..f5f0d4b94d 100644 --- a/usr/src/uts/common/os/swapgeneric.c +++ b/usr/src/uts/common/os/swapgeneric.c @@ -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_driver(char *drv); 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 @@ _info(struct modinfo *modinfop) 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 @@ rootconf(void) */ 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 @@ getrootdev(void) { 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 @@ loadrootmodules(void) 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 @@ loop: 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 @@ get_bootpath_prop(char *bootpath) "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 @@ load_bootpath_drivers(char *bootpath) 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 @@ netboot_over_ib(char *bootpath) 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 @@ netboot_over_ib(char *bootpath) } 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); +} diff --git a/usr/src/uts/common/sys/bootprops.h b/usr/src/uts/common/sys/bootprops.h index ed6dd8bd7a..d3eec9d2fd 100644 --- a/usr/src/uts/common/sys/bootprops.h +++ b/usr/src/uts/common/sys/bootprops.h @@ -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 @@ extern "C" { #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 @@ kifioctl(TIUSER *tiptr, int cmd, struct netbuf *nbuf, char *ifname); */ 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 @@ typedef struct _ib_tgt_prop { 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 @@ typedef struct _ib_boot_prop { 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 diff --git a/usr/src/uts/common/sys/idm/idm.h b/usr/src/uts/common/sys/idm/idm.h index cb5e256ef3..ada422a1b0 100644 --- a/usr/src/uts/common/sys/idm/idm.h +++ b/usr/src/uts/common/sys/idm/idm.h @@ -181,6 +181,7 @@ typedef struct { 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 { diff --git a/usr/src/uts/i86pc/os/ibft.c b/usr/src/uts/i86pc/os/ibft.c index ab7e52e4ae..43ffad5e81 100644 --- a/usr/src/uts/i86pc/os/ibft.c +++ b/usr/src/uts/i86pc/os/ibft.c @@ -374,6 +374,8 @@ iscsi_parse_ibft_initiator(char *begin_of_ibft, 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 @@ iscsi_parse_ibft_target(char *begin_of_ibft, iscsi_ibft_tgt_t *tgtp) 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 @@ iscsi_parse_ibft_target(char *begin_of_ibft, iscsi_ibft_tgt_t *tgtp) (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 @@ iscsi_parse_ibft_target(char *begin_of_ibft, iscsi_ibft_tgt_t *tgtp) (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 @@ iscsi_parse_ibft_target(char *begin_of_ibft, iscsi_ibft_tgt_t *tgtp) 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 @@ iscsi_parse_ibft_target(char *begin_of_ibft, iscsi_ibft_tgt_t *tgtp) (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( diff --git a/usr/src/uts/sparc/os/iscsi_boot.c b/usr/src/uts/sparc/os/iscsi_boot.c index 4a928c6a0e..78f7e8549c 100644 --- a/usr/src/uts/sparc/os/iscsi_boot.c +++ b/usr/src/uts/sparc/os/iscsi_boot.c @@ -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); } |