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