103 */ |
90 */ |
104 icp->conn_sig = ISCSI_SIG_CONN; |
91 icp->conn_sig = ISCSI_SIG_CONN; |
105 icp->conn_state = ISCSI_CONN_STATE_FREE; |
92 icp->conn_state = ISCSI_CONN_STATE_FREE; |
106 mutex_init(&icp->conn_state_mutex, NULL, MUTEX_DRIVER, NULL); |
93 mutex_init(&icp->conn_state_mutex, NULL, MUTEX_DRIVER, NULL); |
107 cv_init(&icp->conn_state_change, NULL, CV_DRIVER, NULL); |
94 cv_init(&icp->conn_state_change, NULL, CV_DRIVER, NULL); |
|
95 mutex_init(&icp->conn_login_mutex, NULL, MUTEX_DRIVER, NULL); |
|
96 cv_init(&icp->conn_login_cv, NULL, CV_DRIVER, NULL); |
108 icp->conn_state_destroy = B_FALSE; |
97 icp->conn_state_destroy = B_FALSE; |
|
98 idm_sm_audit_init(&icp->conn_state_audit); |
109 icp->conn_sess = isp; |
99 icp->conn_sess = isp; |
110 icp->conn_state_lbolt = ddi_get_lbolt(); |
|
111 |
100 |
112 mutex_enter(&iscsi_oid_mutex); |
101 mutex_enter(&iscsi_oid_mutex); |
113 icp->conn_oid = iscsi_oid++; |
102 icp->conn_oid = iscsi_oid++; |
114 mutex_exit(&iscsi_oid_mutex); |
103 mutex_exit(&iscsi_oid_mutex); |
115 |
104 |
116 /* Creation of the receive thread */ |
105 /* |
117 if (snprintf(th_name, sizeof (th_name) - 1, ISCSI_CONN_RXTH_NAME_FORMAT, |
106 * IDM CN taskq |
|
107 */ |
|
108 |
|
109 if (snprintf(th_name, sizeof (th_name) - 1, |
|
110 ISCSI_CONN_CN_TASKQ_NAME_FORMAT, |
118 icp->conn_sess->sess_hba->hba_oid, icp->conn_sess->sess_oid, |
111 icp->conn_sess->sess_hba->hba_oid, icp->conn_sess->sess_oid, |
119 icp->conn_oid) >= sizeof (th_name)) { |
112 icp->conn_oid) >= sizeof (th_name)) { |
120 cv_destroy(&icp->conn_state_change); |
113 cv_destroy(&icp->conn_state_change); |
121 mutex_destroy(&icp->conn_state_mutex); |
114 mutex_destroy(&icp->conn_state_mutex); |
122 kmem_free(icp, sizeof (iscsi_conn_t)); |
115 kmem_free(icp, sizeof (iscsi_conn_t)); |
123 *icpp = NULL; |
116 *icpp = NULL; |
124 return (ISCSI_STATUS_INTERNAL_ERROR); |
117 return (ISCSI_STATUS_INTERNAL_ERROR); |
125 } |
118 } |
126 |
119 |
127 icp->conn_rx_thread = iscsi_thread_create(isp->sess_hba->hba_dip, |
120 icp->conn_cn_taskq = |
128 th_name, iscsi_rx_thread, icp); |
121 ddi_taskq_create(icp->conn_sess->sess_hba->hba_dip, th_name, 1, |
129 |
122 TASKQ_DEFAULTPRI, 0); |
130 /* Creation of the transfer thread */ |
123 if (icp->conn_cn_taskq == NULL) { |
131 if (snprintf(th_name, sizeof (th_name) - 1, ISCSI_CONN_TXTH_NAME_FORMAT, |
|
132 icp->conn_sess->sess_hba->hba_oid, icp->conn_sess->sess_oid, |
|
133 icp->conn_oid) >= sizeof (th_name)) { |
|
134 iscsi_thread_destroy(icp->conn_rx_thread); |
|
135 cv_destroy(&icp->conn_state_change); |
124 cv_destroy(&icp->conn_state_change); |
136 mutex_destroy(&icp->conn_state_mutex); |
125 mutex_destroy(&icp->conn_state_mutex); |
137 kmem_free(icp, sizeof (iscsi_conn_t)); |
126 kmem_free(icp, sizeof (iscsi_conn_t)); |
138 *icpp = NULL; |
127 *icpp = NULL; |
139 return (ISCSI_STATUS_INTERNAL_ERROR); |
128 return (ISCSI_STATUS_INTERNAL_ERROR); |
140 } |
129 } |
141 |
130 |
|
131 /* Creation of the transfer thread */ |
|
132 if (snprintf(th_name, sizeof (th_name) - 1, ISCSI_CONN_TXTH_NAME_FORMAT, |
|
133 icp->conn_sess->sess_hba->hba_oid, icp->conn_sess->sess_oid, |
|
134 icp->conn_oid) >= sizeof (th_name)) { |
|
135 cv_destroy(&icp->conn_state_change); |
|
136 mutex_destroy(&icp->conn_state_mutex); |
|
137 kmem_free(icp, sizeof (iscsi_conn_t)); |
|
138 ddi_taskq_destroy(icp->conn_cn_taskq); |
|
139 *icpp = NULL; |
|
140 return (ISCSI_STATUS_INTERNAL_ERROR); |
|
141 } |
|
142 |
142 icp->conn_tx_thread = iscsi_thread_create(isp->sess_hba->hba_dip, |
143 icp->conn_tx_thread = iscsi_thread_create(isp->sess_hba->hba_dip, |
143 th_name, iscsi_tx_thread, icp); |
144 th_name, iscsi_tx_thread, icp); |
144 |
145 |
145 /* setup connection queues */ |
146 /* setup connection queues */ |
146 iscsi_init_queue(&icp->conn_queue_active); |
147 iscsi_init_queue(&icp->conn_queue_active); |
|
148 iscsi_init_queue(&icp->conn_queue_idm_aborting); |
147 |
149 |
148 bcopy(addr, &icp->conn_base_addr, sizeof (icp->conn_base_addr)); |
150 bcopy(addr, &icp->conn_base_addr, sizeof (icp->conn_base_addr)); |
149 |
151 |
150 /* Add new connection to the session connection list */ |
152 /* Add new connection to the session connection list */ |
151 icp->conn_cid = isp->sess_conn_next_cid++; |
153 icp->conn_cid = isp->sess_conn_next_cid++; |
182 * transitionary and its unsafe to perform actions |
225 * transitionary and its unsafe to perform actions |
183 * on the connection in those states. Set a flag |
226 * on the connection in those states. Set a flag |
184 * on the connection to influence the transitions |
227 * on the connection to influence the transitions |
185 * to quickly complete. Then wait for a state |
228 * to quickly complete. Then wait for a state |
186 * transition. |
229 * transition. |
|
230 * |
|
231 * ISCSI_CONN_STATE_LOGGED_IN is set immediately at the |
|
232 * start of CN_NOTIFY_FFP processing. icp->conn_state_ffp |
|
233 * is set to true at the end of ffp processing, at which |
|
234 * point any session updates are complete. We don't |
|
235 * want to start offlining the connection before we're |
|
236 * done completing the FFP processing since this might |
|
237 * interrupt the discovery process. |
187 */ |
238 */ |
188 delay = ddi_get_lbolt() + SEC_TO_TICK(SHUTDOWN_TIMEOUT); |
239 delay = ddi_get_lbolt() + SEC_TO_TICK(SHUTDOWN_TIMEOUT); |
189 mutex_enter(&icp->conn_state_mutex); |
240 mutex_enter(&icp->conn_state_mutex); |
190 icp->conn_state_destroy = B_TRUE; |
241 icp->conn_state_destroy = B_TRUE; |
191 while ((icp->conn_state != ISCSI_CONN_STATE_FREE) && |
242 while ((((icp->conn_state != ISCSI_CONN_STATE_FREE) && |
192 (icp->conn_state != ISCSI_CONN_STATE_LOGGED_IN) && |
243 (icp->conn_state != ISCSI_CONN_STATE_LOGGED_IN)) || |
|
244 ((icp->conn_state == ISCSI_CONN_STATE_LOGGED_IN) && |
|
245 !icp->conn_state_ffp)) && |
193 (ddi_get_lbolt() < delay)) { |
246 (ddi_get_lbolt() < delay)) { |
194 /* wait for transition */ |
247 /* wait for transition */ |
195 (void) cv_timedwait(&icp->conn_state_change, |
248 (void) cv_timedwait(&icp->conn_state_change, |
196 &icp->conn_state_mutex, delay); |
249 &icp->conn_state_mutex, delay); |
197 } |
250 } |
198 |
251 |
199 /* Final check whether we can destroy the connection */ |
|
200 switch (icp->conn_state) { |
252 switch (icp->conn_state) { |
201 case ISCSI_CONN_STATE_FREE: |
253 case ISCSI_CONN_STATE_FREE: |
202 /* Easy case - Connection is dead */ |
|
203 break; |
254 break; |
204 case ISCSI_CONN_STATE_LOGGED_IN: |
255 case ISCSI_CONN_STATE_LOGGED_IN: |
205 /* Hard case - Force connection logout */ |
256 if (icp->conn_state_ffp) |
206 (void) iscsi_conn_state_machine(icp, |
257 (void) iscsi_handle_logout(icp); |
207 ISCSI_CONN_EVENT_T9); |
258 else { |
|
259 icp->conn_state_destroy = B_FALSE; |
|
260 mutex_exit(&icp->conn_state_mutex); |
|
261 return (ISCSI_STATUS_INTERNAL_ERROR); |
|
262 } |
208 break; |
263 break; |
209 case ISCSI_CONN_STATE_IN_LOGIN: |
264 case ISCSI_CONN_STATE_IN_LOGIN: |
210 case ISCSI_CONN_STATE_IN_LOGOUT: |
265 case ISCSI_CONN_STATE_IN_LOGOUT: |
211 case ISCSI_CONN_STATE_FAILED: |
266 case ISCSI_CONN_STATE_FAILED: |
212 case ISCSI_CONN_STATE_POLLING: |
267 case ISCSI_CONN_STATE_POLLING: |
213 default: |
268 default: |
214 /* All other cases fail the destroy */ |
|
215 icp->conn_state_destroy = B_FALSE; |
269 icp->conn_state_destroy = B_FALSE; |
216 mutex_exit(&icp->conn_state_mutex); |
270 mutex_exit(&icp->conn_state_mutex); |
217 return (ISCSI_STATUS_INTERNAL_ERROR); |
271 return (ISCSI_STATUS_INTERNAL_ERROR); |
218 } |
272 } |
219 mutex_exit(&icp->conn_state_mutex); |
273 mutex_exit(&icp->conn_state_mutex); |
315 icp->conn_login_min = ddi_get_lbolt() + SEC_TO_TICK(min); |
370 icp->conn_login_min = ddi_get_lbolt() + SEC_TO_TICK(min); |
316 icp->conn_login_max = ddi_get_lbolt() + SEC_TO_TICK(max); |
371 icp->conn_login_max = ddi_get_lbolt() + SEC_TO_TICK(max); |
317 } |
372 } |
318 |
373 |
319 |
374 |
320 |
375 /* |
321 /* |
376 * Process the idm notifications |
322 * iscsi_conn_state_machine - This function is used to drive the |
377 */ |
323 * state machine of the iscsi connection. It takes in a connection |
378 idm_status_t |
324 * and the associated event effecting the connection. |
379 iscsi_client_notify(idm_conn_t *ic, idm_client_notify_t icn, uintptr_t data) |
325 * |
380 { |
326 * 7.1.3 Connection State Diagram for an Initiator |
381 iscsi_cn_task_t *cn; |
327 * Symbolic Names for States: |
382 iscsi_conn_t *icp = ic->ic_handle; |
328 * S1: FREE - State on instantiation, or after successful |
383 iscsi_sess_t *isp; |
329 * connection closure. |
384 |
330 * S2: IN_LOGIN - Waiting for login process to conclude, |
385 /* |
331 * possibly involving several PDU exchanges. |
386 * Don't access icp if the notification is CN_CONNECT_DESTROY |
332 * S3: LOGGED_IN - In Full Feature Phase, waiting for all internal, |
387 * since icp may have already been freed. |
333 * iSCSI, and transport events |
388 * |
334 * S4: IN_LOGOUT - Waiting for the Logout repsonse. |
389 * Handle CN_FFP_ENABLED and CN_CONNECT_DESTROY immediately |
335 * S5: FAILED - The connection has failed. Attempting |
390 */ |
336 * to reconnect. |
391 switch (icn) { |
337 * S6: POLLING - The connection reconnect attempts have |
392 case CN_CONNECT_FAIL: |
338 * failed. Continue to poll at a lower |
393 case CN_LOGIN_FAIL: |
339 * frequency. |
394 /* |
340 * |
395 * Wakeup any thread waiting for login stuff to happen. |
341 * States S3, S4 constitute the Full Feature Phase |
396 */ |
342 * of the connection. |
397 ASSERT(icp != NULL); |
343 * |
398 iscsi_login_update_state(icp, LOGIN_ERROR); |
344 * The state diagram is as follows: |
399 return (IDM_STATUS_SUCCESS); |
345 * ------- |
400 case CN_READY_FOR_LOGIN: |
346 * +-------->/ S1 \<------------------------------+ |
401 idm_conn_hold(ic); /* Released in CN_CONNECT_LOST */ |
347 * | +->\ /<---+ /---\ | |
402 mutex_enter(&icp->conn_state_mutex); |
348 * | / ---+--- |T7/30 T7| | | |
403 icp->conn_state_idm_connected = B_TRUE; |
349 * | + | | \->------ | |
404 cv_broadcast(&icp->conn_state_change); |
350 * | T8| |T1 / T5 / S6 \--->| |
405 mutex_exit(&icp->conn_state_mutex); |
351 * | | | / +----------\ /T30 | |
406 |
352 * | | V / / ------ | |
407 iscsi_login_update_state(icp, LOGIN_READY); |
353 * | | ------- / / ^ | |
408 return (IDM_STATUS_SUCCESS); |
354 * | | / S2 \ / T5 |T7 | |
409 case CN_CONNECT_DESTROY: |
355 * | | \ / +-------------- --+--- | |
410 /* |
356 * | | ---+--- / / S5 \--->| |
411 * We released any dependecies we had on this object in |
357 * | | | / T14/T15 \ /T30 | |
412 * either CN_LOGIN_FAIL or CN_CONNECT_LOST so we just need |
358 * | | |T5 / +-------------> ------ | |
413 * to destroy the IDM connection now. |
359 * | | | / / | |
414 */ |
360 * | | | / / T11 | |
415 idm_ini_conn_destroy(ic); |
361 * | | | / / +----+ | |
416 return (IDM_STATUS_SUCCESS); |
362 * | | V V / | | | |
417 } |
363 * | | ------+ ----+-- | | |
|
364 * | +-----/ S3 \T9/11/ S4 \<+ | |
|
365 * +----------\ /---->\ /----------------+ |
|
366 * ------- ------- T15/T17 |
|
367 * |
|
368 * The state transition table is as follows: |
|
369 * |
|
370 * +-----+---+---+------+------+---+ |
|
371 * |S1 |S2 |S3 |S4 |S5 |S6 | |
|
372 * ---+-----+---+---+------+------+---+ |
|
373 * S1|T1 |T1 | - | - | - | | |
|
374 * ---+-----+---+---+------+------+---+ |
|
375 * S2|T7/30|- |T5 | - | - | | |
|
376 * ---+-----+---+---+------+------+---+ |
|
377 * S3|T8 |- | - |T9/11 |T14/15| | |
|
378 * ---+-----+---+---+------+------+---+ |
|
379 * S4| |- | - |T11 |T15/17| | |
|
380 * ---+-----+---+---+------+------+---+ |
|
381 * S5|T30 | |T5 | | |T7 | |
|
382 * ---+-----+---+---+------+------+---+ |
|
383 * S6|T30 | |T5 | | |T7 | |
|
384 * ---+-----+---+---+------+------+---+ |
|
385 * |
|
386 * Events definitions: |
|
387 * |
|
388 * -T1: Transport connection request was made (e.g., TCP SYN sent). |
|
389 * -T5: The final iSCSI Login response with a Status-Class of zero was |
|
390 * received. |
|
391 * -T7: One of the following events caused the transition: |
|
392 * - Login timed out. |
|
393 * - A transport disconnect indication was received. |
|
394 * - A transport reset was received. |
|
395 * - An internal event indicating a transport timeout was |
|
396 * received. |
|
397 * - An internal event of receiving a Logout repsonse (success) |
|
398 * on another connection for a "close the session" Logout |
|
399 * request was received. |
|
400 * * In all these cases, the transport connection is closed. |
|
401 * -T8: An internal event of receiving a Logout response (success) |
|
402 * on another connection for a "close the session" Logout request |
|
403 * was received, thus closing this connection requiring no further |
|
404 * cleanup. |
|
405 * -T9: An internal event that indicates the readiness to start the |
|
406 * Logout process was received, thus prompting an iSCSI Logout to |
|
407 * be sent by the initiator. |
|
408 * -T11: Async PDU with AsyncEvent "Request Logout" was received. |
|
409 * -T13: An iSCSI Logout response (success) was received, or an internal |
|
410 * event of receiving a Logout response (success) on another |
|
411 * connection was received. |
|
412 * -T14: One or more of the following events case this transition: |
|
413 * - Header Digest Error |
|
414 * - Protocol Error |
|
415 * -T15: One or more of the following events caused this transition: |
|
416 * - Internal event that indicates a transport connection timeout |
|
417 * was received thus prompting transport RESET or transport |
|
418 * connection closure. |
|
419 * - A transport RESET |
|
420 * - A transport disconnect indication. |
|
421 * - Async PDU with AsyncEvent "Drop connection" (for this CID) |
|
422 * - Async PDU with AsyncEvent "Drop all connections" |
|
423 * -T17: One or more of the following events caused this transition: |
|
424 * - Logout response, (failure i.e., a non-zero status) was |
|
425 * received, or Logout timed out. |
|
426 * - Any of the events specified for T15. |
|
427 * -T30: One of the following event caused the transition: |
|
428 * - Thefinal iSCSI Login response was received with a non-zero |
|
429 * Status-Class. |
|
430 */ |
|
431 iscsi_status_t |
|
432 iscsi_conn_state_machine(iscsi_conn_t *icp, iscsi_conn_event_t event) |
|
433 { |
|
434 iscsi_status_t status = ISCSI_STATUS_SUCCESS; |
|
435 |
418 |
436 ASSERT(icp != NULL); |
419 ASSERT(icp != NULL); |
437 ASSERT(mutex_owned(&icp->conn_state_mutex)); |
420 isp = icp->conn_sess; |
438 |
421 |
439 DTRACE_PROBE3(event, iscsi_conn_t *, icp, |
422 /* |
440 char *, iscsi_conn_state_str(icp->conn_state), |
423 * Dispatch notifications to the taskq since they often require |
441 char *, iscsi_conn_event_str(event)); |
424 * long blocking operations. In the case of CN_CONNECT_DESTROY |
442 |
425 * we actually just want to destroy the connection which we |
443 icp->conn_prev_state = icp->conn_state; |
426 * can't do in the IDM taskq context. |
444 icp->conn_state_lbolt = ddi_get_lbolt(); |
427 */ |
445 |
428 cn = kmem_alloc(sizeof (*cn), KM_SLEEP); |
446 switch (icp->conn_state) { |
429 |
447 case ISCSI_CONN_STATE_FREE: |
430 cn->ct_ic = ic; |
448 status = iscsi_conn_state_free(icp, event); |
431 cn->ct_icn = icn; |
|
432 cn->ct_data = data; |
|
433 |
|
434 idm_conn_hold(ic); |
|
435 |
|
436 if (ddi_taskq_dispatch(icp->conn_cn_taskq, |
|
437 iscsi_client_notify_task, cn, DDI_SLEEP) != DDI_SUCCESS) { |
|
438 idm_conn_rele(ic); |
|
439 cmn_err(CE_WARN, "iscsi connection(%u) failure - " |
|
440 "unable to schedule notify task", icp->conn_oid); |
|
441 iscsi_conn_update_state(icp, ISCSI_CONN_STATE_FREE); |
|
442 mutex_enter(&isp->sess_state_mutex); |
|
443 iscsi_sess_state_machine(isp, |
|
444 ISCSI_SESS_EVENT_N6); |
|
445 mutex_exit(&isp->sess_state_mutex); |
|
446 } |
|
447 |
|
448 return (IDM_STATUS_SUCCESS); |
|
449 } |
|
450 |
|
451 static void |
|
452 iscsi_client_notify_task(void *cn_task_void) |
|
453 { |
|
454 iscsi_cn_task_t *cn_task = cn_task_void; |
|
455 iscsi_conn_t *icp; |
|
456 iscsi_sess_t *isp; |
|
457 idm_conn_t *ic; |
|
458 idm_client_notify_t icn; |
|
459 uintptr_t data; |
|
460 idm_ffp_disable_t disable_type; |
|
461 boolean_t in_login; |
|
462 |
|
463 ic = cn_task->ct_ic; |
|
464 icn = cn_task->ct_icn; |
|
465 data = cn_task->ct_data; |
|
466 |
|
467 icp = ic->ic_handle; |
|
468 ASSERT(icp != NULL); |
|
469 isp = icp->conn_sess; |
|
470 |
|
471 switch (icn) { |
|
472 case CN_FFP_ENABLED: |
|
473 mutex_enter(&icp->conn_state_mutex); |
|
474 icp->conn_async_logout = B_FALSE; |
|
475 icp->conn_state_ffp = B_TRUE; |
|
476 cv_broadcast(&icp->conn_state_change); |
|
477 mutex_exit(&icp->conn_state_mutex); |
|
478 |
|
479 /* |
|
480 * This logic assumes that the IDM login-snooping code |
|
481 * and the initiator login code will agree on whether |
|
482 * the connection is in FFP. The reason we do this |
|
483 * is that we don't want to process CN_FFP_DISABLED until |
|
484 * CN_FFP_ENABLED has been full handled. |
|
485 */ |
|
486 mutex_enter(&icp->conn_login_mutex); |
|
487 while (icp->conn_login_state != LOGIN_FFP) { |
|
488 cv_wait(&icp->conn_login_cv, &icp->conn_login_mutex); |
|
489 } |
|
490 mutex_exit(&icp->conn_login_mutex); |
449 break; |
491 break; |
450 case ISCSI_CONN_STATE_IN_LOGIN: |
492 case CN_FFP_DISABLED: |
451 iscsi_conn_state_in_login(icp, event); |
493 disable_type = (idm_ffp_disable_t)data; |
|
494 |
|
495 mutex_enter(&icp->conn_state_mutex); |
|
496 switch (disable_type) { |
|
497 case FD_SESS_LOGOUT: |
|
498 case FD_CONN_LOGOUT: |
|
499 if (icp->conn_async_logout) { |
|
500 /* |
|
501 * Our logout was in response to an |
|
502 * async logout request so treat this |
|
503 * like a connection failure (we will |
|
504 * try to re-establish the connection) |
|
505 */ |
|
506 iscsi_conn_update_state_locked(icp, |
|
507 ISCSI_CONN_STATE_FAILED); |
|
508 } else { |
|
509 /* |
|
510 * Logout due to to user config change, |
|
511 * we will not try to re-establish |
|
512 * the connection. |
|
513 */ |
|
514 iscsi_conn_update_state_locked(icp, |
|
515 ISCSI_CONN_STATE_IN_LOGOUT); |
|
516 /* |
|
517 * Hold off generating the ISCSI_SESS_EVENT_N3 |
|
518 * event until we get the CN_CONNECT_LOST |
|
519 * notification. This matches the pre-IDM |
|
520 * implementation better. |
|
521 */ |
|
522 } |
|
523 break; |
|
524 |
|
525 case FD_CONN_FAIL: |
|
526 default: |
|
527 iscsi_conn_update_state_locked(icp, |
|
528 ISCSI_CONN_STATE_FAILED); |
|
529 break; |
|
530 } |
|
531 |
|
532 icp->conn_state_ffp = B_FALSE; |
|
533 cv_broadcast(&icp->conn_state_change); |
|
534 mutex_exit(&icp->conn_state_mutex); |
|
535 |
452 break; |
536 break; |
453 case ISCSI_CONN_STATE_LOGGED_IN: |
537 case CN_CONNECT_LOST: |
454 iscsi_conn_state_logged_in(icp, event); |
538 /* |
455 break; |
539 * We only care about CN_CONNECT_LOST if we've logged in. IDM |
456 case ISCSI_CONN_STATE_IN_LOGOUT: |
540 * sends a flag as the data payload to indicate whether we |
457 iscsi_conn_state_in_logout(icp, event); |
541 * were trying to login. The CN_LOGIN_FAIL notification |
458 break; |
542 * gives us what we need to know for login failures and |
459 case ISCSI_CONN_STATE_FAILED: |
543 * otherwise we will need to keep a bunch of state to know |
460 iscsi_conn_state_failed(icp, event); |
544 * what CN_CONNECT_LOST means to us. |
461 break; |
545 */ |
462 case ISCSI_CONN_STATE_POLLING: |
546 in_login = (boolean_t)data; |
463 iscsi_conn_state_polling(icp, event); |
547 if (in_login) { |
|
548 mutex_enter(&icp->conn_state_mutex); |
|
549 |
|
550 icp->conn_state_idm_connected = B_FALSE; |
|
551 cv_broadcast(&icp->conn_state_change); |
|
552 mutex_exit(&icp->conn_state_mutex); |
|
553 |
|
554 /* Release connect hold from CN_READY_FOR_LOGIN */ |
|
555 idm_conn_rele(ic); |
|
556 break; |
|
557 } |
|
558 |
|
559 /* Any remaining commands are never going to finish */ |
|
560 iscsi_conn_flush_active_cmds(icp); |
|
561 |
|
562 /* |
|
563 * The connection is no longer active so cleanup any |
|
564 * references to the connection and release any holds so |
|
565 * that IDM can finish cleanup. |
|
566 */ |
|
567 mutex_enter(&icp->conn_state_mutex); |
|
568 if (icp->conn_state != ISCSI_CONN_STATE_FAILED) { |
|
569 |
|
570 mutex_enter(&isp->sess_state_mutex); |
|
571 iscsi_sess_state_machine(isp, ISCSI_SESS_EVENT_N3); |
|
572 mutex_exit(&isp->sess_state_mutex); |
|
573 |
|
574 iscsi_conn_update_state_locked(icp, |
|
575 ISCSI_CONN_STATE_FREE); |
|
576 } else { |
|
577 |
|
578 mutex_enter(&isp->sess_state_mutex); |
|
579 iscsi_sess_state_machine(isp, |
|
580 ISCSI_SESS_EVENT_N5); |
|
581 mutex_exit(&isp->sess_state_mutex); |
|
582 |
|
583 /* |
|
584 * If session type is NORMAL, try to reestablish the |
|
585 * connection. |
|
586 */ |
|
587 if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) { |
|
588 iscsi_conn_retry(isp, icp); |
|
589 } else { |
|
590 |
|
591 mutex_enter(&isp->sess_state_mutex); |
|
592 iscsi_sess_state_machine(isp, |
|
593 ISCSI_SESS_EVENT_N6); |
|
594 mutex_exit(&isp->sess_state_mutex); |
|
595 |
|
596 iscsi_conn_update_state_locked(icp, |
|
597 ISCSI_CONN_STATE_FREE); |
|
598 } |
|
599 } |
|
600 |
|
601 (void) iscsi_thread_stop(icp->conn_tx_thread); |
|
602 |
|
603 icp->conn_state_idm_connected = B_FALSE; |
|
604 cv_broadcast(&icp->conn_state_change); |
|
605 mutex_exit(&icp->conn_state_mutex); |
|
606 |
|
607 /* Release connect hold from CN_READY_FOR_LOGIN */ |
|
608 idm_conn_rele(ic); |
464 break; |
609 break; |
465 default: |
610 default: |
466 ASSERT(FALSE); |
611 ISCSI_CONN_LOG(CE_WARN, |
467 status = ISCSI_STATUS_INTERNAL_ERROR; |
612 "iscsi_client_notify: unknown notification: " |
468 } |
613 "%x: NOT IMPLEMENTED YET: icp: %p ic: %p ", |
469 |
614 icn, (void *)icp, (void *)ic); |
470 cv_broadcast(&icp->conn_state_change); |
615 break; |
471 return (status); |
616 } |
472 } |
617 /* free the task notify structure we allocated in iscsi_client_notify */ |
473 |
618 kmem_free(cn_task, sizeof (*cn_task)); |
474 |
619 |
475 /* |
620 /* Release the hold we acquired in iscsi_client_notify */ |
476 * iscsi_conn_state_str - converts state enum to a string |
621 idm_conn_rele(ic); |
477 */ |
622 } |
478 char * |
|
479 iscsi_conn_state_str(iscsi_conn_state_t state) |
|
480 { |
|
481 switch (state) { |
|
482 case ISCSI_CONN_STATE_FREE: |
|
483 return ("free"); |
|
484 case ISCSI_CONN_STATE_IN_LOGIN: |
|
485 return ("in_login"); |
|
486 case ISCSI_CONN_STATE_LOGGED_IN: |
|
487 return ("logged_in"); |
|
488 case ISCSI_CONN_STATE_IN_LOGOUT: |
|
489 return ("in_logout"); |
|
490 case ISCSI_CONN_STATE_FAILED: |
|
491 return ("failed"); |
|
492 case ISCSI_CONN_STATE_POLLING: |
|
493 return ("polling"); |
|
494 default: |
|
495 return ("unknown"); |
|
496 } |
|
497 } |
|
498 |
|
499 |
623 |
500 /* |
624 /* |
501 * iscsi_conn_sync_params - used to update connection parameters |
625 * iscsi_conn_sync_params - used to update connection parameters |
502 * |
626 * |
503 * Used to update connection parameters with current configured |
627 * Used to update connection parameters with current configured |
760 * +--------------------------------------------------------------------+ |
885 * +--------------------------------------------------------------------+ |
761 * | Internal Connection Interfaces | |
886 * | Internal Connection Interfaces | |
762 * +--------------------------------------------------------------------+ |
887 * +--------------------------------------------------------------------+ |
763 */ |
888 */ |
764 |
889 |
765 |
|
766 /* |
|
767 * iscsi_conn_state_free - |
|
768 * |
|
769 * S1: FREE - State on instantiation, or after successful |
|
770 * connection closure. |
|
771 */ |
|
772 static iscsi_status_t |
|
773 iscsi_conn_state_free(iscsi_conn_t *icp, iscsi_conn_event_t event) |
|
774 { |
|
775 iscsi_sess_t *isp; |
|
776 iscsi_hba_t *ihp; |
|
777 iscsi_task_t *itp; |
|
778 iscsi_status_t status = ISCSI_STATUS_SUCCESS; |
|
779 |
|
780 ASSERT(icp != NULL); |
|
781 isp = icp->conn_sess; |
|
782 ASSERT(isp != NULL); |
|
783 ihp = isp->sess_hba; |
|
784 ASSERT(ihp != NULL); |
|
785 ASSERT(icp->conn_state == ISCSI_CONN_STATE_FREE); |
|
786 |
|
787 /* switch on event change */ |
|
788 switch (event) { |
|
789 /* -T1: Transport connection request was request */ |
|
790 case ISCSI_CONN_EVENT_T1: |
|
791 icp->conn_state = ISCSI_CONN_STATE_IN_LOGIN; |
|
792 |
|
793 /* |
|
794 * Release the connection state mutex cross the |
|
795 * the dispatch of the login task. The login task |
|
796 * will reacquire the connection state mutex when |
|
797 * it pushes the connection successful or failed. |
|
798 */ |
|
799 mutex_exit(&icp->conn_state_mutex); |
|
800 |
|
801 /* start login */ |
|
802 itp = kmem_zalloc(sizeof (iscsi_task_t), KM_SLEEP); |
|
803 itp->t_arg = icp; |
|
804 itp->t_blocking = B_TRUE; |
|
805 |
|
806 /* |
|
807 * Sync base connection information before login |
|
808 * A login redirection might have shifted the |
|
809 * current information from the base. |
|
810 */ |
|
811 bcopy(&icp->conn_base_addr, &icp->conn_curr_addr, |
|
812 sizeof (icp->conn_curr_addr)); |
|
813 |
|
814 status = iscsi_login_start(itp); |
|
815 kmem_free(itp, sizeof (iscsi_task_t)); |
|
816 |
|
817 mutex_enter(&icp->conn_state_mutex); |
|
818 break; |
|
819 |
|
820 /* All other events are invalid for this state */ |
|
821 default: |
|
822 ASSERT(FALSE); |
|
823 status = ISCSI_STATUS_INTERNAL_ERROR; |
|
824 } |
|
825 return (status); |
|
826 } |
|
827 |
|
828 /* |
|
829 * iscsi_conn_state_in_login - During this state we are trying to |
|
830 * connect the TCP connection and make a successful login to the |
|
831 * target. To complete this we have a task queue item that is |
|
832 * trying this processing at this point in time. When the task |
|
833 * queue completed its processing it will issue either a T5/7 |
|
834 * event. |
|
835 */ |
|
836 static void |
|
837 iscsi_conn_state_in_login(iscsi_conn_t *icp, iscsi_conn_event_t event) |
|
838 { |
|
839 iscsi_sess_t *isp; |
|
840 |
|
841 ASSERT(icp != NULL); |
|
842 isp = icp->conn_sess; |
|
843 ASSERT(isp != NULL); |
|
844 ASSERT(icp->conn_state == ISCSI_CONN_STATE_IN_LOGIN); |
|
845 |
|
846 /* switch on event change */ |
|
847 switch (event) { |
|
848 /* |
|
849 * -T5: The final iSCSI Login response with a Status-Class of zero |
|
850 * was received. |
|
851 */ |
|
852 case ISCSI_CONN_EVENT_T5: |
|
853 iscsi_conn_logged_in(isp, icp); |
|
854 break; |
|
855 |
|
856 /* |
|
857 * -T30: One of the following event caused the transition: |
|
858 * - Thefinal iSCSI Login response was received with a non-zero |
|
859 * Status-Class. |
|
860 */ |
|
861 case ISCSI_CONN_EVENT_T30: |
|
862 /* FALLTHRU */ |
|
863 |
|
864 /* |
|
865 * -T7: One of the following events caused the transition: |
|
866 * - Login timed out. |
|
867 * - A transport disconnect indication was received. |
|
868 * - A transport reset was received. |
|
869 * - An internal event indicating a transport timeout was |
|
870 * received. |
|
871 * - An internal event of receiving a Logout repsonse (success) |
|
872 * on another connection for a "close the session" Logout |
|
873 * request was received. |
|
874 * * In all these cases, the transport connection is closed. |
|
875 */ |
|
876 case ISCSI_CONN_EVENT_T7: |
|
877 icp->conn_state = ISCSI_CONN_STATE_FREE; |
|
878 break; |
|
879 |
|
880 /* All other events are invalid for this state */ |
|
881 default: |
|
882 ASSERT(FALSE); |
|
883 } |
|
884 } |
|
885 |
|
886 |
|
887 /* |
|
888 * iscsi_conn_state_logged_in - |
|
889 * |
|
890 */ |
|
891 static void |
|
892 iscsi_conn_state_logged_in(iscsi_conn_t *icp, iscsi_conn_event_t event) |
|
893 { |
|
894 iscsi_sess_t *isp; |
|
895 iscsi_hba_t *ihp; |
|
896 |
|
897 ASSERT(icp != NULL); |
|
898 ASSERT(icp->conn_state == ISCSI_CONN_STATE_LOGGED_IN); |
|
899 isp = icp->conn_sess; |
|
900 ASSERT(isp != NULL); |
|
901 ihp = isp->sess_hba; |
|
902 ASSERT(ihp != NULL); |
|
903 |
|
904 /* switch on event change */ |
|
905 switch (event) { |
|
906 /* |
|
907 * -T8: An internal event of receiving a Logout response (success) |
|
908 * on another connection for a "close the session" Logout request |
|
909 * was received, thus closing this connection requiring no further |
|
910 * cleanup. |
|
911 */ |
|
912 case ISCSI_CONN_EVENT_T8: |
|
913 icp->conn_state = ISCSI_CONN_STATE_FREE; |
|
914 |
|
915 /* stop tx thread */ |
|
916 (void) iscsi_thread_stop(icp->conn_tx_thread); |
|
917 |
|
918 /* Disconnect connection */ |
|
919 iscsi_net->close(icp->conn_socket); |
|
920 |
|
921 /* Notify session that a connection logged out */ |
|
922 mutex_enter(&isp->sess_state_mutex); |
|
923 iscsi_sess_state_machine(icp->conn_sess, ISCSI_SESS_EVENT_N3); |
|
924 mutex_exit(&isp->sess_state_mutex); |
|
925 break; |
|
926 |
|
927 /* |
|
928 * -T9: An internal event that indicates the readiness to start the |
|
929 * Logout process was received, thus prompting an iSCSI Logout |
|
930 * to be sent by the initiator. |
|
931 */ |
|
932 case ISCSI_CONN_EVENT_T9: |
|
933 /* FALLTHRU */ |
|
934 |
|
935 /* |
|
936 * -T11: Aync PDU with AsyncEvent "Request Logout" was recevied |
|
937 */ |
|
938 case ISCSI_CONN_EVENT_T11: |
|
939 icp->conn_state = ISCSI_CONN_STATE_IN_LOGOUT; |
|
940 |
|
941 (void) iscsi_handle_logout(icp); |
|
942 break; |
|
943 |
|
944 /* |
|
945 * -T14: One or more of the following events case this transition: |
|
946 * - Header Digest Error |
|
947 * - Protocol Error |
|
948 */ |
|
949 case ISCSI_CONN_EVENT_T14: |
|
950 icp->conn_state = ISCSI_CONN_STATE_FAILED; |
|
951 |
|
952 /* stop tx thread */ |
|
953 (void) iscsi_thread_stop(icp->conn_tx_thread); |
|
954 |
|
955 /* |
|
956 * Error Recovery Level 0 states we should drop |
|
957 * the connection here. Then we will fall through |
|
958 * and treat this event like a T15. |
|
959 */ |
|
960 iscsi_net->close(icp->conn_socket); |
|
961 |
|
962 /* FALLTHRU */ |
|
963 |
|
964 /* |
|
965 * -T15: One or more of the following events caused this transition |
|
966 * - Internal event that indicates a transport connection timeout |
|
967 * was received thus prompting transport RESET or transport |
|
968 * connection closure. |
|
969 * - A transport RESET |
|
970 * - A transport disconnect indication. |
|
971 * - Async PDU with AsyncEvent "Drop connection" (for this CID) |
|
972 * - Async PDU with AsyncEvent "Drop all connections" |
|
973 */ |
|
974 case ISCSI_CONN_EVENT_T15: |
|
975 icp->conn_state = ISCSI_CONN_STATE_FAILED; |
|
976 |
|
977 /* stop tx thread, no-op if already done for T14 */ |
|
978 (void) iscsi_thread_stop(icp->conn_tx_thread); |
|
979 |
|
980 iscsi_conn_flush_active_cmds(icp); |
|
981 |
|
982 mutex_enter(&isp->sess_state_mutex); |
|
983 iscsi_sess_state_machine(isp, ISCSI_SESS_EVENT_N5); |
|
984 mutex_exit(&isp->sess_state_mutex); |
|
985 |
|
986 /* |
|
987 * If session type is NORMAL, create a new login task |
|
988 * to get this connection reestablished. |
|
989 */ |
|
990 if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) { |
|
991 iscsi_conn_retry(isp, icp); |
|
992 } else { |
|
993 icp->conn_state = ISCSI_CONN_STATE_FREE; |
|
994 mutex_enter(&isp->sess_state_mutex); |
|
995 iscsi_sess_state_machine(isp, ISCSI_SESS_EVENT_N6); |
|
996 mutex_exit(&isp->sess_state_mutex); |
|
997 } |
|
998 break; |
|
999 |
|
1000 /* All other events are invalid for this state */ |
|
1001 default: |
|
1002 ASSERT(FALSE); |
|
1003 } |
|
1004 } |
|
1005 |
|
1006 |
|
1007 /* |
|
1008 * iscsi_conn_state_in_logout - |
|
1009 * |
|
1010 */ |
|
1011 static void |
|
1012 iscsi_conn_state_in_logout(iscsi_conn_t *icp, iscsi_conn_event_t event) |
|
1013 { |
|
1014 iscsi_sess_t *isp = NULL; |
|
1015 |
|
1016 ASSERT(icp != NULL); |
|
1017 ASSERT(icp->conn_state == ISCSI_CONN_STATE_IN_LOGOUT); |
|
1018 isp = icp->conn_sess; |
|
1019 ASSERT(isp != NULL); |
|
1020 |
|
1021 /* switch on event change */ |
|
1022 switch (event) { |
|
1023 /* |
|
1024 * -T11: Async PDU with AsyncEvent "Request Logout" was received again |
|
1025 */ |
|
1026 case ISCSI_CONN_EVENT_T11: |
|
1027 icp->conn_state = ISCSI_CONN_STATE_IN_LOGOUT; |
|
1028 |
|
1029 /* Already in LOGOUT ignore the request */ |
|
1030 break; |
|
1031 |
|
1032 /* |
|
1033 * -T17: One or more of the following events caused this transition: |
|
1034 * - Logout response, (failure i.e., a non-zero status) was |
|
1035 * received, or logout timed out. |
|
1036 * - Any of the events specified for T15 |
|
1037 * |
|
1038 * -T14: One or more of the following events case this transition: |
|
1039 * - Header Digest Error |
|
1040 * - Protocol Error |
|
1041 * |
|
1042 * -T15: One or more of the following events caused this transition |
|
1043 * - Internal event that indicates a transport connection timeout |
|
1044 * was received thus prompting transport RESET or transport |
|
1045 * connection closure. |
|
1046 * - A transport RESET |
|
1047 * - A transport disconnect indication. |
|
1048 * - Async PDU with AsyncEvent "Drop connection" (for this CID) |
|
1049 * - Async PDU with AsyncEvent "Drop all connections" |
|
1050 */ |
|
1051 case ISCSI_CONN_EVENT_T17: |
|
1052 case ISCSI_CONN_EVENT_T14: |
|
1053 case ISCSI_CONN_EVENT_T15: |
|
1054 icp->conn_state = ISCSI_CONN_STATE_FREE; |
|
1055 |
|
1056 /* stop tx thread */ |
|
1057 (void) iscsi_thread_stop(icp->conn_tx_thread); |
|
1058 |
|
1059 /* Disconnect Connection */ |
|
1060 iscsi_net->close(icp->conn_socket); |
|
1061 |
|
1062 iscsi_conn_flush_active_cmds(icp); |
|
1063 |
|
1064 /* Notify session of a failed logout */ |
|
1065 mutex_enter(&isp->sess_state_mutex); |
|
1066 iscsi_sess_state_machine(icp->conn_sess, ISCSI_SESS_EVENT_N3); |
|
1067 mutex_exit(&isp->sess_state_mutex); |
|
1068 break; |
|
1069 |
|
1070 /* All other events are invalid for this state */ |
|
1071 default: |
|
1072 ASSERT(FALSE); |
|
1073 } |
|
1074 } |
|
1075 |
|
1076 |
|
1077 /* |
|
1078 * iscsi_conn_state_failed - |
|
1079 * |
|
1080 */ |
|
1081 static void |
|
1082 iscsi_conn_state_failed(iscsi_conn_t *icp, iscsi_conn_event_t event) |
|
1083 { |
|
1084 iscsi_sess_t *isp; |
|
1085 |
|
1086 ASSERT(icp != NULL); |
|
1087 ASSERT(icp->conn_state == ISCSI_CONN_STATE_FAILED); |
|
1088 isp = icp->conn_sess; |
|
1089 ASSERT(isp != NULL); |
|
1090 |
|
1091 /* switch on event change */ |
|
1092 switch (event) { |
|
1093 |
|
1094 /* |
|
1095 * -T5: The final iSCSI Login response with a Status-Class of zero |
|
1096 * was received. |
|
1097 */ |
|
1098 case ISCSI_CONN_EVENT_T5: |
|
1099 iscsi_conn_logged_in(isp, icp); |
|
1100 break; |
|
1101 |
|
1102 /* |
|
1103 * -T30: One of the following event caused the transition: |
|
1104 * - Thefinal iSCSI Login response was received with a non-zero |
|
1105 * Status-Class. |
|
1106 */ |
|
1107 case ISCSI_CONN_EVENT_T30: |
|
1108 icp->conn_state = ISCSI_CONN_STATE_FREE; |
|
1109 |
|
1110 mutex_enter(&isp->sess_state_mutex); |
|
1111 iscsi_sess_state_machine(isp, ISCSI_SESS_EVENT_N6); |
|
1112 mutex_exit(&isp->sess_state_mutex); |
|
1113 |
|
1114 break; |
|
1115 |
|
1116 /* |
|
1117 * -T7: One of the following events caused the transition: |
|
1118 * - Login timed out. |
|
1119 * - A transport disconnect indication was received. |
|
1120 * - A transport reset was received. |
|
1121 * - An internal event indicating a transport timeout was |
|
1122 * received. |
|
1123 * - An internal event of receiving a Logout repsonse (success) |
|
1124 * on another connection for a "close the session" Logout |
|
1125 * request was received. |
|
1126 * * In all these cases, the transport connection is closed. |
|
1127 */ |
|
1128 case ISCSI_CONN_EVENT_T7: |
|
1129 icp->conn_state = ISCSI_CONN_STATE_POLLING; |
|
1130 |
|
1131 mutex_enter(&isp->sess_state_mutex); |
|
1132 iscsi_sess_state_machine(isp, ISCSI_SESS_EVENT_N6); |
|
1133 mutex_exit(&isp->sess_state_mutex); |
|
1134 |
|
1135 iscsi_conn_retry(isp, icp); |
|
1136 break; |
|
1137 |
|
1138 /* There are no valid transition out of this state. */ |
|
1139 default: |
|
1140 ASSERT(FALSE); |
|
1141 } |
|
1142 } |
|
1143 |
|
1144 /* |
|
1145 * iscsi_conn_state_polling - |
|
1146 * |
|
1147 * S6: POLLING - State on instantiation, or after successful |
|
1148 * connection closure. |
|
1149 */ |
|
1150 static void |
|
1151 iscsi_conn_state_polling(iscsi_conn_t *icp, iscsi_conn_event_t event) |
|
1152 { |
|
1153 iscsi_sess_t *isp = NULL; |
|
1154 |
|
1155 ASSERT(icp != NULL); |
|
1156 ASSERT(icp->conn_state == ISCSI_CONN_STATE_POLLING); |
|
1157 isp = icp->conn_sess; |
|
1158 ASSERT(isp != NULL); |
|
1159 |
|
1160 /* switch on event change */ |
|
1161 switch (event) { |
|
1162 /* |
|
1163 * -T5: The final iSCSI Login response with a Status-Class of zero |
|
1164 * was received. |
|
1165 */ |
|
1166 case ISCSI_CONN_EVENT_T5: |
|
1167 iscsi_conn_logged_in(isp, icp); |
|
1168 break; |
|
1169 |
|
1170 /* |
|
1171 * -T30: One of the following event caused the transition: |
|
1172 * - Thefinal iSCSI Login response was received with a non-zero |
|
1173 * Status-Class. |
|
1174 */ |
|
1175 case ISCSI_CONN_EVENT_T30: |
|
1176 icp->conn_state = ISCSI_CONN_STATE_FREE; |
|
1177 |
|
1178 mutex_enter(&isp->sess_state_mutex); |
|
1179 iscsi_sess_state_machine(isp, ISCSI_SESS_EVENT_N6); |
|
1180 mutex_exit(&isp->sess_state_mutex); |
|
1181 |
|
1182 break; |
|
1183 |
|
1184 /* |
|
1185 * -T7: One of the following events caused the transition: |
|
1186 * - Login timed out. |
|
1187 * - A transport disconnect indication was received. |
|
1188 * - A transport reset was received. |
|
1189 * - An internal event indicating a transport timeout was |
|
1190 * received. |
|
1191 * - An internal event of receiving a Logout repsonse (success) |
|
1192 * on another connection for a "close the session" Logout |
|
1193 * request was received. |
|
1194 * * In all these cases, the transport connection is closed. |
|
1195 */ |
|
1196 case ISCSI_CONN_EVENT_T7: |
|
1197 /* |
|
1198 * If session type is NORMAL, create a new login task |
|
1199 * to get this connection reestablished. |
|
1200 */ |
|
1201 if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) { |
|
1202 iscsi_conn_retry(isp, icp); |
|
1203 } else { |
|
1204 icp->conn_state = ISCSI_CONN_STATE_FREE; |
|
1205 } |
|
1206 break; |
|
1207 |
|
1208 /* All other events are invalid for this state */ |
|
1209 default: |
|
1210 ASSERT(FALSE); |
|
1211 } |
|
1212 } |
|
1213 |
|
1214 /* |
|
1215 * iscsi_conn_event_str - converts event enum to a string |
|
1216 */ |
|
1217 static char * |
|
1218 iscsi_conn_event_str(iscsi_conn_event_t event) |
|
1219 { |
|
1220 switch (event) { |
|
1221 case ISCSI_CONN_EVENT_T1: |
|
1222 return ("T1"); |
|
1223 case ISCSI_CONN_EVENT_T5: |
|
1224 return ("T5"); |
|
1225 case ISCSI_CONN_EVENT_T7: |
|
1226 return ("T7"); |
|
1227 case ISCSI_CONN_EVENT_T8: |
|
1228 return ("T8"); |
|
1229 case ISCSI_CONN_EVENT_T9: |
|
1230 return ("T9"); |
|
1231 case ISCSI_CONN_EVENT_T11: |
|
1232 return ("T11"); |
|
1233 case ISCSI_CONN_EVENT_T14: |
|
1234 return ("T14"); |
|
1235 case ISCSI_CONN_EVENT_T15: |
|
1236 return ("T15"); |
|
1237 case ISCSI_CONN_EVENT_T17: |
|
1238 return ("T17"); |
|
1239 case ISCSI_CONN_EVENT_T30: |
|
1240 return ("T30"); |
|
1241 |
|
1242 default: |
|
1243 return ("unknown"); |
|
1244 } |
|
1245 } |
|
1246 |
|
1247 /* |
890 /* |
1248 * iscsi_conn_flush_active_cmds - flush all active icmdps |
891 * iscsi_conn_flush_active_cmds - flush all active icmdps |
1249 * for a connection. |
892 * for a connection. |
1250 */ |
893 */ |
1251 static void |
894 static void |
1345 itp->t_blocking = B_FALSE; |
971 itp->t_blocking = B_FALSE; |
1346 if (ddi_taskq_dispatch(isp->sess_taskq, |
972 if (ddi_taskq_dispatch(isp->sess_taskq, |
1347 (void(*)())iscsi_login_start, itp, DDI_SLEEP) != |
973 (void(*)())iscsi_login_start, itp, DDI_SLEEP) != |
1348 DDI_SUCCESS) { |
974 DDI_SUCCESS) { |
1349 kmem_free(itp, sizeof (iscsi_task_t)); |
975 kmem_free(itp, sizeof (iscsi_task_t)); |
1350 cmn_err(CE_WARN, |
976 cmn_err(CE_WARN, "iscsi connection(%u) failure - " |
1351 "iscsi connection(%u) failure - " |
977 "unable to schedule login task", icp->conn_oid); |
1352 "unable to schedule login task", |
978 |
1353 icp->conn_oid); |
979 iscsi_conn_update_state(icp, ISCSI_CONN_STATE_FREE); |
1354 |
|
1355 icp->conn_state = ISCSI_CONN_STATE_FREE; |
|
1356 mutex_enter(&isp->sess_state_mutex); |
980 mutex_enter(&isp->sess_state_mutex); |
1357 iscsi_sess_state_machine(isp, |
981 iscsi_sess_state_machine(isp, |
1358 ISCSI_SESS_EVENT_N6); |
982 ISCSI_SESS_EVENT_N6); |
1359 mutex_exit(&isp->sess_state_mutex); |
983 mutex_exit(&isp->sess_state_mutex); |
1360 } |
984 } |
1361 } |
985 } |
|
986 |
|
987 void |
|
988 iscsi_conn_update_state(iscsi_conn_t *icp, iscsi_conn_state_t |
|
989 next_state) |
|
990 { |
|
991 mutex_enter(&icp->conn_state_mutex); |
|
992 (void) iscsi_conn_update_state_locked(icp, next_state); |
|
993 mutex_exit(&icp->conn_state_mutex); |
|
994 } |
|
995 |
|
996 void |
|
997 iscsi_conn_update_state_locked(iscsi_conn_t *icp, |
|
998 iscsi_conn_state_t next_state) |
|
999 { |
|
1000 ASSERT(mutex_owned(&icp->conn_state_mutex)); |
|
1001 next_state = (next_state > ISCSI_CONN_STATE_MAX) ? |
|
1002 ISCSI_CONN_STATE_MAX : next_state; |
|
1003 idm_sm_audit_state_change(&icp->conn_state_audit, |
|
1004 SAS_ISCSI_CONN, icp->conn_state, next_state); |
|
1005 switch (next_state) { |
|
1006 case ISCSI_CONN_STATE_FREE: |
|
1007 case ISCSI_CONN_STATE_IN_LOGIN: |
|
1008 case ISCSI_CONN_STATE_LOGGED_IN: |
|
1009 case ISCSI_CONN_STATE_IN_LOGOUT: |
|
1010 case ISCSI_CONN_STATE_FAILED: |
|
1011 case ISCSI_CONN_STATE_POLLING: |
|
1012 ISCSI_CONN_LOG(CE_NOTE, |
|
1013 "iscsi_conn_update_state conn %p %s(%d) -> %s(%d)", |
|
1014 (void *)icp, |
|
1015 iscsi_ics_name[icp->conn_state], icp->conn_state, |
|
1016 iscsi_ics_name[next_state], next_state); |
|
1017 icp->conn_prev_state = icp->conn_state; |
|
1018 icp->conn_state = next_state; |
|
1019 cv_broadcast(&icp->conn_state_change); |
|
1020 break; |
|
1021 default: |
|
1022 cmn_err(CE_WARN, "Update state found illegal state: %x " |
|
1023 "prev_state: %x", next_state, icp->conn_prev_state); |
|
1024 ASSERT(0); |
|
1025 } |
|
1026 } |