xref: /illumos-gate/usr/src/uts/common/io/scsi/adapters/iscsi/iscsid.c (revision 968633ad8faee931821fd6b656eb0d96d4b186c0)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * ISCSID --
28  *
29  * Discovery of targets and access to the persistent storage starts here.
30  */
31 
32 #include <sys/thread.h>
33 #include <sys/types.h>
34 #include <sys/proc.h>		/* declares:    p0 */
35 #include <sys/cmn_err.h>
36 #include <sys/scsi/adapters/iscsi_if.h>
37 #include <netinet/in.h>
38 #include "iscsi_targetparam.h"
39 #include "isns_client.h"
40 #include "isns_protocol.h"
41 #include "persistent.h"
42 #include "iscsi.h"
43 #include <sys/ethernet.h>
44 
45 /*
46  * local function prototypes
47  */
48 static boolean_t iscsid_init_config(iscsi_hba_t *ihp);
49 static boolean_t iscsid_init_targets(iscsi_hba_t *ihp);
50 static void iscsid_thread_static(iscsi_thread_t *thread, void *p);
51 static void iscsid_thread_sendtgts(iscsi_thread_t *thread, void *p);
52 static void iscsid_thread_isns(iscsi_thread_t *thread, void *p);
53 static void iscsid_thread_slp(iscsi_thread_t *thread, void *p);
54 static void iscsid_threads_create(iscsi_hba_t *ihp);
55 static void iscsid_threads_destroy(void);
56 static int iscsid_copyto_param_set(uint32_t param_id,
57     iscsi_login_params_t *params, iscsi_param_set_t *ipsp);
58 static void iscsid_add_pg_list_to_cache(iscsi_hba_t *ihp,
59     isns_portal_group_list_t *pg_list);
60 static void iscsid_set_default_initiator_node_settings(iscsi_hba_t *ihp);
61 static void iscsid_remove_target_param(char *name);
62 static 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);
65 
66 static void iscsi_discovery_event(iscsi_hba_t *ihp,
67     iSCSIDiscoveryMethod_t m, boolean_t start);
68 static void iscsi_send_sysevent(iscsi_hba_t *ihp,
69     char *subclass, nvlist_t *np);
70 
71 /*
72  * iSCSI target discovery thread table
73  */
74 typedef struct iscsid_thr_table {
75 	void			(*func_start)(iscsi_thread_t *, void *);
76 	iscsi_thread_t		*thr_id;
77 	iSCSIDiscoveryMethod_t	method;
78 	char			*name;
79 } iscsid_thr_table;
80 
81 static iscsid_thr_table iscsid_thr[] = {
82 	{ iscsid_thread_static, NULL,
83 	    iSCSIDiscoveryMethodStatic,
84 	    "Static" },
85 	{ iscsid_thread_sendtgts, NULL,
86 	    iSCSIDiscoveryMethodSendTargets,
87 	    "SendTarget" },
88 	{ iscsid_thread_slp, NULL,
89 	    iSCSIDiscoveryMethodSLP,
90 	    "SLP" },
91 	{ iscsid_thread_isns, NULL,
92 	    iSCSIDiscoveryMethodISNS,
93 	    "iSNS" },
94 	{ NULL, NULL,
95 	    iSCSIDiscoveryMethodUnknown,
96 	    NULL }
97 };
98 
99 
100 /*
101  * discovery method event table
102  */
103 iSCSIDiscoveryMethod_t	for_failure[] = {
104 	iSCSIDiscoveryMethodStatic,
105 	iSCSIDiscoveryMethodSLP,
106 	iSCSIDiscoveryMethodISNS,
107 	iSCSIDiscoveryMethodSendTargets,
108 	iSCSIDiscoveryMethodUnknown /* terminating value */
109 };
110 
111 /*
112  * discovery configuration semaphore
113  */
114 ksema_t iscsid_config_semaphore;
115 
116 #define	CHECK_METHOD(v) ((dm & v) ? B_TRUE : B_FALSE)
117 
118 /*
119  * iscsid_init -- load data from persistent storage and start discovery threads
120  *
121  * If restart is B_TRUE than someone has issued an ISCSI_DB_RELOAD ioctl.
122  * The most likely reason is that a new database has been copied into
123  * /etc/iscsi and the driver needs to read the contents.
124  */
125 boolean_t
126 iscsid_init(iscsi_hba_t *ihp, boolean_t restart)
127 {
128 	boolean_t		rval = B_FALSE;
129 	iSCSIDiscoveryMethod_t  dm;
130 	iSCSIDiscoveryMethod_t	*fdm;
131 
132 	sema_init(&iscsid_config_semaphore, 1, NULL,
133 	    SEMA_DRIVER, NULL);
134 
135 	rval = persistent_init(restart);
136 	if (rval == B_TRUE) {
137 		rval = iscsid_init_config(ihp);
138 		if (rval == B_TRUE) {
139 			rval = iscsid_init_targets(ihp);
140 		}
141 	}
142 
143 	if (rval == B_TRUE) {
144 		if (restart == B_FALSE) {
145 			iscsid_threads_create(ihp);
146 		}
147 
148 		dm = persistent_disc_meth_get();
149 		rval = iscsid_enable_discovery(ihp, dm, B_FALSE);
150 		if (rval == B_TRUE) {
151 			rval = iscsid_disable_discovery(ihp, ~dm);
152 		}
153 	}
154 
155 	if (rval == B_FALSE) {
156 		/*
157 		 * In case of failure the events still need to be sent
158 		 * because the door daemon will pause until all these
159 		 * events have occurred.
160 		 */
161 		for (fdm = &for_failure[0]; *fdm != iSCSIDiscoveryMethodUnknown;
162 		    fdm++) {
163 			/* ---- Send both start and end events ---- */
164 			iscsi_discovery_event(ihp, *fdm, B_TRUE);
165 			iscsi_discovery_event(ihp, *fdm, B_FALSE);
166 		}
167 	}
168 
169 	return (rval);
170 }
171 
172 /*
173  * iscsid_fini -- do whatever is required to clean up
174  */
175 /* ARGSUSED */
176 void
177 iscsid_fini()
178 {
179 	iscsid_threads_destroy();
180 	persistent_fini();
181 	sema_destroy(&iscsid_config_semaphore);
182 }
183 
184 /*
185  * iscsid_props -- returns discovery thread information, used by ioctl code
186  */
187 void
188 iscsid_props(iSCSIDiscoveryProperties_t *props)
189 {
190 	iSCSIDiscoveryMethod_t  dm;
191 
192 	dm = persistent_disc_meth_get();
193 
194 	props->vers = ISCSI_INTERFACE_VERSION;
195 
196 	/* ---- change once thread is implemented ---- */
197 	props->iSNSDiscoverySettable		= B_FALSE;
198 	props->SLPDiscoverySettable		= B_FALSE;
199 	props->StaticDiscoverySettable		= B_TRUE;
200 	props->SendTargetsDiscoverySettable	= B_TRUE;
201 	props->iSNSDiscoveryMethod		= iSNSDiscoveryMethodStatic;
202 
203 	props->iSNSDiscoveryEnabled = CHECK_METHOD(iSCSIDiscoveryMethodISNS);
204 	props->StaticDiscoveryEnabled =
205 	    CHECK_METHOD(iSCSIDiscoveryMethodStatic);
206 	props->SendTargetsDiscoveryEnabled =
207 	    CHECK_METHOD(iSCSIDiscoveryMethodSendTargets);
208 	props->SLPDiscoveryEnabled = CHECK_METHOD(iSCSIDiscoveryMethodSLP);
209 }
210 
211 /*
212  * iscsid_enable_discovery - start specified discovery methods
213  */
214 /* ARGSUSED */
215 boolean_t
216 iscsid_enable_discovery(iscsi_hba_t *ihp, iSCSIDiscoveryMethod_t idm,
217     boolean_t poke)
218 {
219 	boolean_t		rval = B_TRUE;
220 	iscsid_thr_table	*dt;
221 
222 	/*
223 	 * start the specified discovery method(s)
224 	 */
225 	for (dt = &iscsid_thr[0]; dt->method != iSCSIDiscoveryMethodUnknown;
226 	    dt++) {
227 		if (idm & dt->method) {
228 			if (dt->thr_id != NULL) {
229 				rval = iscsi_thread_start(dt->thr_id);
230 				if (rval == B_FALSE) {
231 					break;
232 				}
233 				if (poke == B_TRUE) {
234 					iscsi_thread_send_wakeup(dt->thr_id);
235 				}
236 			} else {
237 				/*
238 				 * unexpected condition.  The threads for each
239 				 * discovery method should have started at
240 				 * initialization
241 				 */
242 				ASSERT(B_FALSE);
243 			}
244 		}
245 	} /* END for() */
246 
247 	return (rval);
248 }
249 
250 
251 /*
252  * iscsid_disable_discovery - stop specified discovery methods
253  */
254 boolean_t
255 iscsid_disable_discovery(iscsi_hba_t *ihp, iSCSIDiscoveryMethod_t idm)
256 {
257 	boolean_t		rval = B_TRUE;
258 	iscsid_thr_table	*dt;
259 
260 	/*
261 	 * stop the specified discovery method(s)
262 	 */
263 	for (dt = &iscsid_thr[0]; dt->method != iSCSIDiscoveryMethodUnknown;
264 	    dt++) {
265 		if (idm & dt->method) {
266 
267 			/* signal discovery event change - begin */
268 			iscsi_discovery_event(ihp, dt->method, B_TRUE);
269 
270 			/* Attempt to logout of all associated targets */
271 			rval = iscsid_del(ihp, NULL, dt->method, NULL);
272 			if (rval == B_TRUE) {
273 				/* Successfully logged out of targets */
274 				if (dt->thr_id != NULL) {
275 					rval = iscsi_thread_stop(dt->thr_id);
276 					if (rval == B_FALSE) {
277 						/*
278 						 * signal discovery
279 						 * event change - end
280 						 */
281 						iscsi_discovery_event(ihp,
282 						    dt->method, B_FALSE);
283 						break;
284 					}
285 
286 				} else {
287 					/*
288 					 * unexpected condition.  The threads
289 					 * for each discovery method should
290 					 * have started at initialization
291 					 */
292 					ASSERT(B_FALSE);
293 				}
294 			}
295 
296 			/* signal discovery event change - end */
297 			iscsi_discovery_event(ihp, dt->method, B_FALSE);
298 
299 		}
300 	} /* END for() */
301 
302 	return (rval);
303 }
304 
305 /*
306  * iscsid_poke_discovery - wakeup discovery methods to find any new targets
307  * and wait for all discovery processes to complete.
308  */
309 void
310 iscsid_poke_discovery(iscsi_hba_t *ihp, iSCSIDiscoveryMethod_t method)
311 {
312 #define	ISCSI_DISCOVERY_DELAY	1
313 
314 	iSCSIDiscoveryMethod_t	dm;
315 	iscsid_thr_table	*dt;
316 
317 	ASSERT(ihp != NULL);
318 
319 	/* reset discovery flags */
320 	mutex_enter(&ihp->hba_discovery_events_mutex);
321 	ihp->hba_discovery_in_progress = B_TRUE;
322 	ihp->hba_discovery_events = iSCSIDiscoveryMethodUnknown;
323 	mutex_exit(&ihp->hba_discovery_events_mutex);
324 
325 	/* start all enabled discovery methods */
326 	dm = persistent_disc_meth_get();
327 	for (dt = &iscsid_thr[0]; dt->method != iSCSIDiscoveryMethodUnknown;
328 	    dt++) {
329 		if ((method == iSCSIDiscoveryMethodUnknown) ||
330 		    (method == dt->method)) {
331 			if ((dm & dt->method) && (dt->thr_id != NULL)) {
332 				iscsi_thread_send_wakeup(dt->thr_id);
333 			} else {
334 				iscsi_discovery_event(ihp, dt->method, B_TRUE);
335 				iscsi_discovery_event(ihp, dt->method, B_FALSE);
336 			}
337 		} else {
338 			iscsi_discovery_event(ihp, dt->method, B_TRUE);
339 			iscsi_discovery_event(ihp, dt->method, B_FALSE);
340 		}
341 	}
342 
343 	mutex_enter(&ihp->hba_discovery_events_mutex);
344 	while (ihp->hba_discovery_events != ISCSI_ALL_DISCOVERY_METHODS) {
345 		mutex_exit(&ihp->hba_discovery_events_mutex);
346 		delay(SEC_TO_TICK(ISCSI_DISCOVERY_DELAY));
347 		mutex_enter(&ihp->hba_discovery_events_mutex);
348 	}
349 	ihp->hba_discovery_in_progress = B_FALSE;
350 	mutex_exit(&ihp->hba_discovery_events_mutex);
351 
352 }
353 
354 /*
355  * iscsid_do_sendtgts - issue send targets command to the given discovery
356  * address and then add the discovered targets to the discovery queue
357  */
358 void
359 iscsid_do_sendtgts(entry_t *disc_addr)
360 {
361 
362 #define	SENDTGTS_DEFAULT_NUM_TARGETS    10
363 
364 	int			stl_sz;
365 	int			stl_num_tgts = SENDTGTS_DEFAULT_NUM_TARGETS;
366 	iscsi_sendtgts_list_t	*stl_hdr = NULL;
367 	boolean_t		retry = B_TRUE;
368 	char			inp_buf[INET6_ADDRSTRLEN];
369 	const char		*ip;
370 	int			ctr;
371 	int			rc;
372 	iscsi_hba_t *ihp;
373 
374 	/* allocate and initialize sendtargets list header */
375 	stl_sz = sizeof (*stl_hdr) + ((stl_num_tgts - 1) *
376 	    sizeof (iscsi_sendtgts_entry_t));
377 	stl_hdr = kmem_zalloc(stl_sz, KM_SLEEP);
378 
379 retry_sendtgts:
380 	stl_hdr->stl_in_cnt = stl_num_tgts;
381 	bcopy(disc_addr, &(stl_hdr->stl_entry),
382 	    sizeof (stl_hdr->stl_entry));
383 	stl_hdr->stl_entry.e_vers = ISCSI_INTERFACE_VERSION;
384 
385 	/* lock interface so only one SendTargets operation occurs */
386 	if ((ihp = (iscsi_hba_t *)ddi_get_soft_state(iscsi_state, 0)) == NULL) {
387 		cmn_err(CE_NOTE, "!iscsi discovery failure - SendTargets. "
388 		    "failure to get soft state");
389 		kmem_free(stl_hdr, stl_sz);
390 		return;
391 	}
392 	sema_p(&ihp->hba_sendtgts_semaphore);
393 	rc = iscsi_ioctl_sendtgts_get(ihp, stl_hdr);
394 	sema_v(&ihp->hba_sendtgts_semaphore);
395 	if (rc) {
396 		ip = inet_ntop((disc_addr->e_insize ==
397 		    sizeof (struct in_addr) ? AF_INET : AF_INET6),
398 		    &disc_addr->e_u, inp_buf, sizeof (inp_buf));
399 		cmn_err(CE_NOTE,
400 		    "iscsi discovery failure - SendTargets (%s)\n", ip);
401 		kmem_free(stl_hdr, stl_sz);
402 		return;
403 	}
404 
405 	/* check if all targets received */
406 	if (stl_hdr->stl_in_cnt < stl_hdr->stl_out_cnt) {
407 		if (retry == B_TRUE) {
408 			stl_num_tgts = stl_hdr->stl_out_cnt;
409 			kmem_free(stl_hdr, stl_sz);
410 			stl_sz = sizeof (*stl_hdr) +
411 			    ((stl_num_tgts - 1) *
412 			    sizeof (iscsi_sendtgts_entry_t));
413 			stl_hdr = kmem_zalloc(stl_sz, KM_SLEEP);
414 			retry = B_FALSE;
415 			goto retry_sendtgts;
416 		} else {
417 			ip = inet_ntop((disc_addr->e_insize ==
418 			    sizeof (struct in_addr) ?
419 			    AF_INET : AF_INET6), &disc_addr->e_u,
420 			    inp_buf, sizeof (inp_buf));
421 			cmn_err(CE_NOTE, "iscsi discovery failure - "
422 			    "SendTargets overflow (%s)\n", ip);
423 			kmem_free(stl_hdr, stl_sz);
424 			return;
425 		}
426 	}
427 
428 	for (ctr = 0; ctr < stl_hdr->stl_out_cnt; ctr++) {
429 		iscsi_sockaddr_t addr_dsc;
430 		iscsi_sockaddr_t addr_tgt;
431 
432 		iscsid_addr_to_sockaddr(disc_addr->e_insize,
433 		    &disc_addr->e_u, disc_addr->e_port, &addr_dsc.sin);
434 		iscsid_addr_to_sockaddr(
435 		    stl_hdr->stl_list[ctr].ste_ipaddr.a_addr.i_insize,
436 		    &(stl_hdr->stl_list[ctr].ste_ipaddr.a_addr.i_addr),
437 		    stl_hdr->stl_list[ctr].ste_ipaddr.a_port,
438 		    &addr_tgt.sin);
439 
440 		(void) iscsid_add(ihp, iSCSIDiscoveryMethodSendTargets,
441 		    &addr_dsc.sin, (char *)stl_hdr->stl_list[ctr].ste_name,
442 		    stl_hdr->stl_list[ctr].ste_tpgt,
443 		    &addr_tgt.sin);
444 	}
445 	kmem_free(stl_hdr, stl_sz);
446 }
447 
448 void
449 iscsid_do_isns_query_one_server(iscsi_hba_t *ihp, entry_t *isns_server)
450 {
451 	int pg_sz, query_status;
452 	iscsi_addr_t *ap;
453 	isns_portal_group_list_t *pg_list;
454 
455 	ap = (iscsi_addr_t *)kmem_zalloc(sizeof (iscsi_addr_t), KM_SLEEP);
456 	ap->a_port = isns_server->e_port;
457 	ap->a_addr.i_insize = isns_server->e_insize;
458 
459 	if (isns_server->e_insize == sizeof (struct in_addr)) {
460 		ap->a_addr.i_addr.in4.s_addr = (isns_server->e_u.u_in4.s_addr);
461 	} else if (isns_server->e_insize == sizeof (struct in6_addr)) {
462 		bcopy(&(isns_server->e_u.u_in6.s6_addr),
463 		    ap->a_addr.i_addr.in6.s6_addr, 16);
464 	} else {
465 		kmem_free(ap, sizeof (iscsi_addr_t));
466 		return;
467 	}
468 
469 	pg_list = NULL;
470 	query_status = isns_query_one_server(
471 	    ap, ihp->hba_isid,
472 	    ihp->hba_name, ihp->hba_alias,
473 	    ISNS_INITIATOR_NODE_TYPE, &pg_list);
474 	kmem_free(ap, sizeof (iscsi_addr_t));
475 	if (query_status != isns_ok || pg_list == NULL) {
476 		DTRACE_PROBE1(iscsid_do_isns_query_one_server_status,
477 		    int, query_status);
478 		return;
479 	}
480 
481 	iscsid_add_pg_list_to_cache(ihp, pg_list);
482 	pg_sz = sizeof (isns_portal_group_list_t);
483 	if (pg_list->pg_out_cnt > 0) {
484 		pg_sz += (pg_list->pg_out_cnt - 1) *
485 		    sizeof (isns_portal_group_t);
486 	}
487 	kmem_free(pg_list, pg_sz);
488 }
489 
490 void
491 iscsid_do_isns_query(iscsi_hba_t *ihp)
492 {
493 	int pg_sz, query_status;
494 	isns_portal_group_list_t *pg_list;
495 
496 	pg_list = NULL;
497 	query_status = isns_query(ihp->hba_isid,
498 	    ihp->hba_name,
499 	    ihp->hba_alias,
500 	    ISNS_INITIATOR_NODE_TYPE,
501 	    &pg_list);
502 	if ((query_status != isns_ok &&
503 	    query_status != isns_op_partially_failed) ||
504 	    pg_list == NULL) {
505 		DTRACE_PROBE1(iscsid_do_isns_query_status,
506 		    int, query_status);
507 		return;
508 	}
509 	iscsid_add_pg_list_to_cache(ihp, pg_list);
510 
511 	pg_sz = sizeof (isns_portal_group_list_t);
512 	if (pg_list->pg_out_cnt > 0) {
513 		pg_sz += (pg_list->pg_out_cnt - 1) *
514 		    sizeof (isns_portal_group_t);
515 	}
516 	kmem_free(pg_list, pg_sz);
517 }
518 
519 /*
520  * iscsid_config_one - for the given target name, attempt
521  * to login to all targets associated with name.  If target
522  * name is not found in discovery queue, reset the discovery
523  * queue, kick the discovery processes, and then retry.
524  *
525  * NOTE: The caller of this function must hold the
526  *	iscsid_config_semaphore across this call.
527  */
528 void
529 iscsid_config_one(iscsi_hba_t *ihp, char *name, boolean_t protect)
530 {
531 	boolean_t	rc;
532 
533 	rc = iscsid_login_tgt(ihp, name,
534 	    iSCSIDiscoveryMethodUnknown, NULL);
535 	/*
536 	 * If we didn't login to the device we might have
537 	 * to update our discovery information and attempt
538 	 * the login again.
539 	 */
540 	if (rc == B_FALSE) {
541 		/*
542 		 * Stale /dev links can cause us to get floods
543 		 * of config requests.  Prevent these repeated
544 		 * requests from causing unneeded discovery updates
545 		 * if ISCSI_CONFIG_STORM_PROTECT is set.
546 		 */
547 		if ((protect == B_FALSE) ||
548 		    (ddi_get_lbolt() > ihp->hba_config_lbolt +
549 		    SEC_TO_TICK(ihp->hba_config_storm_delay))) {
550 			ihp->hba_config_lbolt = ddi_get_lbolt();
551 			iscsid_poke_discovery(ihp, iSCSIDiscoveryMethodUnknown);
552 			(void) iscsid_login_tgt(ihp, name,
553 			    iSCSIDiscoveryMethodUnknown, NULL);
554 		}
555 	}
556 }
557 
558 /*
559  * iscsid_config_all - reset the discovery queue, kick the
560  * discovery processes, and login to all targets found
561  *
562  * NOTE: The caller of this function must hold the
563  *	iscsid_config_semaphore across this call.
564  */
565 void
566 iscsid_config_all(iscsi_hba_t *ihp, boolean_t protect)
567 {
568 	/*
569 	 * Stale /dev links can cause us to get floods
570 	 * of config requests.  Prevent these repeated
571 	 * requests from causing unneeded discovery updates
572 	 * if ISCSI_CONFIG_STORM_PROTECT is set.
573 	 */
574 	if ((protect == B_FALSE) ||
575 	    (ddi_get_lbolt() > ihp->hba_config_lbolt +
576 	    SEC_TO_TICK(ihp->hba_config_storm_delay))) {
577 		ihp->hba_config_lbolt = ddi_get_lbolt();
578 		iscsid_poke_discovery(ihp, iSCSIDiscoveryMethodUnknown);
579 	}
580 	(void) iscsid_login_tgt(ihp, NULL,
581 	    iSCSIDiscoveryMethodUnknown, NULL);
582 }
583 
584 /*
585  * isns_scn_callback - iSNS client received an SCN
586  *
587  * This code processes the iSNS client SCN events.  These
588  * could relate to the addition, removal, or update of a
589  * logical unit.
590  */
591 void
592 isns_scn_callback(void *arg)
593 {
594 	int				i, pg_sz;
595 	int				qry_status;
596 	isns_portal_group_list_t	*pg_list;
597 	uint32_t			scn_type;
598 	iscsi_hba_t			*ihp;
599 
600 	if (arg == NULL) {
601 		/* No argument */
602 		return;
603 	}
604 
605 	if ((ihp = (iscsi_hba_t *)ddi_get_soft_state(iscsi_state, 0)) == NULL) {
606 		return;
607 	}
608 
609 	scn_type = ((isns_scn_callback_arg_t *)arg)->scn_type;
610 	DTRACE_PROBE1(isns_scn_callback_scn_type, int, scn_type);
611 	switch (scn_type) {
612 	/*
613 	 * ISNS_OBJ_ADDED - An object has been added.
614 	 */
615 	case ISNS_OBJ_ADDED:
616 		/* Query iSNS server for contact information */
617 		pg_list = NULL;
618 		qry_status = isns_query_one_node(
619 		    ((isns_scn_callback_arg_t *)arg)->source_key_attr,
620 		    ihp->hba_isid,
621 		    ihp->hba_name,
622 		    (uint8_t *)"",
623 		    ISNS_INITIATOR_NODE_TYPE,
624 		    &pg_list);
625 
626 		/* Verify portal group is found */
627 		if ((qry_status != isns_ok &&
628 		    qry_status != isns_op_partially_failed) ||
629 		    pg_list == NULL) {
630 			break;
631 		}
632 
633 		DTRACE_PROBE1(pg_list,
634 		    isns_portal_group_list_t *, pg_list);
635 
636 		/* Add all portals for logical unit to discovery cache */
637 		for (i = 0; i < pg_list->pg_out_cnt; i++) {
638 			iscsi_sockaddr_t addr_dsc;
639 			iscsi_sockaddr_t addr_tgt;
640 
641 			iscsid_addr_to_sockaddr(
642 			    pg_list->pg_list[i].isns_server_ip.i_insize,
643 			    &pg_list->pg_list[i].isns_server_ip.i_addr,
644 			    pg_list->pg_list[i].isns_server_port,
645 			    &addr_dsc.sin);
646 			iscsid_addr_to_sockaddr(pg_list->pg_list[i].insize,
647 			    &pg_list->pg_list[i].pg_ip_addr,
648 			    pg_list->pg_list[i].pg_port, &addr_tgt.sin);
649 
650 			(void) iscsid_add(ihp, iSCSIDiscoveryMethodISNS,
651 			    &addr_dsc.sin, (char *)pg_list->pg_list[i].
652 			    pg_iscsi_name, pg_list->pg_list[i].pg_tag,
653 			    &addr_tgt.sin);
654 
655 			/* Force target to login */
656 			(void) iscsid_login_tgt(ihp, (char *)pg_list->
657 			    pg_list[i].pg_iscsi_name, iSCSIDiscoveryMethodISNS,
658 			    NULL);
659 		}
660 
661 		if (pg_list != NULL) {
662 			pg_sz = sizeof (isns_portal_group_list_t);
663 			if (pg_list->pg_out_cnt > 0) {
664 				pg_sz += (pg_list->pg_out_cnt - 1) *
665 				    sizeof (isns_portal_group_t);
666 			}
667 			kmem_free(pg_list, pg_sz);
668 		}
669 		break;
670 
671 	/*
672 	 * ISNS_OBJ_REMOVED - logical unit has been removed
673 	 */
674 	case ISNS_OBJ_REMOVED:
675 		if (iscsid_del(ihp,
676 		    (char *)((isns_scn_callback_arg_t *)arg)->
677 		    source_key_attr, iSCSIDiscoveryMethodISNS, NULL) !=
678 		    B_TRUE) {
679 			cmn_err(CE_NOTE, "iscsi initiator - "
680 			    "isns remove scn failed for target %s\n",
681 			    (char *)((isns_scn_callback_arg_t *)arg)->
682 			    source_key_attr);
683 
684 		}
685 		break;
686 
687 	/*
688 	 * ISNS_OBJ_UPDATED - logical unit has changed
689 	 */
690 	case ISNS_OBJ_UPDATED:
691 		cmn_err(CE_NOTE, "iscsi initiator - "
692 		    "received iSNS update SCN for %s\n",
693 		    (char *)((isns_scn_callback_arg_t *)arg)->
694 		    source_key_attr);
695 		break;
696 
697 	/*
698 	 * ISNS_OBJ_UNKNOWN -
699 	 */
700 	default:
701 		cmn_err(CE_NOTE, "iscsi initiator - "
702 		    "received unknown iSNS SCN type 0x%x\n", scn_type);
703 		break;
704 	}
705 
706 	kmem_free(arg, sizeof (isns_scn_callback_arg_t));
707 }
708 
709 
710 /*
711  * iscsid_add - Creates discovered session and connection
712  */
713 static boolean_t
714 iscsid_add(iscsi_hba_t *ihp, iSCSIDiscoveryMethod_t method,
715     struct sockaddr *addr_dsc, char *target_name, int tpgt,
716     struct sockaddr *addr_tgt)
717 {
718 	boolean_t	    rtn = B_TRUE;
719 	iscsi_sess_t	    *isp;
720 	iscsi_conn_t	    *icp;
721 	uint_t		    oid;
722 	int		    idx;
723 	int		    isid;
724 	iscsi_config_sess_t *ics;
725 	int		    size;
726 	char		    *tmp;
727 
728 	ASSERT(ihp != NULL);
729 	ASSERT(addr_dsc != NULL);
730 	ASSERT(target_name != NULL);
731 	ASSERT(addr_tgt != NULL);
732 
733 	/* setup initial buffer for configured session information */
734 	size = sizeof (*ics);
735 	ics = kmem_zalloc(size, KM_SLEEP);
736 	ics->ics_in = 1;
737 
738 	/* get configured sessions information */
739 	tmp = target_name;
740 	if (persistent_get_config_session(tmp, ics) == B_FALSE) {
741 		/*
742 		 * No target information available check for
743 		 * initiator information.
744 		 */
745 		tmp = (char *)ihp->hba_name;
746 		if (persistent_get_config_session(tmp, ics) == B_FALSE) {
747 			/*
748 			 * No hba information is
749 			 * found.  So assume default
750 			 * one session unbound behavior.
751 			 */
752 			ics->ics_out = 1;
753 			ics->ics_bound = B_TRUE;
754 		}
755 	}
756 
757 	/* Check to see if we need to get more information */
758 	if (ics->ics_out > 1) {
759 		/* record new size and free last buffer */
760 		idx = ics->ics_out;
761 		size = ISCSI_SESSION_CONFIG_SIZE(ics->ics_out);
762 		kmem_free(ics, sizeof (*ics));
763 
764 		/* allocate new buffer */
765 		ics = kmem_zalloc(size, KM_SLEEP);
766 		ics->ics_in = idx;
767 
768 		/* get configured sessions information */
769 		if (persistent_get_config_session(tmp, ics) != B_TRUE) {
770 			cmn_err(CE_NOTE, "iscsi session(%s) - "
771 			    "unable to get configured session information\n",
772 			    target_name);
773 			kmem_free(ics, size);
774 			return (B_FALSE);
775 		}
776 	}
777 
778 	/* loop for all configured sessions */
779 	rw_enter(&ihp->hba_sess_list_rwlock, RW_WRITER);
780 	for (isid = 0; isid < ics->ics_out; isid++) {
781 		/* create or find matching session */
782 		isp = iscsi_sess_create(ihp, method, addr_dsc, target_name,
783 		    tpgt, isid, ISCSI_SESS_TYPE_NORMAL, &oid);
784 		if (isp == NULL) {
785 			rtn = B_FALSE;
786 			break;
787 		}
788 
789 		/* create or find matching connection */
790 		if (!ISCSI_SUCCESS(iscsi_conn_create(addr_tgt, isp, &icp))) {
791 			rtn = B_FALSE;
792 			break;
793 		}
794 	}
795 	rw_exit(&ihp->hba_sess_list_rwlock);
796 	kmem_free(ics, size);
797 	return (rtn);
798 }
799 
800 /*
801  * iscsid_del - Attempts to delete all associated sessions
802  */
803 boolean_t
804 iscsid_del(iscsi_hba_t *ihp, char *target_name,
805     iSCSIDiscoveryMethod_t method, struct sockaddr *addr_dsc)
806 {
807 	boolean_t	rtn = B_TRUE;
808 	iscsi_status_t	status;
809 	iscsi_sess_t	*isp;
810 	char		name[ISCSI_MAX_NAME_LEN];
811 
812 	ASSERT(ihp != NULL);
813 	/* target name can be NULL or !NULL */
814 	/* addr_dsc can be NULL or !NULL */
815 
816 	rw_enter(&ihp->hba_sess_list_rwlock, RW_WRITER);
817 	isp = ihp->hba_sess_list;
818 	while (isp != NULL) {
819 		/*
820 		 * If no target_name is listed (meaning all targets)
821 		 * or this specific target was listed. And the same
822 		 * discovery method discovered this target then
823 		 * continue evaulation.  Otherwise fail.
824 		 */
825 		if (((target_name == NULL) ||
826 		    (strcmp((char *)isp->sess_name, target_name) == 0)) &&
827 		    (isp->sess_discovered_by == method)) {
828 			boolean_t try_destroy;
829 
830 			/*
831 			 * If iSNS, SendTargets, or Static then special
832 			 * handling for disc_addr.
833 			 */
834 			if ((method == iSCSIDiscoveryMethodISNS) ||
835 			    (method == iSCSIDiscoveryMethodSendTargets)) {
836 				/*
837 				 * If NULL addr_dsc (meaning all disc_addr)
838 				 * or matching discovered addr.
839 				 */
840 				if ((addr_dsc == NULL) ||
841 				    (bcmp(addr_dsc, &isp->sess_discovered_addr,
842 				    SIZEOF_SOCKADDR(
843 				    &isp->sess_discovered_addr.sin)) == 0)) {
844 					try_destroy = B_TRUE;
845 				} else {
846 					try_destroy = B_FALSE;
847 				}
848 			} else if (method == iSCSIDiscoveryMethodStatic) {
849 				/*
850 				 * If NULL addr_dsc (meaning all disc_addr)
851 				 * or matching active connection.
852 				 */
853 				if ((addr_dsc == NULL) ||
854 				    ((isp->sess_conn_act != NULL) &&
855 				    (bcmp(addr_dsc,
856 				    &isp->sess_conn_act->conn_base_addr.sin,
857 				    SIZEOF_SOCKADDR(
858 				    &isp->sess_conn_act->conn_base_addr.sin))
859 				    == 0))) {
860 					try_destroy = B_TRUE;
861 				} else {
862 					try_destroy = B_FALSE;
863 				}
864 			} else {
865 				/* Unknown discovery specified */
866 				try_destroy = B_TRUE;
867 			}
868 
869 			if (try_destroy == B_TRUE) {
870 				(void) strcpy(name, (char *)isp->sess_name);
871 				status = iscsi_sess_destroy(isp);
872 				if (ISCSI_SUCCESS(status)) {
873 					iscsid_remove_target_param(name);
874 					isp = ihp->hba_sess_list;
875 				} else {
876 					/*
877 					 * The most likely destroy failure
878 					 * is that ndi/mdi offline failed.
879 					 * This means that the resource is
880 					 * in_use/busy.
881 					 */
882 					cmn_err(CE_NOTE, "iscsi session(%d) - "
883 					    "session logout failed (%d)\n",
884 					    isp->sess_oid, status);
885 					isp = isp->sess_next;
886 					rtn = B_FALSE;
887 				}
888 			} else {
889 				isp = isp->sess_next;
890 			}
891 		} else {
892 			isp = isp->sess_next;
893 		}
894 	}
895 	rw_exit(&ihp->hba_sess_list_rwlock);
896 	return (rtn);
897 }
898 
899 
900 /*
901  * iscsid_login_tgt - request target(s) to login
902  */
903 boolean_t
904 iscsid_login_tgt(iscsi_hba_t *ihp, char *target_name,
905     iSCSIDiscoveryMethod_t method, struct sockaddr *addr_dsc)
906 {
907 	boolean_t	rtn = B_FALSE;
908 	iscsi_sess_t	*isp;
909 
910 	ASSERT(ihp != NULL);
911 
912 	rw_enter(&ihp->hba_sess_list_rwlock, RW_WRITER);
913 	/* Loop thru sessions */
914 	isp = ihp->hba_sess_list;
915 	while (isp != NULL) {
916 		boolean_t try_online;
917 
918 		if (target_name == NULL) {
919 			if (method == iSCSIDiscoveryMethodUnknown) {
920 				/* unknown method mean login to all */
921 				try_online = B_TRUE;
922 			} else if (isp->sess_discovered_by & method) {
923 				if ((method == iSCSIDiscoveryMethodISNS) ||
924 				    (method ==
925 				    iSCSIDiscoveryMethodSendTargets)) {
926 					if ((addr_dsc == NULL) ||
927 					    (bcmp(&isp->sess_discovered_addr,
928 					    addr_dsc, SIZEOF_SOCKADDR(
929 					    &isp->sess_discovered_addr.sin))
930 					    == 0)) {
931 						/*
932 						 * iSNS or sendtarget
933 						 * discovery and discovery
934 						 * address is NULL or match
935 						 */
936 						try_online = B_TRUE;
937 					} else {
938 						/* addr_dsc not a match */
939 						try_online = B_FALSE;
940 					}
941 				} else {
942 					/* static configuration */
943 					try_online = B_TRUE;
944 				}
945 			} else {
946 				/* method not a match */
947 				try_online = B_FALSE;
948 			}
949 		} else if (strcmp(target_name, (char *)isp->sess_name) == 0) {
950 			/* target_name match */
951 			try_online = B_TRUE;
952 		} else {
953 			/* target_name not a match */
954 			try_online = B_FALSE;
955 		}
956 
957 		if (try_online == B_TRUE) {
958 			iscsi_sess_online(isp);
959 			rtn = B_TRUE;
960 		}
961 		isp = isp->sess_next;
962 	}
963 	rw_exit(&ihp->hba_sess_list_rwlock);
964 	return (rtn);
965 }
966 
967 /*
968  * +--------------------------------------------------------------------+
969  * | Local Helper Functions                                             |
970  * +--------------------------------------------------------------------+
971  */
972 
973 /*
974  * iscsid_init_config -- initialize configuration parameters of iSCSI initiator
975  */
976 static boolean_t
977 iscsid_init_config(iscsi_hba_t *ihp)
978 {
979 	iscsi_param_set_t	ips;
980 	void *v = NULL;
981 	char *name;
982 	char *initiatorName;
983 	persistent_param_t	pp;
984 	uint32_t		param_id;
985 	int			rc;
986 
987 	/* allocate memory to hold initiator names */
988 	initiatorName = kmem_zalloc(ISCSI_MAX_NAME_LEN, KM_SLEEP);
989 
990 	/*
991 	 * initialize iSCSI initiator name
992 	 */
993 	bzero(&ips, sizeof (ips));
994 	if (persistent_initiator_name_get(initiatorName,
995 	    ISCSI_MAX_NAME_LEN) == B_TRUE) {
996 		(void) strncpy((char *)ips.s_value.v_name, initiatorName,
997 		    sizeof (ips.s_value.v_name));
998 
999 		ips.s_vers	= ISCSI_INTERFACE_VERSION;
1000 		ips.s_param	= ISCSI_LOGIN_PARAM_INITIATOR_NAME;
1001 
1002 		(void) iscsi_set_params(&ips, ihp, B_FALSE);
1003 	} else {
1004 		/*
1005 		 * if we don't have an initiator-node name it's most
1006 		 * likely because this is a fresh install (or we
1007 		 * couldn't read the persistent store properly).  Set
1008 		 * a default initiator name so the initiator can
1009 		 * be brought up properly.
1010 		 */
1011 		iscsid_set_default_initiator_node_settings(ihp);
1012 	}
1013 
1014 	/*
1015 	 * initialize iSCSI initiator alias (if any)
1016 	 */
1017 	bzero(&ips, sizeof (ips));
1018 	if (persistent_alias_name_get((char *)ips.s_value.v_name,
1019 	    sizeof (ips.s_value.v_name)) == B_TRUE) {
1020 		ips.s_param	= ISCSI_LOGIN_PARAM_INITIATOR_ALIAS;
1021 		(void) iscsi_set_params(&ips, ihp, B_FALSE);
1022 	} else {
1023 		/* EMPTY */
1024 		/* No alias defined - not a problem. */
1025 	}
1026 
1027 	/*
1028 	 * load up the overriden iSCSI initiator parameters
1029 	 */
1030 	name = kmem_zalloc(ISCSI_MAX_NAME_LEN, KM_SLEEP);
1031 	persistent_param_lock();
1032 	v = NULL;
1033 	while (persistent_param_next(&v, name, &pp) == B_TRUE) {
1034 		if (strncmp(name, initiatorName, ISCSI_MAX_NAME_LEN) == 0) {
1035 			ips.s_oid = ihp->hba_oid;
1036 			ips.s_vers = ISCSI_INTERFACE_VERSION;
1037 			for (param_id = 0; param_id < ISCSI_NUM_LOGIN_PARAM;
1038 			    param_id++) {
1039 				if (pp.p_bitmap & (1 << param_id)) {
1040 					rc = iscsid_copyto_param_set(param_id,
1041 					    &pp.p_params, &ips);
1042 					if (rc == 0) {
1043 						rc = iscsi_set_params(&ips,
1044 						    ihp, B_FALSE);
1045 					}
1046 					if (rc != 0) {
1047 						/* note error but continue  */
1048 						cmn_err(CE_NOTE,
1049 						    "Failed to set "
1050 						    "param %d for OID %d",
1051 						    ips.s_param, ips.s_oid);
1052 					}
1053 				}
1054 			} /* END for() */
1055 			break;
1056 		}
1057 	} /* END while() */
1058 	persistent_param_unlock();
1059 
1060 	kmem_free(initiatorName, ISCSI_MAX_NAME_LEN);
1061 	kmem_free(name, ISCSI_MAX_NAME_LEN);
1062 	return (B_TRUE);
1063 }
1064 
1065 
1066 /*
1067  * iscsid_init_targets -- Load up the driver with known static targets and
1068  * targets whose parameters have been modified.
1069  *
1070  * This is done so that the CLI can find a list of targets the driver
1071  * currently knows about.
1072  *
1073  * The driver doesn't need to log into these targets.  Log in is done based
1074  * upon the enabled discovery methods.
1075  */
1076 static boolean_t
1077 iscsid_init_targets(iscsi_hba_t *ihp)
1078 {
1079 	void			*v = NULL;
1080 	char			*name;
1081 	iscsi_param_set_t	ips;
1082 	persistent_param_t	pp;
1083 	char			*iname;
1084 	uint32_t		param_id;
1085 	int			rc;
1086 
1087 	ASSERT(ihp != NULL);
1088 
1089 	/* allocate memory to hold target names */
1090 	name = kmem_zalloc(ISCSI_MAX_NAME_LEN, KM_SLEEP);
1091 
1092 	/*
1093 	 * load up targets whose parameters have been overriden
1094 	 */
1095 
1096 	/* ---- only need to be set once ---- */
1097 	bzero(&ips, sizeof (ips));
1098 	ips.s_vers = ISCSI_INTERFACE_VERSION;
1099 
1100 	/* allocate memory to hold initiator name */
1101 	iname = kmem_zalloc(ISCSI_MAX_NAME_LEN, KM_SLEEP);
1102 	(void) persistent_initiator_name_get(iname, ISCSI_MAX_NAME_LEN);
1103 
1104 	persistent_param_lock();
1105 	v = NULL;
1106 	while (persistent_param_next(&v, name, &pp) == B_TRUE) {
1107 
1108 		if (strncmp(iname, name, ISCSI_MAX_NAME_LEN) == 0) {
1109 			/*
1110 			 * target name matched initiator's name so,
1111 			 * continue to next target.  Initiator's
1112 			 * parmeters have already been set.
1113 			 */
1114 			continue;
1115 		}
1116 
1117 		ips.s_oid = iscsi_targetparam_get_oid((unsigned char *)name);
1118 
1119 		for (param_id = 0; param_id < ISCSI_NUM_LOGIN_PARAM;
1120 		    param_id++) {
1121 			if (pp.p_bitmap & (1 << param_id)) {
1122 				rc = iscsid_copyto_param_set(param_id,
1123 				    &pp.p_params, &ips);
1124 				if (rc == 0) {
1125 					rc = iscsi_set_params(&ips,
1126 					    ihp, B_FALSE);
1127 				}
1128 				if (rc != 0) {
1129 					/* note error but continue  ---- */
1130 					cmn_err(CE_NOTE, "Failed to set "
1131 					    "param %d for OID %d",
1132 					    ips.s_param, ips.s_oid);
1133 				}
1134 			}
1135 		} /* END for() */
1136 	} /* END while() */
1137 	persistent_param_unlock();
1138 
1139 	kmem_free(iname, ISCSI_MAX_NAME_LEN);
1140 	kmem_free(name, ISCSI_MAX_NAME_LEN);
1141 
1142 	return (B_TRUE);
1143 }
1144 
1145 
1146 /*
1147  * iscsid_thread_static -- If static discovery is enabled, this routine obtains
1148  * all statically configured targets from the peristent store and issues a
1149  * login request to the driver.
1150  */
1151 /* ARGSUSED */
1152 static void
1153 iscsid_thread_static(iscsi_thread_t *thread, void *p)
1154 {
1155 	iSCSIDiscoveryMethod_t	dm;
1156 	entry_t			entry;
1157 	char			name[ISCSI_MAX_NAME_LEN];
1158 	void			*v = NULL;
1159 	iscsi_hba_t		*ihp = (iscsi_hba_t *)p;
1160 
1161 	while (iscsi_thread_wait(thread, -1) != 0) {
1162 		iscsi_discovery_event(ihp, iSCSIDiscoveryMethodStatic, B_TRUE);
1163 
1164 		/* ---- ensure static target discovery is enabled ---- */
1165 		dm = persistent_disc_meth_get();
1166 		if ((dm & iSCSIDiscoveryMethodStatic) == 0) {
1167 			cmn_err(CE_NOTE,
1168 			    "iscsi discovery failure - "
1169 			    "StaticTargets method is not enabled");
1170 			iscsi_discovery_event(ihp,
1171 			    iSCSIDiscoveryMethodStatic, B_FALSE);
1172 			continue;
1173 		}
1174 
1175 		/*
1176 		 * walk list of the statically configured targets from the
1177 		 * persistent store
1178 		 */
1179 		v = NULL;
1180 		persistent_static_addr_lock();
1181 		while (persistent_static_addr_next(&v, name, &entry) ==
1182 		    B_TRUE) {
1183 			iscsi_sockaddr_t addr;
1184 
1185 			iscsid_addr_to_sockaddr(entry.e_insize,
1186 			    &(entry.e_u), entry.e_port, &addr.sin);
1187 
1188 			(void) iscsid_add(ihp, iSCSIDiscoveryMethodStatic,
1189 			    &addr.sin, name, entry.e_tpgt, &addr.sin);
1190 		}
1191 		persistent_static_addr_unlock();
1192 		iscsi_discovery_event(ihp, iSCSIDiscoveryMethodStatic, B_FALSE);
1193 	}
1194 }
1195 
1196 
1197 /*
1198  * iscsid_thread_sendtgts -- If SendTargets discovery is enabled, this routine
1199  * obtains all target discovery addresses configured from the peristent store
1200  * and probe the IP/port addresses for possible targets.  It will then issue
1201  * a login request to the driver for all discoveryed targets.
1202  */
1203 static void
1204 iscsid_thread_sendtgts(iscsi_thread_t *thread, void *p)
1205 {
1206 	iscsi_hba_t		*ihp = (iscsi_hba_t *)p;
1207 	iSCSIDiscoveryMethod_t	dm;
1208 	entry_t			entry;
1209 	void			*v = NULL;
1210 
1211 	while (iscsi_thread_wait(thread, -1) != 0) {
1212 		iscsi_discovery_event(ihp, iSCSIDiscoveryMethodSendTargets,
1213 		    B_TRUE);
1214 
1215 		/* ---- ensure SendTargets discovery is enabled ---- */
1216 		dm = persistent_disc_meth_get();
1217 		if ((dm & iSCSIDiscoveryMethodSendTargets) == 0) {
1218 			cmn_err(CE_NOTE,
1219 			    "iscsi discovery failure - "
1220 			    "SendTargets method is not enabled");
1221 			iscsi_discovery_event(ihp,
1222 			    iSCSIDiscoveryMethodSendTargets, B_FALSE);
1223 			continue;
1224 		}
1225 		/*
1226 		 * walk list of the SendTarget discovery addresses from the
1227 		 * persistent store
1228 		 */
1229 		v = NULL;
1230 		persistent_disc_addr_lock();
1231 		while (persistent_disc_addr_next(&v, &entry) == B_TRUE) {
1232 			iscsid_do_sendtgts(&entry);
1233 		}
1234 		persistent_disc_addr_unlock();
1235 
1236 		iscsi_discovery_event(ihp, iSCSIDiscoveryMethodSendTargets,
1237 		    B_FALSE);
1238 	}
1239 }
1240 
1241 /*
1242  * iscsid_thread_slp -- If SLP discovery is enabled,  this routine provides
1243  * the SLP discovery service.
1244  */
1245 static void
1246 iscsid_thread_slp(iscsi_thread_t *thread, void *p)
1247 {
1248 	iscsi_hba_t  *ihp = (iscsi_hba_t *)p;
1249 
1250 	do {
1251 		/*
1252 		 * Even though we don't have support for SLP at this point
1253 		 * we'll send the events if someone has enabled this thread.
1254 		 * If this is not done the daemon waiting for discovery to
1255 		 * complete will pause forever holding up the boot process.
1256 		 */
1257 		iscsi_discovery_event(ihp, iSCSIDiscoveryMethodSLP, B_TRUE);
1258 		iscsi_discovery_event(ihp, iSCSIDiscoveryMethodSLP, B_FALSE);
1259 	} while (iscsi_thread_wait(thread, -1) != 0);
1260 }
1261 
1262 /*
1263  * iscsid_thread_isns --
1264  */
1265 static void
1266 iscsid_thread_isns(iscsi_thread_t *thread, void *ptr)
1267 {
1268 	iscsi_hba_t		*ihp = (iscsi_hba_t *)ptr;
1269 	iSCSIDiscoveryMethod_t	dm;
1270 
1271 	while (iscsi_thread_wait(thread, -1) != 0) {
1272 		iscsi_discovery_event(ihp, iSCSIDiscoveryMethodISNS, B_TRUE);
1273 
1274 		/* ---- ensure iSNS discovery is enabled ---- */
1275 		dm = persistent_disc_meth_get();
1276 		if ((dm & iSCSIDiscoveryMethodISNS) == 0) {
1277 			cmn_err(CE_NOTE,
1278 			    "iscsi discovery failure - "
1279 			    "iSNS method is not enabled");
1280 			iscsi_discovery_event(ihp,
1281 			    iSCSIDiscoveryMethodISNS, B_FALSE);
1282 			continue;
1283 		}
1284 
1285 		(void) isns_reg(ihp->hba_isid,
1286 		    ihp->hba_name,
1287 		    ISCSI_MAX_NAME_LEN,
1288 		    ihp->hba_alias,
1289 		    ISCSI_MAX_NAME_LEN,
1290 		    ISNS_INITIATOR_NODE_TYPE,
1291 		    isns_scn_callback);
1292 		iscsid_do_isns_query(ihp);
1293 		iscsi_discovery_event(ihp, iSCSIDiscoveryMethodISNS, B_FALSE);
1294 	}
1295 
1296 	/* Thread stopped. Deregister from iSNS servers(s). */
1297 	(void) isns_dereg(ihp->hba_isid, ihp->hba_name);
1298 }
1299 
1300 
1301 /*
1302  * iscsid_threads_create -- Creates all the discovery threads.
1303  */
1304 static void
1305 iscsid_threads_create(iscsi_hba_t *ihp)
1306 {
1307 	iscsid_thr_table	*t;
1308 
1309 	/*
1310 	 * start a thread for each discovery method
1311 	 */
1312 	for (t = &iscsid_thr[0]; t->method != iSCSIDiscoveryMethodUnknown;
1313 	    t++) {
1314 		if (t->thr_id == NULL) {
1315 			t->thr_id = iscsi_thread_create(ihp->hba_dip, t->name,
1316 			    t->func_start, ihp);
1317 		}
1318 	}
1319 }
1320 
1321 /*
1322  * iscsid_threads_destroy -- Destroys all the discovery threads.
1323  */
1324 static void
1325 iscsid_threads_destroy(void)
1326 {
1327 	iscsid_thr_table	*t;
1328 
1329 	for (t = &iscsid_thr[0]; t->method != iSCSIDiscoveryMethodUnknown;
1330 	    t++) {
1331 		if (t->thr_id != NULL) {
1332 			iscsi_thread_destroy(t->thr_id);
1333 			t->thr_id = NULL;
1334 		}
1335 	}
1336 }
1337 
1338 /*
1339  * iscsid_copyto_param_set - helper function for iscsid_init_params.
1340  */
1341 static int
1342 iscsid_copyto_param_set(uint32_t param_id, iscsi_login_params_t *params,
1343     iscsi_param_set_t *ipsp)
1344 {
1345 	int rtn = 0;
1346 
1347 	if (param_id >= ISCSI_NUM_LOGIN_PARAM) {
1348 		return (EINVAL);
1349 	}
1350 
1351 	switch (param_id) {
1352 
1353 	/*
1354 	 * Boolean parameters
1355 	 */
1356 	case ISCSI_LOGIN_PARAM_DATA_SEQUENCE_IN_ORDER:
1357 		ipsp->s_value.v_bool = params->data_pdu_in_order;
1358 		break;
1359 	case ISCSI_LOGIN_PARAM_IMMEDIATE_DATA:
1360 		ipsp->s_value.v_bool = params->immediate_data;
1361 		break;
1362 	case ISCSI_LOGIN_PARAM_INITIAL_R2T:
1363 		ipsp->s_value.v_bool = params->initial_r2t;
1364 		break;
1365 	case ISCSI_LOGIN_PARAM_DATA_PDU_IN_ORDER:
1366 		ipsp->s_value.v_bool = params->data_pdu_in_order;
1367 		break;
1368 
1369 	/*
1370 	 * Integer parameters
1371 	 */
1372 	case ISCSI_LOGIN_PARAM_HEADER_DIGEST:
1373 		ipsp->s_value.v_integer = params->header_digest;
1374 		break;
1375 	case ISCSI_LOGIN_PARAM_DATA_DIGEST:
1376 		ipsp->s_value.v_integer = params->data_digest;
1377 		break;
1378 	case ISCSI_LOGIN_PARAM_DEFAULT_TIME_2_RETAIN:
1379 		ipsp->s_value.v_integer = params->default_time_to_retain;
1380 		break;
1381 	case ISCSI_LOGIN_PARAM_DEFAULT_TIME_2_WAIT:
1382 		ipsp->s_value.v_integer = params->default_time_to_wait;
1383 		break;
1384 	case ISCSI_LOGIN_PARAM_MAX_RECV_DATA_SEGMENT_LENGTH:
1385 		ipsp->s_value.v_integer = params->max_recv_data_seg_len;
1386 		break;
1387 	case ISCSI_LOGIN_PARAM_FIRST_BURST_LENGTH:
1388 		ipsp->s_value.v_integer = params->first_burst_length;
1389 		break;
1390 	case ISCSI_LOGIN_PARAM_MAX_BURST_LENGTH:
1391 		ipsp->s_value.v_integer =  params->max_burst_length;
1392 		break;
1393 
1394 	/*
1395 	 * Integer parameters which currently are unsettable
1396 	 */
1397 	case ISCSI_LOGIN_PARAM_MAX_CONNECTIONS:
1398 	case ISCSI_LOGIN_PARAM_OUTSTANDING_R2T:
1399 	case ISCSI_LOGIN_PARAM_ERROR_RECOVERY_LEVEL:
1400 	/* ---- drop through to default case ---- */
1401 	default:
1402 		rtn = EINVAL;
1403 		break;
1404 	}
1405 
1406 	/* if all is well, set the parameter identifier */
1407 	if (rtn == 0) {
1408 		ipsp->s_param = param_id;
1409 	}
1410 
1411 	return (rtn);
1412 }
1413 
1414 /*
1415  * iscsid_add_pg_list_to_cache - Add portal groups in the list to the
1416  * discovery cache.
1417  */
1418 static void
1419 iscsid_add_pg_list_to_cache(iscsi_hba_t *ihp,
1420     isns_portal_group_list_t *pg_list)
1421 {
1422 	int		    i;
1423 
1424 	for (i = 0; i < pg_list->pg_out_cnt; i++) {
1425 		iscsi_sockaddr_t addr_dsc;
1426 		iscsi_sockaddr_t addr_tgt;
1427 
1428 		iscsid_addr_to_sockaddr(
1429 		    pg_list->pg_list[i].isns_server_ip.i_insize,
1430 		    &pg_list->pg_list[i].isns_server_ip.i_addr,
1431 		    pg_list->pg_list[i].isns_server_port,
1432 		    &addr_dsc.sin);
1433 		iscsid_addr_to_sockaddr(
1434 		    pg_list->pg_list[i].insize,
1435 		    &pg_list->pg_list[i].pg_ip_addr,
1436 		    pg_list->pg_list[i].pg_port,
1437 		    &addr_tgt.sin);
1438 
1439 		(void) iscsid_add(ihp, iSCSIDiscoveryMethodISNS, &addr_dsc.sin,
1440 		    (char *)pg_list->pg_list[i].pg_iscsi_name,
1441 		    pg_list->pg_list[i].pg_tag, &addr_tgt.sin);
1442 	}
1443 }
1444 
1445 /*
1446  * set_initiator_name - set default initiator name and alias.
1447  *
1448  * This sets the default initiator name and alias.  The
1449  * initiator name is composed of sun's reverse domain name
1450  * and registration followed and a unique classifier.  This
1451  * classifier is the mac address of the first NIC in the
1452  * host and a timestamp to make sure the classifier is
1453  * unique if the NIC is moved between hosts.  The alias
1454  * is just the hostname.
1455  */
1456 static void
1457 iscsid_set_default_initiator_node_settings(iscsi_hba_t *ihp)
1458 {
1459 	int		    i;
1460 	time_t		    x;
1461 	struct ether_addr   eaddr;
1462 	char		    val[10];
1463 	iscsi_chap_props_t  *chap = NULL;
1464 
1465 	/* Set default initiator-node name */
1466 	(void) snprintf((char *)ihp->hba_name,
1467 	    ISCSI_MAX_NAME_LEN,
1468 	    "iqn.1986-03.com.sun:01:");
1469 
1470 	(void) localetheraddr(NULL, &eaddr);
1471 	for (i = 0; i <  ETHERADDRL; i++) {
1472 		(void) snprintf(val, sizeof (val), "%02x",
1473 		    eaddr.ether_addr_octet[i]);
1474 		(void) strncat((char *)ihp->hba_name, val, ISCSI_MAX_NAME_LEN);
1475 	}
1476 
1477 	/* Set default initiator-node alias */
1478 	x = ddi_get_time();
1479 	(void) snprintf(val, sizeof (val), ".%lx", x);
1480 	(void) strncat((char *)ihp->hba_name, val, ISCSI_MAX_NAME_LEN);
1481 	(void) persistent_initiator_name_set((char *)ihp->hba_name);
1482 	if (ihp->hba_alias[0] == '\0') {
1483 		(void) strncpy((char *)ihp->hba_alias,
1484 		    utsname.nodename, ISCSI_MAX_NAME_LEN);
1485 		ihp->hba_alias_length = strlen((char *)ihp->hba_alias);
1486 		(void) persistent_alias_name_set((char *)ihp->hba_alias);
1487 	}
1488 
1489 	/* Set default initiator-node CHAP settings */
1490 	if (persistent_initiator_name_get((char *)ihp->hba_name,
1491 	    ISCSI_MAX_NAME_LEN) == B_TRUE) {
1492 		chap = (iscsi_chap_props_t *)kmem_zalloc(sizeof (*chap),
1493 		    KM_SLEEP);
1494 		if (persistent_chap_get((char *)ihp->hba_name, chap) ==
1495 		    B_FALSE) {
1496 			bcopy((char *)ihp->hba_name, chap->c_user,
1497 			    strlen((char *)ihp->hba_name));
1498 			chap->c_user_len = strlen((char *)ihp->hba_name);
1499 			(void) persistent_chap_set((char *)ihp->hba_name, chap);
1500 		}
1501 		kmem_free(chap, sizeof (*chap));
1502 	}
1503 }
1504 
1505 static void
1506 iscsid_remove_target_param(char *name)
1507 {
1508 	persistent_param_t  *pparam;
1509 	uint32_t	    t_oid;
1510 	iscsi_config_sess_t *ics;
1511 
1512 	ASSERT(name != NULL);
1513 
1514 	/*
1515 	 * Remove target-param <-> target mapping.
1516 	 * Only remove if there is not any overridden
1517 	 * parameters in the persistent store
1518 	 */
1519 	pparam = (persistent_param_t *)kmem_zalloc(sizeof (*pparam), KM_SLEEP);
1520 
1521 	/*
1522 	 * setup initial buffer for configured session
1523 	 * information
1524 	 */
1525 	ics = (iscsi_config_sess_t *)kmem_zalloc(sizeof (*ics), KM_SLEEP);
1526 	ics->ics_in = 1;
1527 
1528 	if ((persistent_param_get(name, pparam) == B_FALSE) &&
1529 	    (persistent_get_config_session(name, ics) == B_FALSE))  {
1530 		t_oid = iscsi_targetparam_get_oid((uchar_t *)name);
1531 		(void) iscsi_targetparam_remove_target(t_oid);
1532 	}
1533 
1534 	kmem_free(pparam, sizeof (*pparam));
1535 	pparam = NULL;
1536 	kmem_free(ics, sizeof (*ics));
1537 	ics = NULL;
1538 }
1539 
1540 /*
1541  * iscsid_addr_to_sockaddr - convert other types to struct sockaddr
1542  */
1543 void
1544 iscsid_addr_to_sockaddr(int src_insize, void *src_addr, int src_port,
1545     struct sockaddr *dst_addr)
1546 {
1547 	ASSERT((src_insize == sizeof (struct in_addr)) ||
1548 	    (src_insize == sizeof (struct in6_addr)));
1549 	ASSERT(src_addr != NULL);
1550 	ASSERT(dst_addr != NULL);
1551 
1552 	bzero(dst_addr, sizeof (*dst_addr));
1553 
1554 	/* translate discovery information */
1555 	if (src_insize == sizeof (struct in_addr)) {
1556 		struct sockaddr_in *addr_in =
1557 		    (struct sockaddr_in *)dst_addr;
1558 		addr_in->sin_family = AF_INET;
1559 		bcopy(src_addr, &addr_in->sin_addr.s_addr,
1560 		    sizeof (struct in_addr));
1561 		addr_in->sin_port = htons(src_port);
1562 	} else {
1563 		struct sockaddr_in6 *addr_in6 =
1564 		    (struct sockaddr_in6 *)dst_addr;
1565 		addr_in6->sin6_family = AF_INET6;
1566 		bcopy(src_addr, &addr_in6->sin6_addr.s6_addr,
1567 		    sizeof (struct in6_addr));
1568 		addr_in6->sin6_port = htons(src_port);
1569 	}
1570 }
1571 
1572 /*
1573  * iscsi_discovery_event -- send event associated with discovery operations
1574  *
1575  * Each discovery event has a start and end event. Which is sent is based
1576  * on the boolean argument start with the obvious results.
1577  */
1578 static void
1579 iscsi_discovery_event(iscsi_hba_t *ihp, iSCSIDiscoveryMethod_t m,
1580     boolean_t start)
1581 {
1582 	char	*subclass = NULL;
1583 
1584 	mutex_enter(&ihp->hba_discovery_events_mutex);
1585 	switch (m) {
1586 	case iSCSIDiscoveryMethodStatic:
1587 		if (start == B_TRUE) {
1588 			subclass = ESC_ISCSI_STATIC_START;
1589 		} else {
1590 			ihp->hba_discovery_events |= iSCSIDiscoveryMethodStatic;
1591 			subclass = ESC_ISCSI_STATIC_END;
1592 		}
1593 		break;
1594 
1595 	case iSCSIDiscoveryMethodSendTargets:
1596 		if (start == B_TRUE) {
1597 			subclass = ESC_ISCSI_SEND_TARGETS_START;
1598 		} else {
1599 			ihp->hba_discovery_events |=
1600 			    iSCSIDiscoveryMethodSendTargets;
1601 			subclass = ESC_ISCSI_SEND_TARGETS_END;
1602 		}
1603 		break;
1604 
1605 	case iSCSIDiscoveryMethodSLP:
1606 		if (start == B_TRUE) {
1607 			subclass = ESC_ISCSI_SLP_START;
1608 		} else {
1609 			ihp->hba_discovery_events |= iSCSIDiscoveryMethodSLP;
1610 			subclass = ESC_ISCSI_SLP_END;
1611 		}
1612 		break;
1613 
1614 	case iSCSIDiscoveryMethodISNS:
1615 		if (start == B_TRUE) {
1616 			subclass = ESC_ISCSI_ISNS_START;
1617 		} else {
1618 			ihp->hba_discovery_events |= iSCSIDiscoveryMethodISNS;
1619 			subclass = ESC_ISCSI_ISNS_END;
1620 		}
1621 		break;
1622 	}
1623 	mutex_exit(&ihp->hba_discovery_events_mutex);
1624 	iscsi_send_sysevent(ihp, subclass, NULL);
1625 }
1626 
1627 /*
1628  * iscsi_send_sysevent -- send sysevent using iscsi class
1629  */
1630 static void
1631 iscsi_send_sysevent(iscsi_hba_t *ihp, char *subclass, nvlist_t *np)
1632 {
1633 	(void) ddi_log_sysevent(ihp->hba_dip, DDI_VENDOR_SUNW, EC_ISCSI,
1634 	    subclass, np, NULL, DDI_SLEEP);
1635 }
1636