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