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