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