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