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