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