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