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 26 #include <sys/cpuvar.h> 27 #include <sys/types.h> 28 #include <sys/conf.h> 29 #include <sys/file.h> 30 #include <sys/ddi.h> 31 #include <sys/sunddi.h> 32 #include <sys/modctl.h> 33 #include <sys/sysmacros.h> 34 35 #include <sys/socket.h> 36 #include <sys/strsubr.h> 37 #include <sys/note.h> 38 #include <sys/sdt.h> 39 40 #include <sys/stmf.h> 41 #include <sys/stmf_ioctl.h> 42 #include <sys/portif.h> 43 #include <sys/idm/idm.h> 44 45 #define ISCSIT_SESS_SM_STRINGS 46 #include <iscsit.h> 47 48 49 50 typedef struct { 51 list_node_t se_ctx_node; 52 iscsit_session_event_t se_ctx_event; 53 iscsit_conn_t *se_event_data; 54 } sess_event_ctx_t; 55 56 static void 57 sess_sm_event_locked(iscsit_sess_t *ist, iscsit_session_event_t event, 58 iscsit_conn_t *ict); 59 60 static void 61 sess_sm_event_dispatch(iscsit_sess_t *ist, sess_event_ctx_t *ctx); 62 63 static void 64 sess_sm_q1_free(iscsit_sess_t *ist, sess_event_ctx_t *ctx); 65 66 static void 67 sess_sm_q2_active(iscsit_sess_t *ist, sess_event_ctx_t *ctx); 68 69 static void 70 sess_sm_q3_logged_in(iscsit_sess_t *ist, sess_event_ctx_t *ctx); 71 72 static void 73 sess_sm_q4_failed(iscsit_sess_t *ist, sess_event_ctx_t *ctx); 74 75 static void 76 sess_sm_q5_continue(iscsit_sess_t *ist, sess_event_ctx_t *ctx); 77 78 static void 79 sess_sm_q6_done(iscsit_sess_t *ist, sess_event_ctx_t *ctx); 80 81 static void 82 sess_sm_q7_error(iscsit_sess_t *ist, sess_event_ctx_t *ctx); 83 84 static void 85 sess_sm_new_state(iscsit_sess_t *ist, sess_event_ctx_t *ctx, 86 iscsit_session_state_t new_state); 87 88 89 static uint16_t 90 iscsit_tsih_alloc(void) 91 { 92 uintptr_t result; 93 94 result = (uintptr_t)vmem_alloc(iscsit_global.global_tsih_pool, 95 1, VM_NOSLEEP | VM_NEXTFIT); 96 97 /* ISCSI_UNSPEC_TSIH (0) indicates failure */ 98 if (result > ISCSI_MAX_TSIH) { 99 vmem_free(iscsit_global.global_tsih_pool, (void *)result, 1); 100 result = ISCSI_UNSPEC_TSIH; 101 } 102 103 return ((uint16_t)result); 104 } 105 106 static void 107 iscsit_tsih_free(uint16_t tsih) 108 { 109 vmem_free(iscsit_global.global_tsih_pool, (void *)(uintptr_t)tsih, 1); 110 } 111 112 113 iscsit_sess_t * 114 iscsit_sess_create(iscsit_tgt_t *tgt, iscsit_conn_t *ict, 115 uint32_t cmdsn, uint8_t *isid, uint16_t tag, 116 char *initiator_name, char *target_name, 117 uint8_t *error_class, uint8_t *error_detail) 118 { 119 iscsit_sess_t *result; 120 121 122 /* 123 * Even if this session create "fails" for some reason we still need 124 * to return a valid session pointer so that we can send the failed 125 * login response. 126 */ 127 result = kmem_zalloc(sizeof (*result), KM_SLEEP); 128 129 /* Allocate TSIH */ 130 if ((result->ist_tsih = iscsit_tsih_alloc()) == ISCSI_UNSPEC_TSIH) { 131 /* Out of TSIH's */ 132 *error_class = ISCSI_STATUS_CLASS_TARGET_ERR; 133 *error_detail = ISCSI_LOGIN_STATUS_NO_RESOURCES; 134 /* 135 * Continue initializing this session so we can use it 136 * to complete the login process. 137 */ 138 } 139 140 idm_sm_audit_init(&result->ist_state_audit); 141 rw_init(&result->ist_sn_rwlock, NULL, RW_DRIVER, NULL); 142 mutex_init(&result->ist_mutex, NULL, MUTEX_DEFAULT, NULL); 143 cv_init(&result->ist_cv, NULL, CV_DEFAULT, NULL); 144 list_create(&result->ist_events, sizeof (sess_event_ctx_t), 145 offsetof(sess_event_ctx_t, se_ctx_node)); 146 list_create(&result->ist_conn_list, sizeof (iscsit_conn_t), 147 offsetof(iscsit_conn_t, ict_sess_ln)); 148 149 result->ist_state = SS_Q1_FREE; 150 result->ist_last_state = SS_Q1_FREE; 151 bcopy(isid, result->ist_isid, ISCSI_ISID_LEN); 152 result->ist_tpgt_tag = tag; 153 154 result->ist_tgt = tgt; 155 result->ist_expcmdsn = cmdsn + 1; 156 result->ist_maxcmdsn = result->ist_expcmdsn + 1; 157 158 result->ist_initiator_name = 159 kmem_alloc(strlen(initiator_name) + 1, KM_SLEEP); 160 (void) strcpy(result->ist_initiator_name, initiator_name); 161 if (target_name) { 162 /* A discovery session might not have a target name */ 163 result->ist_target_name = 164 kmem_alloc(strlen(target_name) + 1, KM_SLEEP); 165 (void) strcpy(result->ist_target_name, target_name); 166 } 167 idm_refcnt_init(&result->ist_refcnt, result); 168 169 /* Login code will fill in ist_stmf_sess if necessary */ 170 171 /* Kick session state machine (also binds connection to session) */ 172 iscsit_sess_sm_event(result, SE_CONN_IN_LOGIN, ict); 173 174 *error_class = ISCSI_STATUS_CLASS_SUCCESS; 175 /* 176 * As noted above we must return a session pointer even if something 177 * failed. The resources will get freed later. 178 */ 179 return (result); 180 } 181 182 static void 183 iscsit_sess_unref(void *ist_void) 184 { 185 iscsit_sess_t *ist = ist_void; 186 187 /* 188 * State machine has run to completion, destroy session 189 * 190 * If we have an associated STMF session we should clean it 191 * up now. 192 * 193 * This session is no longer associated with a target at this 194 * point so don't touch the target. 195 */ 196 mutex_enter(&ist->ist_mutex); 197 ASSERT(ist->ist_conn_count == 0); 198 if (ist->ist_stmf_sess != NULL) { 199 stmf_deregister_scsi_session(ist->ist_lport, 200 ist->ist_stmf_sess); 201 kmem_free(ist->ist_stmf_sess->ss_rport_id, 202 sizeof (scsi_devid_desc_t) + 203 strlen(ist->ist_initiator_name) + 1); 204 stmf_free(ist->ist_stmf_sess); 205 } 206 mutex_exit(&ist->ist_mutex); 207 208 iscsit_sess_destroy(ist); 209 } 210 211 void 212 iscsit_sess_destroy(iscsit_sess_t *ist) 213 { 214 idm_refcnt_destroy(&ist->ist_refcnt); 215 if (ist->ist_initiator_name) 216 kmem_free(ist->ist_initiator_name, 217 strlen(ist->ist_initiator_name) + 1); 218 if (ist->ist_initiator_alias) 219 kmem_free(ist->ist_initiator_alias, 220 strlen(ist->ist_initiator_alias) + 1); 221 if (ist->ist_target_name) 222 kmem_free(ist->ist_target_name, 223 strlen(ist->ist_target_name) + 1); 224 if (ist->ist_target_alias) 225 kmem_free(ist->ist_target_alias, 226 strlen(ist->ist_target_alias) + 1); 227 list_destroy(&ist->ist_conn_list); 228 list_destroy(&ist->ist_events); 229 cv_destroy(&ist->ist_cv); 230 mutex_destroy(&ist->ist_mutex); 231 rw_destroy(&ist->ist_sn_rwlock); 232 kmem_free(ist, sizeof (*ist)); 233 } 234 235 void 236 iscsit_sess_close(iscsit_sess_t *ist) 237 { 238 iscsit_conn_t *ict; 239 240 mutex_enter(&ist->ist_mutex); 241 /* 242 * Note in the session state that we are forcing this session 243 * to close so that the session state machine can avoid 244 * pointless delays like transitions to SS_Q4_FAILED state. 245 */ 246 ist->ist_admin_close = B_TRUE; 247 if (ist->ist_state == SS_Q3_LOGGED_IN) { 248 for (ict = list_head(&ist->ist_conn_list); 249 ict != NULL; 250 ict = list_next(&ist->ist_conn_list, ict)) { 251 iscsit_send_async_event(ict, 252 ISCSI_ASYNC_EVENT_REQUEST_LOGOUT); 253 } 254 } 255 mutex_exit(&ist->ist_mutex); 256 } 257 258 259 void 260 iscsit_sess_bind_conn(iscsit_sess_t *ist, iscsit_conn_t *ict) 261 { 262 iscsit_conn_hold(ict); 263 iscsit_sess_hold(ist); 264 ict->ict_sess = ist; 265 mutex_enter(&ist->ist_mutex); 266 ist->ist_conn_count++; 267 list_insert_tail(&ist->ist_conn_list, ict); 268 mutex_exit(&ist->ist_mutex); 269 } 270 271 void 272 iscsit_sess_unbind_conn(iscsit_sess_t *ist, iscsit_conn_t *ict) 273 { 274 mutex_enter(&ist->ist_mutex); 275 list_remove(&ist->ist_conn_list, ict); 276 ist->ist_conn_count--; 277 mutex_exit(&ist->ist_mutex); 278 iscsit_sess_rele(ist); 279 iscsit_conn_rele(ict); 280 } 281 282 void 283 iscsit_sess_hold(iscsit_sess_t *ist) 284 { 285 idm_refcnt_hold(&ist->ist_refcnt); 286 } 287 288 void 289 iscsit_sess_rele(iscsit_sess_t *ist) 290 { 291 idm_refcnt_rele(&ist->ist_refcnt); 292 } 293 294 iscsit_conn_t * 295 iscsit_sess_lookup_conn(iscsit_sess_t *ist, uint16_t cid) 296 { 297 iscsit_conn_t *result; 298 299 mutex_enter(&ist->ist_mutex); 300 for (result = list_head(&ist->ist_conn_list); 301 result != NULL; 302 result = list_next(&ist->ist_conn_list, result)) { 303 if (result->ict_cid == cid) { 304 iscsit_conn_hold(result); 305 mutex_exit(&ist->ist_mutex); 306 return (result); 307 } 308 } 309 mutex_exit(&ist->ist_mutex); 310 311 return (NULL); 312 } 313 314 iscsit_sess_t * 315 iscsit_sess_reinstate(iscsit_tgt_t *tgt, iscsit_sess_t *ist, iscsit_conn_t *ict, 316 uint8_t *error_class, uint8_t *error_detail) 317 { 318 iscsit_sess_t *new_sess; 319 320 mutex_enter(&ist->ist_mutex); 321 322 /* 323 * Session reinstatement replaces a current session with a new session. 324 * The new session will have the same ISID as the existing session. 325 */ 326 new_sess = iscsit_sess_create(tgt, ict, 0, 327 ist->ist_isid, ist->ist_tpgt_tag, 328 ist->ist_initiator_name, ist->ist_target_name, 329 error_class, error_detail); 330 ASSERT(new_sess != NULL); 331 332 /* Copy additional fields from original session */ 333 new_sess->ist_expcmdsn = ist->ist_expcmdsn; 334 new_sess->ist_maxcmdsn = ist->ist_expcmdsn + 1; 335 336 if (ist->ist_state != SS_Q6_DONE && 337 ist->ist_state != SS_Q7_ERROR) { 338 /* 339 * Generate reinstate event 340 */ 341 sess_sm_event_locked(ist, SE_SESSION_REINSTATE, NULL); 342 } 343 mutex_exit(&ist->ist_mutex); 344 345 return (new_sess); 346 } 347 348 int 349 iscsit_sess_avl_compare(const void *void_sess1, const void *void_sess2) 350 { 351 const iscsit_sess_t *sess1 = void_sess1; 352 const iscsit_sess_t *sess2 = void_sess2; 353 int result; 354 355 /* 356 * Sort by initiator name, then ISID then portal group tag 357 */ 358 result = strcmp(sess1->ist_initiator_name, sess2->ist_initiator_name); 359 if (result < 0) { 360 return (-1); 361 } else if (result > 0) { 362 return (1); 363 } 364 365 /* 366 * Initiator names match, compare ISIDs 367 */ 368 result = memcmp(sess1->ist_isid, sess2->ist_isid, ISCSI_ISID_LEN); 369 if (result < 0) { 370 return (-1); 371 } else if (result > 0) { 372 return (1); 373 } 374 375 /* 376 * ISIDs match, compare portal group tags 377 */ 378 if (sess1->ist_tpgt_tag < sess2->ist_tpgt_tag) { 379 return (-1); 380 } else if (sess1->ist_tpgt_tag > sess2->ist_tpgt_tag) { 381 return (1); 382 } 383 384 /* 385 * Portal group tags match, compare TSIHs 386 */ 387 if (sess1->ist_tsih < sess2->ist_tsih) { 388 return (-1); 389 } else if (sess1->ist_tsih > sess2->ist_tsih) { 390 return (1); 391 } 392 393 /* 394 * Sessions match 395 */ 396 return (0); 397 } 398 399 400 /* 401 * State machine 402 */ 403 404 void 405 iscsit_sess_sm_event(iscsit_sess_t *ist, iscsit_session_event_t event, 406 iscsit_conn_t *ict) 407 { 408 mutex_enter(&ist->ist_mutex); 409 sess_sm_event_locked(ist, event, ict); 410 mutex_exit(&ist->ist_mutex); 411 } 412 413 static void 414 sess_sm_event_locked(iscsit_sess_t *ist, iscsit_session_event_t event, 415 iscsit_conn_t *ict) 416 { 417 sess_event_ctx_t *ctx; 418 419 iscsit_sess_hold(ist); 420 421 ctx = kmem_zalloc(sizeof (*ctx), KM_SLEEP); 422 423 ctx->se_ctx_event = event; 424 ctx->se_event_data = ict; 425 426 list_insert_tail(&ist->ist_events, ctx); 427 /* 428 * Use the icl_busy flag to keep the state machine single threaded. 429 * This also serves as recursion avoidance since this flag will 430 * always be set if we call login_sm_event from within the 431 * state machine code. 432 */ 433 if (!ist->ist_sm_busy) { 434 ist->ist_sm_busy = B_TRUE; 435 while (!list_is_empty(&ist->ist_events)) { 436 ctx = list_head(&ist->ist_events); 437 list_remove(&ist->ist_events, ctx); 438 idm_sm_audit_event(&ist->ist_state_audit, 439 SAS_ISCSIT_SESS, (int)ist->ist_state, 440 (int)ctx->se_ctx_event, (uintptr_t)ict); 441 mutex_exit(&ist->ist_mutex); 442 sess_sm_event_dispatch(ist, ctx); 443 mutex_enter(&ist->ist_mutex); 444 } 445 ist->ist_sm_busy = B_FALSE; 446 447 } 448 449 iscsit_sess_rele(ist); 450 } 451 452 static void 453 sess_sm_event_dispatch(iscsit_sess_t *ist, sess_event_ctx_t *ctx) 454 { 455 iscsit_conn_t *ict; 456 457 DTRACE_PROBE2(session__event, iscsit_sess_t *, ist, 458 sess_event_ctx_t *, ctx); 459 460 IDM_SM_LOG(CE_NOTE, "sess_sm_event_dispatch: sess %p event %s(%d)", 461 (void *)ist, iscsit_se_name[ctx->se_ctx_event], ctx->se_ctx_event); 462 463 /* State independent actions */ 464 switch (ctx->se_ctx_event) { 465 case SE_CONN_IN_LOGIN: 466 ict = ctx->se_event_data; 467 iscsit_sess_bind_conn(ist, ict); 468 break; 469 case SE_CONN_FAIL: 470 ict = ctx->se_event_data; 471 iscsit_sess_unbind_conn(ist, ict); 472 break; 473 } 474 475 /* State dependent actions */ 476 switch (ist->ist_state) { 477 case SS_Q1_FREE: 478 sess_sm_q1_free(ist, ctx); 479 break; 480 case SS_Q2_ACTIVE: 481 sess_sm_q2_active(ist, ctx); 482 break; 483 case SS_Q3_LOGGED_IN: 484 sess_sm_q3_logged_in(ist, ctx); 485 break; 486 case SS_Q4_FAILED: 487 sess_sm_q4_failed(ist, ctx); 488 break; 489 case SS_Q5_CONTINUE: 490 sess_sm_q5_continue(ist, ctx); 491 break; 492 case SS_Q6_DONE: 493 sess_sm_q6_done(ist, ctx); 494 break; 495 case SS_Q7_ERROR: 496 sess_sm_q7_error(ist, ctx); 497 break; 498 default: 499 ASSERT(0); 500 break; 501 } 502 503 kmem_free(ctx, sizeof (*ctx)); 504 } 505 506 static void 507 sess_sm_q1_free(iscsit_sess_t *ist, sess_event_ctx_t *ctx) 508 { 509 switch (ctx->se_ctx_event) { 510 case SE_CONN_IN_LOGIN: 511 /* N1 */ 512 sess_sm_new_state(ist, ctx, SS_Q2_ACTIVE); 513 break; 514 default: 515 ASSERT(0); 516 break; 517 } 518 } 519 520 521 static void 522 sess_sm_q2_active(iscsit_sess_t *ist, sess_event_ctx_t *ctx) 523 { 524 switch (ctx->se_ctx_event) { 525 case SE_CONN_LOGGED_IN: 526 /* N2 track FFP connections */ 527 ist->ist_ffp_conn_count++; 528 sess_sm_new_state(ist, ctx, SS_Q3_LOGGED_IN); 529 break; 530 case SE_CONN_IN_LOGIN: 531 /* N2.1, don't care stay in this state */ 532 break; 533 case SE_CONN_FAIL: 534 /* N9 */ 535 sess_sm_new_state(ist, ctx, SS_Q7_ERROR); 536 break; 537 case SE_SESSION_REINSTATE: 538 /* N11 */ 539 sess_sm_new_state(ist, ctx, SS_Q6_DONE); 540 break; 541 default: 542 ASSERT(0); 543 break; 544 } 545 } 546 547 static void 548 sess_sm_q3_logged_in(iscsit_sess_t *ist, sess_event_ctx_t *ctx) 549 { 550 iscsit_conn_t *ict; 551 552 switch (ctx->se_ctx_event) { 553 case SE_CONN_IN_LOGIN: 554 case SE_CONN_FAIL: 555 /* N2.2, don't care */ 556 break; 557 case SE_CONN_LOGGED_IN: 558 /* N2.2, track FFP connections */ 559 ist->ist_ffp_conn_count++; 560 break; 561 case SE_CONN_FFP_FAIL: 562 case SE_CONN_FFP_DISABLE: 563 /* 564 * Event data from event context is the associated connection 565 * which in this case happens to be the last FFP connection 566 * for the session. In certain cases we need to refer 567 * to this last valid connection (i.e. RFC3720 section 12.16) 568 * so we'll save off a pointer here for later use. 569 */ 570 ASSERT(ist->ist_ffp_conn_count >= 1); 571 ist->ist_failed_conn = (iscsit_conn_t *)ctx->se_event_data; 572 ist->ist_ffp_conn_count--; 573 if (ist->ist_ffp_conn_count == 0) { 574 /* 575 * N5(fail) or N3(disable) 576 * 577 * If the event is SE_CONN_FFP_FAIL but we are 578 * in the midst of an administrative session close 579 * because of a service or target offline then 580 * there is no need to go to "failed" state. 581 */ 582 sess_sm_new_state(ist, ctx, 583 ((ctx->se_ctx_event == SE_CONN_FFP_DISABLE) || 584 (ist->ist_admin_close)) ? 585 SS_Q6_DONE : SS_Q4_FAILED); 586 } 587 break; 588 case SE_SESSION_CLOSE: 589 case SE_SESSION_REINSTATE: 590 /* N3 */ 591 mutex_enter(&ist->ist_mutex); 592 if (ctx->se_ctx_event == SE_SESSION_CLOSE) { 593 ASSERT(ist->ist_ffp_conn_count >= 1); 594 ist->ist_ffp_conn_count--; 595 } 596 for (ict = list_head(&ist->ist_conn_list); 597 ict != NULL; 598 ict = list_next(&ist->ist_conn_list, ict)) { 599 if ((ctx->se_ctx_event == SE_SESSION_CLOSE) && 600 ((iscsit_conn_t *)ctx->se_event_data == ict)) { 601 /* 602 * Skip this connection since it will 603 * see the logout response 604 */ 605 continue; 606 } 607 idm_conn_event(ict->ict_ic, CE_LOGOUT_SESSION_SUCCESS, 608 NULL); 609 } 610 mutex_exit(&ist->ist_mutex); 611 612 sess_sm_new_state(ist, ctx, SS_Q6_DONE); 613 break; 614 default: 615 ASSERT(0); 616 break; 617 } 618 } 619 620 static void 621 sess_sm_timeout(void *arg) 622 { 623 iscsit_sess_t *ist = arg; 624 625 iscsit_sess_sm_event(ist, SE_SESSION_TIMEOUT, NULL); 626 } 627 628 static void 629 sess_sm_q4_failed(iscsit_sess_t *ist, sess_event_ctx_t *ctx) 630 { 631 /* Session timer must not be running when we leave this event */ 632 switch (ctx->se_ctx_event) { 633 case SE_CONN_IN_LOGIN: 634 /* N7 */ 635 sess_sm_new_state(ist, ctx, SS_Q5_CONTINUE); 636 break; 637 case SE_SESSION_REINSTATE: 638 /* N6 */ 639 (void) untimeout(ist->ist_state_timeout); 640 /*FALLTHROUGH*/ 641 case SE_SESSION_TIMEOUT: 642 /* N6 */ 643 sess_sm_new_state(ist, ctx, SS_Q6_DONE); 644 break; 645 case SE_CONN_FAIL: 646 /* Don't care */ 647 break; 648 default: 649 ASSERT(0); 650 break; 651 } 652 } 653 654 static void 655 sess_sm_q5_continue(iscsit_sess_t *ist, sess_event_ctx_t *ctx) 656 { 657 switch (ctx->se_ctx_event) { 658 case SE_CONN_FAIL: 659 /* N5 */ 660 sess_sm_new_state(ist, ctx, SS_Q4_FAILED); 661 break; 662 case SE_CONN_LOGGED_IN: 663 /* N10 */ 664 sess_sm_new_state(ist, ctx, SS_Q3_LOGGED_IN); 665 break; 666 case SE_SESSION_REINSTATE: 667 /* N11 */ 668 sess_sm_new_state(ist, ctx, SS_Q6_DONE); 669 break; 670 default: 671 ASSERT(0); 672 break; 673 } 674 } 675 676 static void 677 sess_sm_q6_done(iscsit_sess_t *ist, sess_event_ctx_t *ctx) 678 { 679 /* Terminal state */ 680 switch (ctx->se_ctx_event) { 681 case SE_CONN_FFP_FAIL: 682 case SE_CONN_FFP_DISABLE: 683 ASSERT(ist->ist_ffp_conn_count >= 1); 684 ist->ist_ffp_conn_count--; 685 break; 686 case SE_CONN_FAIL: 687 if (ist->ist_conn_count == 0) { 688 idm_refcnt_async_wait_ref(&ist->ist_refcnt, 689 &iscsit_sess_unref); 690 } 691 break; 692 default: 693 break; 694 } 695 } 696 697 static void 698 sess_sm_q7_error(iscsit_sess_t *ist, sess_event_ctx_t *ctx) 699 { 700 /* Terminal state */ 701 switch (ctx->se_ctx_event) { 702 case SE_CONN_FAIL: 703 if (ist->ist_conn_count == 0) { 704 idm_refcnt_async_wait_ref(&ist->ist_refcnt, 705 &iscsit_sess_unref); 706 } 707 break; 708 default: 709 break; 710 } 711 } 712 713 static void 714 sess_sm_new_state(iscsit_sess_t *ist, sess_event_ctx_t *ctx, 715 iscsit_session_state_t new_state) 716 { 717 int t2r_secs; 718 719 /* 720 * Validate new state 721 */ 722 ASSERT(new_state != SS_UNDEFINED); 723 ASSERT3U(new_state, <, SS_MAX_STATE); 724 725 new_state = (new_state < SS_MAX_STATE) ? 726 new_state : SS_UNDEFINED; 727 728 IDM_SM_LOG(CE_NOTE, "sess_sm_new_state: sess %p, evt %s(%d), " 729 "%s(%d) --> %s(%d)\n", (void *) ist, 730 iscsit_se_name[ctx->se_ctx_event], ctx->se_ctx_event, 731 iscsit_ss_name[ist->ist_state], ist->ist_state, 732 iscsit_ss_name[new_state], new_state); 733 734 DTRACE_PROBE3(sess__state__change, 735 iscsit_sess_t *, ist, sess_event_ctx_t *, ctx, 736 iscsit_session_state_t, new_state); 737 738 mutex_enter(&ist->ist_mutex); 739 idm_sm_audit_state_change(&ist->ist_state_audit, SAS_ISCSIT_SESS, 740 (int)ist->ist_state, (int)new_state); 741 ist->ist_last_state = ist->ist_state; 742 ist->ist_state = new_state; 743 mutex_exit(&ist->ist_mutex); 744 745 switch (ist->ist_state) { 746 case SS_Q1_FREE: 747 break; 748 case SS_Q2_ACTIVE: 749 iscsit_tgt_bind_sess(ist->ist_tgt, ist); 750 break; 751 case SS_Q3_LOGGED_IN: 752 break; 753 case SS_Q4_FAILED: 754 t2r_secs = 755 ist->ist_failed_conn->ict_op.op_default_time_2_retain; 756 ist->ist_state_timeout = timeout(sess_sm_timeout, ist, 757 drv_usectohz(t2r_secs*1000000)); 758 break; 759 case SS_Q5_CONTINUE: 760 break; 761 case SS_Q6_DONE: 762 case SS_Q7_ERROR: 763 /* 764 * We won't need our TSIH anymore and it represents an 765 * implicit reference to the global TSIH pool. Get rid 766 * of it. 767 */ 768 if (ist->ist_tsih != ISCSI_UNSPEC_TSIH) { 769 iscsit_tsih_free(ist->ist_tsih); 770 } 771 772 /* 773 * We don't want this session to show up anymore so unbind 774 * it now. After this call this session cannot have any 775 * references outside itself (implicit or explicit). 776 */ 777 iscsit_tgt_unbind_sess(ist->ist_tgt, ist); 778 779 /* 780 * If we have more connections bound then more events 781 * are comming so don't wait for idle yet. 782 */ 783 if (ist->ist_conn_count == 0) { 784 idm_refcnt_async_wait_ref(&ist->ist_refcnt, 785 &iscsit_sess_unref); 786 } 787 break; 788 default: 789 ASSERT(0); 790 /*NOTREACHED*/ 791 } 792 } 793