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