Print this page
3866 panic in idm module
3867 stmfCreateLu failed: GUID_IN_USE
3868 iscsi target not accepting any new connections
Reviewed by: Sebastien Roy <sebastien.roy@delphix.com>
Reviewed by: Jeremy Jones <jeremy@delphix.com>
Reviewed by: Eric Diven <eric.diven@delphix.com>
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/idm/idm_conn_sm.c
+++ new/usr/src/uts/common/io/idm/idm_conn_sm.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
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
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 /*
23 23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24 + * Copyright (c) 2013 by Delphix. All rights reserved.
24 25 */
25 26
26 27 #include <sys/cpuvar.h>
27 28 #include <sys/ddi.h>
28 29 #include <sys/sunddi.h>
29 30 #include <sys/modctl.h>
30 31 #include <sys/socket.h>
31 32 #include <sys/strsubr.h>
32 33 #include <sys/note.h>
33 34 #include <sys/sdt.h>
34 35
35 36 #define IDM_CONN_SM_STRINGS
36 37 #define IDM_CN_NOTIFY_STRINGS
37 38 #include <sys/idm/idm.h>
38 39
39 40 boolean_t idm_sm_logging = B_FALSE;
40 41
41 42 extern idm_global_t idm; /* Global state */
42 43
43 44 static void
44 45 idm_conn_event_handler(void *event_ctx_opaque);
45 46
46 47 static void
47 48 idm_state_s1_free(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
48 49
49 50 static void
50 51 idm_state_s2_xpt_wait(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
51 52
52 53 static void
53 54 idm_state_s3_xpt_up(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
54 55
55 56 static void
56 57 idm_state_s4_in_login(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
57 58
58 59 static void
59 60 idm_state_s5_logged_in(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
60 61
61 62 static void
62 63 idm_state_s6_in_logout(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
63 64
64 65 static void
65 66 idm_logout_req_timeout(void *arg);
66 67
67 68 static void
68 69 idm_state_s7_logout_req(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
69 70
70 71 static void
71 72 idm_state_s8_cleanup(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
72 73
73 74 static void
74 75 idm_state_s9_init_error(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
75 76
76 77 static void
77 78 idm_state_s9a_rejected(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
78 79
79 80 static void
80 81 idm_state_s9b_wait_snd_done_cb(idm_pdu_t *pdu,
81 82 idm_status_t status);
82 83
83 84 static void
84 85 idm_state_s9b_wait_snd_done(idm_conn_t *ic,
85 86 idm_conn_event_ctx_t *event_ctx);
86 87
87 88 static void
88 89 idm_state_s10_in_cleanup(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
89 90
90 91 static void
91 92 idm_state_s11_complete(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
92 93
93 94 static void
94 95 idm_state_s12_enable_dm(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
95 96
96 97 static void
97 98 idm_update_state(idm_conn_t *ic, idm_conn_state_t new_state,
98 99 idm_conn_event_ctx_t *event_ctx);
99 100
100 101 static void
101 102 idm_conn_unref(void *ic_void);
102 103
103 104 static void
104 105 idm_conn_reject_unref(void *ic_void);
105 106
106 107 static idm_pdu_event_action_t
107 108 idm_conn_sm_validate_pdu(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx,
108 109 idm_pdu_t *pdu);
109 110
110 111 static idm_status_t
111 112 idm_ffp_enable(idm_conn_t *ic);
112 113
113 114 static void
114 115 idm_ffp_disable(idm_conn_t *ic, idm_ffp_disable_t disable_type);
115 116
116 117 static void
117 118 idm_initial_login_actions(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
118 119
119 120 static void
120 121 idm_login_success_actions(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
121 122
122 123 idm_status_t
123 124 idm_conn_sm_init(idm_conn_t *ic)
124 125 {
125 126 char taskq_name[32];
126 127
127 128 /*
128 129 * Caller should have assigned a unique connection ID. Use this
129 130 * connection ID to create a unique connection name string
130 131 */
131 132 ASSERT(ic->ic_internal_cid != 0);
132 133 (void) snprintf(taskq_name, sizeof (taskq_name) - 1, "conn_sm%08x",
133 134 ic->ic_internal_cid);
134 135
135 136 ic->ic_state_taskq = taskq_create(taskq_name, 1, minclsyspri, 4, 16384,
136 137 TASKQ_PREPOPULATE);
137 138 if (ic->ic_state_taskq == NULL) {
138 139 return (IDM_STATUS_FAIL);
139 140 }
140 141
141 142 idm_sm_audit_init(&ic->ic_state_audit);
142 143 mutex_init(&ic->ic_state_mutex, NULL, MUTEX_DEFAULT, NULL);
143 144 cv_init(&ic->ic_state_cv, NULL, CV_DEFAULT, NULL);
144 145
145 146 ic->ic_state = CS_S1_FREE;
146 147 ic->ic_last_state = CS_S1_FREE;
147 148
148 149 return (IDM_STATUS_SUCCESS);
149 150 }
150 151
151 152 void
152 153 idm_conn_sm_fini(idm_conn_t *ic)
153 154 {
154 155
155 156 /*
156 157 * The connection may only be partially created. If there
157 158 * is no taskq, then the connection SM was not initialized.
158 159 */
159 160 if (ic->ic_state_taskq == NULL) {
160 161 return;
161 162 }
162 163
163 164 taskq_destroy(ic->ic_state_taskq);
164 165
165 166 cv_destroy(&ic->ic_state_cv);
166 167 /*
167 168 * The thread that generated the event that got us here may still
168 169 * hold the ic_state_mutex. Once it is released we can safely
169 170 * destroy it since there is no way to locate the object now.
170 171 */
171 172 mutex_enter(&ic->ic_state_mutex);
172 173 mutex_destroy(&ic->ic_state_mutex);
173 174 }
174 175
175 176 void
176 177 idm_conn_event(idm_conn_t *ic, idm_conn_event_t event, uintptr_t event_info)
177 178 {
178 179 mutex_enter(&ic->ic_state_mutex);
179 180 idm_conn_event_locked(ic, event, event_info, CT_NONE);
180 181 mutex_exit(&ic->ic_state_mutex);
181 182 }
182 183
183 184
184 185 idm_status_t
185 186 idm_conn_reinstate_event(idm_conn_t *old_ic, idm_conn_t *new_ic)
186 187 {
187 188 int result;
188 189
189 190 mutex_enter(&old_ic->ic_state_mutex);
190 191 if (((old_ic->ic_conn_type == CONN_TYPE_INI) &&
191 192 (old_ic->ic_state != CS_S8_CLEANUP)) ||
192 193 ((old_ic->ic_conn_type == CONN_TYPE_TGT) &&
193 194 (old_ic->ic_state < CS_S5_LOGGED_IN))) {
194 195 result = IDM_STATUS_FAIL;
195 196 } else {
196 197 result = IDM_STATUS_SUCCESS;
197 198 new_ic->ic_reinstate_conn = old_ic;
198 199 idm_conn_event_locked(new_ic->ic_reinstate_conn,
199 200 CE_CONN_REINSTATE, (uintptr_t)new_ic, CT_NONE);
200 201 }
201 202 mutex_exit(&old_ic->ic_state_mutex);
202 203
203 204 return (result);
204 205 }
205 206
206 207 void
207 208 idm_conn_tx_pdu_event(idm_conn_t *ic, idm_conn_event_t event,
208 209 uintptr_t event_info)
209 210 {
210 211 ASSERT(mutex_owned(&ic->ic_state_mutex));
211 212 ic->ic_pdu_events++;
212 213 idm_conn_event_locked(ic, event, event_info, CT_TX_PDU);
213 214 }
214 215
215 216 void
216 217 idm_conn_rx_pdu_event(idm_conn_t *ic, idm_conn_event_t event,
217 218 uintptr_t event_info)
218 219 {
219 220 ASSERT(mutex_owned(&ic->ic_state_mutex));
220 221 ic->ic_pdu_events++;
221 222 idm_conn_event_locked(ic, event, event_info, CT_RX_PDU);
222 223 }
223 224
224 225 void
225 226 idm_conn_event_locked(idm_conn_t *ic, idm_conn_event_t event,
226 227 uintptr_t event_info, idm_pdu_event_type_t pdu_event_type)
227 228 {
228 229 idm_conn_event_ctx_t *event_ctx;
229 230
230 231 ASSERT(mutex_owned(&ic->ic_state_mutex));
231 232
232 233 idm_sm_audit_event(&ic->ic_state_audit, SAS_IDM_CONN,
233 234 (int)ic->ic_state, (int)event, event_info);
234 235
235 236 /*
236 237 * It's very difficult to prevent a few straggling events
237 238 * at the end. For example idm_sorx_thread will generate
238 239 * a CE_TRANSPORT_FAIL event when it exits. Rather than
239 240 * push complicated restrictions all over the code to
240 241 * prevent this we will simply drop the events (and in
241 242 * the case of PDU events release them appropriately)
242 243 * since they are irrelevant once we are in a terminal state.
243 244 * Of course those threads need to have appropriate holds on
244 245 * the connection otherwise it might disappear.
245 246 */
246 247 if ((ic->ic_state == CS_S9_INIT_ERROR) ||
247 248 (ic->ic_state == CS_S9A_REJECTED) ||
248 249 (ic->ic_state == CS_S11_COMPLETE)) {
249 250 if ((pdu_event_type == CT_TX_PDU) ||
250 251 (pdu_event_type == CT_RX_PDU)) {
251 252 ic->ic_pdu_events--;
252 253 idm_pdu_complete((idm_pdu_t *)event_info,
253 254 IDM_STATUS_SUCCESS);
254 255 }
255 256 IDM_SM_LOG(CE_NOTE, "*** Dropping event %s (%d) because of"
256 257 "state %s (%d)",
257 258 idm_ce_name[event], event,
258 259 idm_cs_name[ic->ic_state], ic->ic_state);
259 260 return;
260 261 }
261 262
262 263 /*
263 264 * Normal event handling
264 265 */
265 266 idm_conn_hold(ic);
266 267
267 268 event_ctx = kmem_zalloc(sizeof (*event_ctx), KM_SLEEP);
268 269 event_ctx->iec_ic = ic;
269 270 event_ctx->iec_event = event;
270 271 event_ctx->iec_info = event_info;
271 272 event_ctx->iec_pdu_event_type = pdu_event_type;
272 273
273 274 (void) taskq_dispatch(ic->ic_state_taskq, &idm_conn_event_handler,
274 275 event_ctx, TQ_SLEEP);
275 276 }
276 277
277 278 static void
278 279 idm_conn_event_handler(void *event_ctx_opaque)
279 280 {
280 281 idm_conn_event_ctx_t *event_ctx = event_ctx_opaque;
281 282 idm_conn_t *ic = event_ctx->iec_ic;
282 283 idm_pdu_t *pdu = (idm_pdu_t *)event_ctx->iec_info;
283 284 idm_pdu_event_action_t action;
284 285
285 286 IDM_SM_LOG(CE_NOTE, "idm_conn_event_handler: conn %p event %s(%d)",
286 287 (void *)ic, idm_ce_name[event_ctx->iec_event],
287 288 event_ctx->iec_event);
288 289 DTRACE_PROBE2(conn__event,
289 290 idm_conn_t *, ic, idm_conn_event_ctx_t *, event_ctx);
290 291
291 292 /*
292 293 * Validate event
293 294 */
294 295 ASSERT(event_ctx->iec_event != CE_UNDEFINED);
295 296 ASSERT3U(event_ctx->iec_event, <, CE_MAX_EVENT);
296 297
297 298 /*
298 299 * Validate current state
299 300 */
300 301 ASSERT(ic->ic_state != CS_S0_UNDEFINED);
301 302 ASSERT3U(ic->ic_state, <, CS_MAX_STATE);
302 303
303 304 /*
304 305 * Validate PDU-related events against the current state. If a PDU
305 306 * is not allowed in the current state we change the event to a
306 307 * protocol error. This simplifies the state-specific event handlers.
307 308 * For example the CS_S2_XPT_WAIT state only needs to handle the
308 309 * CE_TX_PROTOCOL_ERROR and CE_RX_PROTOCOL_ERROR events since
309 310 * no PDU's can be transmitted or received in that state.
310 311 */
311 312 event_ctx->iec_pdu_forwarded = B_FALSE;
312 313 if (event_ctx->iec_pdu_event_type != CT_NONE) {
313 314 ASSERT(pdu != NULL);
314 315 action = idm_conn_sm_validate_pdu(ic, event_ctx, pdu);
315 316
316 317 switch (action) {
317 318 case CA_TX_PROTOCOL_ERROR:
318 319 /*
319 320 * Change event and forward the PDU
320 321 */
321 322 event_ctx->iec_event = CE_TX_PROTOCOL_ERROR;
322 323 break;
323 324 case CA_RX_PROTOCOL_ERROR:
324 325 /*
325 326 * Change event and forward the PDU.
326 327 */
327 328 event_ctx->iec_event = CE_RX_PROTOCOL_ERROR;
328 329 break;
329 330 case CA_FORWARD:
330 331 /*
331 332 * Let the state-specific event handlers take
332 333 * care of it.
333 334 */
334 335 break;
335 336 case CA_DROP:
336 337 /*
337 338 * It never even happened
338 339 */
339 340 IDM_SM_LOG(CE_NOTE, "*** drop PDU %p", (void *) pdu);
340 341 idm_pdu_complete(pdu, IDM_STATUS_FAIL);
341 342 break;
342 343 default:
343 344 ASSERT(0);
344 345 break;
345 346 }
346 347 }
347 348
348 349 switch (ic->ic_state) {
349 350 case CS_S1_FREE:
350 351 idm_state_s1_free(ic, event_ctx);
351 352 break;
352 353 case CS_S2_XPT_WAIT:
353 354 idm_state_s2_xpt_wait(ic, event_ctx);
354 355 break;
355 356 case CS_S3_XPT_UP:
356 357 idm_state_s3_xpt_up(ic, event_ctx);
357 358 break;
358 359 case CS_S4_IN_LOGIN:
359 360 idm_state_s4_in_login(ic, event_ctx);
360 361 break;
361 362 case CS_S5_LOGGED_IN:
362 363 idm_state_s5_logged_in(ic, event_ctx);
363 364 break;
364 365 case CS_S6_IN_LOGOUT:
365 366 idm_state_s6_in_logout(ic, event_ctx);
366 367 break;
367 368 case CS_S7_LOGOUT_REQ:
368 369 idm_state_s7_logout_req(ic, event_ctx);
369 370 break;
370 371 case CS_S8_CLEANUP:
371 372 idm_state_s8_cleanup(ic, event_ctx);
372 373 break;
373 374 case CS_S9A_REJECTED:
374 375 idm_state_s9a_rejected(ic, event_ctx);
375 376 break;
376 377 case CS_S9B_WAIT_SND_DONE:
377 378 idm_state_s9b_wait_snd_done(ic, event_ctx);
378 379 break;
379 380 case CS_S9_INIT_ERROR:
380 381 idm_state_s9_init_error(ic, event_ctx);
381 382 break;
382 383 case CS_S10_IN_CLEANUP:
383 384 idm_state_s10_in_cleanup(ic, event_ctx);
384 385 break;
385 386 case CS_S11_COMPLETE:
386 387 idm_state_s11_complete(ic, event_ctx);
387 388 break;
388 389 case CS_S12_ENABLE_DM:
389 390 idm_state_s12_enable_dm(ic, event_ctx);
390 391 break;
391 392 default:
392 393 ASSERT(0);
393 394 break;
394 395 }
395 396
396 397 /*
397 398 * Now that we've updated the state machine, if this was
398 399 * a PDU-related event take the appropriate action on the PDU
399 400 * (transmit it, forward it to the clients RX callback, drop
400 401 * it, etc).
401 402 */
402 403 if (event_ctx->iec_pdu_event_type != CT_NONE) {
403 404 switch (action) {
404 405 case CA_TX_PROTOCOL_ERROR:
405 406 idm_pdu_tx_protocol_error(ic, pdu);
406 407 break;
407 408 case CA_RX_PROTOCOL_ERROR:
408 409 idm_pdu_rx_protocol_error(ic, pdu);
409 410 break;
410 411 case CA_FORWARD:
411 412 if (!event_ctx->iec_pdu_forwarded) {
412 413 if (event_ctx->iec_pdu_event_type ==
413 414 CT_RX_PDU) {
414 415 idm_pdu_rx_forward(ic, pdu);
415 416 } else {
416 417 idm_pdu_tx_forward(ic, pdu);
417 418 }
418 419 }
419 420 break;
420 421 default:
421 422 ASSERT(0);
422 423 break;
423 424 }
424 425 }
425 426
426 427 /*
427 428 * Update outstanding PDU event count (see idm_pdu_tx for
428 429 * how this is used)
429 430 */
430 431 if ((event_ctx->iec_pdu_event_type == CT_TX_PDU) ||
431 432 (event_ctx->iec_pdu_event_type == CT_RX_PDU)) {
432 433 mutex_enter(&ic->ic_state_mutex);
433 434 ic->ic_pdu_events--;
434 435 mutex_exit(&ic->ic_state_mutex);
435 436 }
436 437
437 438 idm_conn_rele(ic);
438 439 kmem_free(event_ctx, sizeof (*event_ctx));
439 440 }
440 441
441 442 static void
442 443 idm_state_s1_free(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
443 444 {
444 445 switch (event_ctx->iec_event) {
445 446 case CE_CONNECT_REQ:
446 447 /* T1 */
447 448 idm_update_state(ic, CS_S2_XPT_WAIT, event_ctx);
448 449 break;
449 450 case CE_CONNECT_ACCEPT:
450 451 /* T3 */
451 452 idm_update_state(ic, CS_S3_XPT_UP, event_ctx);
452 453 break;
453 454 case CE_TX_PROTOCOL_ERROR:
454 455 case CE_RX_PROTOCOL_ERROR:
455 456 /* This should never happen */
456 457 idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
457 458 break;
458 459 default:
459 460 ASSERT(0);
460 461 /*NOTREACHED*/
461 462 }
462 463 }
463 464
464 465
465 466 static void
466 467 idm_state_s2_xpt_wait(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
467 468 {
468 469 switch (event_ctx->iec_event) {
469 470 case CE_CONNECT_SUCCESS:
470 471 /* T4 */
471 472 idm_update_state(ic, CS_S4_IN_LOGIN, event_ctx);
472 473 break;
473 474 case CE_TRANSPORT_FAIL:
474 475 case CE_CONNECT_FAIL:
475 476 case CE_LOGOUT_OTHER_CONN_RCV:
476 477 case CE_TX_PROTOCOL_ERROR:
477 478 case CE_RX_PROTOCOL_ERROR:
478 479 /* T2 */
479 480 idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
480 481 break;
481 482 default:
482 483 ASSERT(0);
483 484 /*NOTREACHED*/
484 485 }
485 486 }
486 487
487 488
488 489 static void
489 490 idm_login_timeout(void *arg)
490 491 {
491 492 idm_conn_t *ic = arg;
492 493
493 494 idm_conn_event(ic, CE_LOGIN_TIMEOUT, NULL);
494 495 }
495 496
496 497 static void
497 498 idm_state_s3_xpt_up(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
498 499 {
499 500 switch (event_ctx->iec_event) {
500 501 case CE_LOGIN_RCV:
501 502 /* T4 */
502 503 idm_initial_login_actions(ic, event_ctx);
503 504 idm_update_state(ic, CS_S4_IN_LOGIN, event_ctx);
504 505 break;
505 506 case CE_LOGIN_TIMEOUT:
506 507 /*
507 508 * Don't need to cancel login timer since the timer is
508 509 * presumed to be the source of this event.
509 510 */
510 511 (void) idm_notify_client(ic, CN_LOGIN_FAIL, NULL);
511 512 idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
512 513 break;
513 514 case CE_CONNECT_REJECT:
514 515 /*
515 516 * Iscsit doesn't want to hear from us again in this case.
516 517 * Since it rejected the connection it doesn't have a
517 518 * connection context to handle additional notifications.
518 519 * IDM needs to just clean things up on its own.
519 520 */
520 521 (void) untimeout(ic->ic_state_timeout);
521 522 idm_update_state(ic, CS_S9A_REJECTED, event_ctx);
522 523 break;
523 524 case CE_CONNECT_FAIL:
524 525 case CE_TRANSPORT_FAIL:
525 526 case CE_LOGOUT_OTHER_CONN_SND:
526 527 /* T6 */
527 528 (void) untimeout(ic->ic_state_timeout);
528 529 (void) idm_notify_client(ic, CN_LOGIN_FAIL, NULL);
529 530 idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
530 531 break;
531 532 case CE_TX_PROTOCOL_ERROR:
532 533 case CE_RX_PROTOCOL_ERROR:
533 534 /* Don't care */
534 535 break;
535 536 default:
536 537 ASSERT(0);
537 538 /*NOTREACHED*/
538 539 }
539 540 }
540 541
541 542 static void
542 543 idm_state_s4_in_login(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
543 544 {
544 545 idm_pdu_t *pdu;
545 546
546 547 /*
547 548 * Login timer should no longer be active after leaving this
548 549 * state.
549 550 */
550 551 switch (event_ctx->iec_event) {
551 552 case CE_LOGIN_SUCCESS_RCV:
552 553 case CE_LOGIN_SUCCESS_SND:
553 554 ASSERT(ic->ic_client_callback == NULL);
554 555
555 556 (void) untimeout(ic->ic_state_timeout);
556 557 idm_login_success_actions(ic, event_ctx);
557 558 if (ic->ic_rdma_extensions) {
558 559 /* T19 */
559 560 idm_update_state(ic, CS_S12_ENABLE_DM, event_ctx);
560 561 } else {
561 562 /* T5 */
562 563 idm_update_state(ic, CS_S5_LOGGED_IN, event_ctx);
563 564 }
564 565 break;
565 566 case CE_LOGIN_TIMEOUT:
566 567 /* T7 */
567 568 (void) idm_notify_client(ic, CN_LOGIN_FAIL, NULL);
568 569 idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
569 570 break;
570 571 case CE_LOGIN_FAIL_SND:
571 572 /*
572 573 * Allow the logout response pdu to be sent and defer
573 574 * the state machine cleanup until the completion callback.
574 575 * Only 1 level or callback interposition is allowed.
575 576 */
576 577 (void) untimeout(ic->ic_state_timeout);
577 578 pdu = (idm_pdu_t *)event_ctx->iec_info;
578 579 ASSERT(ic->ic_client_callback == NULL);
579 580 ic->ic_client_callback = pdu->isp_callback;
580 581 pdu->isp_callback =
581 582 idm_state_s9b_wait_snd_done_cb;
582 583 idm_update_state(ic, CS_S9B_WAIT_SND_DONE,
583 584 event_ctx);
584 585 break;
585 586 case CE_LOGIN_FAIL_RCV:
586 587 ASSERT(ic->ic_client_callback == NULL);
587 588 /*
588 589 * Need to deliver this PDU to the initiator now because after
589 590 * we update the state to CS_S9_INIT_ERROR the initiator will
590 591 * no longer be in an appropriate state.
591 592 */
592 593 event_ctx->iec_pdu_forwarded = B_TRUE;
593 594 pdu = (idm_pdu_t *)event_ctx->iec_info;
594 595 idm_pdu_rx_forward(ic, pdu);
595 596 /* FALLTHROUGH */
596 597 case CE_TRANSPORT_FAIL:
597 598 case CE_LOGOUT_OTHER_CONN_SND:
598 599 case CE_LOGOUT_OTHER_CONN_RCV:
599 600 /* T7 */
600 601 (void) untimeout(ic->ic_state_timeout);
601 602 (void) idm_notify_client(ic, CN_LOGIN_FAIL, NULL);
↓ open down ↓ |
568 lines elided |
↑ open up ↑ |
602 603 idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
603 604 break;
604 605 case CE_LOGOUT_SESSION_SUCCESS:
605 606 /*
606 607 * T8
607 608 * A session reinstatement request can be received while a
608 609 * session is active and a login is in process. The iSCSI
609 610 * connections are shut down by a CE_LOGOUT_SESSION_SUCCESS
610 611 * event sent from the session to the IDM layer.
611 612 */
613 + (void) untimeout(ic->ic_state_timeout);
612 614 if (IDM_CONN_ISTGT(ic)) {
613 615 ic->ic_transport_ops->it_tgt_conn_disconnect(ic);
614 616 } else {
615 617 ic->ic_transport_ops->it_ini_conn_disconnect(ic);
616 618 }
617 619 idm_update_state(ic, CS_S11_COMPLETE, event_ctx);
618 620 break;
619 621
620 622 case CE_LOGIN_SND:
621 623 ASSERT(ic->ic_client_callback == NULL);
622 624 /*
623 625 * Initiator connections will see initial login PDU
624 626 * in this state. Target connections see initial
625 627 * login PDU in "xpt up" state.
626 628 */
627 629 mutex_enter(&ic->ic_state_mutex);
628 630 if (!(ic->ic_state_flags & CF_INITIAL_LOGIN)) {
629 631 idm_initial_login_actions(ic, event_ctx);
630 632 }
631 633 mutex_exit(&ic->ic_state_mutex);
632 634 break;
633 635 case CE_MISC_TX:
634 636 case CE_MISC_RX:
635 637 case CE_LOGIN_RCV:
636 638 case CE_TX_PROTOCOL_ERROR:
637 639 case CE_RX_PROTOCOL_ERROR:
638 640 /* Don't care */
639 641 break;
640 642 default:
641 643 ASSERT(0);
642 644 /*NOTREACHED*/
643 645 }
644 646 }
645 647
646 648
647 649 static void
648 650 idm_state_s5_logged_in(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
649 651 {
650 652 switch (event_ctx->iec_event) {
651 653 case CE_MISC_RX:
652 654 /* MC/S: when removing the non-leading connection */
653 655 case CE_LOGOUT_THIS_CONN_RCV:
654 656 case CE_LOGOUT_THIS_CONN_SND:
655 657 case CE_LOGOUT_OTHER_CONN_RCV:
656 658 case CE_LOGOUT_OTHER_CONN_SND:
657 659 /* T9 */
658 660 idm_ffp_disable(ic, FD_CONN_LOGOUT); /* Explicit logout */
659 661 idm_update_state(ic, CS_S6_IN_LOGOUT, event_ctx);
660 662 break;
661 663 case CE_LOGOUT_SESSION_RCV:
662 664 case CE_LOGOUT_SESSION_SND:
663 665 /* T9 */
664 666 idm_ffp_disable(ic, FD_SESS_LOGOUT); /* Explicit logout */
665 667 idm_update_state(ic, CS_S6_IN_LOGOUT, event_ctx);
666 668 break;
667 669 case CE_LOGOUT_SESSION_SUCCESS:
668 670 /* T8 */
669 671 idm_ffp_disable(ic, FD_SESS_LOGOUT); /* Explicit logout */
670 672
671 673 /* Close connection */
672 674 if (IDM_CONN_ISTGT(ic)) {
673 675 ic->ic_transport_ops->it_tgt_conn_disconnect(ic);
674 676 } else {
675 677 ic->ic_transport_ops->it_ini_conn_disconnect(ic);
676 678 }
677 679
678 680 idm_update_state(ic, CS_S11_COMPLETE, event_ctx);
679 681 break;
680 682 case CE_ASYNC_LOGOUT_RCV:
681 683 case CE_ASYNC_LOGOUT_SND:
682 684 /* T11 */
683 685 idm_update_state(ic, CS_S7_LOGOUT_REQ, event_ctx);
684 686 break;
685 687 case CE_TRANSPORT_FAIL:
686 688 case CE_ASYNC_DROP_CONN_RCV:
687 689 case CE_ASYNC_DROP_CONN_SND:
688 690 case CE_ASYNC_DROP_ALL_CONN_RCV:
689 691 case CE_ASYNC_DROP_ALL_CONN_SND:
690 692 /* T15 */
691 693 idm_ffp_disable(ic, FD_CONN_FAIL); /* Implicit logout */
692 694 idm_update_state(ic, CS_S8_CLEANUP, event_ctx);
693 695 break;
694 696 case CE_MISC_TX:
695 697 case CE_TX_PROTOCOL_ERROR:
696 698 case CE_RX_PROTOCOL_ERROR:
697 699 case CE_LOGIN_TIMEOUT:
698 700 /* Don't care */
699 701 break;
700 702 default:
701 703 ASSERT(0);
702 704 }
703 705 }
704 706
705 707 static void
706 708 idm_state_s6_in_logout_success_snd_done(idm_pdu_t *pdu, idm_status_t status)
707 709 {
708 710 idm_conn_t *ic = pdu->isp_ic;
709 711
710 712 /*
711 713 * This pdu callback can be invoked by the tx thread,
712 714 * so run the disconnect code from another thread.
713 715 */
714 716 pdu->isp_status = status;
715 717 idm_conn_event(ic, CE_LOGOUT_SUCCESS_SND_DONE, (uintptr_t)pdu);
716 718 }
717 719
718 720 static void
719 721 idm_state_s6_in_logout_fail_snd_done(idm_pdu_t *pdu, idm_status_t status)
720 722 {
721 723 idm_conn_t *ic = pdu->isp_ic;
722 724
723 725 /*
724 726 * This pdu callback can be invoked by the tx thread,
725 727 * so run the disconnect code from another thread.
726 728 */
727 729 pdu->isp_status = status;
728 730 idm_conn_event(ic, CE_LOGOUT_FAIL_SND_DONE, (uintptr_t)pdu);
729 731 }
730 732
731 733 static void
732 734 idm_state_s6_in_logout(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
733 735 {
734 736 idm_pdu_t *pdu;
735 737
736 738 switch (event_ctx->iec_event) {
737 739 case CE_LOGOUT_SUCCESS_SND_DONE:
738 740 pdu = (idm_pdu_t *)event_ctx->iec_info;
739 741
740 742 /* Close connection (if it's not already closed) */
741 743 ASSERT(IDM_CONN_ISTGT(ic));
742 744 ic->ic_transport_ops->it_tgt_conn_disconnect(ic);
743 745
744 746 /* restore client callback */
745 747 pdu->isp_callback = ic->ic_client_callback;
746 748 ic->ic_client_callback = NULL;
747 749 idm_pdu_complete(pdu, pdu->isp_status);
748 750 idm_update_state(ic, CS_S11_COMPLETE, event_ctx);
749 751 break;
750 752 case CE_LOGOUT_FAIL_SND_DONE:
751 753 pdu = (idm_pdu_t *)event_ctx->iec_info;
752 754 /* restore client callback */
753 755 pdu->isp_callback = ic->ic_client_callback;
754 756 ic->ic_client_callback = NULL;
755 757 idm_pdu_complete(pdu, pdu->isp_status);
756 758 idm_update_state(ic, CS_S8_CLEANUP, event_ctx);
757 759 break;
758 760 case CE_LOGOUT_SUCCESS_SND:
759 761 case CE_LOGOUT_FAIL_SND:
760 762 /*
761 763 * Allow the logout response pdu to be sent and defer
762 764 * the state machine update until the completion callback.
763 765 * Only 1 level or callback interposition is allowed.
764 766 */
765 767 pdu = (idm_pdu_t *)event_ctx->iec_info;
766 768 ASSERT(ic->ic_client_callback == NULL);
767 769 ic->ic_client_callback = pdu->isp_callback;
768 770 if (event_ctx->iec_event == CE_LOGOUT_SUCCESS_SND) {
769 771 pdu->isp_callback =
770 772 idm_state_s6_in_logout_success_snd_done;
771 773 } else {
772 774 pdu->isp_callback =
773 775 idm_state_s6_in_logout_fail_snd_done;
774 776 }
775 777 break;
776 778 case CE_LOGOUT_SUCCESS_RCV:
777 779 /*
778 780 * Need to deliver this PDU to the initiator now because after
779 781 * we update the state to CS_S11_COMPLETE the initiator will
780 782 * no longer be in an appropriate state.
781 783 */
782 784 event_ctx->iec_pdu_forwarded = B_TRUE;
783 785 pdu = (idm_pdu_t *)event_ctx->iec_info;
784 786 idm_pdu_rx_forward(ic, pdu);
785 787 /* FALLTHROUGH */
786 788 case CE_LOGOUT_SESSION_SUCCESS:
787 789 /* T13 */
788 790
789 791 /* Close connection (if it's not already closed) */
790 792 if (IDM_CONN_ISTGT(ic)) {
791 793 ic->ic_transport_ops->it_tgt_conn_disconnect(ic);
792 794 } else {
793 795 ic->ic_transport_ops->it_ini_conn_disconnect(ic);
794 796 }
795 797
796 798 idm_update_state(ic, CS_S11_COMPLETE, event_ctx);
797 799 break;
798 800 case CE_ASYNC_LOGOUT_RCV:
799 801 /* T14 Do nothing */
800 802 break;
801 803 case CE_TRANSPORT_FAIL:
802 804 case CE_ASYNC_DROP_CONN_RCV:
803 805 case CE_ASYNC_DROP_CONN_SND:
804 806 case CE_ASYNC_DROP_ALL_CONN_RCV:
805 807 case CE_ASYNC_DROP_ALL_CONN_SND:
806 808 case CE_LOGOUT_FAIL_RCV:
807 809 idm_update_state(ic, CS_S8_CLEANUP, event_ctx);
808 810 break;
809 811 case CE_TX_PROTOCOL_ERROR:
810 812 case CE_RX_PROTOCOL_ERROR:
811 813 case CE_MISC_TX:
812 814 case CE_MISC_RX:
813 815 case CE_LOGIN_TIMEOUT:
814 816 /* Don't care */
815 817 break;
816 818 default:
817 819 ASSERT(0);
818 820 }
819 821 }
820 822
821 823
822 824 static void
823 825 idm_logout_req_timeout(void *arg)
824 826 {
825 827 idm_conn_t *ic = arg;
826 828
827 829 idm_conn_event(ic, CE_LOGOUT_TIMEOUT, NULL);
828 830 }
829 831
830 832 static void
831 833 idm_state_s7_logout_req(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
832 834 {
833 835 /* Must cancel logout timer before leaving this state */
834 836 switch (event_ctx->iec_event) {
835 837 case CE_LOGOUT_THIS_CONN_RCV:
836 838 case CE_LOGOUT_THIS_CONN_SND:
837 839 case CE_LOGOUT_OTHER_CONN_RCV:
838 840 case CE_LOGOUT_OTHER_CONN_SND:
839 841 /* T10 */
840 842 if (IDM_CONN_ISTGT(ic)) {
841 843 (void) untimeout(ic->ic_state_timeout);
842 844 }
843 845 idm_ffp_disable(ic, FD_CONN_LOGOUT); /* Explicit logout */
844 846 idm_update_state(ic, CS_S6_IN_LOGOUT, event_ctx);
845 847 break;
846 848 case CE_LOGOUT_SESSION_RCV:
847 849 case CE_LOGOUT_SESSION_SND:
848 850 /* T10 */
849 851 if (IDM_CONN_ISTGT(ic)) {
850 852 (void) untimeout(ic->ic_state_timeout);
851 853 }
852 854 idm_ffp_disable(ic, FD_SESS_LOGOUT); /* Explicit logout */
853 855 idm_update_state(ic, CS_S6_IN_LOGOUT, event_ctx);
854 856 break;
855 857 case CE_ASYNC_LOGOUT_RCV:
856 858 case CE_ASYNC_LOGOUT_SND:
857 859 /* T12 Do nothing */
858 860 break;
859 861 case CE_TRANSPORT_FAIL:
860 862 case CE_ASYNC_DROP_CONN_RCV:
861 863 case CE_ASYNC_DROP_CONN_SND:
862 864 case CE_ASYNC_DROP_ALL_CONN_RCV:
863 865 case CE_ASYNC_DROP_ALL_CONN_SND:
864 866 /* T16 */
865 867 if (IDM_CONN_ISTGT(ic)) {
866 868 (void) untimeout(ic->ic_state_timeout);
867 869 }
868 870 /* FALLTHROUGH */
869 871 case CE_LOGOUT_TIMEOUT:
870 872 idm_ffp_disable(ic, FD_CONN_FAIL); /* Implicit logout */
871 873 idm_update_state(ic, CS_S8_CLEANUP, event_ctx);
872 874 break;
873 875 case CE_LOGOUT_SESSION_SUCCESS:
874 876 /* T18 */
875 877 if (IDM_CONN_ISTGT(ic)) {
876 878 (void) untimeout(ic->ic_state_timeout);
877 879 }
878 880 idm_ffp_disable(ic, FD_SESS_LOGOUT); /* Explicit logout */
879 881
880 882 /* Close connection (if it's not already closed) */
881 883 if (IDM_CONN_ISTGT(ic)) {
882 884 ic->ic_transport_ops->it_tgt_conn_disconnect(ic);
883 885 } else {
884 886 ic->ic_transport_ops->it_ini_conn_disconnect(ic);
885 887 }
886 888
887 889 idm_update_state(ic, CS_S11_COMPLETE, event_ctx);
888 890 break;
889 891 case CE_TX_PROTOCOL_ERROR:
890 892 case CE_RX_PROTOCOL_ERROR:
891 893 case CE_MISC_TX:
892 894 case CE_MISC_RX:
893 895 case CE_LOGIN_TIMEOUT:
894 896 /* Don't care */
895 897 break;
896 898 default:
897 899 ASSERT(0);
898 900 }
899 901 }
900 902
901 903
902 904 static void
903 905 idm_cleanup_timeout(void *arg)
904 906 {
905 907 idm_conn_t *ic = arg;
906 908
907 909 idm_conn_event(ic, CE_CLEANUP_TIMEOUT, NULL);
908 910 }
909 911
910 912 static void
911 913 idm_state_s8_cleanup(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
912 914 {
913 915 idm_pdu_t *pdu;
914 916
915 917 /*
916 918 * Need to cancel the cleanup timeout before leaving this state
917 919 * if it hasn't already fired.
918 920 */
919 921 switch (event_ctx->iec_event) {
920 922 case CE_LOGOUT_SUCCESS_RCV:
921 923 case CE_LOGOUT_SUCCESS_SND:
922 924 case CE_LOGOUT_SESSION_SUCCESS:
923 925 (void) untimeout(ic->ic_state_timeout);
924 926 /*FALLTHROUGH*/
925 927 case CE_CLEANUP_TIMEOUT:
926 928 /* M1 */
927 929 idm_update_state(ic, CS_S11_COMPLETE, event_ctx);
928 930 break;
929 931 case CE_LOGOUT_OTHER_CONN_RCV:
930 932 case CE_LOGOUT_OTHER_CONN_SND:
931 933 /* M2 */
932 934 idm_update_state(ic, CS_S10_IN_CLEANUP, event_ctx);
933 935 break;
934 936 case CE_LOGOUT_SUCCESS_SND_DONE:
935 937 case CE_LOGOUT_FAIL_SND_DONE:
936 938 pdu = (idm_pdu_t *)event_ctx->iec_info;
937 939 /* restore client callback */
938 940 pdu->isp_callback = ic->ic_client_callback;
939 941 ic->ic_client_callback = NULL;
940 942 idm_pdu_complete(pdu, pdu->isp_status);
941 943 break;
942 944 case CE_LOGOUT_SESSION_RCV:
943 945 case CE_LOGOUT_SESSION_SND:
944 946 case CE_TX_PROTOCOL_ERROR:
945 947 case CE_RX_PROTOCOL_ERROR:
946 948 case CE_MISC_TX:
947 949 case CE_MISC_RX:
948 950 case CE_TRANSPORT_FAIL:
949 951 case CE_LOGIN_TIMEOUT:
950 952 case CE_LOGOUT_TIMEOUT:
951 953 /* Don't care */
952 954 break;
953 955 default:
954 956 ASSERT(0);
955 957 }
956 958 }
957 959
958 960 /* ARGSUSED */
959 961 static void
960 962 idm_state_s9_init_error(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
961 963 {
962 964 /* All events ignored in this state */
963 965 }
964 966
965 967 /* ARGSUSED */
966 968 static void
967 969 idm_state_s9a_rejected(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
968 970 {
969 971 /* All events ignored in this state */
970 972 }
971 973
972 974
973 975 static void
974 976 idm_state_s9b_wait_snd_done_cb(idm_pdu_t *pdu, idm_status_t status)
975 977 {
976 978 idm_conn_t *ic = pdu->isp_ic;
977 979
978 980 /*
979 981 * This pdu callback can be invoked by the tx thread,
980 982 * so run the disconnect code from another thread.
981 983 */
982 984 pdu->isp_status = status;
983 985 idm_conn_event(ic, CE_LOGIN_FAIL_SND_DONE, (uintptr_t)pdu);
984 986 }
985 987
986 988 /*
987 989 * CS_S9B_WAIT_SND_DONE -- wait for callback completion.
988 990 */
989 991 /* ARGSUSED */
990 992 static void
991 993 idm_state_s9b_wait_snd_done(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
992 994 {
993 995 idm_pdu_t *pdu;
994 996 /*
995 997 * Wait for completion of the login fail sequence and then
996 998 * go to state S9_INIT_ERROR to clean up the connection.
997 999 */
998 1000 switch (event_ctx->iec_event) {
999 1001 case CE_LOGIN_FAIL_SND_DONE:
1000 1002 pdu = (idm_pdu_t *)event_ctx->iec_info;
1001 1003 /* restore client callback */
1002 1004 pdu->isp_callback = ic->ic_client_callback;
1003 1005 ic->ic_client_callback = NULL;
1004 1006 idm_pdu_complete(pdu, pdu->isp_status);
1005 1007 idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
1006 1008 break;
1007 1009
1008 1010 /* All other events ignored */
1009 1011 }
1010 1012 }
1011 1013
1012 1014
1013 1015
1014 1016
1015 1017 static void
1016 1018 idm_state_s10_in_cleanup(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
1017 1019 {
1018 1020 idm_pdu_t *pdu;
1019 1021
1020 1022 /*
1021 1023 * Need to cancel the cleanup timeout before leaving this state
1022 1024 * if it hasn't already fired.
1023 1025 */
1024 1026 switch (event_ctx->iec_event) {
1025 1027 case CE_LOGOUT_FAIL_RCV:
1026 1028 case CE_LOGOUT_FAIL_SND:
1027 1029 idm_update_state(ic, CS_S8_CLEANUP, event_ctx);
1028 1030 break;
1029 1031 case CE_LOGOUT_SUCCESS_SND:
1030 1032 case CE_LOGOUT_SUCCESS_RCV:
1031 1033 case CE_LOGOUT_SESSION_SUCCESS:
1032 1034 (void) untimeout(ic->ic_state_timeout);
1033 1035 /*FALLTHROUGH*/
1034 1036 case CE_CLEANUP_TIMEOUT:
1035 1037 idm_update_state(ic, CS_S11_COMPLETE, event_ctx);
1036 1038 break;
1037 1039 case CE_LOGOUT_SUCCESS_SND_DONE:
1038 1040 case CE_LOGOUT_FAIL_SND_DONE:
1039 1041 pdu = (idm_pdu_t *)event_ctx->iec_info;
1040 1042 /* restore client callback */
1041 1043 pdu->isp_callback = ic->ic_client_callback;
1042 1044 ic->ic_client_callback = NULL;
1043 1045 idm_pdu_complete(pdu, pdu->isp_status);
1044 1046 break;
1045 1047 case CE_TX_PROTOCOL_ERROR:
1046 1048 case CE_RX_PROTOCOL_ERROR:
1047 1049 case CE_MISC_TX:
1048 1050 case CE_MISC_RX:
1049 1051 case CE_LOGIN_TIMEOUT:
1050 1052 case CE_LOGOUT_TIMEOUT:
1051 1053 /* Don't care */
1052 1054 break;
1053 1055 default:
1054 1056 ASSERT(0);
1055 1057 }
1056 1058 }
1057 1059
1058 1060 /* ARGSUSED */
1059 1061 static void
1060 1062 idm_state_s11_complete(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
1061 1063 {
1062 1064 idm_pdu_t *pdu;
1063 1065
1064 1066 /*
1065 1067 * Cleanup logout success/fail completion if it's been delayed
1066 1068 * until now.
1067 1069 *
1068 1070 * All new events are filtered out before reaching this state, but
1069 1071 * there might already be events in the event queue, so handle the
1070 1072 * SND_DONE events here. Note that if either of the following
1071 1073 * SND_DONE events happens AFTER the change to state S11, then the
1072 1074 * event filter inside dm_conn_event_locked does enough cleanup.
1073 1075 */
1074 1076 switch (event_ctx->iec_event) {
1075 1077 case CE_LOGOUT_SUCCESS_SND_DONE:
1076 1078 case CE_LOGOUT_FAIL_SND_DONE:
1077 1079 pdu = (idm_pdu_t *)event_ctx->iec_info;
1078 1080 /* restore client callback */
1079 1081 pdu->isp_callback = ic->ic_client_callback;
1080 1082 ic->ic_client_callback = NULL;
1081 1083 idm_pdu_complete(pdu, pdu->isp_status);
1082 1084 break;
1083 1085 }
1084 1086
1085 1087 }
1086 1088
1087 1089 static void
1088 1090 idm_state_s12_enable_dm(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
1089 1091 {
1090 1092 switch (event_ctx->iec_event) {
1091 1093 case CE_ENABLE_DM_SUCCESS:
1092 1094 /* T20 */
1093 1095 idm_update_state(ic, CS_S5_LOGGED_IN, event_ctx);
1094 1096 break;
1095 1097 case CE_ENABLE_DM_FAIL:
1096 1098 /* T21 */
1097 1099 idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
1098 1100 break;
1099 1101 case CE_TRANSPORT_FAIL:
1100 1102 /*
1101 1103 * We expect to always hear back from the transport layer
1102 1104 * once we have an "enable data-mover" request outstanding.
1103 1105 * Therefore we'll ignore other events that may occur even
1104 1106 * when they clearly indicate a problem and wait for
1105 1107 * CE_ENABLE_DM_FAIL. On a related note this means the
1106 1108 * transport must ensure that it eventually completes the
1107 1109 * "enable data-mover" operation with either success or
1108 1110 * failure -- otherwise we'll be stuck here.
1109 1111 */
1110 1112 break;
1111 1113 default:
1112 1114 ASSERT(0);
1113 1115 break;
1114 1116 }
1115 1117 }
1116 1118
1117 1119 static void
1118 1120 idm_update_state(idm_conn_t *ic, idm_conn_state_t new_state,
1119 1121 idm_conn_event_ctx_t *event_ctx)
1120 1122 {
1121 1123 int rc;
1122 1124 idm_status_t idm_status;
1123 1125
1124 1126 /*
1125 1127 * Validate new state
1126 1128 */
1127 1129 ASSERT(new_state != CS_S0_UNDEFINED);
1128 1130 ASSERT3U(new_state, <, CS_MAX_STATE);
1129 1131
1130 1132 /*
1131 1133 * Update state in context. We protect this with a mutex
1132 1134 * even though the state machine code is single threaded so that
1133 1135 * other threads can check the state value atomically.
1134 1136 */
1135 1137 new_state = (new_state < CS_MAX_STATE) ?
1136 1138 new_state : CS_S0_UNDEFINED;
1137 1139
1138 1140 IDM_SM_LOG(CE_NOTE, "idm_update_state: conn %p, evt %s(%d), "
1139 1141 "%s(%d) --> %s(%d)", (void *)ic,
1140 1142 idm_ce_name[event_ctx->iec_event], event_ctx->iec_event,
1141 1143 idm_cs_name[ic->ic_state], ic->ic_state,
1142 1144 idm_cs_name[new_state], new_state);
1143 1145
1144 1146 DTRACE_PROBE2(conn__state__change,
1145 1147 idm_conn_t *, ic, idm_conn_state_t, new_state);
1146 1148
1147 1149 mutex_enter(&ic->ic_state_mutex);
1148 1150 idm_sm_audit_state_change(&ic->ic_state_audit, SAS_IDM_CONN,
1149 1151 (int)ic->ic_state, (int)new_state);
1150 1152 ic->ic_last_state = ic->ic_state;
1151 1153 ic->ic_state = new_state;
1152 1154 cv_signal(&ic->ic_state_cv);
1153 1155 mutex_exit(&ic->ic_state_mutex);
1154 1156
1155 1157 switch (ic->ic_state) {
1156 1158 case CS_S1_FREE:
1157 1159 ASSERT(0); /* Initial state, can't return */
1158 1160 break;
1159 1161 case CS_S2_XPT_WAIT:
1160 1162 if ((rc = idm_ini_conn_finish(ic)) != 0) {
1161 1163 idm_conn_event(ic, CE_CONNECT_FAIL, NULL);
1162 1164 } else {
1163 1165 idm_conn_event(ic, CE_CONNECT_SUCCESS, NULL);
1164 1166 }
1165 1167 break;
1166 1168 case CS_S3_XPT_UP:
1167 1169 /*
1168 1170 * Finish any connection related setup including
1169 1171 * waking up the idm_tgt_conn_accept thread.
1170 1172 * and starting the login timer. If the function
1171 1173 * fails then we return to "free" state.
1172 1174 */
1173 1175 if ((rc = idm_tgt_conn_finish(ic)) != IDM_STATUS_SUCCESS) {
1174 1176 switch (rc) {
1175 1177 case IDM_STATUS_REJECT:
1176 1178 idm_conn_event(ic, CE_CONNECT_REJECT, NULL);
1177 1179 break;
1178 1180 default:
1179 1181 idm_conn_event(ic, CE_CONNECT_FAIL, NULL);
1180 1182 break;
1181 1183 }
1182 1184 }
1183 1185
1184 1186 /*
1185 1187 * First login received will cause a transition to
1186 1188 * CS_S4_IN_LOGIN. Start login timer.
1187 1189 */
1188 1190 ic->ic_state_timeout = timeout(idm_login_timeout, ic,
1189 1191 drv_usectohz(IDM_LOGIN_SECONDS*1000000));
1190 1192 break;
1191 1193 case CS_S4_IN_LOGIN:
1192 1194 if (ic->ic_conn_type == CONN_TYPE_INI) {
1193 1195 (void) idm_notify_client(ic, CN_READY_FOR_LOGIN, NULL);
1194 1196 mutex_enter(&ic->ic_state_mutex);
1195 1197 ic->ic_state_flags |= CF_LOGIN_READY;
1196 1198 cv_signal(&ic->ic_state_cv);
1197 1199 mutex_exit(&ic->ic_state_mutex);
1198 1200 }
1199 1201 break;
1200 1202 case CS_S5_LOGGED_IN:
1201 1203 ASSERT(!ic->ic_ffp);
1202 1204 /*
1203 1205 * IDM can go to FFP before the initiator but it
1204 1206 * needs to go to FFP after the target (IDM target should
1205 1207 * go to FFP after notify_ack).
1206 1208 */
1207 1209 idm_status = idm_ffp_enable(ic);
1208 1210 if (idm_status != IDM_STATUS_SUCCESS) {
1209 1211 idm_conn_event(ic, CE_TRANSPORT_FAIL, NULL);
1210 1212 }
1211 1213
1212 1214 if (ic->ic_reinstate_conn) {
1213 1215 /* Connection reinstatement is complete */
1214 1216 idm_conn_event(ic->ic_reinstate_conn,
1215 1217 CE_CONN_REINSTATE_SUCCESS, NULL);
1216 1218 }
1217 1219 break;
1218 1220 case CS_S6_IN_LOGOUT:
1219 1221 break;
1220 1222 case CS_S7_LOGOUT_REQ:
1221 1223 /* Start logout timer for target connections */
1222 1224 if (IDM_CONN_ISTGT(ic)) {
1223 1225 ic->ic_state_timeout = timeout(idm_logout_req_timeout,
1224 1226 ic, drv_usectohz(IDM_LOGOUT_SECONDS*1000000));
1225 1227 }
1226 1228 break;
1227 1229 case CS_S8_CLEANUP:
1228 1230 /* Close connection (if it's not already closed) */
1229 1231 if (IDM_CONN_ISTGT(ic)) {
1230 1232 ic->ic_transport_ops->it_tgt_conn_disconnect(ic);
1231 1233 } else {
1232 1234 ic->ic_transport_ops->it_ini_conn_disconnect(ic);
1233 1235 }
1234 1236
1235 1237 /* Stop executing active tasks */
1236 1238 idm_task_abort(ic, NULL, AT_INTERNAL_SUSPEND);
1237 1239
1238 1240 /* Start logout timer */
1239 1241 ic->ic_state_timeout = timeout(idm_cleanup_timeout, ic,
1240 1242 drv_usectohz(IDM_CLEANUP_SECONDS*1000000));
1241 1243 break;
1242 1244 case CS_S10_IN_CLEANUP:
1243 1245 break;
1244 1246 case CS_S9A_REJECTED:
1245 1247 /*
1246 1248 * We never finished establishing the connection so no
1247 1249 * disconnect. No client notifications because the client
1248 1250 * rejected the connection.
1249 1251 */
1250 1252 idm_refcnt_async_wait_ref(&ic->ic_refcnt,
1251 1253 &idm_conn_reject_unref);
1252 1254 break;
1253 1255 case CS_S9B_WAIT_SND_DONE:
1254 1256 break;
1255 1257 case CS_S9_INIT_ERROR:
1256 1258 if (IDM_CONN_ISTGT(ic)) {
1257 1259 ic->ic_transport_ops->it_tgt_conn_disconnect(ic);
1258 1260 } else {
1259 1261 mutex_enter(&ic->ic_state_mutex);
1260 1262 ic->ic_state_flags |= CF_ERROR;
1261 1263 ic->ic_conn_sm_status = IDM_STATUS_FAIL;
1262 1264 cv_signal(&ic->ic_state_cv);
1263 1265 mutex_exit(&ic->ic_state_mutex);
1264 1266 if (ic->ic_last_state != CS_S1_FREE &&
1265 1267 ic->ic_last_state != CS_S2_XPT_WAIT) {
1266 1268 ic->ic_transport_ops->it_ini_conn_disconnect(
1267 1269 ic);
1268 1270 } else {
1269 1271 (void) idm_notify_client(ic, CN_CONNECT_FAIL,
1270 1272 NULL);
1271 1273 }
1272 1274 }
1273 1275 /*FALLTHROUGH*/
1274 1276 case CS_S11_COMPLETE:
1275 1277 /*
1276 1278 * No more traffic on this connection. If this is an
1277 1279 * initiator connection and we weren't connected yet
1278 1280 * then don't send the "connect lost" event.
1279 1281 * It's useful to the initiator to know whether we were
1280 1282 * logging in at the time so send that information in the
1281 1283 * data field.
1282 1284 */
1283 1285 if (IDM_CONN_ISTGT(ic) ||
1284 1286 ((ic->ic_last_state != CS_S1_FREE) &&
1285 1287 (ic->ic_last_state != CS_S2_XPT_WAIT))) {
1286 1288 (void) idm_notify_client(ic, CN_CONNECT_LOST,
1287 1289 (uintptr_t)(ic->ic_last_state == CS_S4_IN_LOGIN));
1288 1290 }
1289 1291
1290 1292 /* Abort all tasks */
1291 1293 idm_task_abort(ic, NULL, AT_INTERNAL_ABORT);
1292 1294
1293 1295 /*
1294 1296 * Handle terminal state actions on the global taskq so
1295 1297 * we can clean up all the connection resources from
1296 1298 * a separate thread context.
1297 1299 */
1298 1300 idm_refcnt_async_wait_ref(&ic->ic_refcnt, &idm_conn_unref);
1299 1301 break;
1300 1302 case CS_S12_ENABLE_DM:
1301 1303
1302 1304 /*
1303 1305 * The Enable DM state indicates the initiator to initiate
1304 1306 * the hello sequence and the target to get ready to accept
1305 1307 * the iSER Hello Message.
1306 1308 */
1307 1309 idm_status = (IDM_CONN_ISINI(ic)) ?
1308 1310 ic->ic_transport_ops->it_ini_enable_datamover(ic) :
1309 1311 ic->ic_transport_ops->it_tgt_enable_datamover(ic);
1310 1312
1311 1313 if (idm_status == IDM_STATUS_SUCCESS) {
1312 1314 idm_conn_event(ic, CE_ENABLE_DM_SUCCESS, NULL);
1313 1315 } else {
1314 1316 idm_conn_event(ic, CE_ENABLE_DM_FAIL, NULL);
1315 1317 }
1316 1318
1317 1319 break;
1318 1320
1319 1321 default:
1320 1322 ASSERT(0);
1321 1323 break;
1322 1324
1323 1325 }
1324 1326 }
1325 1327
1326 1328
1327 1329 static void
1328 1330 idm_conn_unref(void *ic_void)
1329 1331 {
1330 1332 idm_conn_t *ic = ic_void;
1331 1333
1332 1334 /*
1333 1335 * Client should not be notified that the connection is destroyed
1334 1336 * until all references on the idm connection have been removed.
1335 1337 * Otherwise references on the associated client context would need
1336 1338 * to be tracked separately which seems like a waste (at least when
1337 1339 * there is a one for one correspondence with references on the
1338 1340 * IDM connection).
1339 1341 */
1340 1342 if (IDM_CONN_ISTGT(ic)) {
1341 1343 (void) idm_notify_client(ic, CN_CONNECT_DESTROY, NULL);
1342 1344 idm_svc_conn_destroy(ic);
1343 1345 } else {
1344 1346 /* Initiator may destroy connection during this call */
1345 1347 (void) idm_notify_client(ic, CN_CONNECT_DESTROY, NULL);
1346 1348 }
1347 1349 }
1348 1350
1349 1351 static void
1350 1352 idm_conn_reject_unref(void *ic_void)
1351 1353 {
1352 1354 idm_conn_t *ic = ic_void;
1353 1355
1354 1356 ASSERT(IDM_CONN_ISTGT(ic));
1355 1357
1356 1358 /* Don't notify the client since it rejected the connection */
1357 1359 idm_svc_conn_destroy(ic);
1358 1360 }
1359 1361
1360 1362
1361 1363
1362 1364 static idm_pdu_event_action_t
1363 1365 idm_conn_sm_validate_pdu(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx,
1364 1366 idm_pdu_t *pdu)
1365 1367 {
1366 1368 char *reason_string;
1367 1369 idm_pdu_event_action_t action;
1368 1370
1369 1371 ASSERT((event_ctx->iec_pdu_event_type == CT_RX_PDU) ||
1370 1372 (event_ctx->iec_pdu_event_type == CT_TX_PDU));
1371 1373
1372 1374 /*
1373 1375 * Let's check the simple stuff first. Make sure if this is a
1374 1376 * target connection that the PDU is appropriate for a target
1375 1377 * and if this is an initiator connection that the PDU is
1376 1378 * appropriate for an initiator. This code is not in the data
1377 1379 * path so organization is more important than performance.
1378 1380 */
1379 1381 switch (IDM_PDU_OPCODE(pdu)) {
1380 1382 case ISCSI_OP_NOOP_OUT:
1381 1383 case ISCSI_OP_SCSI_CMD:
1382 1384 case ISCSI_OP_SCSI_TASK_MGT_MSG:
1383 1385 case ISCSI_OP_LOGIN_CMD:
1384 1386 case ISCSI_OP_TEXT_CMD:
1385 1387 case ISCSI_OP_SCSI_DATA:
1386 1388 case ISCSI_OP_LOGOUT_CMD:
1387 1389 case ISCSI_OP_SNACK_CMD:
1388 1390 /*
1389 1391 * Only the initiator should send these PDU's and
1390 1392 * only the target should receive them.
1391 1393 */
1392 1394 if (IDM_CONN_ISINI(ic) &&
1393 1395 (event_ctx->iec_pdu_event_type == CT_RX_PDU)) {
1394 1396 reason_string = "Invalid RX PDU for initiator";
1395 1397 action = CA_RX_PROTOCOL_ERROR;
1396 1398 goto validate_pdu_done;
1397 1399 }
1398 1400
1399 1401 if (IDM_CONN_ISTGT(ic) &&
1400 1402 (event_ctx->iec_pdu_event_type == CT_TX_PDU)) {
1401 1403 reason_string = "Invalid TX PDU for target";
1402 1404 action = CA_TX_PROTOCOL_ERROR;
1403 1405 goto validate_pdu_done;
1404 1406 }
1405 1407 break;
1406 1408 case ISCSI_OP_NOOP_IN:
1407 1409 case ISCSI_OP_SCSI_RSP:
1408 1410 case ISCSI_OP_SCSI_TASK_MGT_RSP:
1409 1411 case ISCSI_OP_LOGIN_RSP:
1410 1412 case ISCSI_OP_TEXT_RSP:
1411 1413 case ISCSI_OP_SCSI_DATA_RSP:
1412 1414 case ISCSI_OP_LOGOUT_RSP:
1413 1415 case ISCSI_OP_RTT_RSP:
1414 1416 case ISCSI_OP_ASYNC_EVENT:
1415 1417 case ISCSI_OP_REJECT_MSG:
1416 1418 /*
1417 1419 * Only the target should send these PDU's and
1418 1420 * only the initiator should receive them.
1419 1421 */
1420 1422 if (IDM_CONN_ISTGT(ic) &&
1421 1423 (event_ctx->iec_pdu_event_type == CT_RX_PDU)) {
1422 1424 reason_string = "Invalid RX PDU for target";
1423 1425 action = CA_RX_PROTOCOL_ERROR;
1424 1426 goto validate_pdu_done;
1425 1427 }
1426 1428
1427 1429 if (IDM_CONN_ISINI(ic) &&
1428 1430 (event_ctx->iec_pdu_event_type == CT_TX_PDU)) {
1429 1431 reason_string = "Invalid TX PDU for initiator";
1430 1432 action = CA_TX_PROTOCOL_ERROR;
1431 1433 goto validate_pdu_done;
1432 1434 }
1433 1435 break;
1434 1436 default:
1435 1437 reason_string = "Unknown PDU Type";
1436 1438 action = ((event_ctx->iec_pdu_event_type == CT_TX_PDU) ?
1437 1439 CA_TX_PROTOCOL_ERROR : CA_RX_PROTOCOL_ERROR);
1438 1440 goto validate_pdu_done;
1439 1441 }
1440 1442
1441 1443 /*
1442 1444 * Now validate the opcodes against the current state.
1443 1445 */
1444 1446 reason_string = "PDU not allowed in current state";
1445 1447 switch (IDM_PDU_OPCODE(pdu)) {
1446 1448 case ISCSI_OP_NOOP_OUT:
1447 1449 case ISCSI_OP_NOOP_IN:
1448 1450 /*
1449 1451 * Obviously S1-S3 are not allowed since login hasn't started.
1450 1452 * S8 is probably out as well since the connection has been
1451 1453 * dropped.
1452 1454 */
1453 1455 switch (ic->ic_state) {
1454 1456 case CS_S4_IN_LOGIN:
1455 1457 case CS_S5_LOGGED_IN:
1456 1458 case CS_S6_IN_LOGOUT:
1457 1459 case CS_S7_LOGOUT_REQ:
1458 1460 action = CA_FORWARD;
1459 1461 goto validate_pdu_done;
1460 1462 case CS_S8_CLEANUP:
1461 1463 case CS_S10_IN_CLEANUP:
1462 1464 action = CA_DROP;
1463 1465 break;
1464 1466 default:
1465 1467 action = ((event_ctx->iec_pdu_event_type == CT_TX_PDU) ?
1466 1468 CA_TX_PROTOCOL_ERROR : CA_RX_PROTOCOL_ERROR);
1467 1469 goto validate_pdu_done;
1468 1470 }
1469 1471 /*NOTREACHED*/
1470 1472 case ISCSI_OP_SCSI_CMD:
1471 1473 case ISCSI_OP_SCSI_RSP:
1472 1474 case ISCSI_OP_SCSI_TASK_MGT_MSG:
1473 1475 case ISCSI_OP_SCSI_TASK_MGT_RSP:
1474 1476 case ISCSI_OP_SCSI_DATA:
1475 1477 case ISCSI_OP_SCSI_DATA_RSP:
1476 1478 case ISCSI_OP_RTT_RSP:
1477 1479 case ISCSI_OP_SNACK_CMD:
1478 1480 case ISCSI_OP_TEXT_CMD:
1479 1481 case ISCSI_OP_TEXT_RSP:
1480 1482 switch (ic->ic_state) {
1481 1483 case CS_S5_LOGGED_IN:
1482 1484 case CS_S6_IN_LOGOUT:
1483 1485 case CS_S7_LOGOUT_REQ:
1484 1486 action = CA_FORWARD;
1485 1487 goto validate_pdu_done;
1486 1488 case CS_S8_CLEANUP:
1487 1489 case CS_S10_IN_CLEANUP:
1488 1490 action = CA_DROP;
1489 1491 break;
1490 1492 default:
1491 1493 action = ((event_ctx->iec_pdu_event_type == CT_TX_PDU) ?
1492 1494 CA_TX_PROTOCOL_ERROR : CA_RX_PROTOCOL_ERROR);
1493 1495 goto validate_pdu_done;
1494 1496 }
1495 1497 /*NOTREACHED*/
1496 1498 case ISCSI_OP_LOGOUT_CMD:
1497 1499 case ISCSI_OP_LOGOUT_RSP:
1498 1500 case ISCSI_OP_REJECT_MSG:
1499 1501 case ISCSI_OP_ASYNC_EVENT:
1500 1502 switch (ic->ic_state) {
1501 1503 case CS_S5_LOGGED_IN:
1502 1504 case CS_S6_IN_LOGOUT:
1503 1505 case CS_S7_LOGOUT_REQ:
1504 1506 action = CA_FORWARD;
1505 1507 goto validate_pdu_done;
1506 1508 case CS_S8_CLEANUP:
1507 1509 case CS_S10_IN_CLEANUP:
1508 1510 action = CA_DROP;
1509 1511 break;
1510 1512 default:
1511 1513 action = ((event_ctx->iec_pdu_event_type == CT_TX_PDU) ?
1512 1514 CA_TX_PROTOCOL_ERROR : CA_RX_PROTOCOL_ERROR);
1513 1515 goto validate_pdu_done;
1514 1516 }
1515 1517 /*NOTREACHED*/
1516 1518 case ISCSI_OP_LOGIN_CMD:
1517 1519 case ISCSI_OP_LOGIN_RSP:
1518 1520 switch (ic->ic_state) {
1519 1521 case CS_S3_XPT_UP:
1520 1522 case CS_S4_IN_LOGIN:
1521 1523 action = CA_FORWARD;
1522 1524 goto validate_pdu_done;
1523 1525 default:
1524 1526 action = ((event_ctx->iec_pdu_event_type == CT_TX_PDU) ?
1525 1527 CA_TX_PROTOCOL_ERROR : CA_RX_PROTOCOL_ERROR);
1526 1528 goto validate_pdu_done;
1527 1529 }
1528 1530 /*NOTREACHED*/
1529 1531 default:
1530 1532 /* This should never happen -- we already checked above */
1531 1533 ASSERT(0);
1532 1534 /*NOTREACHED*/
1533 1535 }
1534 1536
1535 1537 action = ((event_ctx->iec_pdu_event_type == CT_TX_PDU) ?
1536 1538 CA_TX_PROTOCOL_ERROR : CA_RX_PROTOCOL_ERROR);
1537 1539
1538 1540 validate_pdu_done:
1539 1541 if (action != CA_FORWARD) {
1540 1542 DTRACE_PROBE2(idm__int__protocol__error,
1541 1543 idm_conn_event_ctx_t *, event_ctx,
1542 1544 char *, reason_string);
1543 1545 }
1544 1546
1545 1547 return (action);
1546 1548 }
1547 1549
1548 1550 /* ARGSUSED */
1549 1551 void
1550 1552 idm_pdu_tx_protocol_error(idm_conn_t *ic, idm_pdu_t *pdu)
1551 1553 {
1552 1554 /*
1553 1555 * Return the PDU to the caller indicating it was a protocol error.
1554 1556 * Caller can take appropriate action.
1555 1557 */
1556 1558 idm_pdu_complete(pdu, IDM_STATUS_PROTOCOL_ERROR);
1557 1559 }
1558 1560
1559 1561 void
1560 1562 idm_pdu_rx_protocol_error(idm_conn_t *ic, idm_pdu_t *pdu)
1561 1563 {
1562 1564 /*
1563 1565 * Forward PDU to caller indicating it is a protocol error.
1564 1566 * Caller should take appropriate action.
1565 1567 */
1566 1568 (*ic->ic_conn_ops.icb_rx_error)(ic, pdu, IDM_STATUS_PROTOCOL_ERROR);
1567 1569 }
1568 1570
1569 1571 idm_status_t
1570 1572 idm_notify_client(idm_conn_t *ic, idm_client_notify_t cn, uintptr_t data)
1571 1573 {
1572 1574 /*
1573 1575 * We may want to make this more complicated at some point but
1574 1576 * for now lets just call the client's notify function and return
1575 1577 * the status.
1576 1578 */
1577 1579 ASSERT(!mutex_owned(&ic->ic_state_mutex));
1578 1580 cn = (cn > CN_MAX) ? CN_MAX : cn;
1579 1581 IDM_SM_LOG(CE_NOTE, "idm_notify_client: ic=%p %s(%d)\n",
1580 1582 (void *)ic, idm_cn_strings[cn], cn);
1581 1583 return ((*ic->ic_conn_ops.icb_client_notify)(ic, cn, data));
1582 1584 }
1583 1585
1584 1586 static idm_status_t
1585 1587 idm_ffp_enable(idm_conn_t *ic)
1586 1588 {
1587 1589 idm_status_t rc;
1588 1590
1589 1591 /*
1590 1592 * On the initiator side the client will see this notification
1591 1593 * before the actual login succes PDU. This shouldn't be a big
1592 1594 * deal since the initiator drives the connection. It can simply
1593 1595 * wait for the login response then start sending SCSI commands.
1594 1596 * Kind ugly though compared with the way things work on target
1595 1597 * connections.
1596 1598 */
1597 1599 mutex_enter(&ic->ic_state_mutex);
1598 1600 ic->ic_ffp = B_TRUE;
1599 1601 mutex_exit(&ic->ic_state_mutex);
1600 1602
1601 1603 rc = idm_notify_client(ic, CN_FFP_ENABLED, NULL);
1602 1604 if (rc != IDM_STATUS_SUCCESS) {
1603 1605 mutex_enter(&ic->ic_state_mutex);
1604 1606 ic->ic_ffp = B_FALSE;
1605 1607 mutex_exit(&ic->ic_state_mutex);
1606 1608 }
1607 1609 return (rc);
1608 1610 }
1609 1611
1610 1612 static void
1611 1613 idm_ffp_disable(idm_conn_t *ic, idm_ffp_disable_t disable_type)
1612 1614 {
1613 1615 mutex_enter(&ic->ic_state_mutex);
1614 1616 ic->ic_ffp = B_FALSE;
1615 1617 mutex_exit(&ic->ic_state_mutex);
1616 1618
1617 1619 /* Client can't "fail" CN_FFP_DISABLED */
1618 1620 (void) idm_notify_client(ic, CN_FFP_DISABLED,
1619 1621 (uintptr_t)disable_type);
1620 1622 }
1621 1623
1622 1624 static void
1623 1625 idm_initial_login_actions(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
1624 1626 {
1625 1627 ASSERT((event_ctx->iec_event == CE_LOGIN_RCV) ||
1626 1628 (event_ctx->iec_event == CE_LOGIN_SND));
1627 1629
1628 1630 /*
1629 1631 * Currently it's not clear what we would do here -- since
1630 1632 * we went to the trouble of coding an "initial login" hook
1631 1633 * we'll leave it in for now. Remove before integration if
1632 1634 * it's not used for anything.
1633 1635 */
1634 1636 ic->ic_state_flags |= CF_INITIAL_LOGIN;
1635 1637 }
1636 1638
1637 1639 static void
1638 1640 idm_login_success_actions(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
1639 1641 {
1640 1642 idm_pdu_t *pdu = (idm_pdu_t *)event_ctx->iec_info;
1641 1643 iscsi_login_hdr_t *login_req =
1642 1644 (iscsi_login_hdr_t *)pdu->isp_hdr;
1643 1645
1644 1646 ASSERT((event_ctx->iec_event == CE_LOGIN_SUCCESS_RCV) ||
1645 1647 (event_ctx->iec_event == CE_LOGIN_SUCCESS_SND));
1646 1648
1647 1649 /*
1648 1650 * Save off CID
1649 1651 */
1650 1652 mutex_enter(&ic->ic_state_mutex);
1651 1653 ic->ic_login_cid = ntohs(login_req->cid);
1652 1654 ic->ic_login_info_valid = B_TRUE;
1653 1655
1654 1656 mutex_exit(&ic->ic_state_mutex);
1655 1657 }
↓ open down ↓ |
1034 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX