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