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