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