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