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