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