1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * 25 * iSCSI session interfaces 26 */ 27 28 #include <sys/bootprops.h> 29 #include "iscsi.h" 30 #include "persistent.h" 31 #include "iscsi_targetparam.h" 32 33 #define ISCSI_SESS_ENUM_TIMEOUT_DEFAULT 60 34 #define SCSI_INQUIRY_PQUAL_MASK 0xE0 35 36 /* 37 * used to store report lun information found 38 * 39 * lun_valid: if TRUE means the entry contains a valid entry 40 * lun_found: if TRUE means the lun has been found in the sess_lun_list 41 * lun_num: contains the lun_number 42 */ 43 typedef struct replun_data { 44 boolean_t lun_valid; 45 boolean_t lun_found; 46 uint16_t lun_num; 47 } replun_data_t; 48 49 int iscsi_sess_enum_timeout = ISCSI_SESS_ENUM_TIMEOUT_DEFAULT; 50 51 /* 52 * The following private tunable, settable via 53 * set iscsi:iscsi_sess_max_delay = 64 54 * in /etc/system, provides customer relief for configurations max interval in 55 * seconds of retry for a unreachable target during the login. 56 */ 57 int iscsi_sess_max_delay = ISCSI_DEFAULT_MAX_STORM_DELAY; 58 59 /* internal interfaces */ 60 /* LINTED E_STATIC_UNUSED */ 61 static iscsi_sess_t *iscsi_sess_alloc(iscsi_hba_t *ihp, iscsi_sess_type_t type); 62 static char *iscsi_sess_event_str(iscsi_sess_event_t event); 63 static iscsi_status_t iscsi_sess_threads_create(iscsi_sess_t *isp); 64 static void iscsi_sess_flush(iscsi_sess_t *isp); 65 static void iscsi_sess_offline_luns(iscsi_sess_t *isp); 66 static iscsi_status_t retrieve_lundata(uint32_t lun_count, unsigned char *buf, 67 iscsi_sess_t *isp, uint16_t *lun_data, uint8_t *lun_addr_type); 68 69 /* internal state machine interfaces */ 70 static void iscsi_sess_state_free(iscsi_sess_t *isp, 71 iscsi_sess_event_t event); 72 static void iscsi_sess_state_logged_in(iscsi_sess_t *isp, 73 iscsi_sess_event_t event); 74 static void iscsi_sess_state_failed(iscsi_sess_t *isp, 75 iscsi_sess_event_t event); 76 static void iscsi_sess_state_in_flush(iscsi_sess_t *isp, 77 iscsi_sess_event_t event); 78 static void iscsi_sess_state_flushed(iscsi_sess_t *isp, 79 iscsi_sess_event_t event); 80 81 /* internal enumeration interfaces */ 82 static void iscsi_sess_enumeration(void *arg); 83 static iscsi_status_t iscsi_sess_testunitready(iscsi_sess_t *isp); 84 static iscsi_status_t iscsi_sess_reportluns(iscsi_sess_t *isp); 85 static void iscsi_sess_inquiry(iscsi_sess_t *isp, uint16_t lun_num, 86 uint8_t lun_addr_type); 87 88 /* 89 * +--------------------------------------------------------------------+ 90 * | External Session Interfaces | 91 * +--------------------------------------------------------------------+ 92 */ 93 94 iscsi_sess_t * 95 iscsi_sess_create(iscsi_hba_t *ihp, iSCSIDiscoveryMethod_t method, 96 struct sockaddr *addr_dsc, char *target_name, int tpgt, uchar_t isid_lsb, 97 iscsi_sess_type_t type, uint32_t *oid) 98 { 99 iscsi_sess_t *isp = NULL; 100 int len = 0; 101 char *tq_name; 102 char *th_name; 103 104 len = strlen(target_name); 105 106 for (isp = ihp->hba_sess_list; isp; isp = isp->sess_next) { 107 /* Match target name and LSB ISID */ 108 if ((strcmp((char *)isp->sess_name, target_name) == 0) && 109 (isp->sess_isid[5] == isid_lsb)) { 110 111 /* Match TPGT */ 112 if (isp->sess_tpgt_conf == tpgt) { 113 /* Found mathing session, return oid/ptr */ 114 *oid = isp->sess_oid; 115 return (isp); 116 } 117 118 /* 119 * Also protect against creating duplicate 120 * sessions with different configured tpgt 121 * values. default vs. defined. 122 */ 123 if ((((isp->sess_tpgt_conf == ISCSI_DEFAULT_TPGT) && 124 (tpgt != ISCSI_DEFAULT_TPGT)) || 125 ((isp->sess_tpgt_conf != ISCSI_DEFAULT_TPGT) && 126 (tpgt == ISCSI_DEFAULT_TPGT)))) { 127 /* Dangerous configuration. Fail Request */ 128 return (NULL); 129 } 130 } 131 } 132 133 isp = (iscsi_sess_t *)kmem_zalloc(sizeof (iscsi_sess_t), KM_SLEEP); 134 /* 135 * If this session is not a Send Targets session, set the target 136 * that this session is associated with. 137 */ 138 if (strncmp(target_name, SENDTARGETS_DISCOVERY, 139 strlen(SENDTARGETS_DISCOVERY))) { 140 isp->sess_target_oid = iscsi_targetparam_get_oid( 141 (uchar_t *)target_name); 142 } 143 144 if (method & iSCSIDiscoveryMethodBoot) { 145 /* This is boot session. */ 146 isp->sess_boot = B_TRUE; 147 } else { 148 isp->sess_boot = B_FALSE; 149 } 150 151 /* Associate session with this discovery method */ 152 method = method & ~(iSCSIDiscoveryMethodBoot); 153 154 isp->sess_discovered_by = method; 155 if (addr_dsc == NULL) { 156 bzero(&isp->sess_discovered_addr, 157 sizeof (isp->sess_discovered_addr)); 158 } else { 159 bcopy(addr_dsc, &isp->sess_discovered_addr, 160 SIZEOF_SOCKADDR(addr_dsc)); 161 } 162 163 /* assign unique key for the session */ 164 mutex_enter(&iscsi_oid_mutex); 165 isp->sess_oid = iscsi_oid++; 166 *oid = isp->sess_oid; 167 mutex_exit(&iscsi_oid_mutex); 168 169 /* setup session parameters */ 170 isp->sess_name_length = 0; 171 isp->sess_sig = ISCSI_SIG_SESS; 172 isp->sess_state = ISCSI_SESS_STATE_FREE; 173 mutex_init(&isp->sess_state_mutex, NULL, MUTEX_DRIVER, NULL); 174 isp->sess_hba = ihp; 175 isp->sess_enum_in_progress = B_FALSE; 176 177 isp->sess_isid[0] = ISCSI_SUN_ISID_0; 178 isp->sess_isid[1] = ISCSI_SUN_ISID_1; 179 isp->sess_isid[2] = ISCSI_SUN_ISID_2; 180 isp->sess_isid[3] = ISCSI_SUN_ISID_3; 181 isp->sess_isid[4] = 0; 182 isp->sess_isid[5] = isid_lsb; 183 184 isp->sess_cmdsn = 1; 185 isp->sess_expcmdsn = 1; 186 isp->sess_maxcmdsn = 1; 187 isp->sess_last_err = NoError; 188 isp->sess_tsid = 0; 189 isp->sess_type = type; 190 191 /* copy default driver login parameters */ 192 bcopy(&ihp->hba_params, &isp->sess_params, 193 sizeof (iscsi_login_params_t)); 194 195 /* copy target name into session */ 196 bcopy((char *)target_name, isp->sess_name, len); 197 isp->sess_name_length = len; 198 isp->sess_tpgt_conf = tpgt; 199 isp->sess_tpgt_nego = ISCSI_DEFAULT_TPGT; 200 201 /* initialize pending and completion queues */ 202 iscsi_init_queue(&isp->sess_queue_pending); 203 iscsi_init_queue(&isp->sess_queue_completion); 204 205 /* setup sessions lun list */ 206 isp->sess_lun_list = NULL; 207 rw_init(&isp->sess_lun_list_rwlock, NULL, RW_DRIVER, NULL); 208 209 /* setup sessions connection list */ 210 isp->sess_conn_act = NULL; 211 isp->sess_conn_list = NULL; 212 rw_init(&isp->sess_conn_list_rwlock, NULL, RW_DRIVER, NULL); 213 214 mutex_init(&isp->sess_cmdsn_mutex, NULL, MUTEX_DRIVER, NULL); 215 216 /* create the session task queue */ 217 tq_name = kmem_zalloc(ISCSI_TH_MAX_NAME_LEN, KM_SLEEP); 218 if (snprintf(tq_name, (ISCSI_TH_MAX_NAME_LEN - 1), 219 ISCSI_SESS_LOGIN_TASKQ_NAME_FORMAT, ihp->hba_oid, isp->sess_oid) < 220 ISCSI_TH_MAX_NAME_LEN) { 221 isp->sess_taskq = ddi_taskq_create(ihp->hba_dip, 222 tq_name, 1, TASKQ_DEFAULTPRI, 0); 223 } 224 kmem_free(tq_name, ISCSI_TH_MAX_NAME_LEN); 225 if (isp->sess_taskq == NULL) { 226 goto iscsi_sess_cleanup2; 227 } 228 229 /* startup watchdog */ 230 th_name = kmem_zalloc(ISCSI_TH_MAX_NAME_LEN, KM_SLEEP); 231 if (snprintf(th_name, (ISCSI_TH_MAX_NAME_LEN - 1), 232 ISCSI_SESS_WD_NAME_FORMAT, ihp->hba_oid, isp->sess_oid) < 233 ISCSI_TH_MAX_NAME_LEN) { 234 isp->sess_wd_thread = iscsi_thread_create(ihp->hba_dip, 235 th_name, iscsi_wd_thread, isp); 236 (void) iscsi_thread_start(isp->sess_wd_thread); 237 } 238 kmem_free(th_name, ISCSI_TH_MAX_NAME_LEN); 239 if (isp->sess_wd_thread == NULL) { 240 goto iscsi_sess_cleanup1; 241 } 242 243 /* Add new target to the hba target list */ 244 if (ihp->hba_sess_list == NULL) { 245 ihp->hba_sess_list = isp; 246 } else { 247 isp->sess_next = ihp->hba_sess_list; 248 ihp->hba_sess_list = isp; 249 } 250 KSTAT_INC_HBA_CNTR_SESS(ihp); 251 252 (void) iscsi_sess_kstat_init(isp); 253 254 return (isp); 255 256 iscsi_sess_cleanup1: 257 ddi_taskq_destroy(isp->sess_taskq); 258 iscsi_sess_cleanup2: 259 mutex_destroy(&isp->sess_cmdsn_mutex); 260 rw_destroy(&isp->sess_conn_list_rwlock); 261 rw_destroy(&isp->sess_lun_list_rwlock); 262 iscsi_destroy_queue(&isp->sess_queue_completion); 263 iscsi_destroy_queue(&isp->sess_queue_pending); 264 mutex_destroy(&isp->sess_state_mutex); 265 kmem_free(isp, sizeof (iscsi_sess_t)); 266 267 return (NULL); 268 } 269 270 /* 271 * iscsi_sess_get - return the session structure for based on a 272 * passed in oid and hba instance. 273 */ 274 int 275 iscsi_sess_get(uint32_t oid, iscsi_hba_t *ihp, iscsi_sess_t **ispp) 276 { 277 int rval = 0; 278 iscsi_sess_t *isp = NULL; 279 280 ASSERT(ihp != NULL); 281 ASSERT(ispp != NULL); 282 283 /* See if we already created this session */ 284 for (isp = ihp->hba_sess_list; isp; isp = isp->sess_next) { 285 /* compare target name as the unique identifier */ 286 if (isp->sess_oid == oid) { 287 /* Found matching session */ 288 break; 289 } 290 } 291 292 /* If not null this session is already available */ 293 if (isp != NULL) { 294 /* Existing session, return it */ 295 *ispp = isp; 296 } else { 297 rval = EFAULT; 298 } 299 return (rval); 300 } 301 302 /* 303 * iscsi_sess_online - initiate online of sessions connections 304 */ 305 void 306 iscsi_sess_online(iscsi_sess_t *isp) 307 { 308 iscsi_hba_t *ihp; 309 iscsi_conn_t *icp; 310 int idx; 311 312 ASSERT(isp != NULL); 313 ihp = isp->sess_hba; 314 ASSERT(ihp != NULL); 315 316 /* 317 * Stale /dev links can cause us to get floods 318 * of config requests. To prevent these repeated 319 * requests from causing unneeded login to the 320 * unreachable target, we won't try it during 321 * the delay. 322 */ 323 if (ddi_get_lbolt() < isp->sess_failure_lbolt + 324 SEC_TO_TICK(isp->sess_storm_delay)) { 325 return; 326 } 327 328 /* 329 * Perform a crude version of round robin to 330 * determine which connection to use for 331 * this session. Since byte 5 in session ID 332 * is overridden for full feature session, 333 * the connection to be selected depends on 334 * the result of sess_isid[5] devided by the 335 * next connection ID. 336 * If MS/T is enabled and there are multiple 337 * IPs are available on the target, we can 338 * select different IPs to connect in this 339 * way. 340 */ 341 icp = isp->sess_conn_act; 342 if (icp == NULL) { 343 icp = isp->sess_conn_list; 344 for (idx = 0; idx < (isp->sess_isid[5] % 345 isp->sess_conn_next_cid); idx++) { 346 ASSERT(icp->conn_next != NULL); 347 icp = icp->conn_next; 348 } 349 isp->sess_conn_act = icp; 350 } 351 352 if (icp == NULL) { 353 cmn_err(CE_NOTE, "iscsi session(%d) - " 354 "no connection assigned", isp->sess_oid); 355 return; 356 } 357 358 /* 359 * If connection is in free state, start 360 * login. If already logged in, try to 361 * re-enumerate LUs on the session. 362 */ 363 mutex_enter(&icp->conn_state_mutex); 364 if (icp->conn_state == ISCSI_CONN_STATE_FREE) { 365 /* 366 * attempt to login into the first connection in our connection 367 * list. If this fails, we will try the next connection 368 * in our list until end of the list. 369 */ 370 while (icp != NULL) { 371 if (iscsi_conn_state_machine( 372 icp, ISCSI_CONN_EVENT_T1) == 373 ISCSI_STATUS_SUCCESS) { 374 mutex_exit(&icp->conn_state_mutex); 375 break; 376 } else { 377 mutex_exit(&icp->conn_state_mutex); 378 icp = icp->conn_next; 379 if (icp != NULL) { 380 mutex_enter(&icp->conn_state_mutex); 381 } 382 } 383 } 384 isp->sess_conn_act = icp; 385 if (icp == NULL) { 386 /* the target for this session is unreachable */ 387 isp->sess_failure_lbolt = ddi_get_lbolt(); 388 if (isp->sess_storm_delay == 0) { 389 isp->sess_storm_delay++; 390 } else { 391 392 if ((isp->sess_storm_delay * 2) < 393 iscsi_sess_max_delay) { 394 isp->sess_storm_delay = 395 isp->sess_storm_delay * 2; 396 } else { 397 isp->sess_storm_delay = 398 iscsi_sess_max_delay; 399 } 400 } 401 402 } else { 403 isp->sess_storm_delay = 0; 404 isp->sess_failure_lbolt = 0; 405 } 406 } else if (icp->conn_state == ISCSI_CONN_STATE_LOGGED_IN) { 407 mutex_exit(&icp->conn_state_mutex); 408 mutex_enter(&isp->sess_state_mutex); 409 iscsi_sess_state_machine(isp, 410 ISCSI_SESS_EVENT_N1); 411 mutex_exit(&isp->sess_state_mutex); 412 } else { 413 mutex_exit(&icp->conn_state_mutex); 414 } 415 } 416 417 /* 418 * iscsi_sess_destroy - Destroys a iscsi session structure 419 * and de-associates it from the hba. 420 */ 421 iscsi_status_t 422 iscsi_sess_destroy(iscsi_sess_t *isp) 423 { 424 iscsi_status_t rval = ISCSI_STATUS_SUCCESS; 425 iscsi_status_t tmprval = ISCSI_STATUS_SUCCESS; 426 iscsi_hba_t *ihp; 427 iscsi_sess_t *t_isp; 428 iscsi_lun_t *ilp; 429 iscsi_conn_t *icp; 430 431 ASSERT(isp != NULL); 432 ihp = isp->sess_hba; 433 ASSERT(ihp != NULL); 434 435 /* 436 * The first step in tearing down the session 437 * has to be offlining all the LUNs. This will 438 * ensure there is no outstanding IO by upper 439 * level drivers. If this fails then we are 440 * unable to destroy the session. 441 * 442 * Try all luns and continue upon failure 443 * to remove what is removable before returning 444 * the last error. 445 */ 446 rw_enter(&isp->sess_lun_list_rwlock, RW_WRITER); 447 ilp = isp->sess_lun_list; 448 while (ilp != NULL) { 449 iscsi_lun_t *ilp_next = ilp->lun_next; 450 451 tmprval = iscsi_lun_destroy(ihp, ilp); 452 if (!ISCSI_SUCCESS(tmprval)) { 453 rval = tmprval; 454 } 455 ilp = ilp_next; 456 } 457 rw_exit(&isp->sess_lun_list_rwlock); 458 459 if (!ISCSI_SUCCESS(rval)) { 460 return (rval); 461 } 462 463 /* The next step is to logout of the connections. */ 464 icp = isp->sess_conn_list; 465 while (icp != NULL) { 466 rval = iscsi_conn_offline(icp); 467 if (ISCSI_SUCCESS(rval)) { 468 /* Succes, Continue processing... */ 469 icp = icp->conn_next; 470 } else { 471 /* Failure, Stop processing... */ 472 rw_exit(&isp->sess_conn_list_rwlock); 473 return (rval); 474 } 475 } 476 477 /* 478 * At this point all connections should be in 479 * a FREE state which will have pushed the session 480 * to a FREE state. 481 */ 482 ASSERT(isp->sess_state == ISCSI_SESS_STATE_FREE); 483 484 /* Stop watchdog before destroying connections */ 485 iscsi_thread_destroy(isp->sess_wd_thread); 486 487 /* Destroy connections */ 488 rw_enter(&isp->sess_conn_list_rwlock, RW_WRITER); 489 icp = isp->sess_conn_list; 490 while (icp != NULL) { 491 rval = iscsi_conn_destroy(icp); 492 if (!ISCSI_SUCCESS(rval)) { 493 rw_exit(&isp->sess_conn_list_rwlock); 494 return (rval); 495 } 496 icp = isp->sess_conn_list; 497 } 498 rw_exit(&isp->sess_conn_list_rwlock); 499 500 /* Destroy session task queue */ 501 ddi_taskq_destroy(isp->sess_taskq); 502 503 /* destroy pending and completion queues */ 504 iscsi_destroy_queue(&isp->sess_queue_pending); 505 iscsi_destroy_queue(&isp->sess_queue_completion); 506 507 /* Remove session from ihp */ 508 if (ihp->hba_sess_list == isp) { 509 /* session first item in list */ 510 ihp->hba_sess_list = isp->sess_next; 511 } else { 512 /* 513 * search hba list for isp pointing 514 * to session being removed. Then 515 * update that sessions next pointer. 516 */ 517 t_isp = ihp->hba_sess_list; 518 while (t_isp->sess_next != NULL) { 519 if (t_isp->sess_next == isp) { 520 break; 521 } 522 t_isp = t_isp->sess_next; 523 } 524 if (t_isp->sess_next == isp) { 525 t_isp->sess_next = isp->sess_next; 526 } else { 527 /* couldn't find session */ 528 ASSERT(FALSE); 529 } 530 } 531 532 /* Destroy this Sessions Data */ 533 (void) iscsi_sess_kstat_term(isp); 534 rw_destroy(&isp->sess_lun_list_rwlock); 535 rw_destroy(&isp->sess_conn_list_rwlock); 536 mutex_destroy(&isp->sess_cmdsn_mutex); 537 mutex_destroy(&isp->sess_state_mutex); 538 kmem_free(isp, sizeof (iscsi_sess_t)); 539 540 return (rval); 541 } 542 543 extern ib_boot_prop_t *iscsiboot_prop; 544 /* 545 * static iscsi_sess_set_auth - 546 * 547 */ 548 boolean_t 549 iscsi_sess_set_auth(iscsi_sess_t *isp) 550 { 551 char *init_name; 552 iscsi_chap_props_t *chap = NULL; 553 iscsi_auth_props_t *auth = NULL; 554 uchar_t *tmp = NULL; 555 556 if (isp == (iscsi_sess_t *)NULL) { 557 return (B_FALSE); 558 } 559 560 /* Obtain initiator's name */ 561 if (isp->sess_hba == (iscsi_hba_t *)NULL) { 562 return (B_FALSE); 563 } 564 565 init_name = (char *)isp->sess_hba->hba_name; 566 567 /* Zero out the session authentication structure */ 568 bzero(&isp->sess_auth, sizeof (iscsi_auth_t)); 569 570 if (isp->sess_boot == B_FALSE) { 571 572 auth = (iscsi_auth_props_t *)kmem_zalloc 573 (sizeof (iscsi_auth_props_t), KM_SLEEP); 574 /* Obtain target's authentication settings. */ 575 if (persistent_auth_get((char *)isp->sess_name, auth) 576 != B_TRUE) { 577 /* 578 * If no target authentication settings found, 579 * try to obtain system wide configuration 580 * (from the initiator). 581 */ 582 bzero(auth, sizeof (*auth)); 583 if (persistent_auth_get(init_name, auth) != B_TRUE) { 584 bzero(auth, sizeof (*auth)); 585 auth->a_auth_method = authMethodNone; 586 } 587 588 /* 589 * We do not support system wide bi-directional 590 * auth flag. 591 */ 592 auth->a_bi_auth = B_FALSE; 593 } 594 595 chap = (iscsi_chap_props_t *)kmem_zalloc 596 (sizeof (iscsi_chap_props_t), KM_SLEEP); 597 598 /* 599 * Initialize the target-side chap name to the session name 600 * if no chap settings have been saved for the current session. 601 */ 602 if (persistent_chap_get((char *)isp->sess_name, chap) 603 == B_FALSE) { 604 int name_len = strlen((char *)isp->sess_name); 605 bcopy((char *)isp->sess_name, chap->c_user, name_len); 606 chap->c_user_len = name_len; 607 (void) (persistent_chap_set((char *)isp->sess_name, 608 chap)); 609 bzero(chap, sizeof (*chap)); 610 } 611 612 if (auth->a_auth_method & authMethodCHAP) { 613 /* Obtain initiator's CHAP settings. */ 614 if (persistent_chap_get(init_name, chap) == B_FALSE) { 615 /* No initiator secret defined. */ 616 kmem_free(chap, sizeof (iscsi_chap_props_t)); 617 /* Set authentication method to NONE */ 618 isp->sess_auth.password_length = 0; 619 kmem_free(auth, sizeof (iscsi_auth_props_t)); 620 return (B_FALSE); 621 } 622 623 bcopy(chap->c_user, isp->sess_auth.username, 624 sizeof (chap->c_user)); 625 bcopy(chap->c_secret, isp->sess_auth.password, 626 sizeof (chap->c_secret)); 627 isp->sess_auth.password_length = chap->c_secret_len; 628 } else { 629 /* Set authentication method to NONE */ 630 isp->sess_auth.password_length = 0; 631 } 632 633 /* 634 * Consider enabling bidirectional authentication only if 635 * authentication method is not NONE. 636 */ 637 if (auth->a_auth_method & authMethodCHAP && 638 auth->a_bi_auth == B_TRUE) { 639 /* Enable bi-directional authentication. */ 640 isp->sess_auth.bidirectional_auth = 1; 641 642 bzero(chap, sizeof (*chap)); 643 /* Obtain target's CHAP settings. */ 644 if (persistent_chap_get((char *)isp->sess_name, chap) 645 == B_TRUE) { 646 bcopy(chap->c_secret, 647 isp->sess_auth.password_in, 648 sizeof (chap->c_secret)); 649 bcopy(chap->c_user, isp->sess_auth.username_in, 650 strlen((char *)chap->c_user)); 651 isp->sess_auth.password_length_in = 652 chap->c_secret_len; 653 } else { 654 /* 655 * No target secret defined. 656 * RADIUS server should have been enabled. 657 */ 658 /* EMPTY */ 659 } 660 } else { 661 /* Disable bi-directional authentication */ 662 isp->sess_auth.bidirectional_auth = 0; 663 } 664 665 if (auth != NULL) { 666 kmem_free(auth, sizeof (iscsi_auth_props_t)); 667 } 668 if (chap != NULL) { 669 kmem_free(chap, sizeof (iscsi_chap_props_t)); 670 } 671 } else { 672 /* 673 * This session is boot session. We will use the CHAP and 674 * the user name got from the boot property structure instead 675 * of persistent sotre. 676 */ 677 if (iscsiboot_prop == NULL) { 678 return (B_FALSE); 679 } 680 681 if (iscsiboot_prop->boot_init.ini_chap_sec == NULL) { 682 return (B_FALSE); 683 } 684 685 /* CHAP secret */ 686 (void) bcopy(iscsiboot_prop->boot_init.ini_chap_sec, 687 isp->sess_auth.password, 688 strlen((char *)iscsiboot_prop->boot_init.ini_chap_sec)); 689 690 /* 691 * If chap name is not set, 692 * we will use initiator name instead. 693 */ 694 if (iscsiboot_prop->boot_init.ini_chap_name == NULL) { 695 (void) bcopy(init_name, isp->sess_auth.username, 696 strlen(init_name)); 697 } else { 698 tmp = iscsiboot_prop->boot_init.ini_chap_name; 699 (void) bcopy(tmp, 700 isp->sess_auth.username, strlen((char *)tmp)); 701 } 702 703 isp->sess_auth.password_length = 704 strlen((char *)iscsiboot_prop->boot_init.ini_chap_sec); 705 706 if (iscsiboot_prop->boot_tgt.tgt_chap_sec != NULL) { 707 /* 708 * Bidirectional authentication is required. 709 */ 710 tmp = iscsiboot_prop->boot_tgt.tgt_chap_sec; 711 (void) bcopy(tmp, 712 isp->sess_auth.password_in, strlen((char *)tmp)); 713 714 /* 715 * If the target's chap name is not set, we will use 716 * session name instead. 717 */ 718 if (iscsiboot_prop->boot_tgt.tgt_chap_name == NULL) { 719 (void) bcopy(isp->sess_name, 720 isp->sess_auth.username_in, 721 isp->sess_name_length); 722 } else { 723 tmp = iscsiboot_prop->boot_tgt.tgt_chap_name; 724 (void) bcopy(tmp, 725 isp->sess_auth.username_in, 726 strlen((char *)tmp)); 727 } 728 tmp = iscsiboot_prop->boot_tgt.tgt_chap_sec; 729 isp->sess_auth.password_length_in = 730 strlen((char *)tmp); 731 isp->sess_auth.bidirectional_auth = 1; 732 } 733 } 734 735 /* Set up authentication buffers only if configured */ 736 if ((isp->sess_auth.password_length != 0) || 737 (isp->sess_auth.password_length_in != 0)) { 738 isp->sess_auth.num_auth_buffers = 5; 739 isp->sess_auth.auth_buffers[0].address = 740 &(isp->sess_auth.auth_client_block); 741 isp->sess_auth.auth_buffers[0].length = 742 sizeof (isp->sess_auth.auth_client_block); 743 isp->sess_auth.auth_buffers[1].address = 744 &(isp->sess_auth.auth_recv_string_block); 745 isp->sess_auth.auth_buffers[1].length = 746 sizeof (isp->sess_auth.auth_recv_string_block); 747 isp->sess_auth.auth_buffers[2].address = 748 &(isp->sess_auth.auth_send_string_block); 749 isp->sess_auth.auth_buffers[2].length = 750 sizeof (isp->sess_auth.auth_send_string_block); 751 isp->sess_auth.auth_buffers[3].address = 752 &(isp->sess_auth.auth_recv_binary_block); 753 isp->sess_auth.auth_buffers[3].length = 754 sizeof (isp->sess_auth.auth_recv_binary_block); 755 isp->sess_auth.auth_buffers[4].address = 756 &(isp->sess_auth.auth_send_binary_block); 757 isp->sess_auth.auth_buffers[4].length = 758 sizeof (isp->sess_auth.auth_send_binary_block); 759 } 760 761 return (B_TRUE); 762 } 763 764 765 /* 766 * iscsi_sess_reserve_itt - Used to reserve an ITT hash slot 767 */ 768 iscsi_status_t 769 iscsi_sess_reserve_itt(iscsi_sess_t *isp, iscsi_cmd_t *icmdp) 770 { 771 /* If no more slots are open fail reservation */ 772 if (isp->sess_cmd_table_count >= ISCSI_CMD_TABLE_SIZE) { 773 return (ISCSI_STATUS_ITT_TABLE_FULL); 774 } 775 776 /* 777 * Find the next available slot. Normally its the 778 * slot pointed to by the session's sess_itt value. 779 * If this is not true the table has become fragmented. 780 * Fragmentation can occur during max loads and IOs 781 * are completed out of order. Defragmentation will 782 * occur when IO slows down and ITT slots are released. 783 */ 784 while (isp->sess_cmd_table[isp->sess_itt % 785 ISCSI_CMD_TABLE_SIZE] != NULL) { 786 isp->sess_itt++; 787 } 788 789 /* reserve slot and update counters */ 790 icmdp->cmd_itt = isp->sess_itt; 791 isp->sess_cmd_table[icmdp->cmd_itt % 792 ISCSI_CMD_TABLE_SIZE] = icmdp; 793 isp->sess_cmd_table_count++; 794 isp->sess_itt++; 795 796 return (ISCSI_STATUS_SUCCESS); 797 } 798 799 /* 800 * iscsi_sess_release_itt - Used to release ITT hash slot 801 */ 802 void 803 iscsi_sess_release_itt(iscsi_sess_t *isp, iscsi_cmd_t *icmdp) 804 { 805 int hash_index = (icmdp->cmd_itt % ISCSI_CMD_TABLE_SIZE); 806 807 ASSERT(isp->sess_cmd_table[hash_index] != NULL); 808 809 /* release slot and update counters */ 810 isp->sess_cmd_table[hash_index] = NULL; 811 isp->sess_cmd_table_count--; 812 } 813 814 /* 815 * iscsi_sess_redrive_io - Used to redrive IO on connections in 816 * a full feature state. 817 */ 818 void 819 iscsi_sess_redrive_io(iscsi_sess_t *isp) 820 { 821 iscsi_conn_t *icp; 822 823 ASSERT(isp != NULL); 824 825 icp = isp->sess_conn_list; 826 while (icp != NULL) { 827 if (ISCSI_CONN_STATE_FULL_FEATURE( 828 icp->conn_state)) { 829 iscsi_thread_send_wakeup( 830 icp->conn_tx_thread); 831 } 832 icp = icp->conn_next; 833 } 834 } 835 836 /* 837 * iscsi_sess_state_machine - 838 * 839 * 7.3.1 Session State Diagram for an Initiator 840 * 841 * Symbolic Names for States: 842 * Q1: FREE - State on instantiation of after cleanup 843 * Q3: LOGGED_IN - Waiting for all session events. 844 * Q4: FAILED - Waiting for session recovery or session cont. 845 * Q5: IN_FLUSH - A login parameter has changed. We are in the 846 * process of flushing active, aborting, and 847 * completed queues. Once flushed the iscsi_ic_thread() 848 * will drop of drop connections (T14) and reconnect 849 * to the target with new values. 850 * Q6: FLUSHED - Active, Aborting and Completed Queues flushed. 851 * Awaiting reconnect or failure. iscsi_tx/ic_threads 852 * are still running and might be timing-out IOs. 853 * State Q3/4 represent the Full Feature Phase operation of the session. 854 * 855 * The state diagram is as follows: 856 * 857 * ------ (N6/7 == NOOP) 858 * / Q1 \ 859 * +----------------------->\ /<-------------+ 860 * | ---+--- | 861 * | N5 |N1 | 862 * | +----+ +-------------+ | | 863 * | | V V | V | 864 * | | ----+-- -----+ | 865 * |N6|N6 / Q4 \ / Q3 \(N6 == NOOP) | 866 * +--+---\ /----+--->\ /-----+---------+ 867 * | ------- /N1 -+---- | N3| 868 * | (N7 == NOOP) / N7| ^ N1/3/5| | 869 * | / | +-------+ | 870 * | +-----+ / | | 871 * | | V / v | 872 * | | ------- -+---- | 873 * |N6|N6 / Q6 \ N5 / Q5 \ | 874 * +--+---\ /<--------\ /-----+---------+ 875 * ------- ------ | N3 876 * (N7 == NOOP) ^ N1/3/5| 877 * +-------+ 878 * 879 * The state transition table is as follows: 880 * 881 * +----+------+----+--------+----+ 882 * |Q1 |Q3 |Q4 |Q5 |Q6 | 883 * -----+----+------+----+--------+----+ 884 * Q1 |N6/7|N1 | - | | | 885 * -----+----+------+----+--------+----+ 886 * Q3 |N3 |N1/3/5|N5 |N7 | | 887 * -----+----+------+----+--------+----+ 888 * Q4 |N6 |N1 |N6/7| | | 889 * -----+----+------+----+--------+----+ 890 * Q5 |N3 | | |N1/3/5/7|N6 | 891 * -----+----+------+----+--------+----+ 892 * Q6 |N6 |N1 |N6/7| | | 893 * -----+----+------+----+--------+----+ 894 * 895 * Event definitions: 896 * 897 * -N1: A connection logged in 898 * -N3: A connection logged out 899 * -N5: A connection failed 900 * -N6: Session state timeout occurred, or a session 901 * reinstatement cleared this session instance. This results in 902 * the freeing of all associated resources and the session state 903 * is discarded. 904 * -N7: Login parameters for session have changed. 905 * Re-negeotation required. 906 */ 907 void 908 iscsi_sess_state_machine(iscsi_sess_t *isp, iscsi_sess_event_t event) 909 { 910 ASSERT(isp != NULL); 911 ASSERT(mutex_owned(&isp->sess_state_mutex)); 912 913 DTRACE_PROBE3(event, iscsi_sess_t *, isp, 914 char *, iscsi_sess_state_str(isp->sess_state), 915 char *, iscsi_sess_event_str(event)); 916 917 isp->sess_prev_state = isp->sess_state; 918 isp->sess_state_lbolt = ddi_get_lbolt(); 919 920 switch (isp->sess_state) { 921 case ISCSI_SESS_STATE_FREE: 922 iscsi_sess_state_free(isp, event); 923 break; 924 case ISCSI_SESS_STATE_LOGGED_IN: 925 iscsi_sess_state_logged_in(isp, event); 926 break; 927 case ISCSI_SESS_STATE_FAILED: 928 iscsi_sess_state_failed(isp, event); 929 break; 930 case ISCSI_SESS_STATE_IN_FLUSH: 931 iscsi_sess_state_in_flush(isp, event); 932 break; 933 case ISCSI_SESS_STATE_FLUSHED: 934 iscsi_sess_state_flushed(isp, event); 935 break; 936 default: 937 ASSERT(FALSE); 938 } 939 } 940 941 942 /* 943 * iscsi_sess_state_str - 944 * 945 */ 946 char * 947 iscsi_sess_state_str(iscsi_sess_state_t state) 948 { 949 switch (state) { 950 case ISCSI_SESS_STATE_FREE: 951 return ("free"); 952 case ISCSI_SESS_STATE_LOGGED_IN: 953 return ("logged_in"); 954 case ISCSI_SESS_STATE_FAILED: 955 return ("failed"); 956 case ISCSI_SESS_STATE_IN_FLUSH: 957 return ("in_flush"); 958 case ISCSI_SESS_STATE_FLUSHED: 959 return ("flushed"); 960 default: 961 return ("unknown"); 962 } 963 } 964 965 966 /* 967 * +--------------------------------------------------------------------+ 968 * | Internal Session Interfaces | 969 * +--------------------------------------------------------------------+ 970 */ 971 972 973 /* 974 * iscsi_sess_state_free - 975 * 976 */ 977 static void 978 iscsi_sess_state_free(iscsi_sess_t *isp, iscsi_sess_event_t event) 979 { 980 iscsi_status_t status; 981 iscsi_hba_t *ihp; 982 iscsi_task_t *itp; 983 984 ASSERT(isp != NULL); 985 ihp = isp->sess_hba; 986 ASSERT(ihp != NULL); 987 ASSERT(isp->sess_state == ISCSI_SESS_STATE_FREE); 988 989 /* switch on event change */ 990 switch (event) { 991 /* 992 * -N1: A connection logged in 993 */ 994 case ISCSI_SESS_EVENT_N1: 995 status = iscsi_sess_threads_create(isp); 996 if (ISCSI_SUCCESS(status)) { 997 isp->sess_state = ISCSI_SESS_STATE_LOGGED_IN; 998 if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) { 999 cmn_err(CE_NOTE, 1000 "!iscsi session(%u) %s online\n", 1001 isp->sess_oid, isp->sess_name); 1002 1003 if (isp->sess_enum_in_progress == B_FALSE) { 1004 isp->sess_enum_in_progress = B_TRUE; 1005 mutex_exit(&isp->sess_state_mutex); 1006 1007 /* start enumeration */ 1008 itp = kmem_zalloc(sizeof (iscsi_task_t), 1009 KM_SLEEP); 1010 itp->t_arg = isp; 1011 itp->t_blocking = B_TRUE; 1012 iscsi_sess_enumeration(itp); 1013 kmem_free(itp, sizeof (iscsi_task_t)); 1014 1015 mutex_enter(&isp->sess_state_mutex); 1016 isp->sess_enum_in_progress = B_FALSE; 1017 } 1018 } 1019 } else { 1020 ASSERT(FALSE); 1021 } 1022 break; 1023 1024 /* 1025 * -N6: Session state timeout occurred, or a session 1026 * reinstatement cleared this session instance. This results in 1027 * the freeing of all associated resources and the session state 1028 * is discarded. 1029 */ 1030 case ISCSI_SESS_EVENT_N6: 1031 /* FALLTHRU */ 1032 1033 /* 1034 * -N7: Login parameters for session have changed. 1035 * Re-negeotation required. 1036 */ 1037 case ISCSI_SESS_EVENT_N7: 1038 /* NOOP - not connected */ 1039 break; 1040 1041 /* All other events are invalid for this state */ 1042 default: 1043 ASSERT(FALSE); 1044 } 1045 } 1046 1047 1048 /* 1049 * iscsi_sess_logged_in - 1050 * 1051 */ 1052 static void 1053 iscsi_sess_state_logged_in(iscsi_sess_t *isp, iscsi_sess_event_t event) 1054 { 1055 iscsi_task_t *itp; 1056 1057 ASSERT(isp != NULL); 1058 ASSERT(isp->sess_state == ISCSI_SESS_STATE_LOGGED_IN); 1059 1060 /* switch on event change */ 1061 switch (event) { 1062 /* 1063 * -N1: At least one transport connection reached the 1064 * LOGGED_IN state 1065 */ 1066 case ISCSI_SESS_EVENT_N1: 1067 /* 1068 * A different connection already logged in. If the 1069 * session is NORMAL, just re-enumerate the session. 1070 */ 1071 if ((isp->sess_type == ISCSI_SESS_TYPE_NORMAL) && 1072 (isp->sess_enum_in_progress == B_FALSE)) { 1073 isp->sess_enum_in_progress = B_TRUE; 1074 mutex_exit(&isp->sess_state_mutex); 1075 1076 /* start enumeration */ 1077 itp = kmem_zalloc(sizeof (iscsi_task_t), KM_SLEEP); 1078 itp->t_arg = isp; 1079 itp->t_blocking = B_TRUE; 1080 iscsi_sess_enumeration(itp); 1081 kmem_free(itp, sizeof (iscsi_task_t)); 1082 1083 mutex_enter(&isp->sess_state_mutex); 1084 isp->sess_enum_in_progress = B_FALSE; 1085 } 1086 break; 1087 1088 /* 1089 * -N3: A connection logged out. 1090 */ 1091 case ISCSI_SESS_EVENT_N3: 1092 /* FALLTHRU */ 1093 1094 /* 1095 * -N5: A connection failed 1096 */ 1097 case ISCSI_SESS_EVENT_N5: 1098 /* 1099 * MC/S: If this is the last connection to 1100 * fail then move the the failed state. 1101 */ 1102 if (event == ISCSI_SESS_EVENT_N3) { 1103 isp->sess_state = ISCSI_SESS_STATE_FREE; 1104 } else { 1105 isp->sess_state = ISCSI_SESS_STATE_FAILED; 1106 } 1107 1108 /* no longer connected reset nego tpgt */ 1109 isp->sess_tpgt_nego = ISCSI_DEFAULT_TPGT; 1110 1111 iscsi_sess_flush(isp); 1112 1113 if (event == ISCSI_SESS_EVENT_N3) { 1114 if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) { 1115 cmn_err(CE_NOTE, 1116 "!iscsi session(%u) %s offline\n", 1117 isp->sess_oid, isp->sess_name); 1118 } 1119 iscsi_sess_offline_luns(isp); 1120 } 1121 1122 /* 1123 * During the process of offlining the LUNs our ic 1124 * thread might be calling back into the driver via 1125 * a target driver failure path to do a reset or something 1126 * we need to release the sess_state_mutex while we 1127 * are killing these threads to they don't get deadlocked. 1128 */ 1129 mutex_exit(&isp->sess_state_mutex); 1130 iscsi_thread_destroy(isp->sess_ic_thread); 1131 mutex_enter(&isp->sess_state_mutex); 1132 break; 1133 1134 /* 1135 * -N6: Session state timeout occurred, or a session 1136 * reinstatement cleared this session instance. This results in 1137 * the freeing of all associated resources and the session state 1138 * is discarded. 1139 */ 1140 case ISCSI_SESS_EVENT_N6: 1141 /* NOOP - Not last connection */ 1142 break; 1143 1144 /* 1145 * -N7: Login parameters for session have changed. 1146 * Re-negeotation required. 1147 */ 1148 case ISCSI_SESS_EVENT_N7: 1149 isp->sess_state = ISCSI_SESS_STATE_IN_FLUSH; 1150 break; 1151 1152 /* All other events are invalid for this state */ 1153 default: 1154 ASSERT(FALSE); 1155 } 1156 } 1157 1158 1159 /* 1160 * iscsi_sess_state_failed - 1161 * 1162 */ 1163 static void 1164 iscsi_sess_state_failed(iscsi_sess_t *isp, iscsi_sess_event_t event) 1165 { 1166 iscsi_status_t rval; 1167 iscsi_hba_t *ihp; 1168 iscsi_task_t *itp; 1169 1170 ASSERT(isp != NULL); 1171 ihp = isp->sess_hba; 1172 ASSERT(ihp != NULL); 1173 ASSERT(isp->sess_state == ISCSI_SESS_STATE_FAILED); 1174 1175 /* switch on event change */ 1176 switch (event) { 1177 /* -N1: A session continuation attempt succeeded */ 1178 case ISCSI_SESS_EVENT_N1: 1179 rval = iscsi_sess_threads_create(isp); 1180 if (ISCSI_SUCCESS(rval)) { 1181 isp->sess_state = ISCSI_SESS_STATE_LOGGED_IN; 1182 if ((isp->sess_type == ISCSI_SESS_TYPE_NORMAL) && 1183 (isp->sess_enum_in_progress == B_FALSE)) { 1184 isp->sess_enum_in_progress = B_TRUE; 1185 mutex_exit(&isp->sess_state_mutex); 1186 1187 /* start enumeration */ 1188 itp = kmem_zalloc(sizeof (iscsi_task_t), 1189 KM_SLEEP); 1190 itp->t_arg = isp; 1191 itp->t_blocking = B_FALSE; 1192 if (ddi_taskq_dispatch(isp->sess_taskq, 1193 iscsi_sess_enumeration, itp, DDI_SLEEP) != 1194 DDI_SUCCESS) { 1195 kmem_free(itp, sizeof (iscsi_task_t)); 1196 cmn_err(CE_WARN, 1197 "iscsi connection (%u) failure - " 1198 "unable to schedule enumeration", 1199 isp->sess_oid); 1200 } 1201 1202 mutex_enter(&isp->sess_state_mutex); 1203 isp->sess_enum_in_progress = B_FALSE; 1204 } 1205 } else { 1206 isp->sess_state = ISCSI_SESS_STATE_FREE; 1207 ASSERT(FALSE); 1208 } 1209 break; 1210 1211 /* 1212 * -N6: Session state timeout occurred, or a session 1213 * reinstatement cleared this session instance. This results in 1214 * the freeing of all associated resources and the session state 1215 * is discarded. 1216 */ 1217 case ISCSI_SESS_EVENT_N6: 1218 isp->sess_state = ISCSI_SESS_STATE_FREE; 1219 1220 if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) { 1221 cmn_err(CE_NOTE, "!iscsi session(%u) %s offline\n", 1222 isp->sess_oid, isp->sess_name); 1223 } 1224 1225 mutex_exit(&isp->sess_state_mutex); 1226 iscsi_sess_offline_luns(isp); 1227 mutex_enter(&isp->sess_state_mutex); 1228 break; 1229 1230 /* 1231 * -N7: Login parameters for session have changed. 1232 * Re-negeotation required. 1233 */ 1234 case ISCSI_SESS_EVENT_N7: 1235 /* NOOP - not connected */ 1236 break; 1237 1238 /* All other events are invalid for this state */ 1239 default: 1240 ASSERT(FALSE); 1241 } 1242 } 1243 1244 1245 /* 1246 * iscsi_sess_state_in_flush - 1247 * 1248 */ 1249 static void 1250 iscsi_sess_state_in_flush(iscsi_sess_t *isp, iscsi_sess_event_t event) 1251 { 1252 ASSERT(isp != NULL); 1253 ASSERT(isp->sess_state == ISCSI_SESS_STATE_IN_FLUSH); 1254 1255 /* switch on event change */ 1256 switch (event) { 1257 /* -N1: A session continuation attempt succeeded */ 1258 case ISCSI_SESS_EVENT_N1: 1259 /* NOOP - connections already online */ 1260 break; 1261 1262 /* 1263 * -N3: A connection logged out. 1264 */ 1265 case ISCSI_SESS_EVENT_N3: 1266 /* FALLTHRU */ 1267 1268 /* 1269 * -N5: A connection failed 1270 */ 1271 case ISCSI_SESS_EVENT_N5: 1272 /* 1273 * MC/S: If this is the last connection to 1274 * fail then move the the failed state. 1275 */ 1276 if (event == ISCSI_SESS_EVENT_N3) { 1277 isp->sess_state = ISCSI_SESS_STATE_FREE; 1278 } else { 1279 isp->sess_state = ISCSI_SESS_STATE_FLUSHED; 1280 } 1281 1282 /* no longer connected reset nego tpgt */ 1283 isp->sess_tpgt_nego = ISCSI_DEFAULT_TPGT; 1284 iscsi_sess_flush(isp); 1285 1286 if (event == ISCSI_SESS_EVENT_N3) { 1287 if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) { 1288 cmn_err(CE_NOTE, 1289 "!iscsi session(%u) %s offline\n", 1290 isp->sess_oid, isp->sess_name); 1291 } 1292 iscsi_sess_offline_luns(isp); 1293 } 1294 1295 /* 1296 * During the process of offlining the LUNs our ic 1297 * thread might be calling back into the driver via 1298 * a target driver failure path to do a reset or something 1299 * we need to release the sess_state_mutex while we 1300 * are killing these threads to they don't get deadlocked. 1301 */ 1302 mutex_exit(&isp->sess_state_mutex); 1303 iscsi_thread_destroy(isp->sess_ic_thread); 1304 mutex_enter(&isp->sess_state_mutex); 1305 break; 1306 1307 /* 1308 * -N6: Session state timeout occurred, or a session 1309 * reinstatement cleared this session instance. This results in 1310 * the freeing of all associated resources and the session state 1311 * is discarded. 1312 */ 1313 case ISCSI_SESS_EVENT_N6: 1314 /* NOOP - Not last connection */ 1315 break; 1316 1317 /* 1318 * -N7: Login parameters for session have changed. 1319 * Re-negeotation required. 1320 */ 1321 case ISCSI_SESS_EVENT_N7: 1322 /* NOOP - Already attempting to update */ 1323 break; 1324 1325 /* All other events are invalid for this state */ 1326 default: 1327 ASSERT(FALSE); 1328 } 1329 } 1330 1331 1332 /* 1333 * iscsi_sess_state_flushed - 1334 * 1335 */ 1336 static void 1337 iscsi_sess_state_flushed(iscsi_sess_t *isp, iscsi_sess_event_t event) 1338 { 1339 iscsi_status_t rval; 1340 iscsi_hba_t *ihp; 1341 iscsi_task_t *itp; 1342 1343 ASSERT(isp != NULL); 1344 ASSERT(isp->sess_state == ISCSI_SESS_STATE_FLUSHED); 1345 ihp = isp->sess_hba; 1346 ASSERT(ihp != NULL); 1347 1348 /* switch on event change */ 1349 switch (event) { 1350 /* -N1: A session continuation attempt succeeded */ 1351 case ISCSI_SESS_EVENT_N1: 1352 rval = iscsi_sess_threads_create(isp); 1353 if (ISCSI_SUCCESS(rval)) { 1354 isp->sess_state = ISCSI_SESS_STATE_LOGGED_IN; 1355 if ((isp->sess_type == ISCSI_SESS_TYPE_NORMAL) && 1356 (isp->sess_enum_in_progress == B_FALSE)) { 1357 isp->sess_enum_in_progress = B_TRUE; 1358 mutex_exit(&isp->sess_state_mutex); 1359 1360 /* start enumeration */ 1361 itp = kmem_zalloc(sizeof (iscsi_task_t), 1362 KM_SLEEP); 1363 itp->t_arg = isp; 1364 itp->t_blocking = B_FALSE; 1365 if (ddi_taskq_dispatch(isp->sess_taskq, 1366 iscsi_sess_enumeration, itp, DDI_SLEEP) != 1367 DDI_SUCCESS) { 1368 kmem_free(itp, sizeof (iscsi_task_t)); 1369 cmn_err(CE_WARN, 1370 "iscsi connection (%u) failure - " 1371 "unable to schedule enumeration", 1372 isp->sess_oid); 1373 } 1374 1375 mutex_enter(&isp->sess_state_mutex); 1376 isp->sess_enum_in_progress = B_FALSE; 1377 } 1378 } else { 1379 isp->sess_state = ISCSI_SESS_STATE_FREE; 1380 ASSERT(FALSE); 1381 } 1382 break; 1383 1384 /* 1385 * -N6: Session state timeout occurred, or a session 1386 * reinstatement cleared this session instance. This results in 1387 * the freeing of all associated resources and the session state 1388 * is discarded. 1389 */ 1390 case ISCSI_SESS_EVENT_N6: 1391 isp->sess_state = ISCSI_SESS_STATE_FREE; 1392 1393 if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) { 1394 cmn_err(CE_NOTE, "!iscsi session(%u) %s offline\n", 1395 isp->sess_oid, isp->sess_name); 1396 } 1397 1398 mutex_exit(&isp->sess_state_mutex); 1399 iscsi_sess_offline_luns(isp); 1400 mutex_enter(&isp->sess_state_mutex); 1401 break; 1402 1403 /* 1404 * -N7: Login parameters for session have changed. 1405 * Re-negeotation required. 1406 */ 1407 case ISCSI_SESS_EVENT_N7: 1408 /* NOOP - not connected */ 1409 break; 1410 1411 /* All other events are invalid for this state */ 1412 default: 1413 ASSERT(FALSE); 1414 } 1415 } 1416 1417 /* 1418 * iscsi_sess_event_str - 1419 * 1420 */ 1421 static char * 1422 iscsi_sess_event_str(iscsi_sess_event_t event) 1423 { 1424 switch (event) { 1425 case ISCSI_SESS_EVENT_N1: 1426 return ("N1"); 1427 case ISCSI_SESS_EVENT_N3: 1428 return ("N3"); 1429 case ISCSI_SESS_EVENT_N5: 1430 return ("N5"); 1431 case ISCSI_SESS_EVENT_N6: 1432 return ("N6"); 1433 case ISCSI_SESS_EVENT_N7: 1434 return ("N7"); 1435 default: 1436 return ("unknown"); 1437 } 1438 } 1439 1440 /* 1441 * iscsi_sess_thread_create - 1442 * 1443 */ 1444 static iscsi_status_t 1445 iscsi_sess_threads_create(iscsi_sess_t *isp) 1446 { 1447 iscsi_hba_t *ihp; 1448 char th_name[ISCSI_TH_MAX_NAME_LEN]; 1449 1450 ASSERT(isp != NULL); 1451 ihp = isp->sess_hba; 1452 ASSERT(ihp != NULL); 1453 1454 /* Completion thread creation. */ 1455 if (snprintf(th_name, sizeof (th_name) - 1, 1456 ISCSI_SESS_IOTH_NAME_FORMAT, ihp->hba_oid, 1457 isp->sess_oid) >= sizeof (th_name)) { 1458 return (ISCSI_STATUS_INTERNAL_ERROR); 1459 } 1460 1461 isp->sess_ic_thread = iscsi_thread_create(ihp->hba_dip, 1462 th_name, iscsi_ic_thread, isp); 1463 1464 if (isp->sess_ic_thread == NULL) { 1465 return (ISCSI_STATUS_INTERNAL_ERROR); 1466 } 1467 1468 (void) iscsi_thread_start(isp->sess_ic_thread); 1469 1470 return (ISCSI_STATUS_SUCCESS); 1471 } 1472 1473 /* 1474 * iscsi_sess_enumeration - This function is used to drive the enumeration 1475 * of LUs on a session. It will first prepare the target by sending test 1476 * unit ready commands, then it will issue a report luns. If the report 1477 * luns is successful then it will process all the luns in the report. 1478 * If report luns is not successful we will do a stepping enumeration 1479 * of luns until no more luns are found. 1480 */ 1481 static void 1482 iscsi_sess_enumeration(void *arg) 1483 { 1484 iscsi_task_t *itp = (iscsi_task_t *)arg; 1485 iscsi_sess_t *isp; 1486 iscsi_status_t rval = ISCSI_STATUS_SUCCESS; 1487 1488 ASSERT(itp != NULL); 1489 isp = (iscsi_sess_t *)itp->t_arg; 1490 ASSERT(isp != NULL); 1491 1492 /* 1493 * Send initial TEST_UNIT_READY to target. If it fails this we 1494 * stop our enumeration as the target is not responding properly. 1495 */ 1496 rval = iscsi_sess_testunitready(isp); 1497 if (ISCSI_SUCCESS(rval)) { 1498 /* 1499 * Now we know the target is ready start our enumeration with 1500 * REPORT LUNs, If this fails we will have to fall back to 1501 * stepping 1502 */ 1503 rval = iscsi_sess_reportluns(isp); 1504 if (!ISCSI_SUCCESS(rval)) { 1505 /* 1506 * report luns failed so lets just check for LUN 0. 1507 * This will match fcp's enumeration support and 1508 * avoid issues with older devices like the A5K that 1509 * respond poorly. 1510 */ 1511 if (isp->sess_lun_list == NULL) { 1512 iscsi_sess_inquiry(isp, 0, 0); 1513 } 1514 } 1515 } else { 1516 cmn_err(CE_NOTE, "iscsi session(%u) unable to enumerate " 1517 "logical units - test unit ready failed", isp->sess_oid); 1518 } 1519 1520 if (itp->t_blocking == B_FALSE) { 1521 kmem_free(itp, sizeof (iscsi_task_t)); 1522 } 1523 } 1524 1525 /* 1526 * iscsi_sess_testunitready - This is used during enumeration to 1527 * ensure an array is ready to be enumerated. 1528 */ 1529 static iscsi_status_t 1530 iscsi_sess_testunitready(iscsi_sess_t *isp) 1531 { 1532 iscsi_status_t rval = ISCSI_STATUS_SUCCESS; 1533 int retries = 0; 1534 struct uscsi_cmd ucmd; 1535 char cdb[CDB_GROUP0]; 1536 1537 ASSERT(isp != NULL); 1538 1539 /* loop until successful sending test unit ready or retries out */ 1540 do { 1541 /* cdb is all zeros */ 1542 bzero(&cdb[0], CDB_GROUP0); 1543 1544 /* setup uscsi cmd */ 1545 bzero(&ucmd, sizeof (struct uscsi_cmd)); 1546 ucmd.uscsi_timeout = iscsi_sess_enum_timeout; 1547 ucmd.uscsi_cdb = &cdb[0]; 1548 ucmd.uscsi_cdblen = CDB_GROUP0; 1549 1550 /* send test unit ready to lun zero on this session */ 1551 rval = iscsi_handle_passthru(isp, 0, &ucmd); 1552 1553 /* 1554 * If passthru was successful then we were able to 1555 * communicate with the target, continue enumeration. 1556 */ 1557 if (ISCSI_SUCCESS(rval)) { 1558 break; 1559 } 1560 1561 } while (retries++ < 3); 1562 1563 return (rval); 1564 } 1565 1566 #define SCSI_REPORTLUNS_ADDRESS_SIZE 8 1567 #define SCSI_REPORTLUNS_ADDRESS_MASK 0xC0 1568 #define SCSI_REPORTLUNS_ADDRESS_PERIPHERAL 0x00 1569 #define SCSI_REPORTLUNS_ADDRESS_FLAT_SPACE 0x40 1570 #define SCSI_REPORTLUNS_ADDRESS_LOGICAL_UNIT 0x80 1571 #define SCSI_REPORTLUNS_ADDRESS_EXTENDED_UNIT 0xC0 1572 #define SCSI_REPORTLUNS_ADDRESS_LOGICAL_UNIT_2B 0x00 1573 #define SCSI_REPORTLUNS_ADDRESS_LOGICAL_UNIT_4B 0x01 1574 #define SCSI_REPORTLUNS_ADDRESS_LOGICAL_UNIT_6B 0x10 1575 #define SCSI_REPORTLUNS_ADDRESS_LOGICAL_UNIT_8B 0x20 1576 #define SCSI_REPORTLUNS_ADDRESS_LOGICAL_UNIT_SIZE 0x30 1577 1578 /* 1579 * iscsi_sess_reportluns - This is used during enumeration to 1580 * ensure an array is ready to be enumerated. 1581 */ 1582 static iscsi_status_t 1583 iscsi_sess_reportluns(iscsi_sess_t *isp) 1584 { 1585 iscsi_status_t rval = ISCSI_STATUS_SUCCESS; 1586 iscsi_hba_t *ihp; 1587 struct uscsi_cmd ucmd; 1588 unsigned char cdb[CDB_GROUP5]; 1589 unsigned char *buf = NULL; 1590 int buf_len = sizeof (struct scsi_inquiry); 1591 uint32_t lun_list_length = 0; 1592 uint16_t lun_num = 0; 1593 uint8_t lun_addr_type = 0; 1594 uint32_t lun_count = 0; 1595 uint32_t lun_start = 0; 1596 uint32_t lun_total = 0; 1597 int retries = 0; 1598 iscsi_lun_t *ilp = NULL; 1599 replun_data_t *saved_replun_ptr = NULL; 1600 1601 ASSERT(isp != NULL); 1602 ihp = isp->sess_hba; 1603 ASSERT(ihp != NULL); 1604 1605 /* 1606 * Attempt to send report luns until we successfully 1607 * get all the data or the retries run out. 1608 */ 1609 do { 1610 /* 1611 * Allocate our buffer based on current buf_len. 1612 * buf_len may change after we received a response 1613 * from the target. 1614 */ 1615 if (buf == NULL) { 1616 buf = kmem_zalloc(buf_len, KM_SLEEP); 1617 } 1618 1619 /* setup cdb */ 1620 bzero(&cdb, CDB_GROUP5); 1621 cdb[0] = SCMD_REPORT_LUNS; 1622 cdb[6] = (buf_len & 0xff000000) >> 24; 1623 cdb[7] = (buf_len & 0x00ff0000) >> 16; 1624 cdb[8] = (buf_len & 0x0000ff00) >> 8; 1625 cdb[9] = (buf_len & 0x000000ff); 1626 1627 /* setup uscsi cmd */ 1628 bzero(&ucmd, sizeof (struct uscsi_cmd)); 1629 ucmd.uscsi_flags = USCSI_READ; 1630 ucmd.uscsi_timeout = iscsi_sess_enum_timeout; 1631 ucmd.uscsi_cdb = (char *)&cdb[0]; 1632 ucmd.uscsi_cdblen = CDB_GROUP5; 1633 ucmd.uscsi_bufaddr = (char *)buf; 1634 ucmd.uscsi_buflen = buf_len; 1635 1636 /* send uscsi cmd to lun 0 on session */ 1637 rval = iscsi_handle_passthru(isp, 0, &ucmd); 1638 1639 /* If passthru successful but not scsi status update istatus */ 1640 if (ISCSI_SUCCESS(rval) && 1641 (ucmd.uscsi_status != STATUS_GOOD)) { 1642 rval = ISCSI_STATUS_USCSI_FAILED; 1643 } 1644 1645 /* If successful, check if we have all the data */ 1646 if (ISCSI_SUCCESS(rval)) { 1647 /* total data - header (SCSI_REPORTLUNS_ADDRESS_SIZE) */ 1648 lun_list_length = htonl(*(uint32_t *)buf); 1649 1650 if (buf_len >= lun_list_length + 1651 SCSI_REPORTLUNS_ADDRESS_SIZE) { 1652 /* we have all the data, were done */ 1653 break; 1654 } 1655 1656 /* 1657 * We don't have all the data. free up the 1658 * memory for the next pass and update the 1659 * buf_len 1660 */ 1661 kmem_free(buf, buf_len); 1662 buf = NULL; 1663 buf_len = lun_list_length + 1664 SCSI_REPORTLUNS_ADDRESS_SIZE; 1665 } else { 1666 retries++; 1667 } 1668 1669 } while (retries < 3); 1670 1671 /* If not successful go no farther */ 1672 if (!ISCSI_SUCCESS(rval)) { 1673 kmem_free(buf, buf_len); 1674 return (rval); 1675 } 1676 1677 /* 1678 * find out the number of luns returned by the SCSI ReportLun call 1679 * and allocate buffer space 1680 */ 1681 lun_total = lun_list_length / SCSI_REPORTLUNS_ADDRESS_SIZE; 1682 saved_replun_ptr = kmem_zalloc(lun_total * sizeof (replun_data_t), 1683 KM_SLEEP); 1684 1685 /* 1686 * walk the isp->sess_lun_list 1687 * for each lun in this list 1688 * look to see if this lun is in the SCSI ReportLun list we 1689 * just retrieved 1690 * if it is in the SCSI ReportLun list and it is already ONLINE 1691 * nothing needs to be done 1692 * if it is in the SCSI ReportLun list and it is OFFLINE, 1693 * issue the iscsi_lun_online() 1694 * if it isn't in the SCSI ReportLunlist then 1695 * issue the iscsi_sess_inquiry() 1696 * 1697 * as we walk the SCSI ReportLun list, we save this lun information 1698 * into the buffer we just allocated. This will save us from 1699 * having to figure out this information later 1700 */ 1701 lun_start = 0; 1702 rw_enter(&isp->sess_lun_list_rwlock, RW_READER); 1703 for (ilp = isp->sess_lun_list; ilp; ilp = ilp->lun_next) { 1704 for (lun_count = lun_start; 1705 lun_count < lun_total; lun_count++) { 1706 /* 1707 * if the first lun in saved_replun_ptr buffer has already 1708 * been found we can move on and do not have to check this lun 1709 * in the future 1710 */ 1711 if (lun_count == lun_start && 1712 saved_replun_ptr[lun_start].lun_found) { 1713 lun_start++; 1714 continue; 1715 } 1716 /* 1717 * check to see if the lun we are looking for is in the 1718 * saved_replun_ptr buffer 1719 * if it is, process the lun 1720 * if it isn't, then we must go to SCSI 1721 * Report Lun buffer 1722 * we retrieved to get lun info 1723 */ 1724 if (saved_replun_ptr[lun_count].lun_valid == 1725 B_TRUE) { 1726 if (saved_replun_ptr[lun_count].lun_num == 1727 ilp->lun_num) { 1728 /* 1729 * the lun we are looking for is found 1730 * 1731 * if the state of the lun is currently OFFLINE, 1732 * turn it back online 1733 */ 1734 if (ilp->lun_state == 1735 ISCSI_LUN_STATE_OFFLINE) { 1736 DTRACE_PROBE2( 1737 sess_reportluns_lun_is_not_online, 1738 int, ilp->lun_num, int, 1739 ilp->lun_state); 1740 iscsi_lun_online(ihp, ilp); 1741 } 1742 saved_replun_ptr[lun_count].lun_found = B_TRUE; 1743 break; 1744 } 1745 } else { 1746 /* 1747 * lun information is not found in the saved_replun 1748 * buffer, retrieve lun information from the SCSI 1749 * Report Lun buffer and store this information in 1750 * the saved_replun buffer 1751 */ 1752 if (retrieve_lundata(lun_count, buf, isp, &lun_num, 1753 &lun_addr_type) != ISCSI_STATUS_SUCCESS) { 1754 continue; 1755 } 1756 saved_replun_ptr[lun_count].lun_valid = B_TRUE; 1757 saved_replun_ptr[lun_count].lun_num = lun_num; 1758 if (ilp->lun_num == lun_num) { 1759 /* 1760 * lun is found in the SCSI Report Lun buffer 1761 * make sure the lun is in the ONLINE state 1762 */ 1763 saved_replun_ptr[lun_count].lun_found = B_TRUE; 1764 if (ilp->lun_state == 1765 ISCSI_LUN_STATE_OFFLINE) { 1766 #define SRLINON sess_reportluns_lun_is_not_online 1767 DTRACE_PROBE2( 1768 SRLINON, 1769 int, ilp->lun_num, int, 1770 ilp->lun_state); 1771 1772 iscsi_lun_online( 1773 ihp, ilp); 1774 #undef SRLINON 1775 } 1776 break; 1777 } 1778 } 1779 } 1780 1781 if (lun_count == lun_total) { 1782 /* 1783 * this lun we found in the sess->lun_list does not exist 1784 * anymore, need to offline this lun 1785 */ 1786 1787 DTRACE_PROBE2(sess_reportluns_lun_no_longer_exists, 1788 int, ilp->lun_num, int, ilp->lun_state); 1789 1790 if (ilp->lun_state == ISCSI_LUN_STATE_ONLINE) { 1791 (void) iscsi_lun_offline(ihp, ilp, B_FALSE); 1792 } 1793 } 1794 } 1795 rw_exit(&isp->sess_lun_list_rwlock); 1796 1797 /* 1798 * look for new luns that we found in the SCSI Report Lun buffer that 1799 * we did not have in the sess->lun_list and add them into the list 1800 */ 1801 for (lun_count = lun_start; lun_count < lun_total; lun_count++) { 1802 if (saved_replun_ptr[lun_count].lun_valid == B_FALSE) { 1803 /* 1804 * lun information is not in the 1805 * saved_replun buffer, retrieve 1806 * it from the SCSI Report Lun buffer 1807 */ 1808 if (retrieve_lundata(lun_count, buf, isp, 1809 &lun_num, &lun_addr_type) != ISCSI_STATUS_SUCCESS) { 1810 continue; 1811 } 1812 } else { 1813 /* 1814 * lun information is in the saved_replun buffer 1815 * if this lun has been found already, then we can move on 1816 */ 1817 if (saved_replun_ptr[lun_count].lun_found == B_TRUE) { 1818 continue; 1819 } 1820 lun_num = saved_replun_ptr[lun_count].lun_num; 1821 } 1822 1823 1824 /* New luns found should not conflict with existing luns */ 1825 rw_enter(&isp->sess_lun_list_rwlock, RW_READER); 1826 for (ilp = isp->sess_lun_list; ilp; ilp = ilp->lun_next) { 1827 if (ilp->lun_num == lun_num) { 1828 break; 1829 } 1830 } 1831 rw_exit(&isp->sess_lun_list_rwlock); 1832 1833 if (ilp == NULL) { 1834 /* new lun found, add this lun */ 1835 iscsi_sess_inquiry(isp, lun_num, lun_addr_type); 1836 } else { 1837 cmn_err(CE_NOTE, 1838 "!Duplicate Lun Number(%d) recieved from " 1839 "Target(%s)", lun_num, isp->sess_name); 1840 } 1841 } 1842 1843 kmem_free(buf, buf_len); 1844 kmem_free(saved_replun_ptr, lun_total * sizeof (replun_data_t)); 1845 return (rval); 1846 } 1847 1848 #define ISCSI_MAX_INQUIRY_BUF_SIZE 0xFF 1849 #define ISCSI_MAX_INQUIRY_RETRIES 3 1850 1851 /* 1852 * iscsi_sess_inquiry - Final processing of a LUN before we create a tgt 1853 * mapping. We need to collect the stardard inquiry page and the 1854 * vendor identification page for this LUN. If both of these are 1855 * successful and the identification page contains a NAA or EUI type 1856 * we will continue. Otherwise we fail the creation of a tgt for 1857 * this LUN. 1858 * 1859 * The GUID creation in this function will be removed 1860 * we are pushing to have all this GUID code somewhere else. 1861 */ 1862 static void 1863 iscsi_sess_inquiry(iscsi_sess_t *isp, uint16_t lun_num, uint8_t lun_addr_type) 1864 { 1865 iscsi_status_t rval; 1866 struct uscsi_cmd ucmd; 1867 uchar_t cdb[CDB_GROUP0]; 1868 uchar_t *inq; 1869 size_t inq_len; 1870 uchar_t *inq83; 1871 size_t inq83_len; 1872 int retries; 1873 ddi_devid_t devid; 1874 char *guid = NULL; 1875 1876 ASSERT(isp != NULL); 1877 1878 inq = kmem_zalloc(ISCSI_MAX_INQUIRY_BUF_SIZE, KM_SLEEP); 1879 inq83 = kmem_zalloc(ISCSI_MAX_INQUIRY_BUF_SIZE, KM_SLEEP); 1880 1881 /* 1882 * STANDARD INQUIRY - We need the standard inquiry information 1883 * to feed into the scsi_hba_nodename_compatible_get function. 1884 * This function is used to detemine which driver will bind 1885 * on top of us, via the compatible id. 1886 */ 1887 bzero(&cdb, CDB_GROUP0); 1888 cdb[0] = SCMD_INQUIRY; 1889 cdb[4] = ISCSI_MAX_INQUIRY_BUF_SIZE; 1890 1891 bzero(&ucmd, sizeof (struct uscsi_cmd)); 1892 ucmd.uscsi_flags = USCSI_READ; 1893 ucmd.uscsi_timeout = iscsi_sess_enum_timeout; 1894 ucmd.uscsi_cdb = (char *)&cdb[0]; 1895 ucmd.uscsi_cdblen = CDB_GROUP0; 1896 ucmd.uscsi_bufaddr = (char *)inq; 1897 ucmd.uscsi_buflen = ISCSI_MAX_INQUIRY_BUF_SIZE; 1898 1899 /* Attempt to get inquiry information until successful or retries */ 1900 retries = 0; 1901 do { 1902 /* issue passthru */ 1903 rval = iscsi_handle_passthru(isp, lun_num, &ucmd); 1904 1905 /* If we were successful but scsi stat failed update istatus */ 1906 if (ISCSI_SUCCESS(rval) && 1907 (ucmd.uscsi_status != STATUS_GOOD)) { 1908 rval = ISCSI_STATUS_USCSI_FAILED; 1909 } 1910 1911 /* If successful break */ 1912 if (ISCSI_SUCCESS(rval)) { 1913 inq_len = ISCSI_MAX_INQUIRY_BUF_SIZE - ucmd.uscsi_resid; 1914 break; 1915 } 1916 1917 /* loop until we are successful or retries run out */ 1918 } while (retries++ < ISCSI_MAX_INQUIRY_RETRIES); 1919 1920 /* If failed don't continue */ 1921 if (!ISCSI_SUCCESS(rval)) { 1922 cmn_err(CE_NOTE, "iscsi session(%u) unable to enumerate " 1923 "logical unit - inquiry failed lun %d", 1924 isp->sess_oid, lun_num); 1925 1926 goto inq_done; 1927 } 1928 1929 /* 1930 * T-10 SPC Section 6.4.2. Standard INQUIRY Peripheral 1931 * qualifier of 000b is the only type we should attempt 1932 * to plumb under the IO stack. 1933 */ 1934 if ((inq[0] & SCSI_INQUIRY_PQUAL_MASK) != 0x00) { 1935 goto inq_done; 1936 } 1937 1938 /* 1939 * VENDOR IDENTIFICATION INQUIRY - This will be used to identify 1940 * a unique lunId. This Id is passed to the mdi alloc calls so 1941 * we can properly plumb into scsi_vhci/mpxio. 1942 */ 1943 1944 bzero(&cdb, CDB_GROUP0); 1945 cdb[0] = SCMD_INQUIRY; 1946 cdb[1] = 0x01; /* EVP bit */ 1947 cdb[2] = 0x83; 1948 cdb[4] = ISCSI_MAX_INQUIRY_BUF_SIZE; 1949 1950 ucmd.uscsi_flags = USCSI_READ; 1951 ucmd.uscsi_timeout = iscsi_sess_enum_timeout; 1952 ucmd.uscsi_cdb = (char *)&cdb[0]; 1953 ucmd.uscsi_cdblen = CDB_GROUP0; 1954 ucmd.uscsi_bufaddr = (char *)inq83; 1955 ucmd.uscsi_buflen = ISCSI_MAX_INQUIRY_BUF_SIZE; 1956 1957 /* Attempt to get inquiry information until successful or retries */ 1958 retries = 0; 1959 do { 1960 /* issue passthru command */ 1961 rval = iscsi_handle_passthru(isp, lun_num, &ucmd); 1962 1963 /* If we were successful but scsi stat failed update istatus */ 1964 if (ISCSI_SUCCESS(rval) && 1965 (ucmd.uscsi_status != STATUS_GOOD)) { 1966 rval = ISCSI_STATUS_USCSI_FAILED; 1967 } 1968 1969 /* Break if successful */ 1970 if (ISCSI_SUCCESS(rval)) { 1971 inq83_len = ISCSI_MAX_INQUIRY_BUF_SIZE - 1972 ucmd.uscsi_resid; 1973 break; 1974 } 1975 1976 } while (retries++ < ISCSI_MAX_INQUIRY_RETRIES); 1977 1978 /* 1979 * If we were successful collecting page 83 data attempt 1980 * to generate a GUID. If no GUID can be generated then 1981 * the logical unit will skip attempt to plumb under 1982 * scsi_vhci/mpxio. 1983 */ 1984 if (ISCSI_SUCCESS(rval)) { 1985 /* create DEVID from inquiry data */ 1986 if (ddi_devid_scsi_encode( 1987 DEVID_SCSI_ENCODE_VERSION_LATEST, NULL, 1988 inq, inq_len, NULL, 0, inq83, inq83_len, &devid) == 1989 DDI_SUCCESS) { 1990 1991 /* extract GUID from DEVID */ 1992 guid = ddi_devid_to_guid(devid); 1993 1994 /* devid no longer needed */ 1995 ddi_devid_free(devid); 1996 } 1997 } 1998 1999 rval = iscsi_lun_create(isp, lun_num, lun_addr_type, 2000 (struct scsi_inquiry *)inq, guid); 2001 2002 if (guid != NULL) { 2003 /* guid no longer needed */ 2004 ddi_devid_free_guid(guid); 2005 } 2006 2007 inq_done: 2008 /* free up memory now that we are done */ 2009 kmem_free(inq, ISCSI_MAX_INQUIRY_BUF_SIZE); 2010 kmem_free(inq83, ISCSI_MAX_INQUIRY_BUF_SIZE); 2011 } 2012 2013 static iscsi_status_t 2014 retrieve_lundata(uint32_t lun_count, unsigned char *buf, iscsi_sess_t *isp, 2015 uint16_t *lun_num, uint8_t *lun_addr_type) 2016 { 2017 uint32_t lun_idx = 0; 2018 2019 ASSERT(lun_num != NULL); 2020 ASSERT(lun_addr_type != NULL); 2021 2022 lun_idx = (lun_count + 1) * SCSI_REPORTLUNS_ADDRESS_SIZE; 2023 /* determine report luns addressing type */ 2024 switch (buf[lun_idx] & SCSI_REPORTLUNS_ADDRESS_MASK) { 2025 /* 2026 * Vendors in the field have been found to be concatenating 2027 * bus/target/lun to equal the complete lun value instead 2028 * of switching to flat space addressing 2029 */ 2030 /* 00b - peripheral device addressing method */ 2031 case SCSI_REPORTLUNS_ADDRESS_PERIPHERAL: 2032 /* FALLTHRU */ 2033 /* 10b - logical unit addressing method */ 2034 case SCSI_REPORTLUNS_ADDRESS_LOGICAL_UNIT: 2035 /* FALLTHRU */ 2036 /* 01b - flat space addressing method */ 2037 case SCSI_REPORTLUNS_ADDRESS_FLAT_SPACE: 2038 /* byte0 bit0-5=msb lun byte1 bit0-7=lsb lun */ 2039 *lun_addr_type = (buf[lun_idx] & 2040 SCSI_REPORTLUNS_ADDRESS_MASK) >> 6; 2041 *lun_num = (buf[lun_idx] & 0x3F) << 8; 2042 *lun_num |= buf[lun_idx + 1]; 2043 return (ISCSI_STATUS_SUCCESS); 2044 default: /* protocol error */ 2045 cmn_err(CE_NOTE, "iscsi session(%u) unable " 2046 "to enumerate logical units - report " 2047 "luns returned an unsupported format", 2048 isp->sess_oid); 2049 break; 2050 } 2051 return (ISCSI_STATUS_INTERNAL_ERROR); 2052 } 2053 2054 /* 2055 * iscsi_sess_flush - flushes remaining pending io on the session 2056 */ 2057 static void 2058 iscsi_sess_flush(iscsi_sess_t *isp) 2059 { 2060 iscsi_cmd_t *icmdp; 2061 2062 ASSERT(isp != NULL); 2063 ASSERT(isp->sess_state != ISCSI_SESS_STATE_LOGGED_IN); 2064 2065 /* 2066 * Flush out any remaining commands in the pending 2067 * queue. 2068 */ 2069 mutex_enter(&isp->sess_queue_pending.mutex); 2070 icmdp = isp->sess_queue_pending.head; 2071 while (icmdp != NULL) { 2072 iscsi_cmd_state_machine(icmdp, 2073 ISCSI_CMD_EVENT_E7, isp); 2074 icmdp = isp->sess_queue_pending.head; 2075 } 2076 mutex_exit(&isp->sess_queue_pending.mutex); 2077 } 2078 2079 /* 2080 * iscsi_sess_offline_luns - offline all this sessions luns 2081 */ 2082 static void 2083 iscsi_sess_offline_luns(iscsi_sess_t *isp) 2084 { 2085 iscsi_lun_t *ilp; 2086 iscsi_hba_t *ihp; 2087 2088 ASSERT(isp != NULL); 2089 ASSERT(isp->sess_state != ISCSI_SESS_STATE_LOGGED_IN); 2090 ihp = isp->sess_hba; 2091 ASSERT(ihp != NULL); 2092 2093 rw_enter(&isp->sess_lun_list_rwlock, RW_READER); 2094 ilp = isp->sess_lun_list; 2095 while (ilp != NULL) { 2096 (void) iscsi_lun_offline(ihp, ilp, B_FALSE); 2097 ilp = ilp->lun_next; 2098 } 2099 rw_exit(&isp->sess_lun_list_rwlock); 2100 } 2101 2102 /* 2103 * iscsi_sess_get_by_target - return the session structure for based on a 2104 * passed in target oid and hba instance. NOTE: There may be 2105 * multiple sessions associated with any given target. In this case, 2106 * we will return the first matching session. This function 2107 * is intended to be used in retrieving target info that is constant 2108 * across sessions (target name, alias, etc.). 2109 */ 2110 int 2111 iscsi_sess_get_by_target(uint32_t target_oid, iscsi_hba_t *ihp, 2112 iscsi_sess_t **ispp) 2113 { 2114 int rval = 0; 2115 iscsi_sess_t *isp = NULL; 2116 2117 ASSERT(ihp != NULL); 2118 ASSERT(ispp != NULL); 2119 2120 /* See if we already created this session */ 2121 for (isp = ihp->hba_sess_list; isp; isp = isp->sess_next) { 2122 /* 2123 * Look for a session associated to the given target. 2124 * Return the first one found. 2125 */ 2126 if (isp->sess_target_oid == target_oid) { 2127 /* Found matching session */ 2128 break; 2129 } 2130 } 2131 2132 /* If not null this session is already available */ 2133 if (isp != NULL) { 2134 /* Existing session, return it */ 2135 *ispp = isp; 2136 } else { 2137 rval = EFAULT; 2138 } 2139 return (rval); 2140 } 2141