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