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