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 connection interfaces 26 */ 27 28 #define ISCSI_ICS_NAMES 29 #include "iscsi.h" 30 #include "persistent.h" 31 #include <sys/bootprops.h> 32 33 extern ib_boot_prop_t *iscsiboot_prop; 34 35 static void iscsi_client_notify_task(void *cn_task_void); 36 37 static void iscsi_conn_flush_active_cmds(iscsi_conn_t *icp); 38 39 #define SHUTDOWN_TIMEOUT 180 /* seconds */ 40 41 extern int modrootloaded; 42 43 boolean_t iscsi_conn_logging = B_FALSE; 44 45 /* 46 * +--------------------------------------------------------------------+ 47 * | External Connection Interfaces | 48 * +--------------------------------------------------------------------+ 49 */ 50 51 /* 52 * iscsi_conn_create - This creates an iscsi connection structure and 53 * associates it with a session structure. The session's sess_conn_list_rwlock 54 * should be held as a writer before calling this function. 55 */ 56 iscsi_status_t 57 iscsi_conn_create(struct sockaddr *addr, iscsi_sess_t *isp, iscsi_conn_t **icpp) 58 { 59 iscsi_conn_t *icp = NULL; 60 char th_name[ISCSI_TH_MAX_NAME_LEN]; 61 62 /* See if this connection already exists */ 63 for (icp = isp->sess_conn_list; icp; icp = icp->conn_next) { 64 65 /* 66 * Compare the ioctl information to see if 67 * its a match for this connection. (This 68 * is done by making sure the IPs are of 69 * the same size and then they are the 70 * same value. 71 */ 72 if (bcmp(&icp->conn_base_addr, addr, 73 SIZEOF_SOCKADDR(addr)) == 0) { 74 /* It's a match, record this connection */ 75 break; 76 } 77 } 78 79 /* If icp is found return it */ 80 if (icp != NULL) { 81 *icpp = icp; 82 return (ISCSI_STATUS_SUCCESS); 83 } 84 85 /* We are creating the connection, allocate, and setup */ 86 icp = (iscsi_conn_t *)kmem_zalloc(sizeof (iscsi_conn_t), KM_SLEEP); 87 88 /* 89 * Setup connection 90 */ 91 icp->conn_sig = ISCSI_SIG_CONN; 92 icp->conn_state = ISCSI_CONN_STATE_FREE; 93 mutex_init(&icp->conn_state_mutex, NULL, MUTEX_DRIVER, NULL); 94 cv_init(&icp->conn_state_change, NULL, CV_DRIVER, NULL); 95 mutex_init(&icp->conn_login_mutex, NULL, MUTEX_DRIVER, NULL); 96 cv_init(&icp->conn_login_cv, NULL, CV_DRIVER, NULL); 97 icp->conn_state_destroy = B_FALSE; 98 idm_sm_audit_init(&icp->conn_state_audit); 99 icp->conn_sess = isp; 100 101 mutex_enter(&iscsi_oid_mutex); 102 icp->conn_oid = iscsi_oid++; 103 mutex_exit(&iscsi_oid_mutex); 104 105 /* 106 * IDM CN taskq 107 */ 108 109 if (snprintf(th_name, sizeof (th_name) - 1, 110 ISCSI_CONN_CN_TASKQ_NAME_FORMAT, 111 icp->conn_sess->sess_hba->hba_oid, icp->conn_sess->sess_oid, 112 icp->conn_oid) >= sizeof (th_name)) { 113 cv_destroy(&icp->conn_state_change); 114 mutex_destroy(&icp->conn_state_mutex); 115 kmem_free(icp, sizeof (iscsi_conn_t)); 116 *icpp = NULL; 117 return (ISCSI_STATUS_INTERNAL_ERROR); 118 } 119 120 icp->conn_cn_taskq = 121 ddi_taskq_create(icp->conn_sess->sess_hba->hba_dip, th_name, 1, 122 TASKQ_DEFAULTPRI, 0); 123 if (icp->conn_cn_taskq == NULL) { 124 cv_destroy(&icp->conn_state_change); 125 mutex_destroy(&icp->conn_state_mutex); 126 kmem_free(icp, sizeof (iscsi_conn_t)); 127 *icpp = NULL; 128 return (ISCSI_STATUS_INTERNAL_ERROR); 129 } 130 131 /* Creation of the transfer thread */ 132 if (snprintf(th_name, sizeof (th_name) - 1, ISCSI_CONN_TXTH_NAME_FORMAT, 133 icp->conn_sess->sess_hba->hba_oid, icp->conn_sess->sess_oid, 134 icp->conn_oid) >= sizeof (th_name)) { 135 cv_destroy(&icp->conn_state_change); 136 mutex_destroy(&icp->conn_state_mutex); 137 kmem_free(icp, sizeof (iscsi_conn_t)); 138 ddi_taskq_destroy(icp->conn_cn_taskq); 139 *icpp = NULL; 140 return (ISCSI_STATUS_INTERNAL_ERROR); 141 } 142 143 icp->conn_tx_thread = iscsi_thread_create(isp->sess_hba->hba_dip, 144 th_name, iscsi_tx_thread, icp); 145 146 /* setup connection queues */ 147 iscsi_init_queue(&icp->conn_queue_active); 148 iscsi_init_queue(&icp->conn_queue_idm_aborting); 149 150 bcopy(addr, &icp->conn_base_addr, sizeof (icp->conn_base_addr)); 151 152 /* Add new connection to the session connection list */ 153 icp->conn_cid = isp->sess_conn_next_cid++; 154 if (isp->sess_conn_list == NULL) { 155 isp->sess_conn_list = isp->sess_conn_list_last_ptr = icp; 156 } else { 157 isp->sess_conn_list_last_ptr->conn_next = icp; 158 isp->sess_conn_list_last_ptr = icp; 159 } 160 161 KSTAT_INC_SESS_CNTR_CONN(isp); 162 (void) iscsi_conn_kstat_init(icp); 163 164 *icpp = icp; 165 166 return (ISCSI_STATUS_SUCCESS); 167 } 168 169 /* 170 * iscsi_conn_online - This attempts to take a connection from 171 * ISCSI_CONN_STATE_FREE to ISCSI_CONN_STATE_LOGGED_IN. 172 */ 173 iscsi_status_t 174 iscsi_conn_online(iscsi_conn_t *icp) 175 { 176 iscsi_task_t *itp; 177 iscsi_status_t rval; 178 179 ASSERT(icp != NULL); 180 ASSERT(mutex_owned(&icp->conn_state_mutex)); 181 ASSERT(icp->conn_state == ISCSI_CONN_STATE_FREE); 182 183 /* 184 * If we are attempting to connect then for the purposes of the 185 * other initiator code we are effectively in ISCSI_CONN_STATE_IN_LOGIN. 186 */ 187 iscsi_conn_update_state_locked(icp, ISCSI_CONN_STATE_IN_LOGIN); 188 mutex_exit(&icp->conn_state_mutex); 189 190 /* 191 * Sync base connection information before login 192 * A login redirection might have shifted the 193 * current information from the base. 194 */ 195 bcopy(&icp->conn_base_addr, &icp->conn_curr_addr, 196 sizeof (icp->conn_curr_addr)); 197 198 itp = kmem_zalloc(sizeof (iscsi_task_t), KM_SLEEP); 199 ASSERT(itp != NULL); 200 201 itp->t_arg = icp; 202 itp->t_blocking = B_TRUE; 203 rval = iscsi_login_start(itp); 204 kmem_free(itp, sizeof (iscsi_task_t)); 205 206 mutex_enter(&icp->conn_state_mutex); 207 208 return (rval); 209 } 210 211 /* 212 * iscsi_conn_offline - This attempts to take a connection from 213 * any state to ISCSI_CONN_STATE_FREE. 214 */ 215 iscsi_status_t 216 iscsi_conn_offline(iscsi_conn_t *icp) 217 { 218 clock_t delay; 219 220 ASSERT(icp != NULL); 221 222 /* 223 * We can only destroy a connection if its either in 224 * a state of FREE or LOGGED. The other states are 225 * transitionary and its unsafe to perform actions 226 * on the connection in those states. Set a flag 227 * on the connection to influence the transitions 228 * to quickly complete. Then wait for a state 229 * transition. 230 * 231 * ISCSI_CONN_STATE_LOGGED_IN is set immediately at the 232 * start of CN_NOTIFY_FFP processing. icp->conn_state_ffp 233 * is set to true at the end of ffp processing, at which 234 * point any session updates are complete. We don't 235 * want to start offlining the connection before we're 236 * done completing the FFP processing since this might 237 * interrupt the discovery process. 238 */ 239 delay = ddi_get_lbolt() + SEC_TO_TICK(SHUTDOWN_TIMEOUT); 240 mutex_enter(&icp->conn_state_mutex); 241 icp->conn_state_destroy = B_TRUE; 242 while ((((icp->conn_state != ISCSI_CONN_STATE_FREE) && 243 (icp->conn_state != ISCSI_CONN_STATE_LOGGED_IN)) || 244 ((icp->conn_state == ISCSI_CONN_STATE_LOGGED_IN) && 245 !icp->conn_state_ffp)) && 246 (ddi_get_lbolt() < delay)) { 247 /* wait for transition */ 248 (void) cv_timedwait(&icp->conn_state_change, 249 &icp->conn_state_mutex, delay); 250 } 251 252 switch (icp->conn_state) { 253 case ISCSI_CONN_STATE_FREE: 254 break; 255 case ISCSI_CONN_STATE_LOGGED_IN: 256 if (icp->conn_state_ffp) 257 (void) iscsi_handle_logout(icp); 258 else { 259 icp->conn_state_destroy = B_FALSE; 260 mutex_exit(&icp->conn_state_mutex); 261 return (ISCSI_STATUS_INTERNAL_ERROR); 262 } 263 break; 264 case ISCSI_CONN_STATE_IN_LOGIN: 265 case ISCSI_CONN_STATE_IN_LOGOUT: 266 case ISCSI_CONN_STATE_FAILED: 267 case ISCSI_CONN_STATE_POLLING: 268 default: 269 icp->conn_state_destroy = B_FALSE; 270 mutex_exit(&icp->conn_state_mutex); 271 return (ISCSI_STATUS_INTERNAL_ERROR); 272 } 273 mutex_exit(&icp->conn_state_mutex); 274 275 return (ISCSI_STATUS_SUCCESS); 276 } 277 278 /* 279 * iscsi_conn_destroy - This destroys an iscsi connection structure 280 * and de-associates it with the session. The connection should 281 * already been in the ISCSI_CONN_STATE_FREE when attempting this 282 * operation. 283 */ 284 iscsi_status_t 285 iscsi_conn_destroy(iscsi_conn_t *icp) 286 { 287 iscsi_sess_t *isp; 288 iscsi_conn_t *t_icp; 289 290 ASSERT(icp != NULL); 291 isp = icp->conn_sess; 292 ASSERT(isp != NULL); 293 294 if (icp->conn_state != ISCSI_CONN_STATE_FREE) { 295 return (ISCSI_STATUS_INTERNAL_ERROR); 296 } 297 298 /* Destroy transfer thread */ 299 iscsi_thread_destroy(icp->conn_tx_thread); 300 ddi_taskq_destroy(icp->conn_cn_taskq); 301 302 /* Terminate connection queues */ 303 iscsi_destroy_queue(&icp->conn_queue_idm_aborting); 304 iscsi_destroy_queue(&icp->conn_queue_active); 305 306 cv_destroy(&icp->conn_login_cv); 307 mutex_destroy(&icp->conn_login_mutex); 308 cv_destroy(&icp->conn_state_change); 309 mutex_destroy(&icp->conn_state_mutex); 310 311 /* 312 * Remove connection from sessions linked list. 313 */ 314 if (isp->sess_conn_list == icp) { 315 /* connection first item in list */ 316 isp->sess_conn_list = icp->conn_next; 317 /* 318 * check if this is also the last item in the list 319 */ 320 if (isp->sess_conn_list_last_ptr == icp) { 321 isp->sess_conn_list_last_ptr = NULL; 322 } 323 } else { 324 /* 325 * search session list for icp pointing 326 * to connection being removed. Then 327 * update that connections next pointer. 328 */ 329 t_icp = isp->sess_conn_list; 330 while (t_icp->conn_next != NULL) { 331 if (t_icp->conn_next == icp) { 332 break; 333 } 334 t_icp = t_icp->conn_next; 335 } 336 if (t_icp->conn_next == icp) { 337 t_icp->conn_next = icp->conn_next; 338 /* 339 * if this is the last connection in the list 340 * update the last_ptr to point to t_icp 341 */ 342 if (isp->sess_conn_list_last_ptr == icp) { 343 isp->sess_conn_list_last_ptr = t_icp; 344 } 345 } else { 346 /* couldn't find session */ 347 ASSERT(FALSE); 348 } 349 } 350 351 /* Free this Connections Data */ 352 iscsi_conn_kstat_term(icp); 353 kmem_free(icp, sizeof (iscsi_conn_t)); 354 355 return (ISCSI_STATUS_SUCCESS); 356 } 357 358 359 /* 360 * iscsi_conn_set_login_min_max - set min/max login window 361 * 362 * Used to set the min and max login window. Input values 363 * are in seconds. 364 */ 365 void 366 iscsi_conn_set_login_min_max(iscsi_conn_t *icp, int min, int max) 367 { 368 ASSERT(icp != NULL); 369 370 icp->conn_login_min = ddi_get_lbolt() + SEC_TO_TICK(min); 371 icp->conn_login_max = ddi_get_lbolt() + SEC_TO_TICK(max); 372 } 373 374 375 /* 376 * Process the idm notifications 377 */ 378 idm_status_t 379 iscsi_client_notify(idm_conn_t *ic, idm_client_notify_t icn, uintptr_t data) 380 { 381 iscsi_cn_task_t *cn; 382 iscsi_conn_t *icp = ic->ic_handle; 383 iscsi_sess_t *isp; 384 385 /* 386 * Don't access icp if the notification is CN_CONNECT_DESTROY 387 * since icp may have already been freed. 388 * 389 * Handle CN_FFP_ENABLED and CN_CONNECT_DESTROY immediately 390 */ 391 switch (icn) { 392 case CN_CONNECT_FAIL: 393 case CN_LOGIN_FAIL: 394 /* 395 * Wakeup any thread waiting for login stuff to happen. 396 */ 397 ASSERT(icp != NULL); 398 iscsi_login_update_state(icp, LOGIN_ERROR); 399 return (IDM_STATUS_SUCCESS); 400 case CN_READY_FOR_LOGIN: 401 idm_conn_hold(ic); /* Released in CN_CONNECT_LOST */ 402 mutex_enter(&icp->conn_state_mutex); 403 icp->conn_state_idm_connected = B_TRUE; 404 cv_broadcast(&icp->conn_state_change); 405 mutex_exit(&icp->conn_state_mutex); 406 407 iscsi_login_update_state(icp, LOGIN_READY); 408 return (IDM_STATUS_SUCCESS); 409 case CN_CONNECT_DESTROY: 410 /* 411 * We released any dependecies we had on this object in 412 * either CN_LOGIN_FAIL or CN_CONNECT_LOST so we just need 413 * to destroy the IDM connection now. 414 */ 415 idm_ini_conn_destroy(ic); 416 return (IDM_STATUS_SUCCESS); 417 } 418 419 ASSERT(icp != NULL); 420 isp = icp->conn_sess; 421 422 /* 423 * Dispatch notifications to the taskq since they often require 424 * long blocking operations. In the case of CN_CONNECT_DESTROY 425 * we actually just want to destroy the connection which we 426 * can't do in the IDM taskq context. 427 */ 428 cn = kmem_alloc(sizeof (*cn), KM_SLEEP); 429 430 cn->ct_ic = ic; 431 cn->ct_icn = icn; 432 cn->ct_data = data; 433 434 idm_conn_hold(ic); 435 436 if (ddi_taskq_dispatch(icp->conn_cn_taskq, 437 iscsi_client_notify_task, cn, DDI_SLEEP) != DDI_SUCCESS) { 438 idm_conn_rele(ic); 439 cmn_err(CE_WARN, "iscsi connection(%u) failure - " 440 "unable to schedule notify task", icp->conn_oid); 441 iscsi_conn_update_state(icp, ISCSI_CONN_STATE_FREE); 442 mutex_enter(&isp->sess_state_mutex); 443 iscsi_sess_state_machine(isp, 444 ISCSI_SESS_EVENT_N6); 445 mutex_exit(&isp->sess_state_mutex); 446 } 447 448 return (IDM_STATUS_SUCCESS); 449 } 450 451 static void 452 iscsi_client_notify_task(void *cn_task_void) 453 { 454 iscsi_cn_task_t *cn_task = cn_task_void; 455 iscsi_conn_t *icp; 456 iscsi_sess_t *isp; 457 idm_conn_t *ic; 458 idm_client_notify_t icn; 459 uintptr_t data; 460 idm_ffp_disable_t disable_type; 461 boolean_t in_login; 462 463 ic = cn_task->ct_ic; 464 icn = cn_task->ct_icn; 465 data = cn_task->ct_data; 466 467 icp = ic->ic_handle; 468 ASSERT(icp != NULL); 469 isp = icp->conn_sess; 470 471 switch (icn) { 472 case CN_FFP_ENABLED: 473 mutex_enter(&icp->conn_state_mutex); 474 icp->conn_async_logout = B_FALSE; 475 icp->conn_state_ffp = B_TRUE; 476 cv_broadcast(&icp->conn_state_change); 477 mutex_exit(&icp->conn_state_mutex); 478 479 /* 480 * This logic assumes that the IDM login-snooping code 481 * and the initiator login code will agree on whether 482 * the connection is in FFP. The reason we do this 483 * is that we don't want to process CN_FFP_DISABLED until 484 * CN_FFP_ENABLED has been full handled. 485 */ 486 mutex_enter(&icp->conn_login_mutex); 487 while (icp->conn_login_state != LOGIN_FFP) { 488 cv_wait(&icp->conn_login_cv, &icp->conn_login_mutex); 489 } 490 mutex_exit(&icp->conn_login_mutex); 491 break; 492 case CN_FFP_DISABLED: 493 disable_type = (idm_ffp_disable_t)data; 494 495 mutex_enter(&icp->conn_state_mutex); 496 switch (disable_type) { 497 case FD_SESS_LOGOUT: 498 case FD_CONN_LOGOUT: 499 if (icp->conn_async_logout) { 500 /* 501 * Our logout was in response to an 502 * async logout request so treat this 503 * like a connection failure (we will 504 * try to re-establish the connection) 505 */ 506 iscsi_conn_update_state_locked(icp, 507 ISCSI_CONN_STATE_FAILED); 508 } else { 509 /* 510 * Logout due to to user config change, 511 * we will not try to re-establish 512 * the connection. 513 */ 514 iscsi_conn_update_state_locked(icp, 515 ISCSI_CONN_STATE_IN_LOGOUT); 516 /* 517 * Hold off generating the ISCSI_SESS_EVENT_N3 518 * event until we get the CN_CONNECT_LOST 519 * notification. This matches the pre-IDM 520 * implementation better. 521 */ 522 } 523 break; 524 525 case FD_CONN_FAIL: 526 default: 527 iscsi_conn_update_state_locked(icp, 528 ISCSI_CONN_STATE_FAILED); 529 break; 530 } 531 532 icp->conn_state_ffp = B_FALSE; 533 cv_broadcast(&icp->conn_state_change); 534 mutex_exit(&icp->conn_state_mutex); 535 536 break; 537 case CN_CONNECT_LOST: 538 /* 539 * We only care about CN_CONNECT_LOST if we've logged in. IDM 540 * sends a flag as the data payload to indicate whether we 541 * were trying to login. The CN_LOGIN_FAIL notification 542 * gives us what we need to know for login failures and 543 * otherwise we will need to keep a bunch of state to know 544 * what CN_CONNECT_LOST means to us. 545 */ 546 in_login = (boolean_t)data; 547 if (in_login) { 548 mutex_enter(&icp->conn_state_mutex); 549 550 icp->conn_state_idm_connected = B_FALSE; 551 cv_broadcast(&icp->conn_state_change); 552 mutex_exit(&icp->conn_state_mutex); 553 554 /* Release connect hold from CN_READY_FOR_LOGIN */ 555 idm_conn_rele(ic); 556 break; 557 } 558 559 /* Any remaining commands are never going to finish */ 560 iscsi_conn_flush_active_cmds(icp); 561 562 /* 563 * The connection is no longer active so cleanup any 564 * references to the connection and release any holds so 565 * that IDM can finish cleanup. 566 */ 567 mutex_enter(&icp->conn_state_mutex); 568 if (icp->conn_state != ISCSI_CONN_STATE_FAILED) { 569 570 mutex_enter(&isp->sess_state_mutex); 571 iscsi_sess_state_machine(isp, ISCSI_SESS_EVENT_N3); 572 mutex_exit(&isp->sess_state_mutex); 573 574 iscsi_conn_update_state_locked(icp, 575 ISCSI_CONN_STATE_FREE); 576 } else { 577 578 mutex_enter(&isp->sess_state_mutex); 579 iscsi_sess_state_machine(isp, 580 ISCSI_SESS_EVENT_N5); 581 mutex_exit(&isp->sess_state_mutex); 582 583 /* 584 * If session type is NORMAL, try to reestablish the 585 * connection. 586 */ 587 if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) { 588 iscsi_conn_retry(isp, icp); 589 } else { 590 591 mutex_enter(&isp->sess_state_mutex); 592 iscsi_sess_state_machine(isp, 593 ISCSI_SESS_EVENT_N6); 594 mutex_exit(&isp->sess_state_mutex); 595 596 iscsi_conn_update_state_locked(icp, 597 ISCSI_CONN_STATE_FREE); 598 } 599 } 600 601 (void) iscsi_thread_stop(icp->conn_tx_thread); 602 603 icp->conn_state_idm_connected = B_FALSE; 604 cv_broadcast(&icp->conn_state_change); 605 mutex_exit(&icp->conn_state_mutex); 606 607 /* Release connect hold from CN_READY_FOR_LOGIN */ 608 idm_conn_rele(ic); 609 break; 610 default: 611 ISCSI_CONN_LOG(CE_WARN, 612 "iscsi_client_notify: unknown notification: " 613 "%x: NOT IMPLEMENTED YET: icp: %p ic: %p ", 614 icn, (void *)icp, (void *)ic); 615 break; 616 } 617 /* free the task notify structure we allocated in iscsi_client_notify */ 618 kmem_free(cn_task, sizeof (*cn_task)); 619 620 /* Release the hold we acquired in iscsi_client_notify */ 621 idm_conn_rele(ic); 622 } 623 624 /* 625 * iscsi_conn_sync_params - used to update connection parameters 626 * 627 * Used to update connection parameters with current configured 628 * parameters in the persistent store. This should be called 629 * before starting to make a new iscsi connection in iscsi_login. 630 */ 631 iscsi_status_t 632 iscsi_conn_sync_params(iscsi_conn_t *icp) 633 { 634 iscsi_sess_t *isp; 635 iscsi_hba_t *ihp; 636 int param_id; 637 persistent_param_t pp; 638 iscsi_config_sess_t *ics; 639 int idx, size; 640 char *name; 641 642 ASSERT(icp != NULL); 643 ASSERT((icp->conn_state == ISCSI_CONN_STATE_IN_LOGIN) || 644 (icp->conn_state == ISCSI_CONN_STATE_FAILED) || 645 (icp->conn_state == ISCSI_CONN_STATE_POLLING)); 646 isp = icp->conn_sess; 647 ASSERT(isp != NULL); 648 ihp = isp->sess_hba; 649 ASSERT(ihp != NULL); 650 651 /* 652 * Check if someone is trying to destroy this 653 * connection. If so fail the sync request, 654 * as a method of fast fail. 655 */ 656 if (icp->conn_state_destroy == B_TRUE) { 657 return (ISCSI_STATUS_SHUTDOWN); 658 } 659 660 bzero(&pp, sizeof (pp)); 661 662 /* First get a copy of the HBA params */ 663 bcopy(&ihp->hba_params, &icp->conn_params, 664 sizeof (iscsi_login_params_t)); 665 666 /* 667 * Now we need to get the session configured 668 * values from the persistent store and apply 669 * them to our connection. 670 */ 671 (void) persistent_param_get((char *)isp->sess_name, &pp); 672 for (param_id = 0; param_id < ISCSI_NUM_LOGIN_PARAM; 673 param_id++) { 674 if (iscsiboot_prop && modrootloaded && 675 !iscsi_chk_bootlun_mpxio(ihp) && isp->sess_boot) { 676 /* 677 * iscsi boot with mpxio disabled 678 * while iscsi booting target's parameter overriden 679 * do no update target's parameters. 680 */ 681 if (pp.p_bitmap) { 682 cmn_err(CE_NOTE, "Adopting " 683 " default login parameters in" 684 " boot session as MPxIO is disabled"); 685 } 686 break; 687 } 688 if (pp.p_bitmap & (1 << param_id)) { 689 690 switch (param_id) { 691 /* 692 * Boolean parameters 693 */ 694 case ISCSI_LOGIN_PARAM_DATA_SEQUENCE_IN_ORDER: 695 icp->conn_params.data_pdu_in_order = 696 pp.p_params.data_pdu_in_order; 697 break; 698 case ISCSI_LOGIN_PARAM_IMMEDIATE_DATA: 699 icp->conn_params.immediate_data = 700 pp.p_params.immediate_data; 701 break; 702 case ISCSI_LOGIN_PARAM_INITIAL_R2T: 703 icp->conn_params.initial_r2t = 704 pp.p_params.initial_r2t; 705 break; 706 case ISCSI_LOGIN_PARAM_DATA_PDU_IN_ORDER: 707 icp->conn_params.data_pdu_in_order = 708 pp.p_params.data_pdu_in_order; 709 break; 710 /* 711 * Integer parameters 712 */ 713 case ISCSI_LOGIN_PARAM_HEADER_DIGEST: 714 icp->conn_params.header_digest = 715 pp.p_params.header_digest; 716 break; 717 case ISCSI_LOGIN_PARAM_DATA_DIGEST: 718 icp->conn_params.data_digest = 719 pp.p_params.data_digest; 720 break; 721 case ISCSI_LOGIN_PARAM_DEFAULT_TIME_2_RETAIN: 722 icp->conn_params.default_time_to_retain = 723 pp.p_params.default_time_to_retain; 724 break; 725 case ISCSI_LOGIN_PARAM_DEFAULT_TIME_2_WAIT: 726 icp->conn_params.default_time_to_wait = 727 pp.p_params.default_time_to_wait; 728 break; 729 case ISCSI_LOGIN_PARAM_MAX_RECV_DATA_SEGMENT_LENGTH: 730 icp->conn_params.max_recv_data_seg_len = 731 pp.p_params.max_recv_data_seg_len; 732 break; 733 case ISCSI_LOGIN_PARAM_FIRST_BURST_LENGTH: 734 icp->conn_params.first_burst_length = 735 pp.p_params.first_burst_length; 736 break; 737 case ISCSI_LOGIN_PARAM_MAX_BURST_LENGTH: 738 icp->conn_params.max_burst_length = 739 pp.p_params.max_burst_length; 740 break; 741 742 /* 743 * Integer parameters which currently are unsettable 744 */ 745 case ISCSI_LOGIN_PARAM_MAX_CONNECTIONS: 746 /* FALLTHRU */ 747 case ISCSI_LOGIN_PARAM_OUTSTANDING_R2T: 748 /* FALLTHRU */ 749 case ISCSI_LOGIN_PARAM_ERROR_RECOVERY_LEVEL: 750 /* FALLTHRU */ 751 default: 752 break; 753 } 754 } 755 } 756 757 /* Skip binding checks on discovery sessions */ 758 if (isp->sess_type == ISCSI_SESS_TYPE_DISCOVERY) { 759 return (ISCSI_STATUS_SUCCESS); 760 } 761 762 /* 763 * Now we need to get the current optional connection 764 * binding information. 765 */ 766 /* setup initial buffer for configured session information */ 767 size = sizeof (*ics); 768 ics = kmem_zalloc(size, KM_SLEEP); 769 ics->ics_in = 1; 770 771 /* get configured sessions information */ 772 name = (char *)isp->sess_name; 773 if (persistent_get_config_session(name, ics) == B_FALSE) { 774 /* 775 * If we were unable to get target level information 776 * then check the initiator level information. 777 */ 778 name = (char *)isp->sess_hba->hba_name; 779 if (persistent_get_config_session(name, ics) == B_FALSE) { 780 /* 781 * No hba information is found. So assume default 782 * one session unbound behavior. 783 */ 784 ics->ics_out = 1; 785 ics->ics_bound = B_FALSE; 786 } 787 } 788 789 if (iscsiboot_prop && (ics->ics_out > 1) && isp->sess_boot && 790 !iscsi_chk_bootlun_mpxio(ihp)) { 791 /* 792 * iscsi booting session with mpxio disabled, 793 * no need set multiple sessions for booting session 794 */ 795 ics->ics_out = 1; 796 ics->ics_bound = B_FALSE; 797 cmn_err(CE_NOTE, "MPxIO is disabled," 798 " no need to configure multiple boot sessions"); 799 } 800 801 /* 802 * Check to make sure this session is still a configured 803 * session. The user might have decreased the session 804 * count. (NOTE: byte 5 of the sess_isid is the session 805 * count (via MS/T). This counter starts at 0.) 806 */ 807 808 809 idx = isp->sess_isid[5]; 810 811 if (iscsiboot_prop && (idx == ISCSI_MAX_CONFIG_SESSIONS)) { 812 /* 813 * This is temporary session for boot session propose 814 * no need to bound IP for this session 815 */ 816 icp->conn_bound = B_FALSE; 817 kmem_free(ics, sizeof (iscsi_config_sess_t)); 818 return (ISCSI_STATUS_SUCCESS); 819 } 820 821 if (ics->ics_out <= idx) { 822 /* 823 * No longer a configured session. Return a 824 * failure so we don't attempt to relogin. 825 */ 826 return (ISCSI_STATUS_SHUTDOWN); 827 } 828 829 /* 830 * If sessions are unbound set this information on 831 * the connection and return success. 832 */ 833 if (ics->ics_bound == B_FALSE) { 834 icp->conn_bound = B_FALSE; 835 kmem_free(ics, sizeof (iscsi_config_sess_t)); 836 return (ISCSI_STATUS_SUCCESS); 837 } 838 839 /* 840 * Since the sessions are bound we need to find the matching 841 * binding information for the session's isid. If this 842 * session's isid is > 0 then we need to get more configured 843 * session information to find the binding info. 844 */ 845 if (idx > 0) { 846 int ics_out; 847 848 ics_out = ics->ics_out; 849 /* record new size and free last buffer */ 850 size = ISCSI_SESSION_CONFIG_SIZE(ics_out); 851 kmem_free(ics, sizeof (*ics)); 852 853 /* allocate new buffer */ 854 ics = kmem_zalloc(size, KM_SLEEP); 855 ics->ics_in = ics_out; 856 857 /* get configured sessions information */ 858 if (persistent_get_config_session(name, ics) != B_TRUE) { 859 cmn_err(CE_NOTE, "iscsi session(%d) - " 860 "unable to get configured session information\n", 861 isp->sess_oid); 862 kmem_free(ics, size); 863 return (ISCSI_STATUS_SHUTDOWN); 864 } 865 } 866 867 /* Copy correct binding information to the connection */ 868 icp->conn_bound = B_TRUE; 869 if (ics->ics_bindings[idx].i_insize == sizeof (struct in_addr)) { 870 bcopy(&ics->ics_bindings[idx].i_addr.in4, 871 &icp->conn_bound_addr.sin4.sin_addr.s_addr, 872 sizeof (struct in_addr)); 873 icp->conn_bound_addr.sin4.sin_family = AF_INET; 874 } else { 875 bcopy(&ics->ics_bindings[idx].i_addr.in6, 876 &icp->conn_bound_addr.sin6.sin6_addr.s6_addr, 877 sizeof (struct in6_addr)); 878 icp->conn_bound_addr.sin6.sin6_family = AF_INET6; 879 } 880 881 kmem_free(ics, size); 882 883 return (ISCSI_STATUS_SUCCESS); 884 } 885 886 /* 887 * +--------------------------------------------------------------------+ 888 * | Internal Connection Interfaces | 889 * +--------------------------------------------------------------------+ 890 */ 891 892 /* 893 * iscsi_conn_flush_active_cmds - flush all active icmdps 894 * for a connection. 895 */ 896 static void 897 iscsi_conn_flush_active_cmds(iscsi_conn_t *icp) 898 { 899 iscsi_cmd_t *icmdp; 900 iscsi_sess_t *isp; 901 boolean_t lock_held = B_FALSE; 902 903 ASSERT(icp != NULL); 904 isp = icp->conn_sess; 905 ASSERT(isp != NULL); 906 907 if (mutex_owned(&icp->conn_queue_active.mutex)) { 908 lock_held = B_TRUE; 909 } else { 910 mutex_enter(&icp->conn_queue_active.mutex); 911 } 912 913 /* Flush active queue */ 914 icmdp = icp->conn_queue_active.head; 915 while (icmdp != NULL) { 916 iscsi_cmd_state_machine(icmdp, 917 ISCSI_CMD_EVENT_E7, isp); 918 icmdp = icp->conn_queue_active.head; 919 } 920 921 /* Wait for active queue to drain */ 922 while (icp->conn_queue_active.count) { 923 mutex_exit(&icp->conn_queue_active.mutex); 924 delay(drv_usectohz(100000)); 925 mutex_enter(&icp->conn_queue_active.mutex); 926 } 927 928 if (lock_held == B_FALSE) { 929 mutex_exit(&icp->conn_queue_active.mutex); 930 } 931 932 /* Wait for IDM abort queue to drain (if necessary) */ 933 mutex_enter(&icp->conn_queue_idm_aborting.mutex); 934 while (icp->conn_queue_idm_aborting.count) { 935 mutex_exit(&icp->conn_queue_idm_aborting.mutex); 936 delay(drv_usectohz(100000)); 937 mutex_enter(&icp->conn_queue_idm_aborting.mutex); 938 } 939 mutex_exit(&icp->conn_queue_idm_aborting.mutex); 940 } 941 942 /* 943 * iscsi_conn_retry - retry connect/login 944 */ 945 void 946 iscsi_conn_retry(iscsi_sess_t *isp, iscsi_conn_t *icp) 947 { 948 iscsi_task_t *itp; 949 950 ASSERT(isp != NULL); 951 ASSERT(icp != NULL); 952 953 /* set login min/max time values */ 954 iscsi_conn_set_login_min_max(icp, 955 ISCSI_CONN_DEFAULT_LOGIN_MIN, 956 ISCSI_CONN_DEFAULT_LOGIN_MAX); 957 958 ISCSI_CONN_LOG(CE_NOTE, "DEBUG: iscsi_conn_retry: icp: %p icp: %p ", 959 (void *)icp, 960 (void *)icp->conn_ic); 961 962 /* 963 * Sync base connection information before login. 964 * A login redirection might have shifted the 965 * current information from the base. 966 */ 967 bcopy(&icp->conn_base_addr, &icp->conn_curr_addr, 968 sizeof (icp->conn_curr_addr)); 969 970 /* schedule login task */ 971 itp = kmem_zalloc(sizeof (iscsi_task_t), KM_SLEEP); 972 itp->t_arg = icp; 973 itp->t_blocking = B_FALSE; 974 if (ddi_taskq_dispatch(isp->sess_taskq, 975 (void(*)())iscsi_login_start, itp, DDI_SLEEP) != 976 DDI_SUCCESS) { 977 kmem_free(itp, sizeof (iscsi_task_t)); 978 cmn_err(CE_WARN, "iscsi connection(%u) failure - " 979 "unable to schedule login task", icp->conn_oid); 980 981 iscsi_conn_update_state(icp, ISCSI_CONN_STATE_FREE); 982 mutex_enter(&isp->sess_state_mutex); 983 iscsi_sess_state_machine(isp, 984 ISCSI_SESS_EVENT_N6); 985 mutex_exit(&isp->sess_state_mutex); 986 } 987 } 988 989 void 990 iscsi_conn_update_state(iscsi_conn_t *icp, iscsi_conn_state_t 991 next_state) 992 { 993 mutex_enter(&icp->conn_state_mutex); 994 (void) iscsi_conn_update_state_locked(icp, next_state); 995 mutex_exit(&icp->conn_state_mutex); 996 } 997 998 void 999 iscsi_conn_update_state_locked(iscsi_conn_t *icp, 1000 iscsi_conn_state_t next_state) 1001 { 1002 ASSERT(mutex_owned(&icp->conn_state_mutex)); 1003 next_state = (next_state > ISCSI_CONN_STATE_MAX) ? 1004 ISCSI_CONN_STATE_MAX : next_state; 1005 idm_sm_audit_state_change(&icp->conn_state_audit, 1006 SAS_ISCSI_CONN, icp->conn_state, next_state); 1007 switch (next_state) { 1008 case ISCSI_CONN_STATE_FREE: 1009 case ISCSI_CONN_STATE_IN_LOGIN: 1010 case ISCSI_CONN_STATE_LOGGED_IN: 1011 case ISCSI_CONN_STATE_IN_LOGOUT: 1012 case ISCSI_CONN_STATE_FAILED: 1013 case ISCSI_CONN_STATE_POLLING: 1014 ISCSI_CONN_LOG(CE_NOTE, 1015 "iscsi_conn_update_state conn %p %s(%d) -> %s(%d)", 1016 (void *)icp, 1017 iscsi_ics_name[icp->conn_state], icp->conn_state, 1018 iscsi_ics_name[next_state], next_state); 1019 icp->conn_prev_state = icp->conn_state; 1020 icp->conn_state = next_state; 1021 cv_broadcast(&icp->conn_state_change); 1022 break; 1023 default: 1024 cmn_err(CE_WARN, "Update state found illegal state: %x " 1025 "prev_state: %x", next_state, icp->conn_prev_state); 1026 ASSERT(0); 1027 } 1028 } 1029