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