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