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