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