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