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