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