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