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