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