Home | History | Annotate | Download | only in iscsi
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 /*
     27  * ISCSID --
     28  *
     29  * Discovery of targets and access to the persistent storage starts here.
     30  */
     31 
     32 #include <sys/thread.h>
     33 #include <sys/types.h>
     34 #include <sys/proc.h>		/* declares:    p0 */
     35 #include <sys/cmn_err.h>
     36 #include <sys/scsi/adapters/iscsi_if.h>
     37 #include <netinet/in.h>
     38 #include "iscsi_targetparam.h"
     39 #include "isns_client.h"
     40 #include "isns_protocol.h"
     41 #include "persistent.h"
     42 #include "iscsi.h"
     43 #include <sys/ethernet.h>
     44 #include <sys/bootprops.h>
     45 
     46 /*
     47  * local function prototypes
     48  */
     49 static boolean_t iscsid_init_config(iscsi_hba_t *ihp);
     50 static boolean_t iscsid_init_targets(iscsi_hba_t *ihp);
     51 static void iscsid_thread_static(iscsi_thread_t *thread, void *p);
     52 static void iscsid_thread_sendtgts(iscsi_thread_t *thread, void *p);
     53 static void iscsid_thread_isns(iscsi_thread_t *thread, void *p);
     54 static void iscsid_thread_slp(iscsi_thread_t *thread, void *p);
     55 static void iscsid_thread_boot_wd(iscsi_thread_t *thread, void *p);
     56 static void iscsid_threads_create(iscsi_hba_t *ihp);
     57 static void iscsid_threads_destroy(void);
     58 static int iscsid_copyto_param_set(uint32_t param_id,
     59     iscsi_login_params_t *params, iscsi_param_set_t *ipsp);
     60 static void iscsid_add_pg_list_to_cache(iscsi_hba_t *ihp,
     61     isns_portal_group_list_t *pg_list);
     62 static void iscsid_remove_target_param(char *name);
     63 static boolean_t iscsid_add(iscsi_hba_t *ihp, iSCSIDiscoveryMethod_t method,
     64     struct sockaddr *addr_dsc, char *target_name, int tpgt,
     65     struct sockaddr *addr_tgt);
     66 static void iscsi_discovery_event(iscsi_hba_t *ihp,
     67     iSCSIDiscoveryMethod_t m, boolean_t start);
     68 static boolean_t iscsid_boot_init_config(iscsi_hba_t *ihp);
     69 static iscsi_sess_t *iscsi_add_boot_sess(iscsi_hba_t *ihp, int isid);
     70 static boolean_t iscsid_make_entry(ib_boot_prop_t *boot_prop_entry,
     71     entry_t *entry);
     72 static boolean_t iscsid_check_active_boot_conn(iscsi_hba_t *ihp);
     73 
     74 extern int modrootloaded;
     75 int iscsi_configroot_retry = 20;
     76 static boolean_t iscsi_configroot_printed = FALSE;
     77 static int iscsi_net_up = 0;
     78 extern ib_boot_prop_t   *iscsiboot_prop;
     79 
     80 #define	ISCSI_CONFIGROOT_DELAY	1
     81 
     82 /*
     83  * iSCSI target discovery thread table
     84  */
     85 typedef struct iscsid_thr_table {
     86 	void			(*func_start)(iscsi_thread_t *, void *);
     87 	iscsi_thread_t		*thr_id;
     88 	iSCSIDiscoveryMethod_t	method;
     89 	char			*name;
     90 } iscsid_thr_table;
     91 
     92 static iscsid_thr_table iscsid_thr[] = {
     93 	{ iscsid_thread_static, NULL,
     94 	    iSCSIDiscoveryMethodStatic,
     95 	    "Static" },
     96 	{ iscsid_thread_sendtgts, NULL,
     97 	    iSCSIDiscoveryMethodSendTargets,
     98 	    "SendTarget" },
     99 	{ iscsid_thread_slp, NULL,
    100 	    iSCSIDiscoveryMethodSLP,
    101 	    "SLP" },
    102 	{ iscsid_thread_isns, NULL,
    103 	    iSCSIDiscoveryMethodISNS,
    104 	    "iSNS" },
    105 	{ NULL, NULL,
    106 	    iSCSIDiscoveryMethodUnknown,
    107 	    NULL }
    108 };
    109 
    110 /*
    111  * discovery method event table
    112  */
    113 iSCSIDiscoveryMethod_t	for_failure[] = {
    114 	iSCSIDiscoveryMethodStatic,
    115 	iSCSIDiscoveryMethodSLP,
    116 	iSCSIDiscoveryMethodISNS,
    117 	iSCSIDiscoveryMethodSendTargets,
    118 	iSCSIDiscoveryMethodUnknown /* terminating value */
    119 };
    120 
    121 /*
    122  * The following private tunable, set in /etc/system, e.g.,
    123  *      set iscsi:iscsi_boot_max_delay = 360
    124  * , provides with customer a max wait time in
    125  * seconds to wait for boot lun online during iscsi boot.
    126  * Defaults to 180s.
    127  */
    128 int iscsi_boot_max_delay = ISCSI_BOOT_DEFAULT_MAX_DELAY;
    129 
    130 /*
    131  * discovery configuration semaphore
    132  */
    133 ksema_t iscsid_config_semaphore;
    134 
    135 static iscsi_thread_t	*iscsi_boot_wd_handle = NULL;
    136 
    137 #define	CHECK_METHOD(v) ((dm & v) ? B_TRUE : B_FALSE)
    138 
    139 /*
    140  * Check if IP is valid
    141  */
    142 static boolean_t
    143 iscsid_ip_check(char *ip)
    144 {
    145 	int	i	= 0;
    146 
    147 	if (!ip)
    148 		return (B_FALSE);
    149 	for (; (ip[i] == 0) && (i < IB_IP_BUFLEN); i++) {}
    150 	if (i == IB_IP_BUFLEN) {
    151 		/* invalid IP address */
    152 		return (B_FALSE);
    153 	}
    154 	return (B_TRUE);
    155 }
    156 
    157 /*
    158  * Make an entry for the boot target.
    159  * return B_TRUE upon success
    160  *        B_FALSE if fail
    161  */
    162 static boolean_t
    163 iscsid_make_entry(ib_boot_prop_t *boot_prop_entry, entry_t *entry)
    164 {
    165 	if (entry == NULL || boot_prop_entry == NULL) {
    166 		return (B_FALSE);
    167 	}
    168 
    169 	if (!iscsid_ip_check(
    170 	    (char *)&boot_prop_entry->boot_tgt.tgt_ip_u))
    171 		return (B_FALSE);
    172 
    173 	if (boot_prop_entry->boot_tgt.sin_family != AF_INET &&
    174 	    boot_prop_entry->boot_tgt.sin_family != AF_INET6)
    175 		return (B_FALSE);
    176 
    177 	entry->e_vers = ISCSI_INTERFACE_VERSION;
    178 
    179 	mutex_enter(&iscsi_oid_mutex);
    180 	entry->e_oid = iscsi_oid++;
    181 	mutex_exit(&iscsi_oid_mutex);
    182 
    183 	entry->e_tpgt = ISCSI_DEFAULT_TPGT;
    184 
    185 	if (boot_prop_entry->boot_tgt.sin_family == AF_INET) {
    186 		entry->e_u.u_in4.s_addr =
    187 		    boot_prop_entry->boot_tgt.tgt_ip_u.u_in4.s_addr;
    188 		entry->e_insize = sizeof (struct in_addr);
    189 	} else {
    190 		(void) bcopy(
    191 		    &boot_prop_entry->boot_tgt.tgt_ip_u.u_in6.s6_addr,
    192 		    entry->e_u.u_in6.s6_addr, 16);
    193 		entry->e_insize = sizeof (struct in6_addr);
    194 	}
    195 
    196 	entry->e_port = boot_prop_entry->boot_tgt.tgt_port;
    197 	entry->e_boot = B_TRUE;
    198 	return (B_TRUE);
    199 }
    200 
    201 /*
    202  * Create the boot session
    203  */
    204 static void
    205 iscsi_boot_session_create(iscsi_hba_t *ihp,
    206     ib_boot_prop_t	*boot_prop_table)
    207 {
    208 	iSCSIDiscoveryMethod_t  dm;
    209 	entry_t			e;
    210 	iscsi_sockaddr_t	addr_dsc;
    211 
    212 	if (ihp == NULL || boot_prop_table == NULL) {
    213 		return;
    214 	}
    215 
    216 	if (!iscsid_ip_check(
    217 	    (char *)&boot_prop_table->boot_tgt.tgt_ip_u)) {
    218 		return;
    219 	}
    220 
    221 	if (boot_prop_table->boot_tgt.tgt_name != NULL) {
    222 		dm = iSCSIDiscoveryMethodStatic |
    223 		    iSCSIDiscoveryMethodBoot;
    224 		if (!iscsid_make_entry(boot_prop_table, &e))
    225 			return;
    226 		iscsid_addr_to_sockaddr(e.e_insize, &e.e_u,
    227 		    e.e_port, &addr_dsc.sin);
    228 
    229 		(void) iscsid_add(ihp, dm, &addr_dsc.sin,
    230 		    (char *)boot_prop_table->boot_tgt.tgt_name,
    231 		    e.e_tpgt, &addr_dsc.sin);
    232 	} else {
    233 		dm = iSCSIDiscoveryMethodSendTargets |
    234 		    iSCSIDiscoveryMethodBoot;
    235 		if (!iscsid_make_entry(boot_prop_table, &e))
    236 			return;
    237 		iscsid_addr_to_sockaddr(e.e_insize, &e.e_u,
    238 		    e.e_port, &addr_dsc.sin);
    239 		iscsid_do_sendtgts(&e);
    240 		(void) iscsid_login_tgt(ihp, NULL, dm,
    241 		    &addr_dsc.sin);
    242 	}
    243 }
    244 
    245 /*
    246  * iscsid_init -- to initialize stuffs related to iscsi daemon,
    247  * and to create boot session if needed
    248  */
    249 boolean_t
    250 iscsid_init(iscsi_hba_t *ihp)
    251 {
    252 	boolean_t		rval = B_TRUE;
    253 
    254 	sema_init(&iscsid_config_semaphore, 1, NULL,
    255 	    SEMA_DRIVER, NULL);
    256 	persistent_init();
    257 	iscsid_threads_create(ihp);
    258 
    259 	if (modrootloaded == 1) {
    260 		/* normal case, load the persistent store */
    261 		if (persistent_load() == B_TRUE) {
    262 			ihp->hba_persistent_loaded = B_TRUE;
    263 		} else {
    264 			return (B_FALSE);
    265 		}
    266 	}
    267 
    268 	if ((modrootloaded == 0) && (iscsiboot_prop != NULL)) {
    269 		if (!iscsid_boot_init_config(ihp)) {
    270 			rval = B_FALSE;
    271 		} else {
    272 			iscsi_boot_session_create(ihp, iscsiboot_prop);
    273 			iscsi_boot_wd_handle =
    274 			    iscsi_thread_create(ihp->hba_dip,
    275 			    "BootWD", iscsid_thread_boot_wd, ihp);
    276 			if (iscsi_boot_wd_handle) {
    277 				rval = iscsi_thread_start(
    278 				    iscsi_boot_wd_handle);
    279 			} else {
    280 				rval = B_FALSE;
    281 			}
    282 		}
    283 		if (rval == B_FALSE) {
    284 			cmn_err(CE_NOTE, "Initializaton of iscsi boot session"
    285 			    " partially failed");
    286 		}
    287 	}
    288 
    289 	return (rval);
    290 }
    291 
    292 /*
    293  * iscsid_start -- start the iscsi initiator daemon, actually this code
    294  * is just to enable discovery methods which are set enabled in
    295  * persistent store, as an economic way to present the 'daemon' funtionality
    296  */
    297 boolean_t
    298 iscsid_start(iscsi_hba_t *ihp) {
    299 	boolean_t		rval = B_FALSE;
    300 	iSCSIDiscoveryMethod_t	dm;
    301 	iSCSIDiscoveryMethod_t	*fdm;
    302 
    303 	rval = iscsid_init_config(ihp);
    304 	if (rval == B_TRUE) {
    305 		rval = iscsid_init_targets(ihp);
    306 	}
    307 
    308 	if (rval == B_TRUE) {
    309 		dm = persistent_disc_meth_get();
    310 		rval = iscsid_enable_discovery(ihp, dm, B_TRUE);
    311 		if (rval == B_TRUE) {
    312 			iscsid_poke_discovery(ihp,
    313 			    iSCSIDiscoveryMethodUnknown);
    314 			(void) iscsid_login_tgt(ihp, NULL,
    315 			    iSCSIDiscoveryMethodUnknown, NULL);
    316 		}
    317 	}
    318 
    319 	if (rval == B_FALSE) {
    320 		/*
    321 		 * In case of failure the events still need to be sent
    322 		 * because the door daemon will pause until all these
    323 		 * events have occurred.
    324 		 */
    325 		for (fdm = &for_failure[0]; *fdm !=
    326 		    iSCSIDiscoveryMethodUnknown; fdm++) {
    327 			/* ---- Send both start and end events ---- */
    328 			iscsi_discovery_event(ihp, *fdm, B_TRUE);
    329 			iscsi_discovery_event(ihp, *fdm, B_FALSE);
    330 		}
    331 	}
    332 
    333 	return (rval);
    334 }
    335 
    336 /*
    337  * iscsid_stop -- stop the iscsi initiator daemon, by disabling
    338  * all the discovery methods first, and then try to stop all
    339  * related threads
    340  */
    341 boolean_t
    342 iscsid_stop(iscsi_hba_t *ihp) {
    343 	boolean_t		rval = B_FALSE;
    344 	iscsi_sess_t		*isp = NULL;
    345 
    346 	if (iscsid_disable_discovery(ihp,
    347 	    ISCSI_ALL_DISCOVERY_METHODS) == B_FALSE) {
    348 		(void) iscsid_enable_discovery(ihp,
    349 		    ISCSI_ALL_DISCOVERY_METHODS, B_TRUE);
    350 		return (rval);
    351 	}
    352 
    353 	/* final check */
    354 	rw_enter(&ihp->hba_sess_list_rwlock, RW_READER);
    355 	if (ihp->hba_sess_list == NULL) {
    356 		rval = B_TRUE;
    357 	} else {
    358 		/*
    359 		 * If only boot session is left, that is OK.
    360 		 * Otherwise, we should consider stop failed.
    361 		 */
    362 		rval = B_TRUE;
    363 		for (isp = ihp->hba_sess_list; isp != NULL;
    364 		    isp = isp->sess_next) {
    365 			if (isp->sess_boot == B_FALSE) {
    366 				rval = B_FALSE;
    367 				break;
    368 			}
    369 		}
    370 	}
    371 	rw_exit(&ihp->hba_sess_list_rwlock);
    372 
    373 	if (rval == B_FALSE) {
    374 		(void) iscsid_enable_discovery(ihp,
    375 		    ISCSI_ALL_DISCOVERY_METHODS, B_TRUE);
    376 		return (rval);
    377 	}
    378 
    379 	return (rval);
    380 }
    381 
    382 /*
    383  * iscsid_fini -- do whatever is required to clean up
    384  */
    385 /* ARGSUSED */
    386 void
    387 iscsid_fini()
    388 {
    389 	if (iscsi_boot_wd_handle != NULL) {
    390 		iscsi_thread_destroy(iscsi_boot_wd_handle);
    391 		iscsi_boot_wd_handle = NULL;
    392 	}
    393 	iscsid_threads_destroy();
    394 	persistent_fini();
    395 	sema_destroy(&iscsid_config_semaphore);
    396 }
    397 
    398 /*
    399  * iscsid_props -- returns discovery thread information, used by ioctl code
    400  */
    401 void
    402 iscsid_props(iSCSIDiscoveryProperties_t *props)
    403 {
    404 	iSCSIDiscoveryMethod_t  dm;
    405 
    406 	dm = persistent_disc_meth_get();
    407 
    408 	props->vers = ISCSI_INTERFACE_VERSION;
    409 
    410 	/* ---- change once thread is implemented ---- */
    411 	props->iSNSDiscoverySettable		= B_FALSE;
    412 	props->SLPDiscoverySettable		= B_FALSE;
    413 	props->StaticDiscoverySettable		= B_TRUE;
    414 	props->SendTargetsDiscoverySettable	= B_TRUE;
    415 	props->iSNSDiscoveryMethod		= iSNSDiscoveryMethodStatic;
    416 
    417 	props->iSNSDiscoveryEnabled = CHECK_METHOD(iSCSIDiscoveryMethodISNS);
    418 	props->StaticDiscoveryEnabled =
    419 	    CHECK_METHOD(iSCSIDiscoveryMethodStatic);
    420 	props->SendTargetsDiscoveryEnabled =
    421 	    CHECK_METHOD(iSCSIDiscoveryMethodSendTargets);
    422 	props->SLPDiscoveryEnabled = CHECK_METHOD(iSCSIDiscoveryMethodSLP);
    423 }
    424 
    425 /*
    426  * iscsid_enable_discovery - start specified discovery methods
    427  */
    428 /* ARGSUSED */
    429 boolean_t
    430 iscsid_enable_discovery(iscsi_hba_t *ihp, iSCSIDiscoveryMethod_t idm,
    431     boolean_t poke)
    432 {
    433 	boolean_t		rval = B_TRUE;
    434 	iscsid_thr_table	*dt;
    435 
    436 	/*
    437 	 * start the specified discovery method(s)
    438 	 */
    439 	for (dt = &iscsid_thr[0]; dt->method != iSCSIDiscoveryMethodUnknown;
    440 	    dt++) {
    441 		if (idm & dt->method) {
    442 			if (dt->thr_id != NULL) {
    443 				rval = iscsi_thread_start(dt->thr_id);
    444 				if (rval == B_FALSE) {
    445 					break;
    446 				}
    447 				if (poke == B_TRUE) {
    448 					(void) iscsi_thread_send_wakeup(
    449 					    dt->thr_id);
    450 				}
    451 			} else {
    452 				/*
    453 				 * unexpected condition.  The threads for each
    454 				 * discovery method should have started at
    455 				 * initialization
    456 				 */
    457 				ASSERT(B_FALSE);
    458 			}
    459 		}
    460 	} /* END for() */
    461 
    462 	return (rval);
    463 }
    464 
    465 
    466 /*
    467  * iscsid_disable_discovery - stop specified discovery methods
    468  */
    469 boolean_t
    470 iscsid_disable_discovery(iscsi_hba_t *ihp, iSCSIDiscoveryMethod_t idm)
    471 {
    472 	boolean_t		rval = B_TRUE;
    473 	iscsid_thr_table	*dt;
    474 
    475 	/*
    476 	 * stop the specified discovery method(s)
    477 	 */
    478 	for (dt = &iscsid_thr[0]; dt->method != iSCSIDiscoveryMethodUnknown;
    479 	    dt++) {
    480 		if (idm & dt->method) {
    481 
    482 			/* signal discovery event change - begin */
    483 			iscsi_discovery_event(ihp, dt->method, B_TRUE);
    484 
    485 			/* Attempt to logout of all associated targets */
    486 			rval = iscsid_del(ihp, NULL, dt->method, NULL);
    487 			if (rval == B_TRUE) {
    488 				/* Successfully logged out of targets */
    489 				if (dt->thr_id != NULL) {
    490 					rval = iscsi_thread_stop(dt->thr_id);
    491 					if (rval == B_FALSE) {
    492 						/*
    493 						 * signal discovery
    494 						 * event change - end
    495 						 */
    496 						iscsi_discovery_event(ihp,
    497 						    dt->method, B_FALSE);
    498 						break;
    499 					}
    500 
    501 				} else {
    502 					/*
    503 					 * unexpected condition.  The threads
    504 					 * for each discovery method should
    505 					 * have started at initialization
    506 					 */
    507 					ASSERT(B_FALSE);
    508 				}
    509 			}
    510 
    511 			/* signal discovery event change - end */
    512 			iscsi_discovery_event(ihp, dt->method, B_FALSE);
    513 
    514 		}
    515 	} /* END for() */
    516 
    517 	return (rval);
    518 }
    519 
    520 /*
    521  * iscsid_poke_discovery - wakeup discovery methods to find any new targets
    522  * and wait for all discovery processes to complete.
    523  */
    524 void
    525 iscsid_poke_discovery(iscsi_hba_t *ihp, iSCSIDiscoveryMethod_t method)
    526 {
    527 #define	ISCSI_DISCOVERY_DELAY	1
    528 
    529 	iSCSIDiscoveryMethod_t	dm;
    530 	iscsid_thr_table	*dt;
    531 	boolean_t		send_wakeup;
    532 
    533 	ASSERT(ihp != NULL);
    534 
    535 	/* reset discovery flags */
    536 	mutex_enter(&ihp->hba_discovery_events_mutex);
    537 	ihp->hba_discovery_in_progress = B_TRUE;
    538 	ihp->hba_discovery_events = iSCSIDiscoveryMethodUnknown;
    539 	mutex_exit(&ihp->hba_discovery_events_mutex);
    540 
    541 	/* start all enabled discovery methods */
    542 	dm = persistent_disc_meth_get();
    543 	for (dt = &iscsid_thr[0]; dt->method != iSCSIDiscoveryMethodUnknown;
    544 	    dt++) {
    545 		send_wakeup = B_FALSE;
    546 
    547 		if ((method == iSCSIDiscoveryMethodUnknown) ||
    548 		    (method == dt->method)) {
    549 			if ((dm & dt->method) && (dt->thr_id != NULL)) {
    550 				if (iscsi_thread_send_wakeup(dt->thr_id) ==
    551 				    B_TRUE) {
    552 					send_wakeup = B_TRUE;
    553 				}
    554 			}
    555 		}
    556 
    557 		if (send_wakeup == B_FALSE) {
    558 			iscsi_discovery_event(ihp, dt->method, B_TRUE);
    559 			iscsi_discovery_event(ihp, dt->method, B_FALSE);
    560 		}
    561 	}
    562 
    563 	mutex_enter(&ihp->hba_discovery_events_mutex);
    564 	while (ihp->hba_discovery_events != ISCSI_ALL_DISCOVERY_METHODS) {
    565 		mutex_exit(&ihp->hba_discovery_events_mutex);
    566 		delay(SEC_TO_TICK(ISCSI_DISCOVERY_DELAY));
    567 		mutex_enter(&ihp->hba_discovery_events_mutex);
    568 	}
    569 	ihp->hba_discovery_in_progress = B_FALSE;
    570 	mutex_exit(&ihp->hba_discovery_events_mutex);
    571 
    572 }
    573 
    574 /*
    575  * iscsid_do_sendtgts - issue send targets command to the given discovery
    576  * address and then add the discovered targets to the discovery queue
    577  */
    578 void
    579 iscsid_do_sendtgts(entry_t *disc_addr)
    580 {
    581 
    582 #define	SENDTGTS_DEFAULT_NUM_TARGETS    10
    583 
    584 	int			stl_sz;
    585 	int			stl_num_tgts = SENDTGTS_DEFAULT_NUM_TARGETS;
    586 	iscsi_sendtgts_list_t	*stl_hdr = NULL;
    587 	boolean_t		retry = B_TRUE;
    588 	char			inp_buf[INET6_ADDRSTRLEN];
    589 	const char		*ip;
    590 	int			ctr;
    591 	int			rc;
    592 	iscsi_hba_t		*ihp;
    593 	iSCSIDiscoveryMethod_t  dm = iSCSIDiscoveryMethodSendTargets;
    594 
    595 	/* allocate and initialize sendtargets list header */
    596 	stl_sz = sizeof (*stl_hdr) + ((stl_num_tgts - 1) *
    597 	    sizeof (iscsi_sendtgts_entry_t));
    598 	stl_hdr = kmem_zalloc(stl_sz, KM_SLEEP);
    599 
    600 retry_sendtgts:
    601 	stl_hdr->stl_in_cnt = stl_num_tgts;
    602 	bcopy(disc_addr, &(stl_hdr->stl_entry),
    603 	    sizeof (stl_hdr->stl_entry));
    604 	stl_hdr->stl_entry.e_vers = ISCSI_INTERFACE_VERSION;
    605 
    606 	/* lock interface so only one SendTargets operation occurs */
    607 	if ((ihp = (iscsi_hba_t *)ddi_get_soft_state(iscsi_state, 0)) == NULL) {
    608 		cmn_err(CE_NOTE, "!iscsi discovery failure - SendTargets. "
    609 		    "failure to get soft state");
    610 		kmem_free(stl_hdr, stl_sz);
    611 		return;
    612 	}
    613 	sema_p(&ihp->hba_sendtgts_semaphore);
    614 	rc = iscsi_ioctl_sendtgts_get(ihp, stl_hdr);
    615 	sema_v(&ihp->hba_sendtgts_semaphore);
    616 	if (rc) {
    617 		ip = inet_ntop((disc_addr->e_insize ==
    618 		    sizeof (struct in_addr) ? AF_INET : AF_INET6),
    619 		    &disc_addr->e_u, inp_buf, sizeof (inp_buf));
    620 		cmn_err(CE_NOTE,
    621 		    "iscsi discovery failure - SendTargets (%s)\n", ip);
    622 		kmem_free(stl_hdr, stl_sz);
    623 		return;
    624 	}
    625 
    626 	/* check if all targets received */
    627 	if (stl_hdr->stl_in_cnt < stl_hdr->stl_out_cnt) {
    628 		if (retry == B_TRUE) {
    629 			stl_num_tgts = stl_hdr->stl_out_cnt;
    630 			kmem_free(stl_hdr, stl_sz);
    631 			stl_sz = sizeof (*stl_hdr) +
    632 			    ((stl_num_tgts - 1) *
    633 			    sizeof (iscsi_sendtgts_entry_t));
    634 			stl_hdr = kmem_zalloc(stl_sz, KM_SLEEP);
    635 			retry = B_FALSE;
    636 			goto retry_sendtgts;
    637 		} else {
    638 			ip = inet_ntop((disc_addr->e_insize ==
    639 			    sizeof (struct in_addr) ?
    640 			    AF_INET : AF_INET6), &disc_addr->e_u,
    641 			    inp_buf, sizeof (inp_buf));
    642 			cmn_err(CE_NOTE, "iscsi discovery failure - "
    643 			    "SendTargets overflow (%s)\n", ip);
    644 			kmem_free(stl_hdr, stl_sz);
    645 			return;
    646 		}
    647 	}
    648 
    649 	for (ctr = 0; ctr < stl_hdr->stl_out_cnt; ctr++) {
    650 		iscsi_sockaddr_t addr_dsc;
    651 		iscsi_sockaddr_t addr_tgt;
    652 
    653 		iscsid_addr_to_sockaddr(disc_addr->e_insize,
    654 		    &disc_addr->e_u, disc_addr->e_port, &addr_dsc.sin);
    655 		iscsid_addr_to_sockaddr(
    656 		    stl_hdr->stl_list[ctr].ste_ipaddr.a_addr.i_insize,
    657 		    &(stl_hdr->stl_list[ctr].ste_ipaddr.a_addr.i_addr),
    658 		    stl_hdr->stl_list[ctr].ste_ipaddr.a_port,
    659 		    &addr_tgt.sin);
    660 		if (disc_addr->e_boot == B_TRUE) {
    661 			dm = dm | iSCSIDiscoveryMethodBoot;
    662 		}
    663 		(void) iscsid_add(ihp, dm,
    664 		    &addr_dsc.sin, (char *)stl_hdr->stl_list[ctr].ste_name,
    665 		    stl_hdr->stl_list[ctr].ste_tpgt,
    666 		    &addr_tgt.sin);
    667 	}
    668 	kmem_free(stl_hdr, stl_sz);
    669 }
    670 
    671 void
    672 iscsid_do_isns_query_one_server(iscsi_hba_t *ihp, entry_t *isns_server)
    673 {
    674 	int pg_sz, query_status;
    675 	iscsi_addr_t *ap;
    676 	isns_portal_group_list_t *pg_list;
    677 
    678 	ap = (iscsi_addr_t *)kmem_zalloc(sizeof (iscsi_addr_t), KM_SLEEP);
    679 	ap->a_port = isns_server->e_port;
    680 	ap->a_addr.i_insize = isns_server->e_insize;
    681 
    682 	if (isns_server->e_insize == sizeof (struct in_addr)) {
    683 		ap->a_addr.i_addr.in4.s_addr = (isns_server->e_u.u_in4.s_addr);
    684 	} else if (isns_server->e_insize == sizeof (struct in6_addr)) {
    685 		bcopy(&(isns_server->e_u.u_in6.s6_addr),
    686 		    ap->a_addr.i_addr.in6.s6_addr, 16);
    687 	} else {
    688 		kmem_free(ap, sizeof (iscsi_addr_t));
    689 		return;
    690 	}
    691 
    692 	pg_list = NULL;
    693 	query_status = isns_query_one_server(
    694 	    ap, ihp->hba_isid,
    695 	    ihp->hba_name, ihp->hba_alias,
    696 	    ISNS_INITIATOR_NODE_TYPE, &pg_list);
    697 	kmem_free(ap, sizeof (iscsi_addr_t));
    698 	if (query_status != isns_ok || pg_list == NULL) {
    699 		DTRACE_PROBE1(iscsid_do_isns_query_one_server_status,
    700 		    int, query_status);
    701 		return;
    702 	}
    703 
    704 	iscsid_add_pg_list_to_cache(ihp, pg_list);
    705 	pg_sz = sizeof (isns_portal_group_list_t);
    706 	if (pg_list->pg_out_cnt > 0) {
    707 		pg_sz += (pg_list->pg_out_cnt - 1) *
    708 		    sizeof (isns_portal_group_t);
    709 	}
    710 	kmem_free(pg_list, pg_sz);
    711 }
    712 
    713 void
    714 iscsid_do_isns_query(iscsi_hba_t *ihp)
    715 {
    716 	int pg_sz, query_status;
    717 	isns_portal_group_list_t *pg_list;
    718 
    719 	pg_list = NULL;
    720 	query_status = isns_query(ihp->hba_isid,
    721 	    ihp->hba_name,
    722 	    ihp->hba_alias,
    723 	    ISNS_INITIATOR_NODE_TYPE,
    724 	    &pg_list);
    725 
    726 	if (pg_list == NULL) {
    727 		DTRACE_PROBE1(iscsid_do_isns_query_status,
    728 		    int, query_status);
    729 		return;
    730 	}
    731 
    732 	if ((query_status != isns_ok &&
    733 	    query_status != isns_op_partially_failed)) {
    734 		DTRACE_PROBE1(iscsid_do_isns_query_status,
    735 		    int, query_status);
    736 		pg_sz = sizeof (isns_portal_group_list_t);
    737 		if (pg_list->pg_out_cnt > 0) {
    738 			pg_sz += (pg_list->pg_out_cnt - 1) *
    739 			    sizeof (isns_portal_group_t);
    740 		}
    741 		kmem_free(pg_list, pg_sz);
    742 		return;
    743 	}
    744 
    745 	iscsid_add_pg_list_to_cache(ihp, pg_list);
    746 
    747 	pg_sz = sizeof (isns_portal_group_list_t);
    748 	if (pg_list->pg_out_cnt > 0) {
    749 		pg_sz += (pg_list->pg_out_cnt - 1) *
    750 		    sizeof (isns_portal_group_t);
    751 	}
    752 	kmem_free(pg_list, pg_sz);
    753 }
    754 
    755 /*
    756  * iscsid_config_one - for the given target name, attempt
    757  * to login to all targets associated with name.  If target
    758  * name is not found in discovery queue, reset the discovery
    759  * queue, kick the discovery processes, and then retry.
    760  *
    761  * NOTE: The caller of this function must hold the
    762  *	iscsid_config_semaphore across this call.
    763  */
    764 void
    765 iscsid_config_one(iscsi_hba_t *ihp, char *name, boolean_t protect)
    766 {
    767 	boolean_t	rc	    =	B_FALSE;
    768 	int		retry	    =	0;
    769 	int		lun_online  =	0;
    770 	int		cur_sec	    =	0;
    771 
    772 	if (!modrootloaded && (iscsiboot_prop != NULL)) {
    773 		if (!iscsi_configroot_printed) {
    774 			cmn_err(CE_NOTE, "Configuring"
    775 			    " iSCSI boot session...");
    776 			iscsi_configroot_printed = B_TRUE;
    777 		}
    778 		if (iscsi_net_up == 0) {
    779 			if (iscsi_net_interface(B_FALSE) ==
    780 			    ISCSI_STATUS_SUCCESS) {
    781 				iscsi_net_up = 1;
    782 			} else {
    783 				cmn_err(CE_WARN, "Failed to configure interface"
    784 				    " for iSCSI boot session");
    785 				return;
    786 			}
    787 		}
    788 		while (rc == B_FALSE && retry <
    789 		    iscsi_configroot_retry) {
    790 			rc = iscsid_login_tgt(ihp, name,
    791 			    iSCSIDiscoveryMethodBoot, NULL);
    792 			if (rc == B_FALSE) {
    793 				/*
    794 				 * create boot session
    795 				 */
    796 				iscsi_boot_session_create(ihp,
    797 				    iscsiboot_prop);
    798 				retry++;
    799 				continue;
    800 			}
    801 			rc = iscsid_check_active_boot_conn(ihp);
    802 			if (rc == B_FALSE) {
    803 				/*
    804 				 * no active connection for the boot
    805 				 * session, retry the login until
    806 				 * one is found or the retry count
    807 				 * is exceeded
    808 				 */
    809 				delay(SEC_TO_TICK(ISCSI_CONFIGROOT_DELAY));
    810 				retry++;
    811 				continue;
    812 			}
    813 			/*
    814 			 * The boot session has been created with active
    815 			 * connection. If the target lun has not been online,
    816 			 * we should wait here for a while
    817 			 */
    818 			do {
    819 				lun_online =
    820 				    iscsiboot_prop->boot_tgt.lun_online;
    821 				if (lun_online == 0) {
    822 					delay(SEC_TO_TICK(
    823 					    ISCSI_CONFIGROOT_DELAY));
    824 					cur_sec++;
    825 				}
    826 			} while ((lun_online == 0) &&
    827 			    (cur_sec < iscsi_boot_max_delay));
    828 			retry++;
    829 		}
    830 		if (!rc) {
    831 			cmn_err(CE_WARN, "Failed to configure iSCSI"
    832 			    " boot session");
    833 		}
    834 	} else {
    835 		rc = iscsid_login_tgt(ihp, name, iSCSIDiscoveryMethodUnknown,
    836 		    NULL);
    837 		/*
    838 		 * If we didn't login to the device we might have
    839 		 * to update our discovery information and attempt
    840 		 * the login again.
    841 		 */
    842 		if (rc == B_FALSE) {
    843 			/*
    844 			 * Stale /dev links can cause us to get floods
    845 			 * of config requests.  Prevent these repeated
    846 			 * requests from causing unneeded discovery updates
    847 			 * if ISCSI_CONFIG_STORM_PROTECT is set.
    848 			 */
    849 			if ((protect == B_FALSE) ||
    850 			    (ddi_get_lbolt() > ihp->hba_config_lbolt +
    851 			    SEC_TO_TICK(ihp->hba_config_storm_delay))) {
    852 				ihp->hba_config_lbolt = ddi_get_lbolt();
    853 				iscsid_poke_discovery(ihp,
    854 				    iSCSIDiscoveryMethodUnknown);
    855 				(void) iscsid_login_tgt(ihp, name,
    856 				    iSCSIDiscoveryMethodUnknown, NULL);
    857 			}
    858 		}
    859 	}
    860 }
    861 
    862 /*
    863  * iscsid_config_all - reset the discovery queue, kick the
    864  * discovery processes, and login to all targets found
    865  *
    866  * NOTE: The caller of this function must hold the
    867  *	iscsid_config_semaphore across this call.
    868  */
    869 void
    870 iscsid_config_all(iscsi_hba_t *ihp, boolean_t protect)
    871 {
    872 	boolean_t	rc		= B_FALSE;
    873 	int		retry	= 0;
    874 	int		lun_online  = 0;
    875 	int		cur_sec	= 0;
    876 
    877 	if (!modrootloaded && iscsiboot_prop != NULL) {
    878 		if (!iscsi_configroot_printed) {
    879 			cmn_err(CE_NOTE, "Configuring"
    880 			    " iSCSI boot session...");
    881 			iscsi_configroot_printed = B_TRUE;
    882 		}
    883 		if (iscsi_net_up == 0) {
    884 			if (iscsi_net_interface(B_FALSE) ==
    885 			    ISCSI_STATUS_SUCCESS) {
    886 				iscsi_net_up = 1;
    887 			}
    888 		}
    889 		while (rc == B_FALSE && retry <
    890 		    iscsi_configroot_retry) {
    891 			rc = iscsid_login_tgt(ihp, NULL,
    892 			    iSCSIDiscoveryMethodBoot, NULL);
    893 			if (rc == B_FALSE) {
    894 				/*
    895 				 * No boot session has been created.
    896 				 * We would like to create the boot
    897 				 * Session first.
    898 				 */
    899 				iscsi_boot_session_create(ihp,
    900 				    iscsiboot_prop);
    901 				retry++;
    902 				continue;
    903 			}
    904 			rc = iscsid_check_active_boot_conn(ihp);
    905 			if (rc == B_FALSE) {
    906 				/*
    907 				 * no active connection for the boot
    908 				 * session, retry the login until
    909 				 * one is found or the retry count
    910 				 * is exceeded
    911 				 */
    912 				delay(SEC_TO_TICK(ISCSI_CONFIGROOT_DELAY));
    913 				retry++;
    914 				continue;
    915 			}
    916 			/*
    917 			 * The boot session has been created with active
    918 			 * connection. If the target lun has not been online,
    919 			 * we should wait here for a while
    920 			 */
    921 			do {
    922 				lun_online =
    923 				    iscsiboot_prop->boot_tgt.lun_online;
    924 				if (lun_online == 0) {
    925 					delay(SEC_TO_TICK(
    926 					    ISCSI_CONFIGROOT_DELAY));
    927 					cur_sec++;
    928 				}
    929 			} while ((lun_online == 0) &&
    930 			    (cur_sec < iscsi_boot_max_delay));
    931 			retry++;
    932 		}
    933 		if (!rc) {
    934 			cmn_err(CE_WARN, "Failed to configure"
    935 			    " boot session");
    936 		}
    937 	} else {
    938 		/*
    939 		 * Stale /dev links can cause us to get floods
    940 		 * of config requests.  Prevent these repeated
    941 		 * requests from causing unneeded discovery updates
    942 		 * if ISCSI_CONFIG_STORM_PROTECT is set.
    943 		 */
    944 		if ((protect == B_FALSE) ||
    945 		    (ddi_get_lbolt() > ihp->hba_config_lbolt +
    946 		    SEC_TO_TICK(ihp->hba_config_storm_delay))) {
    947 			ihp->hba_config_lbolt = ddi_get_lbolt();
    948 			iscsid_poke_discovery(ihp,
    949 			    iSCSIDiscoveryMethodUnknown);
    950 		}
    951 		(void) iscsid_login_tgt(ihp, NULL,
    952 		    iSCSIDiscoveryMethodUnknown, NULL);
    953 	}
    954 }
    955 
    956 /*
    957  * isns_scn_callback - iSNS client received an SCN
    958  *
    959  * This code processes the iSNS client SCN events.  These
    960  * could relate to the addition, removal, or update of a
    961  * logical unit.
    962  */
    963 void
    964 isns_scn_callback(void *arg)
    965 {
    966 	int				i, pg_sz;
    967 	int				qry_status;
    968 	isns_portal_group_list_t	*pg_list;
    969 	uint32_t			scn_type;
    970 	iscsi_hba_t			*ihp;
    971 
    972 	if (arg == NULL) {
    973 		/* No argument */
    974 		return;
    975 	}
    976 
    977 	if ((ihp = (iscsi_hba_t *)ddi_get_soft_state(iscsi_state, 0)) == NULL) {
    978 		kmem_free(arg, sizeof (isns_scn_callback_arg_t));
    979 		return;
    980 	}
    981 
    982 	/*
    983 	 * All isns callbacks are from a standalone taskq
    984 	 * therefore the blocking here doesn't affect the enable/disable
    985 	 * of isns discovery method
    986 	 */
    987 	if (iscsi_client_request_service(ihp) == B_FALSE) {
    988 		kmem_free(arg, sizeof (isns_scn_callback_arg_t));
    989 		return;
    990 	}
    991 
    992 	scn_type = ((isns_scn_callback_arg_t *)arg)->scn_type;
    993 	DTRACE_PROBE1(isns_scn_callback_scn_type, int, scn_type);
    994 	switch (scn_type) {
    995 	/*
    996 	 * ISNS_OBJ_ADDED - An object has been added.
    997 	 */
    998 	case ISNS_OBJ_ADDED:
    999 		/* Query iSNS server for contact information */
   1000 		pg_list = NULL;
   1001 		qry_status = isns_query_one_node(
   1002 		    ((isns_scn_callback_arg_t *)arg)->source_key_attr,
   1003 		    ihp->hba_isid,
   1004 		    ihp->hba_name,
   1005 		    (uint8_t *)"",
   1006 		    ISNS_INITIATOR_NODE_TYPE,
   1007 		    &pg_list);
   1008 
   1009 		/* Verify portal group is found */
   1010 		if ((qry_status != isns_ok &&
   1011 		    qry_status != isns_op_partially_failed) ||
   1012 		    pg_list == NULL) {
   1013 			break;
   1014 		}
   1015 
   1016 		DTRACE_PROBE1(pg_list,
   1017 		    isns_portal_group_list_t *, pg_list);
   1018 
   1019 		/* Add all portals for logical unit to discovery cache */
   1020 		for (i = 0; i < pg_list->pg_out_cnt; i++) {
   1021 			iscsi_sockaddr_t addr_dsc;
   1022 			iscsi_sockaddr_t addr_tgt;
   1023 
   1024 			iscsid_addr_to_sockaddr(
   1025 			    pg_list->pg_list[i].isns_server_ip.i_insize,
   1026 			    &pg_list->pg_list[i].isns_server_ip.i_addr,
   1027 			    pg_list->pg_list[i].isns_server_port,
   1028 			    &addr_dsc.sin);
   1029 			iscsid_addr_to_sockaddr(pg_list->pg_list[i].insize,
   1030 			    &pg_list->pg_list[i].pg_ip_addr,
   1031 			    pg_list->pg_list[i].pg_port, &addr_tgt.sin);
   1032 
   1033 			(void) iscsid_add(ihp, iSCSIDiscoveryMethodISNS,
   1034 			    &addr_dsc.sin, (char *)pg_list->pg_list[i].
   1035 			    pg_iscsi_name, pg_list->pg_list[i].pg_tag,
   1036 			    &addr_tgt.sin);
   1037 
   1038 			/* Force target to login */
   1039 			(void) iscsid_login_tgt(ihp, (char *)pg_list->
   1040 			    pg_list[i].pg_iscsi_name, iSCSIDiscoveryMethodISNS,
   1041 			    NULL);
   1042 		}
   1043 
   1044 		if (pg_list != NULL) {
   1045 			pg_sz = sizeof (isns_portal_group_list_t);
   1046 			if (pg_list->pg_out_cnt > 0) {
   1047 				pg_sz += (pg_list->pg_out_cnt - 1) *
   1048 				    sizeof (isns_portal_group_t);
   1049 			}
   1050 			kmem_free(pg_list, pg_sz);
   1051 		}
   1052 		break;
   1053 
   1054 	/*
   1055 	 * ISNS_OBJ_REMOVED - logical unit has been removed
   1056 	 */
   1057 	case ISNS_OBJ_REMOVED:
   1058 		if (iscsid_del(ihp,
   1059 		    (char *)((isns_scn_callback_arg_t *)arg)->
   1060 		    source_key_attr, iSCSIDiscoveryMethodISNS, NULL) !=
   1061 		    B_TRUE) {
   1062 			cmn_err(CE_NOTE, "iscsi initiator - "
   1063 			    "isns remove scn failed for target %s\n",
   1064 			    (char *)((isns_scn_callback_arg_t *)arg)->
   1065 			    source_key_attr);
   1066 
   1067 		}
   1068 		break;
   1069 
   1070 	/*
   1071 	 * ISNS_OBJ_UPDATED - logical unit has changed
   1072 	 */
   1073 	case ISNS_OBJ_UPDATED:
   1074 		cmn_err(CE_NOTE, "iscsi initiator - "
   1075 		    "received iSNS update SCN for %s\n",
   1076 		    (char *)((isns_scn_callback_arg_t *)arg)->
   1077 		    source_key_attr);
   1078 		break;
   1079 
   1080 	/*
   1081 	 * ISNS_OBJ_UNKNOWN -
   1082 	 */
   1083 	default:
   1084 		cmn_err(CE_NOTE, "iscsi initiator - "
   1085 		    "received unknown iSNS SCN type 0x%x\n", scn_type);
   1086 		break;
   1087 	}
   1088 
   1089 	iscsi_client_release_service(ihp);
   1090 	kmem_free(arg, sizeof (isns_scn_callback_arg_t));
   1091 }
   1092 
   1093 
   1094 /*
   1095  * iscsid_add - Creates discovered session and connection
   1096  */
   1097 static boolean_t
   1098 iscsid_add(iscsi_hba_t *ihp, iSCSIDiscoveryMethod_t method,
   1099     struct sockaddr *addr_dsc, char *target_name, int tpgt,
   1100     struct sockaddr *addr_tgt)
   1101 {
   1102 	boolean_t	    rtn = B_TRUE;
   1103 	iscsi_sess_t	    *isp;
   1104 	iscsi_conn_t	    *icp;
   1105 	uint_t		    oid;
   1106 	int		    idx;
   1107 	int		    isid;
   1108 	iscsi_config_sess_t *ics;
   1109 	int		    size;
   1110 	char		    *tmp;
   1111 
   1112 	ASSERT(ihp != NULL);
   1113 	ASSERT(addr_dsc != NULL);
   1114 	ASSERT(target_name != NULL);
   1115 	ASSERT(addr_tgt != NULL);
   1116 
   1117 	/* setup initial buffer for configured session information */
   1118 	size = sizeof (*ics);
   1119 	ics = kmem_zalloc(size, KM_SLEEP);
   1120 	ics->ics_in = 1;
   1121 
   1122 	/* get configured sessions information */
   1123 	tmp = target_name;
   1124 	if (persistent_get_config_session(tmp, ics) == B_FALSE) {
   1125 		/*
   1126 		 * No target information available check for
   1127 		 * initiator information.
   1128 		 */
   1129 		tmp = (char *)ihp->hba_name;
   1130 		if (persistent_get_config_session(tmp, ics) == B_FALSE) {
   1131 			/*
   1132 			 * No hba information is
   1133 			 * found.  So assume default
   1134 			 * one session unbound behavior.
   1135 			 */
   1136 			ics->ics_out = 1;
   1137 			ics->ics_bound = B_TRUE;
   1138 		}
   1139 	}
   1140 
   1141 	if (iscsiboot_prop && (ics->ics_out > 1) &&
   1142 	    !iscsi_chk_bootlun_mpxio(ihp)) {
   1143 		/*
   1144 		 * iscsi boot with mpxio disabled
   1145 		 * no need to search configured boot session
   1146 		 */
   1147 
   1148 		if (iscsi_cmp_boot_ini_name(tmp) ||
   1149 		    iscsi_cmp_boot_tgt_name(tmp)) {
   1150 			ics->ics_out = 1;
   1151 			ics->ics_bound = B_FALSE;
   1152 		}
   1153 	}
   1154 	/* Check to see if we need to get more information */
   1155 	if (ics->ics_out > 1) {
   1156 		/* record new size and free last buffer */
   1157 		idx = ics->ics_out;
   1158 		size = ISCSI_SESSION_CONFIG_SIZE(ics->ics_out);
   1159 		kmem_free(ics, sizeof (*ics));
   1160 
   1161 		/* allocate new buffer */
   1162 		ics = kmem_zalloc(size, KM_SLEEP);
   1163 		ics->ics_in = idx;
   1164 
   1165 		/* get configured sessions information */
   1166 		if (persistent_get_config_session(tmp, ics) != B_TRUE) {
   1167 			cmn_err(CE_NOTE, "iscsi session(%s) - "
   1168 			    "unable to get configured session information\n",
   1169 			    target_name);
   1170 			kmem_free(ics, size);
   1171 			return (B_FALSE);
   1172 		}
   1173 	}
   1174 
   1175 	/* loop for all configured sessions */
   1176 	rw_enter(&ihp->hba_sess_list_rwlock, RW_WRITER);
   1177 	for (isid = 0; isid < ics->ics_out; isid++) {
   1178 		/* create or find matching session */
   1179 		isp = iscsi_sess_create(ihp, method, addr_dsc, target_name,
   1180 		    tpgt, isid, ISCSI_SESS_TYPE_NORMAL, &oid);
   1181 		if (isp == NULL) {
   1182 			rtn = B_FALSE;
   1183 			break;
   1184 		}
   1185 
   1186 		/* create or find matching connection */
   1187 		if (!ISCSI_SUCCESS(iscsi_conn_create(addr_tgt, isp, &icp))) {
   1188 			/*
   1189 			 * Teardown the session we just created.  It can't
   1190 			 * have any luns or connections associated with it
   1191 			 * so this should always succeed (luckily since what
   1192 			 * would we do if it failed?)
   1193 			 */
   1194 			(void) iscsi_sess_destroy(isp);
   1195 			rtn = B_FALSE;
   1196 			break;
   1197 		}
   1198 	}
   1199 	rw_exit(&ihp->hba_sess_list_rwlock);
   1200 	kmem_free(ics, size);
   1201 	return (rtn);
   1202 }
   1203 
   1204 /*
   1205  * iscsid_del - Attempts to delete all associated sessions
   1206  */
   1207 boolean_t
   1208 iscsid_del(iscsi_hba_t *ihp, char *target_name,
   1209     iSCSIDiscoveryMethod_t method, struct sockaddr *addr_dsc)
   1210 {
   1211 	boolean_t	rtn = B_TRUE;
   1212 	iscsi_status_t	status;
   1213 	iscsi_sess_t	*isp;
   1214 	char		name[ISCSI_MAX_NAME_LEN];
   1215 
   1216 	ASSERT(ihp != NULL);
   1217 	/* target name can be NULL or !NULL */
   1218 	/* addr_dsc can be NULL or !NULL */
   1219 
   1220 	rw_enter(&ihp->hba_sess_list_rwlock, RW_WRITER);
   1221 	isp = ihp->hba_sess_list;
   1222 	while (isp != NULL) {
   1223 		/*
   1224 		 * If no target_name is listed (meaning all targets)
   1225 		 * or this specific target was listed. And the same
   1226 		 * discovery method discovered this target then
   1227 		 * continue evaulation.  Otherwise fail.
   1228 		 */
   1229 		if (((target_name == NULL) ||
   1230 		    (strcmp((char *)isp->sess_name, target_name) == 0)) &&
   1231 		    (isp->sess_discovered_by == method)) {
   1232 			boolean_t try_destroy;
   1233 
   1234 			/*
   1235 			 * If iSNS, SendTargets, or Static then special
   1236 			 * handling for disc_addr.
   1237 			 */
   1238 			if ((method == iSCSIDiscoveryMethodISNS) ||
   1239 			    (method == iSCSIDiscoveryMethodSendTargets)) {
   1240 				/*
   1241 				 * If NULL addr_dsc (meaning all disc_addr)
   1242 				 * or matching discovered addr.
   1243 				 */
   1244 				if ((addr_dsc == NULL) ||
   1245 				    (bcmp(addr_dsc, &isp->sess_discovered_addr,
   1246 				    SIZEOF_SOCKADDR(
   1247 				    &isp->sess_discovered_addr.sin)) == 0)) {
   1248 					try_destroy = B_TRUE;
   1249 				} else {
   1250 					try_destroy = B_FALSE;
   1251 				}
   1252 			} else if (method == iSCSIDiscoveryMethodStatic) {
   1253 				/*
   1254 				 * If NULL addr_dsc (meaning all disc_addr)
   1255 				 * or matching active connection.
   1256 				 */
   1257 				if ((addr_dsc == NULL) ||
   1258 				    ((isp->sess_conn_act != NULL) &&
   1259 				    (bcmp(addr_dsc,
   1260 				    &isp->sess_conn_act->conn_base_addr.sin,
   1261 				    SIZEOF_SOCKADDR(
   1262 				    &isp->sess_conn_act->conn_base_addr.sin))
   1263 				    == 0))) {
   1264 					try_destroy = B_TRUE;
   1265 				} else {
   1266 					try_destroy = B_FALSE;
   1267 				}
   1268 			} else {
   1269 				/* Unknown discovery specified */
   1270 				try_destroy = B_TRUE;
   1271 			}
   1272 
   1273 			if (try_destroy == B_TRUE &&
   1274 			    isp->sess_boot == B_FALSE) {
   1275 				(void) strcpy(name, (char *)isp->sess_name);
   1276 				status = iscsi_sess_destroy(isp);
   1277 				if (ISCSI_SUCCESS(status)) {
   1278 					iscsid_remove_target_param(name);
   1279 					isp = ihp->hba_sess_list;
   1280 				} else {
   1281 					/*
   1282 					 * The most likely destroy failure
   1283 					 * is that ndi/mdi offline failed.
   1284 					 * This means that the resource is
   1285 					 * in_use/busy.
   1286 					 */
   1287 					cmn_err(CE_NOTE, "iscsi session(%d) - "
   1288 					    "session logout failed (%d)\n",
   1289 					    isp->sess_oid, status);
   1290 					isp = isp->sess_next;
   1291 					rtn = B_FALSE;
   1292 				}
   1293 			} else {
   1294 				isp = isp->sess_next;
   1295 			}
   1296 		} else {
   1297 			isp = isp->sess_next;
   1298 		}
   1299 	}
   1300 	rw_exit(&ihp->hba_sess_list_rwlock);
   1301 	return (rtn);
   1302 }
   1303 
   1304 
   1305 /*
   1306  * iscsid_login_tgt - request target(s) to login
   1307  */
   1308 boolean_t
   1309 iscsid_login_tgt(iscsi_hba_t *ihp, char *target_name,
   1310     iSCSIDiscoveryMethod_t method, struct sockaddr *addr_dsc)
   1311 {
   1312 	boolean_t		rtn		= B_FALSE;
   1313 	iscsi_sess_t		*isp		= NULL;
   1314 	iscsi_sess_list_t	*isp_list	= NULL;
   1315 	iscsi_sess_list_t	*last_sess	= NULL;
   1316 	iscsi_sess_list_t	*cur_sess	= NULL;
   1317 	int			total		= 0;
   1318 	ddi_taskq_t		*login_taskq	= NULL;
   1319 	char			taskq_name[ISCSI_TH_MAX_NAME_LEN] = {0};
   1320 	time_t			time_stamp;
   1321 
   1322 	ASSERT(ihp != NULL);
   1323 
   1324 	rw_enter(&ihp->hba_sess_list_rwlock, RW_WRITER);
   1325 	/* Loop thru sessions */
   1326 	isp = ihp->hba_sess_list;
   1327 	while (isp != NULL) {
   1328 		boolean_t try_online;
   1329 		if (!(method & iSCSIDiscoveryMethodBoot)) {
   1330 			if (target_name == NULL) {
   1331 				if (method == iSCSIDiscoveryMethodUnknown) {
   1332 					/* unknown method mean login to all */
   1333 					try_online = B_TRUE;
   1334 				} else if (isp->sess_discovered_by & method) {
   1335 					if ((method ==
   1336 					    iSCSIDiscoveryMethodISNS) ||
   1337 					    (method ==
   1338 					    iSCSIDiscoveryMethodSendTargets)) {
   1339 #define	SESS_DISC_ADDR	isp->sess_discovered_addr.sin
   1340 						if ((addr_dsc == NULL) ||
   1341 						    (bcmp(
   1342 						    &isp->sess_discovered_addr,
   1343 						    addr_dsc, SIZEOF_SOCKADDR(
   1344 						    &SESS_DISC_ADDR))
   1345 						    == 0)) {
   1346 							/*
   1347 							 * iSNS or sendtarget
   1348 							 * discovery and
   1349 							 * discovery address
   1350 							 * is NULL or match
   1351 							 */
   1352 							try_online = B_TRUE;
   1353 						} else {
   1354 						/* addr_dsc not a match */
   1355 							try_online = B_FALSE;
   1356 						}
   1357 #undef SESS_DISC_ADDR
   1358 					} else {
   1359 						/* static configuration */
   1360 						try_online = B_TRUE;
   1361 					}
   1362 				} else {
   1363 					/* method not a match */
   1364 					try_online = B_FALSE;
   1365 				}
   1366 			} else if (strcmp(target_name,
   1367 			    (char *)isp->sess_name) == 0) {
   1368 				/* target_name match */
   1369 				try_online = B_TRUE;
   1370 			} else {
   1371 				/* target_name not a match */
   1372 				try_online = B_FALSE;
   1373 			}
   1374 		} else {
   1375 			/*
   1376 			 * online the boot session.
   1377 			 */
   1378 			if (isp->sess_boot == B_TRUE) {
   1379 				try_online = B_TRUE;
   1380 			}
   1381 		}
   1382 
   1383 		if (try_online == B_TRUE &&
   1384 		    isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
   1385 			total++;
   1386 			/* Copy these sessions to the list. */
   1387 			if (isp_list == NULL) {
   1388 				isp_list =
   1389 				    (iscsi_sess_list_t *)kmem_zalloc(
   1390 				    sizeof (iscsi_sess_list_t), KM_SLEEP);
   1391 				last_sess = isp_list;
   1392 				last_sess->session = isp;
   1393 				last_sess->next = NULL;
   1394 			} else {
   1395 				last_sess->next =
   1396 				    (iscsi_sess_list_t *)kmem_zalloc(
   1397 				    sizeof (iscsi_sess_list_t), KM_SLEEP);
   1398 				last_sess->next->session = isp;
   1399 				last_sess->next->next = NULL;
   1400 				last_sess = last_sess->next;
   1401 			}
   1402 			rtn = B_TRUE;
   1403 		}
   1404 
   1405 		isp = isp->sess_next;
   1406 	}
   1407 
   1408 	if (total > 0) {
   1409 		time_stamp = ddi_get_time();
   1410 		(void) snprintf(taskq_name, (ISCSI_TH_MAX_NAME_LEN - 1),
   1411 		    "login_queue.%lx", time_stamp);
   1412 
   1413 		login_taskq = ddi_taskq_create(ihp->hba_dip,
   1414 		    taskq_name, total, TASKQ_DEFAULTPRI, 0);
   1415 		if (login_taskq == NULL) {
   1416 			while (isp_list != NULL) {
   1417 				cur_sess = isp_list;
   1418 				isp_list = isp_list->next;
   1419 				kmem_free(cur_sess, sizeof (iscsi_sess_list_t));
   1420 			}
   1421 			rtn = B_FALSE;
   1422 			rw_exit(&ihp->hba_sess_list_rwlock);
   1423 			return (rtn);
   1424 		}
   1425 
   1426 		for (cur_sess = isp_list; cur_sess != NULL;
   1427 		    cur_sess = cur_sess->next) {
   1428 			if (ddi_taskq_dispatch(login_taskq,
   1429 			    iscsi_sess_online, (void *)cur_sess->session,
   1430 			    DDI_SLEEP) != DDI_SUCCESS) {
   1431 				cmn_err(CE_NOTE, "Can't dispatch the task "
   1432 				    "for login to the target: %s",
   1433 				    cur_sess->session->sess_name);
   1434 			}
   1435 		}
   1436 
   1437 		ddi_taskq_wait(login_taskq);
   1438 		ddi_taskq_destroy(login_taskq);
   1439 		while (isp_list != NULL) {
   1440 			cur_sess = isp_list;
   1441 			isp_list = isp_list->next;
   1442 			kmem_free(cur_sess, sizeof (iscsi_sess_list_t));
   1443 		}
   1444 
   1445 	}
   1446 
   1447 	rw_exit(&ihp->hba_sess_list_rwlock);
   1448 	return (rtn);
   1449 }
   1450 
   1451 /*
   1452  * +--------------------------------------------------------------------+
   1453  * | Local Helper Functions                                             |
   1454  * +--------------------------------------------------------------------+
   1455  */
   1456 
   1457 /*
   1458  * iscsid_init_config -- initialize configuration parameters of iSCSI initiator
   1459  */
   1460 static boolean_t
   1461 iscsid_init_config(iscsi_hba_t *ihp)
   1462 {
   1463 	iscsi_param_set_t	ips;
   1464 	void *v = NULL;
   1465 	char *name;
   1466 	char *initiatorName;
   1467 	persistent_param_t	pp;
   1468 	persistent_tunable_param_t pparam;
   1469 	uint32_t		param_id;
   1470 	int			rc;
   1471 
   1472 	/* allocate memory to hold initiator names */
   1473 	initiatorName = kmem_zalloc(ISCSI_MAX_NAME_LEN, KM_SLEEP);
   1474 
   1475 	/*
   1476 	 * initialize iSCSI initiator name
   1477 	 */
   1478 	bzero(&ips, sizeof (ips));
   1479 	if (persistent_initiator_name_get(initiatorName,
   1480 	    ISCSI_MAX_NAME_LEN) == B_TRUE) {
   1481 		ips.s_vers	= ISCSI_INTERFACE_VERSION;
   1482 		ips.s_param	= ISCSI_LOGIN_PARAM_INITIATOR_NAME;
   1483 
   1484 		if (iscsiboot_prop && !iscsi_cmp_boot_ini_name(initiatorName)) {
   1485 			(void) strncpy(initiatorName,
   1486 			    (const char *)iscsiboot_prop->boot_init.ini_name,
   1487 			    ISCSI_MAX_NAME_LEN);
   1488 			(void) strncpy((char *)ips.s_value.v_name,
   1489 			    (const char *)iscsiboot_prop->boot_init.ini_name,
   1490 			    sizeof (ips.s_value.v_name));
   1491 			(void) iscsi_set_params(&ips, ihp, B_TRUE);
   1492 			/* use default tunable value */
   1493 			ihp->hba_tunable_params.recv_login_rsp_timeout =
   1494 			    ISCSI_DEFAULT_RX_TIMEOUT_VALUE;
   1495 			ihp->hba_tunable_params.polling_login_delay =
   1496 			    ISCSI_DEFAULT_LOGIN_POLLING_DELAY;
   1497 			ihp->hba_tunable_params.conn_login_max =
   1498 			    ISCSI_DEFAULT_CONN_DEFAULT_LOGIN_MAX;
   1499 			cmn_err(CE_NOTE, "Set initiator's name"
   1500 			    " from firmware");
   1501 		} else {
   1502 			(void) strncpy((char *)ips.s_value.v_name,
   1503 			    initiatorName, sizeof (ips.s_value.v_name));
   1504 
   1505 			(void) iscsi_set_params(&ips, ihp, B_FALSE);
   1506 			if (persistent_get_tunable_param(initiatorName,
   1507 			    &pparam) == B_FALSE) {
   1508 				/* use default value */
   1509 				pparam.p_params.recv_login_rsp_timeout =
   1510 				    ISCSI_DEFAULT_RX_TIMEOUT_VALUE;
   1511 				pparam.p_params.polling_login_delay =
   1512 				    ISCSI_DEFAULT_LOGIN_POLLING_DELAY;
   1513 				pparam.p_params.conn_login_max =
   1514 				    ISCSI_DEFAULT_CONN_DEFAULT_LOGIN_MAX;
   1515 			}
   1516 			bcopy(&pparam.p_params, &ihp->hba_tunable_params,
   1517 			    sizeof (iscsi_tunable_params_t));
   1518 		}
   1519 	} else {
   1520 		/*
   1521 		 * if no initiator-node name available it is most
   1522 		 * likely due to a fresh install, or the persistent
   1523 		 * store is not working correctly. Set
   1524 		 * a default initiator name so that the initiator can
   1525 		 * be brought up properly.
   1526 		 */
   1527 		iscsid_set_default_initiator_node_settings(ihp, B_FALSE);
   1528 		(void) strncpy(initiatorName, (const char *)ihp->hba_name,
   1529 		    ISCSI_MAX_NAME_LEN);
   1530 	}
   1531 
   1532 	/*
   1533 	 * initialize iSCSI initiator alias (if any)
   1534 	 */
   1535 	bzero(&ips, sizeof (ips));
   1536 	if (persistent_alias_name_get((char *)ips.s_value.v_name,
   1537 	    sizeof (ips.s_value.v_name)) == B_TRUE) {
   1538 		ips.s_param	= ISCSI_LOGIN_PARAM_INITIATOR_ALIAS;
   1539 		(void) iscsi_set_params(&ips, ihp, B_FALSE);
   1540 	} else {
   1541 		/* EMPTY */
   1542 		/* No alias defined - not a problem. */
   1543 	}
   1544 
   1545 	/*
   1546 	 * load up the overriden iSCSI initiator parameters
   1547 	 */
   1548 	name = kmem_zalloc(ISCSI_MAX_NAME_LEN, KM_SLEEP);
   1549 	persistent_param_lock();
   1550 	v = NULL;
   1551 	while (persistent_param_next(&v, name, &pp) == B_TRUE) {
   1552 		if (strncmp(name, initiatorName, ISCSI_MAX_NAME_LEN) == 0) {
   1553 			ips.s_oid = ihp->hba_oid;
   1554 			ips.s_vers = ISCSI_INTERFACE_VERSION;
   1555 			for (param_id = 0; param_id < ISCSI_NUM_LOGIN_PARAM;
   1556 			    param_id++) {
   1557 				if (pp.p_bitmap & (1 << param_id)) {
   1558 					rc = iscsid_copyto_param_set(param_id,
   1559 					    &pp.p_params, &ips);
   1560 					if (rc == 0) {
   1561 						rc = iscsi_set_params(&ips,
   1562 						    ihp, B_FALSE);
   1563 					}
   1564 					if (rc != 0) {
   1565 						/* note error but continue  */
   1566 						cmn_err(CE_NOTE,
   1567 						    "Failed to set "
   1568 						    "param %d for OID %d",
   1569 						    ips.s_param, ips.s_oid);
   1570 					}
   1571 				}
   1572 			} /* END for() */
   1573 			if (iscsiboot_prop &&
   1574 			    iscsi_chk_bootlun_mpxio(ihp)) {
   1575 				(void) iscsi_reconfig_boot_sess(ihp);
   1576 			}
   1577 			break;
   1578 		}
   1579 	} /* END while() */
   1580 	persistent_param_unlock();
   1581 
   1582 	kmem_free(initiatorName, ISCSI_MAX_NAME_LEN);
   1583 	kmem_free(name, ISCSI_MAX_NAME_LEN);
   1584 	return (B_TRUE);
   1585 }
   1586 
   1587 
   1588 /*
   1589  * iscsid_init_targets -- Load up the driver with known static targets and
   1590  * targets whose parameters have been modified.
   1591  *
   1592  * This is done so that the CLI can find a list of targets the driver
   1593  * currently knows about.
   1594  *
   1595  * The driver doesn't need to log into these targets.  Log in is done based
   1596  * upon the enabled discovery methods.
   1597  */
   1598 static boolean_t
   1599 iscsid_init_targets(iscsi_hba_t *ihp)
   1600 {
   1601 	void			*v = NULL;
   1602 	char			*name;
   1603 	iscsi_param_set_t	ips;
   1604 	persistent_param_t	pp;
   1605 	char			*iname;
   1606 	uint32_t		param_id;
   1607 	int			rc;
   1608 
   1609 	ASSERT(ihp != NULL);
   1610 
   1611 	/* allocate memory to hold target names */
   1612 	name = kmem_zalloc(ISCSI_MAX_NAME_LEN, KM_SLEEP);
   1613 
   1614 	/*
   1615 	 * load up targets whose parameters have been overriden
   1616 	 */
   1617 
   1618 	/* ---- only need to be set once ---- */
   1619 	bzero(&ips, sizeof (ips));
   1620 	ips.s_vers = ISCSI_INTERFACE_VERSION;
   1621 
   1622 	/* allocate memory to hold initiator name */
   1623 	iname = kmem_zalloc(ISCSI_MAX_NAME_LEN, KM_SLEEP);
   1624 	(void) persistent_initiator_name_get(iname, ISCSI_MAX_NAME_LEN);
   1625 
   1626 	persistent_param_lock();
   1627 	v = NULL;
   1628 	while (persistent_param_next(&v, name, &pp) == B_TRUE) {
   1629 
   1630 		if (strncmp(iname, name, ISCSI_MAX_NAME_LEN) == 0) {
   1631 			/*
   1632 			 * target name matched initiator's name so,
   1633 			 * continue to next target.  Initiator's
   1634 			 * parmeters have already been set.
   1635 			 */
   1636 			continue;
   1637 		}
   1638 
   1639 		if (iscsiboot_prop && iscsi_cmp_boot_tgt_name(name) &&
   1640 		    !iscsi_chk_bootlun_mpxio(ihp)) {
   1641 			/*
   1642 			 * boot target is not mpxio enabled
   1643 			 * simply ignore these overriden parameters
   1644 			 */
   1645 			continue;
   1646 		}
   1647 
   1648 		ips.s_oid = iscsi_targetparam_get_oid((unsigned char *)name);
   1649 
   1650 		for (param_id = 0; param_id < ISCSI_NUM_LOGIN_PARAM;
   1651 		    param_id++) {
   1652 			if (pp.p_bitmap & (1 << param_id)) {
   1653 				rc = iscsid_copyto_param_set(param_id,
   1654 				    &pp.p_params, &ips);
   1655 				if (rc == 0) {
   1656 					rc = iscsi_set_params(&ips,
   1657 					    ihp, B_FALSE);
   1658 				}
   1659 				if (rc != 0) {
   1660 					/* note error but continue  ---- */
   1661 					cmn_err(CE_NOTE, "Failed to set "
   1662 					    "param %d for OID %d",
   1663 					    ips.s_param, ips.s_oid);
   1664 				}
   1665 			}
   1666 		} /* END for() */
   1667 		if (iscsiboot_prop && iscsi_cmp_boot_tgt_name(name) &&
   1668 		    iscsi_chk_bootlun_mpxio(ihp)) {
   1669 			(void) iscsi_reconfig_boot_sess(ihp);
   1670 		}
   1671 	} /* END while() */
   1672 	persistent_param_unlock();
   1673 
   1674 	kmem_free(iname, ISCSI_MAX_NAME_LEN);
   1675 	kmem_free(name, ISCSI_MAX_NAME_LEN);
   1676 
   1677 	return (B_TRUE);
   1678 }
   1679 
   1680 
   1681 /*
   1682  * iscsid_thread_static -- If static discovery is enabled, this routine obtains
   1683  * all statically configured targets from the peristent store and issues a
   1684  * login request to the driver.
   1685  */
   1686 /* ARGSUSED */
   1687 static void
   1688 iscsid_thread_static(iscsi_thread_t *thread, void *p)
   1689 {
   1690 	iSCSIDiscoveryMethod_t	dm;
   1691 	entry_t			entry;
   1692 	char			name[ISCSI_MAX_NAME_LEN];
   1693 	void			*v = NULL;
   1694 	iscsi_hba_t		*ihp = (iscsi_hba_t *)p;
   1695 
   1696 	while (iscsi_thread_wait(thread, -1) != 0) {
   1697 		iscsi_discovery_event(ihp, iSCSIDiscoveryMethodStatic, B_TRUE);
   1698 
   1699 		/* ---- ensure static target discovery is enabled ---- */
   1700 		dm = persistent_disc_meth_get();
   1701 		if ((dm & iSCSIDiscoveryMethodStatic) == 0) {
   1702 			cmn_err(CE_NOTE,
   1703 			    "iscsi discovery failure - "
   1704 			    "StaticTargets method is not enabled");
   1705 			iscsi_discovery_event(ihp,
   1706 			    iSCSIDiscoveryMethodStatic, B_FALSE);
   1707 			continue;
   1708 		}
   1709 
   1710 		/*
   1711 		 * walk list of the statically configured targets from the
   1712 		 * persistent store
   1713 		 */
   1714 		v = NULL;
   1715 		persistent_static_addr_lock();
   1716 		while (persistent_static_addr_next(&v, name, &entry) ==
   1717 		    B_TRUE) {
   1718 			iscsi_sockaddr_t addr;
   1719 
   1720 			iscsid_addr_to_sockaddr(entry.e_insize,
   1721 			    &(entry.e_u), entry.e_port, &addr.sin);
   1722 
   1723 			(void) iscsid_add(ihp, iSCSIDiscoveryMethodStatic,
   1724 			    &addr.sin, name, entry.e_tpgt, &addr.sin);
   1725 		}
   1726 		persistent_static_addr_unlock();
   1727 		iscsi_discovery_event(ihp, iSCSIDiscoveryMethodStatic, B_FALSE);
   1728 	}
   1729 }
   1730 
   1731 
   1732 /*
   1733  * iscsid_thread_sendtgts -- If SendTargets discovery is enabled, this routine
   1734  * obtains all target discovery addresses configured from the peristent store
   1735  * and probe the IP/port addresses for possible targets.  It will then issue
   1736  * a login request to the driver for all discoveryed targets.
   1737  */
   1738 static void
   1739 iscsid_thread_sendtgts(iscsi_thread_t *thread, void *p)
   1740 {
   1741 	iscsi_hba_t		*ihp = (iscsi_hba_t *)p;
   1742 	iSCSIDiscoveryMethod_t	dm;
   1743 	entry_t			entry;
   1744 	void			*v = NULL;
   1745 
   1746 	while (iscsi_thread_wait(thread, -1) != 0) {
   1747 		iscsi_discovery_event(ihp, iSCSIDiscoveryMethodSendTargets,
   1748 		    B_TRUE);
   1749 
   1750 		/* ---- ensure SendTargets discovery is enabled ---- */
   1751 		dm = persistent_disc_meth_get();
   1752 		if ((dm & iSCSIDiscoveryMethodSendTargets) == 0) {
   1753 			cmn_err(CE_NOTE,
   1754 			    "iscsi discovery failure - "
   1755 			    "SendTargets method is not enabled");
   1756 			iscsi_discovery_event(ihp,
   1757 			    iSCSIDiscoveryMethodSendTargets, B_FALSE);
   1758 			continue;
   1759 		}
   1760 		/*
   1761 		 * walk list of the SendTarget discovery addresses from the
   1762 		 * persistent store
   1763 		 */
   1764 		v = NULL;
   1765 		persistent_disc_addr_lock();
   1766 		while (persistent_disc_addr_next(&v, &entry) == B_TRUE) {
   1767 			iscsid_do_sendtgts(&entry);
   1768 		}
   1769 		persistent_disc_addr_unlock();
   1770 
   1771 		iscsi_discovery_event(ihp, iSCSIDiscoveryMethodSendTargets,
   1772 		    B_FALSE);
   1773 	}
   1774 }
   1775 
   1776 /*
   1777  * iscsid_thread_slp -- If SLP discovery is enabled,  this routine provides
   1778  * the SLP discovery service.
   1779  */
   1780 static void
   1781 iscsid_thread_slp(iscsi_thread_t *thread, void *p)
   1782 {
   1783 	iscsi_hba_t  *ihp = (iscsi_hba_t *)p;
   1784 
   1785 	do {
   1786 		/*
   1787 		 * Even though we don't have support for SLP at this point
   1788 		 * we'll send the events if someone has enabled this thread.
   1789 		 * If this is not done the daemon waiting for discovery to
   1790 		 * complete will pause forever holding up the boot process.
   1791 		 */
   1792 		iscsi_discovery_event(ihp, iSCSIDiscoveryMethodSLP, B_TRUE);
   1793 		iscsi_discovery_event(ihp, iSCSIDiscoveryMethodSLP, B_FALSE);
   1794 	} while (iscsi_thread_wait(thread, -1) != 0);
   1795 }
   1796 
   1797 /*
   1798  * iscsid_thread_isns --
   1799  */
   1800 static void
   1801 iscsid_thread_isns(iscsi_thread_t *thread, void *ptr)
   1802 {
   1803 	iscsi_hba_t		*ihp = (iscsi_hba_t *)ptr;
   1804 	iSCSIDiscoveryMethod_t	dm;
   1805 
   1806 	while (iscsi_thread_wait(thread, -1) != 0) {
   1807 		iscsi_discovery_event(ihp, iSCSIDiscoveryMethodISNS, B_TRUE);
   1808 
   1809 		/* ---- ensure iSNS discovery is enabled ---- */
   1810 		dm = persistent_disc_meth_get();
   1811 		if ((dm & iSCSIDiscoveryMethodISNS) == 0) {
   1812 			cmn_err(CE_NOTE,
   1813 			    "iscsi discovery failure - "
   1814 			    "iSNS method is not enabled");
   1815 			iscsi_discovery_event(ihp,
   1816 			    iSCSIDiscoveryMethodISNS, B_FALSE);
   1817 			continue;
   1818 		}
   1819 
   1820 		(void) isns_reg(ihp->hba_isid,
   1821 		    ihp->hba_name,
   1822 		    ISCSI_MAX_NAME_LEN,
   1823 		    ihp->hba_alias,
   1824 		    ISCSI_MAX_NAME_LEN,
   1825 		    ISNS_INITIATOR_NODE_TYPE,
   1826 		    isns_scn_callback);
   1827 		iscsid_do_isns_query(ihp);
   1828 		iscsi_discovery_event(ihp, iSCSIDiscoveryMethodISNS, B_FALSE);
   1829 	}
   1830 
   1831 	/* Thread stopped. Deregister from iSNS servers(s). */
   1832 	(void) isns_dereg(ihp->hba_isid, ihp->hba_name);
   1833 }
   1834 
   1835 
   1836 /*
   1837  * iscsid_threads_create -- Creates all the discovery threads.
   1838  */
   1839 static void
   1840 iscsid_threads_create(iscsi_hba_t *ihp)
   1841 {
   1842 	iscsid_thr_table	*t;
   1843 
   1844 	/*
   1845 	 * start a thread for each discovery method
   1846 	 */
   1847 	for (t = &iscsid_thr[0]; t->method != iSCSIDiscoveryMethodUnknown;
   1848 	    t++) {
   1849 		if (t->thr_id == NULL) {
   1850 			t->thr_id = iscsi_thread_create(ihp->hba_dip, t->name,
   1851 			    t->func_start, ihp);
   1852 		}
   1853 	}
   1854 }
   1855 
   1856 /*
   1857  * iscsid_threads_destroy -- Destroys all the discovery threads.
   1858  */
   1859 static void
   1860 iscsid_threads_destroy(void)
   1861 {
   1862 	iscsid_thr_table	*t;
   1863 
   1864 	for (t = &iscsid_thr[0]; t->method != iSCSIDiscoveryMethodUnknown;
   1865 	    t++) {
   1866 		if (t->thr_id != NULL) {
   1867 			iscsi_thread_destroy(t->thr_id);
   1868 			t->thr_id = NULL;
   1869 		}
   1870 	}
   1871 }
   1872 
   1873 /*
   1874  * iscsid_copyto_param_set - helper function for iscsid_init_params.
   1875  */
   1876 static int
   1877 iscsid_copyto_param_set(uint32_t param_id, iscsi_login_params_t *params,
   1878     iscsi_param_set_t *ipsp)
   1879 {
   1880 	int rtn = 0;
   1881 
   1882 	if (param_id >= ISCSI_NUM_LOGIN_PARAM) {
   1883 		return (EINVAL);
   1884 	}
   1885 
   1886 	switch (param_id) {
   1887 
   1888 	/*
   1889 	 * Boolean parameters
   1890 	 */
   1891 	case ISCSI_LOGIN_PARAM_DATA_SEQUENCE_IN_ORDER:
   1892 		ipsp->s_value.v_bool = params->data_pdu_in_order;
   1893 		break;
   1894 	case ISCSI_LOGIN_PARAM_IMMEDIATE_DATA:
   1895 		ipsp->s_value.v_bool = params->immediate_data;
   1896 		break;
   1897 	case ISCSI_LOGIN_PARAM_INITIAL_R2T:
   1898 		ipsp->s_value.v_bool = params->initial_r2t;
   1899 		break;
   1900 	case ISCSI_LOGIN_PARAM_DATA_PDU_IN_ORDER:
   1901 		ipsp->s_value.v_bool = params->data_pdu_in_order;
   1902 		break;
   1903 
   1904 	/*
   1905 	 * Integer parameters
   1906 	 */
   1907 	case ISCSI_LOGIN_PARAM_HEADER_DIGEST:
   1908 		ipsp->s_value.v_integer = params->header_digest;
   1909 		break;
   1910 	case ISCSI_LOGIN_PARAM_DATA_DIGEST:
   1911 		ipsp->s_value.v_integer = params->data_digest;
   1912 		break;
   1913 	case ISCSI_LOGIN_PARAM_DEFAULT_TIME_2_RETAIN:
   1914 		ipsp->s_value.v_integer = params->default_time_to_retain;
   1915 		break;
   1916 	case ISCSI_LOGIN_PARAM_DEFAULT_TIME_2_WAIT:
   1917 		ipsp->s_value.v_integer = params->default_time_to_wait;
   1918 		break;
   1919 	case ISCSI_LOGIN_PARAM_MAX_RECV_DATA_SEGMENT_LENGTH:
   1920 		ipsp->s_value.v_integer = params->max_recv_data_seg_len;
   1921 		break;
   1922 	case ISCSI_LOGIN_PARAM_FIRST_BURST_LENGTH:
   1923 		ipsp->s_value.v_integer = params->first_burst_length;
   1924 		break;
   1925 	case ISCSI_LOGIN_PARAM_MAX_BURST_LENGTH:
   1926 		ipsp->s_value.v_integer =  params->max_burst_length;
   1927 		break;
   1928 
   1929 	/*
   1930 	 * Integer parameters which currently are unsettable
   1931 	 */
   1932 	case ISCSI_LOGIN_PARAM_MAX_CONNECTIONS:
   1933 	case ISCSI_LOGIN_PARAM_OUTSTANDING_R2T:
   1934 	case ISCSI_LOGIN_PARAM_ERROR_RECOVERY_LEVEL:
   1935 	/* ---- drop through to default case ---- */
   1936 	default:
   1937 		rtn = EINVAL;
   1938 		break;
   1939 	}
   1940 
   1941 	/* if all is well, set the parameter identifier */
   1942 	if (rtn == 0) {
   1943 		ipsp->s_param = param_id;
   1944 	}
   1945 
   1946 	return (rtn);
   1947 }
   1948 
   1949 /*
   1950  * iscsid_add_pg_list_to_cache - Add portal groups in the list to the
   1951  * discovery cache.
   1952  */
   1953 static void
   1954 iscsid_add_pg_list_to_cache(iscsi_hba_t *ihp,
   1955     isns_portal_group_list_t *pg_list)
   1956 {
   1957 	int		    i;
   1958 
   1959 	for (i = 0; i < pg_list->pg_out_cnt; i++) {
   1960 		iscsi_sockaddr_t addr_dsc;
   1961 		iscsi_sockaddr_t addr_tgt;
   1962 
   1963 		iscsid_addr_to_sockaddr(
   1964 		    pg_list->pg_list[i].isns_server_ip.i_insize,
   1965 		    &pg_list->pg_list[i].isns_server_ip.i_addr,
   1966 		    pg_list->pg_list[i].isns_server_port,
   1967 		    &addr_dsc.sin);
   1968 		iscsid_addr_to_sockaddr(
   1969 		    pg_list->pg_list[i].insize,
   1970 		    &pg_list->pg_list[i].pg_ip_addr,
   1971 		    pg_list->pg_list[i].pg_port,
   1972 		    &addr_tgt.sin);
   1973 
   1974 		(void) iscsid_add(ihp, iSCSIDiscoveryMethodISNS, &addr_dsc.sin,
   1975 		    (char *)pg_list->pg_list[i].pg_iscsi_name,
   1976 		    pg_list->pg_list[i].pg_tag, &addr_tgt.sin);
   1977 	}
   1978 }
   1979 
   1980 /*
   1981  * set_initiator_name - set default initiator name and alias.
   1982  *
   1983  * This sets the default initiator name and alias.  The
   1984  * initiator name is composed of sun's reverse domain name
   1985  * and registration followed and a unique classifier.  This
   1986  * classifier is the mac address of the first NIC in the
   1987  * host and a timestamp to make sure the classifier is
   1988  * unique if the NIC is moved between hosts.  The alias
   1989  * is just the hostname.
   1990  */
   1991 void
   1992 iscsid_set_default_initiator_node_settings(iscsi_hba_t *ihp, boolean_t minimal)
   1993 {
   1994 	int		    i;
   1995 	time_t		    x;
   1996 	struct ether_addr   eaddr;
   1997 	char		    val[10];
   1998 	iscsi_chap_props_t  *chap = NULL;
   1999 
   2000 	/* Set default initiator-node name */
   2001 	if (iscsiboot_prop && iscsiboot_prop->boot_init.ini_name != NULL) {
   2002 		(void) strncpy((char *)ihp->hba_name,
   2003 		    (const char *)iscsiboot_prop->boot_init.ini_name,
   2004 		    ISCSI_MAX_NAME_LEN);
   2005 	} else {
   2006 		(void) snprintf((char *)ihp->hba_name,
   2007 		    ISCSI_MAX_NAME_LEN,
   2008 		    "iqn.1986-03.com.sun:01:");
   2009 
   2010 		(void) localetheraddr(NULL, &eaddr);
   2011 		for (i = 0; i <  ETHERADDRL; i++) {
   2012 			(void) snprintf(val, sizeof (val), "%02x",
   2013 			    eaddr.ether_addr_octet[i]);
   2014 			(void) strncat((char *)ihp->hba_name, val,
   2015 			    ISCSI_MAX_NAME_LEN);
   2016 		}
   2017 
   2018 		/* Set default initiator-node alias */
   2019 		x = ddi_get_time();
   2020 		(void) snprintf(val, sizeof (val), ".%lx", x);
   2021 		(void) strncat((char *)ihp->hba_name, val, ISCSI_MAX_NAME_LEN);
   2022 
   2023 		if (ihp->hba_alias[0] == '\0') {
   2024 			(void) strncpy((char *)ihp->hba_alias,
   2025 			    utsname.nodename, ISCSI_MAX_NAME_LEN);
   2026 			ihp->hba_alias_length = strlen((char *)ihp->hba_alias);
   2027 			if (minimal == B_FALSE) {
   2028 				(void) persistent_alias_name_set(
   2029 				    (char *)ihp->hba_alias);
   2030 			}
   2031 		}
   2032 	}
   2033 
   2034 	if (minimal == B_TRUE) {
   2035 		return;
   2036 	}
   2037 
   2038 	(void) persistent_initiator_name_set((char *)ihp->hba_name);
   2039 
   2040 	/* Set default initiator-node CHAP settings */
   2041 	if (persistent_initiator_name_get((char *)ihp->hba_name,
   2042 	    ISCSI_MAX_NAME_LEN) == B_TRUE) {
   2043 		chap = (iscsi_chap_props_t *)kmem_zalloc(sizeof (*chap),
   2044 		    KM_SLEEP);
   2045 		if (persistent_chap_get((char *)ihp->hba_name, chap) ==
   2046 		    B_FALSE) {
   2047 			bcopy((char *)ihp->hba_name, chap->c_user,
   2048 			    strlen((char *)ihp->hba_name));
   2049 			chap->c_user_len = strlen((char *)ihp->hba_name);
   2050 			(void) persistent_chap_set((char *)ihp->hba_name, chap);
   2051 		}
   2052 		kmem_free(chap, sizeof (*chap));
   2053 	}
   2054 }
   2055 
   2056 static void
   2057 iscsid_remove_target_param(char *name)
   2058 {
   2059 	persistent_param_t  *pparam;
   2060 	uint32_t	    t_oid;
   2061 	iscsi_config_sess_t *ics;
   2062 
   2063 	ASSERT(name != NULL);
   2064 
   2065 	/*
   2066 	 * Remove target-param <-> target mapping.
   2067 	 * Only remove if there is not any overridden
   2068 	 * parameters in the persistent store
   2069 	 */
   2070 	pparam = (persistent_param_t *)kmem_zalloc(sizeof (*pparam), KM_SLEEP);
   2071 
   2072 	/*
   2073 	 * setup initial buffer for configured session
   2074 	 * information
   2075 	 */
   2076 	ics = (iscsi_config_sess_t *)kmem_zalloc(sizeof (*ics), KM_SLEEP);
   2077 	ics->ics_in = 1;
   2078 
   2079 	if ((persistent_param_get(name, pparam) == B_FALSE) &&
   2080 	    (persistent_get_config_session(name, ics) == B_FALSE))  {
   2081 		t_oid = iscsi_targetparam_get_oid((uchar_t *)name);
   2082 		(void) iscsi_targetparam_remove_target(t_oid);
   2083 	}
   2084 
   2085 	kmem_free(pparam, sizeof (*pparam));
   2086 	pparam = NULL;
   2087 	kmem_free(ics, sizeof (*ics));
   2088 	ics = NULL;
   2089 }
   2090 
   2091 /*
   2092  * iscsid_addr_to_sockaddr - convert other types to struct sockaddr
   2093  */
   2094 void
   2095 iscsid_addr_to_sockaddr(int src_insize, void *src_addr, int src_port,
   2096     struct sockaddr *dst_addr)
   2097 {
   2098 	ASSERT((src_insize == sizeof (struct in_addr)) ||
   2099 	    (src_insize == sizeof (struct in6_addr)));
   2100 	ASSERT(src_addr != NULL);
   2101 	ASSERT(dst_addr != NULL);
   2102 
   2103 	bzero(dst_addr, sizeof (*dst_addr));
   2104 
   2105 	/* translate discovery information */
   2106 	if (src_insize == sizeof (struct in_addr)) {
   2107 		struct sockaddr_in *addr_in =
   2108 		    (struct sockaddr_in *)dst_addr;
   2109 		addr_in->sin_family = AF_INET;
   2110 		bcopy(src_addr, &addr_in->sin_addr.s_addr,
   2111 		    sizeof (struct in_addr));
   2112 		addr_in->sin_port = htons(src_port);
   2113 	} else {
   2114 		struct sockaddr_in6 *addr_in6 =
   2115 		    (struct sockaddr_in6 *)dst_addr;
   2116 		addr_in6->sin6_family = AF_INET6;
   2117 		bcopy(src_addr, &addr_in6->sin6_addr.s6_addr,
   2118 		    sizeof (struct in6_addr));
   2119 		addr_in6->sin6_port = htons(src_port);
   2120 	}
   2121 }
   2122 
   2123 /*
   2124  * iscsi_discovery_event -- send event associated with discovery operations
   2125  *
   2126  * Each discovery event has a start and end event. Which is sent is based
   2127  * on the boolean argument start with the obvious results.
   2128  */
   2129 static void
   2130 iscsi_discovery_event(iscsi_hba_t *ihp, iSCSIDiscoveryMethod_t m,
   2131     boolean_t start)
   2132 {
   2133 	char	*subclass = NULL;
   2134 
   2135 	mutex_enter(&ihp->hba_discovery_events_mutex);
   2136 	switch (m) {
   2137 	case iSCSIDiscoveryMethodStatic:
   2138 		if (start == B_TRUE) {
   2139 			subclass = ESC_ISCSI_STATIC_START;
   2140 		} else {
   2141 			ihp->hba_discovery_events |= iSCSIDiscoveryMethodStatic;
   2142 			subclass = ESC_ISCSI_STATIC_END;
   2143 		}
   2144 		break;
   2145 
   2146 	case iSCSIDiscoveryMethodSendTargets:
   2147 		if (start == B_TRUE) {
   2148 			subclass = ESC_ISCSI_SEND_TARGETS_START;
   2149 		} else {
   2150 			ihp->hba_discovery_events |=
   2151 			    iSCSIDiscoveryMethodSendTargets;
   2152 			subclass = ESC_ISCSI_SEND_TARGETS_END;
   2153 		}
   2154 		break;
   2155 
   2156 	case iSCSIDiscoveryMethodSLP:
   2157 		if (start == B_TRUE) {
   2158 			subclass = ESC_ISCSI_SLP_START;
   2159 		} else {
   2160 			ihp->hba_discovery_events |= iSCSIDiscoveryMethodSLP;
   2161 			subclass = ESC_ISCSI_SLP_END;
   2162 		}
   2163 		break;
   2164 
   2165 	case iSCSIDiscoveryMethodISNS:
   2166 		if (start == B_TRUE) {
   2167 			subclass = ESC_ISCSI_ISNS_START;
   2168 		} else {
   2169 			ihp->hba_discovery_events |= iSCSIDiscoveryMethodISNS;
   2170 			subclass = ESC_ISCSI_ISNS_END;
   2171 		}
   2172 		break;
   2173 	}
   2174 	mutex_exit(&ihp->hba_discovery_events_mutex);
   2175 	iscsi_send_sysevent(ihp, EC_ISCSI, subclass, NULL);
   2176 }
   2177 
   2178 /*
   2179  * iscsi_send_sysevent -- send sysevent using specified class
   2180  */
   2181 void
   2182 iscsi_send_sysevent(
   2183     iscsi_hba_t	*ihp,
   2184     char	*eventclass,
   2185     char	*subclass,
   2186     nvlist_t	*np)
   2187 {
   2188 	(void) ddi_log_sysevent(ihp->hba_dip, DDI_VENDOR_SUNW, eventclass,
   2189 	    subclass, np, NULL, DDI_SLEEP);
   2190 }
   2191 
   2192 static boolean_t
   2193 iscsid_boot_init_config(iscsi_hba_t *ihp)
   2194 {
   2195 	if (strlen((const char *)iscsiboot_prop->boot_init.ini_name) != 0) {
   2196 		bcopy(iscsiboot_prop->boot_init.ini_name,
   2197 		    ihp->hba_name,
   2198 		    strlen((const char *)iscsiboot_prop->boot_init.ini_name));
   2199 	}
   2200 	/* or using default login param for boot session */
   2201 	return (B_TRUE);
   2202 }
   2203 
   2204 boolean_t
   2205 iscsi_reconfig_boot_sess(iscsi_hba_t *ihp)
   2206 {
   2207 	iscsi_config_sess_t	*ics;
   2208 	int			idx;
   2209 	iscsi_sess_t		*isp, *t_isp;
   2210 	int			isid, size;
   2211 	char			*name;
   2212 	boolean_t		rtn = B_TRUE;
   2213 
   2214 	if (iscsiboot_prop == NULL) {
   2215 		return (B_FALSE);
   2216 	}
   2217 	size = sizeof (*ics);
   2218 	ics = kmem_zalloc(size, KM_SLEEP);
   2219 	ics->ics_in = 1;
   2220 
   2221 	/* get information of number of sessions to be configured */
   2222 	name = (char *)iscsiboot_prop->boot_tgt.tgt_name;
   2223 	if (persistent_get_config_session(name, ics) == B_FALSE) {
   2224 		/*
   2225 		 * No target information available to check
   2226 		 * initiator information. Assume one session
   2227 		 * by default.
   2228 		 */
   2229 		name = (char *)iscsiboot_prop->boot_init.ini_name;
   2230 		if (persistent_get_config_session(name, ics) == B_FALSE) {
   2231 			ics->ics_out = 1;
   2232 			ics->ics_bound = B_TRUE;
   2233 		}
   2234 	}
   2235 
   2236 	/* get necessary information */
   2237 	if (ics->ics_out > 1) {
   2238 		idx = ics->ics_out;
   2239 		size = ISCSI_SESSION_CONFIG_SIZE(ics->ics_out);
   2240 		kmem_free(ics, sizeof (*ics));
   2241 
   2242 		ics = kmem_zalloc(size, KM_SLEEP);
   2243 		ics->ics_in = idx;
   2244 
   2245 		/* get configured sessions information */
   2246 		if (persistent_get_config_session((char *)name,
   2247 		    ics) != B_TRUE) {
   2248 			cmn_err(CE_NOTE, "session(%s) - "
   2249 			    "failed to setup multiple sessions",
   2250 			    name);
   2251 			kmem_free(ics, size);
   2252 			return (B_FALSE);
   2253 		}
   2254 	}
   2255 
   2256 	/* create a temporary session to keep boot session connective */
   2257 	t_isp = iscsi_add_boot_sess(ihp, ISCSI_MAX_CONFIG_SESSIONS);
   2258 	if (t_isp == NULL) {
   2259 		cmn_err(CE_NOTE, "session(%s) - "
   2260 		    "failed to setup multiple sessions", name);
   2261 		rw_exit(&ihp->hba_sess_list_rwlock);
   2262 		kmem_free(ics, size);
   2263 		return (B_FALSE);
   2264 	}
   2265 
   2266 	/* destroy all old boot sessions */
   2267 	rw_enter(&ihp->hba_sess_list_rwlock, RW_WRITER);
   2268 	isp = ihp->hba_sess_list;
   2269 	while (isp != NULL) {
   2270 		if (iscsi_chk_bootlun_mpxio(ihp) && isp->sess_boot) {
   2271 			if (isp->sess_isid[5] != ISCSI_MAX_CONFIG_SESSIONS) {
   2272 				/*
   2273 				 * destroy all stale sessions
   2274 				 * except temporary boot session
   2275 				 */
   2276 				if (ISCSI_SUCCESS(iscsi_sess_destroy(
   2277 				    isp))) {
   2278 					isp = ihp->hba_sess_list;
   2279 				} else {
   2280 					/*
   2281 					 * couldn't destroy stale sessions
   2282 					 * at least poke it to disconnect
   2283 					 */
   2284 					mutex_enter(&isp->sess_state_mutex);
   2285 					iscsi_sess_state_machine(isp,
   2286 					    ISCSI_SESS_EVENT_N7);
   2287 					mutex_exit(&isp->sess_state_mutex);
   2288 					isp = isp->sess_next;
   2289 					cmn_err(CE_NOTE, "session(%s) - "
   2290 					    "failed to setup multiple"
   2291 					    " sessions", name);
   2292 				}
   2293 			} else {
   2294 				isp = isp->sess_next;
   2295 			}
   2296 		} else {
   2297 			isp = isp->sess_next;
   2298 		}
   2299 	}
   2300 	rw_exit(&ihp->hba_sess_list_rwlock);
   2301 
   2302 	for (isid = 0; isid < ics->ics_out; isid++) {
   2303 		isp = iscsi_add_boot_sess(ihp, isid);
   2304 		if (isp == NULL) {
   2305 			cmn_err(CE_NOTE, "session(%s) - failed to setup"
   2306 			    " multiple sessions", name);
   2307 			rtn = B_FALSE;
   2308 			break;
   2309 		}
   2310 	}
   2311 	if (!rtn && (isid == 0)) {
   2312 		/*
   2313 		 * fail to create any new boot session
   2314 		 * so only the temporary session is alive
   2315 		 * quit without destroying it
   2316 		 */
   2317 		kmem_free(ics, size);
   2318 		return (rtn);
   2319 	}
   2320 
   2321 	rw_enter(&ihp->hba_sess_list_rwlock, RW_WRITER);
   2322 	if (!ISCSI_SUCCESS(iscsi_sess_destroy(t_isp))) {
   2323 		/* couldn't destroy temp boot session */
   2324 		cmn_err(CE_NOTE, "session(%s) - "
   2325 		    "failed to setup multiple sessions", name);
   2326 		rw_exit(&ihp->hba_sess_list_rwlock);
   2327 		rtn = B_FALSE;
   2328 	}
   2329 	rw_exit(&ihp->hba_sess_list_rwlock);
   2330 
   2331 	kmem_free(ics, size);
   2332 	return (rtn);
   2333 }
   2334 
   2335 static iscsi_sess_t *
   2336 iscsi_add_boot_sess(iscsi_hba_t *ihp, int isid)
   2337 {
   2338 	iscsi_sess_t	*isp;
   2339 	iscsi_conn_t    *icp;
   2340 	uint_t		oid;
   2341 
   2342 	iscsi_sockaddr_t	addr_dst;
   2343 
   2344 	addr_dst.sin.sa_family = iscsiboot_prop->boot_tgt.sin_family;
   2345 	if (addr_dst.sin.sa_family == AF_INET) {
   2346 		bcopy(&iscsiboot_prop->boot_tgt.tgt_ip_u.u_in4.s_addr,
   2347 		    &addr_dst.sin4.sin_addr.s_addr, sizeof (struct in_addr));
   2348 		addr_dst.sin4.sin_port =
   2349 		    htons(iscsiboot_prop->boot_tgt.tgt_port);
   2350 	} else {
   2351 		bcopy(&iscsiboot_prop->boot_tgt.tgt_ip_u.u_in6.s6_addr,
   2352 		    &addr_dst.sin6.sin6_addr.s6_addr,
   2353 		    sizeof (struct in6_addr));
   2354 		addr_dst.sin6.sin6_port =
   2355 		    htons(iscsiboot_prop->boot_tgt.tgt_port);
   2356 	}
   2357 
   2358 	rw_enter(&ihp->hba_sess_list_rwlock, RW_WRITER);
   2359 	isp = iscsi_sess_create(ihp,
   2360 	    iSCSIDiscoveryMethodBoot|iSCSIDiscoveryMethodStatic,
   2361 	    (struct sockaddr *)&addr_dst,
   2362 	    (char *)iscsiboot_prop->boot_tgt.tgt_name,
   2363 	    ISCSI_DEFAULT_TPGT, isid, ISCSI_SESS_TYPE_NORMAL, &oid);
   2364 	if (isp == NULL) {
   2365 		/* create temp booting session failed */
   2366 		rw_exit(&ihp->hba_sess_list_rwlock);
   2367 		return (NULL);
   2368 	}
   2369 	isp->sess_boot = B_TRUE;
   2370 
   2371 	if (!ISCSI_SUCCESS(iscsi_conn_create((struct sockaddr *)&addr_dst,
   2372 	    isp, &icp))) {
   2373 		rw_exit(&ihp->hba_sess_list_rwlock);
   2374 		return (NULL);
   2375 	}
   2376 
   2377 	rw_exit(&ihp->hba_sess_list_rwlock);
   2378 	/* now online created session */
   2379 	if (iscsid_login_tgt(ihp, (char *)iscsiboot_prop->boot_tgt.tgt_name,
   2380 	    iSCSIDiscoveryMethodBoot|iSCSIDiscoveryMethodStatic,
   2381 	    (struct sockaddr *)&addr_dst) == B_FALSE) {
   2382 		return (NULL);
   2383 	}
   2384 
   2385 	return (isp);
   2386 }
   2387 
   2388 static void
   2389 iscsid_thread_boot_wd(iscsi_thread_t *thread, void *p)
   2390 {
   2391 	int			rc = 1;
   2392 	iscsi_hba_t		*ihp = (iscsi_hba_t *)p;
   2393 	boolean_t		reconfigured = B_FALSE;
   2394 
   2395 	while (rc != 0) {
   2396 		if (iscsiboot_prop && (modrootloaded == 1)) {
   2397 			if (ihp->hba_persistent_loaded == B_FALSE) {
   2398 				if (persistent_load() == B_TRUE) {
   2399 					ihp->hba_persistent_loaded = B_TRUE;
   2400 				}
   2401 			}
   2402 			if ((ihp->hba_persistent_loaded == B_TRUE) &&
   2403 			    (reconfigured == B_FALSE)) {
   2404 				if (iscsi_chk_bootlun_mpxio(ihp) == B_TRUE) {
   2405 					(void) iscsi_reconfig_boot_sess(ihp);
   2406 					iscsid_poke_discovery(ihp,
   2407 					    iSCSIDiscoveryMethodUnknown);
   2408 					(void) iscsid_login_tgt(ihp, NULL,
   2409 					    iSCSIDiscoveryMethodUnknown, NULL);
   2410 				}
   2411 				reconfigured = B_TRUE;
   2412 			}
   2413 			break;
   2414 		}
   2415 		rc = iscsi_thread_wait(thread, SEC_TO_TICK(1));
   2416 	}
   2417 }
   2418 
   2419 boolean_t
   2420 iscsi_cmp_boot_tgt_name(char *name)
   2421 {
   2422 	if (iscsiboot_prop && (strncmp((const char *)name,
   2423 	    (const char *)iscsiboot_prop->boot_tgt.tgt_name,
   2424 	    ISCSI_MAX_NAME_LEN) == 0)) {
   2425 		return (B_TRUE);
   2426 	} else {
   2427 		return (B_FALSE);
   2428 	}
   2429 }
   2430 
   2431 boolean_t
   2432 iscsi_cmp_boot_ini_name(char *name)
   2433 {
   2434 	if (iscsiboot_prop && (strncmp((const char *)name,
   2435 	    (const char *)iscsiboot_prop->boot_init.ini_name,
   2436 	    ISCSI_MAX_NAME_LEN) == 0)) {
   2437 		return (B_TRUE);
   2438 	} else {
   2439 		return (B_FALSE);
   2440 	}
   2441 }
   2442 
   2443 boolean_t
   2444 iscsi_chk_bootlun_mpxio(iscsi_hba_t *ihp)
   2445 {
   2446 	iscsi_sess_t    *isp;
   2447 	iscsi_lun_t	*ilp;
   2448 	isp = ihp->hba_sess_list;
   2449 	boolean_t	tgt_mpxio_enabled = B_FALSE;
   2450 	boolean_t	bootlun_found = B_FALSE;
   2451 	uint16_t    lun_num;
   2452 
   2453 	if (iscsiboot_prop == NULL) {
   2454 		return (B_FALSE);
   2455 	}
   2456 
   2457 	if (!ihp->hba_mpxio_enabled) {
   2458 		return (B_FALSE);
   2459 	}
   2460 
   2461 	lun_num = *((uint64_t *)(iscsiboot_prop->boot_tgt.tgt_boot_lun));
   2462 
   2463 	while (isp != NULL) {
   2464 		if ((strncmp((char *)isp->sess_name,
   2465 		    (const char *)iscsiboot_prop->boot_tgt.tgt_name,
   2466 		    ISCSI_MAX_NAME_LEN) == 0) &&
   2467 		    (isp->sess_boot == B_TRUE)) {
   2468 			/*
   2469 			 * found boot session.
   2470 			 * check its mdi path info is null or not
   2471 			 */
   2472 			ilp = isp->sess_lun_list;
   2473 			while (ilp != NULL) {
   2474 				if (lun_num == ilp->lun_num) {
   2475 					if (ilp->lun_pip) {
   2476 						tgt_mpxio_enabled = B_TRUE;
   2477 					}
   2478 					bootlun_found = B_TRUE;
   2479 				}
   2480 				ilp = ilp->lun_next;
   2481 			}
   2482 		}
   2483 		isp = isp->sess_next;
   2484 	}
   2485 	if (bootlun_found) {
   2486 		return (tgt_mpxio_enabled);
   2487 	} else {
   2488 		/*
   2489 		 * iscsiboot_prop not NULL while no boot lun found
   2490 		 * in most cases this is none iscsi boot while iscsiboot_prop
   2491 		 * is not NULL, in this scenario return iscsi HBA's mpxio config
   2492 		 */
   2493 		return (ihp->hba_mpxio_enabled);
   2494 	}
   2495 }
   2496 
   2497 static boolean_t
   2498 iscsid_check_active_boot_conn(iscsi_hba_t *ihp)
   2499 {
   2500 	iscsi_sess_t	*isp = NULL;
   2501 	iscsi_conn_t	*icp = NULL;
   2502 
   2503 	rw_enter(&ihp->hba_sess_list_rwlock, RW_READER);
   2504 	isp = ihp->hba_sess_list;
   2505 	while (isp != NULL) {
   2506 		if (isp->sess_boot == B_TRUE) {
   2507 			rw_enter(&isp->sess_conn_list_rwlock, RW_READER);
   2508 			icp = isp->sess_conn_list;
   2509 			while (icp != NULL) {
   2510 				if (icp->conn_state ==
   2511 				    ISCSI_CONN_STATE_LOGGED_IN) {
   2512 					rw_exit(&isp->sess_conn_list_rwlock);
   2513 					rw_exit(&ihp->hba_sess_list_rwlock);
   2514 					return (B_TRUE);
   2515 				}
   2516 				icp = icp->conn_next;
   2517 			}
   2518 			rw_exit(&isp->sess_conn_list_rwlock);
   2519 		}
   2520 		isp = isp->sess_next;
   2521 	}
   2522 	rw_exit(&ihp->hba_sess_list_rwlock);
   2523 
   2524 	return (B_FALSE);
   2525 }
   2526