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