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