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