diff options
author | Mike Christie <michaelc@cs.wisc.edu> | 2006-04-06 22:13:39 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2006-04-14 15:05:09 -0400 |
commit | 30a6c65236f9d26e3325cae468f330b833a3878c (patch) | |
tree | 355519ccc74d4b3984c06d7dcb5852282e47c845 /drivers/scsi/iscsi_tcp.c | |
parent | fd7255f51a13ea915099c7e488001dfbbeb05104 (diff) |
[SCSI] iscsi: fix up iscsi eh
The current iscsi_tcp eh is not nicely setup for dm-multipath
and performs some extra task management functions when they
are not needed.
The attached patch:
- Fixes the TMF issues. If a session is rebuilt
then we do not send aborts.
- Fixes the problem where if the host reset fired, we would
return SUCCESS even though we had not really done anything
yet. This ends up causing problem with scsi_error.c's TUR.
- If someone has turned on the userspace nop daemon code to try
and detect network problems before the scsi command timeout
we can now drop and clean up the session before the scsi command
timesout and fires the eh speeding up the time it takes for a
command to go from one patch to another. For network problems
we fail the command with DID_BUS_BUSY so if failfast is set
scsi_decide_disposition fails the command up to dm for it to
try on another path.
- And we had to add some basic iscsi session block code. Previously
if we were trying to repair a session we would retrun a MLQUEUE code
in the queuecommand. This worked but it was not the most efficient
or pretty thing to do since it would take a while to relogin
to the target. For iscsi_tcp/open-iscsi a lot of the iscsi error handler
is in userspace the block code is pretty bare. We will be
adding to that for qla4xxx.
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/iscsi_tcp.c')
-rw-r--r-- | drivers/scsi/iscsi_tcp.c | 659 |
1 files changed, 395 insertions, 264 deletions
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 6e510f3cfbf6..aca3e23b1b9e 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c | |||
@@ -82,6 +82,9 @@ module_param_named(max_lun, iscsi_max_lun, uint, S_IRUGO); | |||
82 | /* global data */ | 82 | /* global data */ |
83 | static kmem_cache_t *taskcache; | 83 | static kmem_cache_t *taskcache; |
84 | 84 | ||
85 | #define session_to_cls(_sess) \ | ||
86 | hostdata_session(_sess->host->hostdata) | ||
87 | |||
85 | static inline void | 88 | static inline void |
86 | iscsi_buf_init_virt(struct iscsi_buf *ibuf, char *vbuf, int size) | 89 | iscsi_buf_init_virt(struct iscsi_buf *ibuf, char *vbuf, int size) |
87 | { | 90 | { |
@@ -230,17 +233,19 @@ iscsi_hdr_extract(struct iscsi_conn *conn) | |||
230 | return 0; | 233 | return 0; |
231 | } | 234 | } |
232 | 235 | ||
233 | static inline void | 236 | /* |
234 | iscsi_ctask_cleanup(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | 237 | * must be called with session lock |
238 | */ | ||
239 | static void | ||
240 | __iscsi_ctask_cleanup(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | ||
235 | { | 241 | { |
236 | struct scsi_cmnd *sc = ctask->sc; | ||
237 | struct iscsi_session *session = conn->session; | 242 | struct iscsi_session *session = conn->session; |
243 | struct scsi_cmnd *sc; | ||
238 | 244 | ||
239 | spin_lock(&session->lock); | 245 | sc = ctask->sc; |
240 | if (unlikely(!sc)) { | 246 | if (unlikely(!sc)) |
241 | spin_unlock(&session->lock); | ||
242 | return; | 247 | return; |
243 | } | 248 | |
244 | if (sc->sc_data_direction == DMA_TO_DEVICE) { | 249 | if (sc->sc_data_direction == DMA_TO_DEVICE) { |
245 | struct iscsi_data_task *dtask, *n; | 250 | struct iscsi_data_task *dtask, *n; |
246 | /* WRITE: cleanup Data-Out's if any */ | 251 | /* WRITE: cleanup Data-Out's if any */ |
@@ -252,7 +257,20 @@ iscsi_ctask_cleanup(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | |||
252 | ctask->xmstate = XMSTATE_IDLE; | 257 | ctask->xmstate = XMSTATE_IDLE; |
253 | ctask->r2t = NULL; | 258 | ctask->r2t = NULL; |
254 | ctask->sc = NULL; | 259 | ctask->sc = NULL; |
260 | list_del(&ctask->running); | ||
261 | |||
255 | __kfifo_put(session->cmdpool.queue, (void*)&ctask, sizeof(void*)); | 262 | __kfifo_put(session->cmdpool.queue, (void*)&ctask, sizeof(void*)); |
263 | |||
264 | sc->scsi_done(sc); | ||
265 | } | ||
266 | |||
267 | static void | ||
268 | iscsi_ctask_cleanup(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | ||
269 | { | ||
270 | struct iscsi_session *session = conn->session; | ||
271 | |||
272 | spin_lock(&session->lock); | ||
273 | __iscsi_ctask_cleanup(conn, ctask); | ||
256 | spin_unlock(&session->lock); | 274 | spin_unlock(&session->lock); |
257 | } | 275 | } |
258 | 276 | ||
@@ -311,7 +329,6 @@ out: | |||
311 | (long)sc, sc->result, ctask->itt); | 329 | (long)sc, sc->result, ctask->itt); |
312 | conn->scsirsp_pdus_cnt++; | 330 | conn->scsirsp_pdus_cnt++; |
313 | iscsi_ctask_cleanup(conn, ctask); | 331 | iscsi_ctask_cleanup(conn, ctask); |
314 | sc->scsi_done(sc); | ||
315 | return rc; | 332 | return rc; |
316 | } | 333 | } |
317 | 334 | ||
@@ -395,6 +412,7 @@ iscsi_solicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, | |||
395 | 412 | ||
396 | dtask = mempool_alloc(ctask->datapool, GFP_ATOMIC); | 413 | dtask = mempool_alloc(ctask->datapool, GFP_ATOMIC); |
397 | BUG_ON(!dtask); | 414 | BUG_ON(!dtask); |
415 | INIT_LIST_HEAD(&dtask->item); | ||
398 | hdr = &dtask->hdr; | 416 | hdr = &dtask->hdr; |
399 | memset(hdr, 0, sizeof(struct iscsi_data)); | 417 | memset(hdr, 0, sizeof(struct iscsi_data)); |
400 | hdr->ttt = r2t->ttt; | 418 | hdr->ttt = r2t->ttt; |
@@ -710,8 +728,6 @@ iscsi_hdr_recv(struct iscsi_conn *conn) | |||
710 | conn->tmfrsp_pdus_cnt++; | 728 | conn->tmfrsp_pdus_cnt++; |
711 | spin_lock(&session->lock); | 729 | spin_lock(&session->lock); |
712 | if (conn->tmabort_state == TMABORT_INITIAL) { | 730 | if (conn->tmabort_state == TMABORT_INITIAL) { |
713 | __kfifo_put(session->mgmtpool.queue, | ||
714 | (void*)&mtask, sizeof(void*)); | ||
715 | conn->tmabort_state = | 731 | conn->tmabort_state = |
716 | ((struct iscsi_tm_rsp *)hdr)-> | 732 | ((struct iscsi_tm_rsp *)hdr)-> |
717 | response == ISCSI_TMF_RSP_COMPLETE ? | 733 | response == ISCSI_TMF_RSP_COMPLETE ? |
@@ -986,7 +1002,6 @@ done: | |||
986 | (long)sc, sc->result, ctask->itt); | 1002 | (long)sc, sc->result, ctask->itt); |
987 | conn->scsirsp_pdus_cnt++; | 1003 | conn->scsirsp_pdus_cnt++; |
988 | iscsi_ctask_cleanup(conn, ctask); | 1004 | iscsi_ctask_cleanup(conn, ctask); |
989 | sc->scsi_done(sc); | ||
990 | } | 1005 | } |
991 | 1006 | ||
992 | return rc; | 1007 | return rc; |
@@ -1460,6 +1475,7 @@ iscsi_solicit_data_cont(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, | |||
1460 | 1475 | ||
1461 | dtask = mempool_alloc(ctask->datapool, GFP_ATOMIC); | 1476 | dtask = mempool_alloc(ctask->datapool, GFP_ATOMIC); |
1462 | BUG_ON(!dtask); | 1477 | BUG_ON(!dtask); |
1478 | INIT_LIST_HEAD(&dtask->item); | ||
1463 | hdr = &dtask->hdr; | 1479 | hdr = &dtask->hdr; |
1464 | memset(hdr, 0, sizeof(struct iscsi_data)); | 1480 | memset(hdr, 0, sizeof(struct iscsi_data)); |
1465 | hdr->ttt = r2t->ttt; | 1481 | hdr->ttt = r2t->ttt; |
@@ -1506,6 +1522,7 @@ iscsi_unsolicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | |||
1506 | 1522 | ||
1507 | dtask = mempool_alloc(ctask->datapool, GFP_ATOMIC); | 1523 | dtask = mempool_alloc(ctask->datapool, GFP_ATOMIC); |
1508 | BUG_ON(!dtask); | 1524 | BUG_ON(!dtask); |
1525 | INIT_LIST_HEAD(&dtask->item); | ||
1509 | hdr = &dtask->hdr; | 1526 | hdr = &dtask->hdr; |
1510 | memset(hdr, 0, sizeof(struct iscsi_data)); | 1527 | memset(hdr, 0, sizeof(struct iscsi_data)); |
1511 | hdr->ttt = cpu_to_be32(ISCSI_RESERVED_TAG); | 1528 | hdr->ttt = cpu_to_be32(ISCSI_RESERVED_TAG); |
@@ -1550,6 +1567,7 @@ iscsi_cmd_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, | |||
1550 | 1567 | ||
1551 | BUG_ON(__kfifo_len(ctask->r2tqueue)); | 1568 | BUG_ON(__kfifo_len(ctask->r2tqueue)); |
1552 | 1569 | ||
1570 | INIT_LIST_HEAD(&ctask->running); | ||
1553 | ctask->sc = sc; | 1571 | ctask->sc = sc; |
1554 | ctask->conn = conn; | 1572 | ctask->conn = conn; |
1555 | ctask->hdr.opcode = ISCSI_OP_SCSI_CMD; | 1573 | ctask->hdr.opcode = ISCSI_OP_SCSI_CMD; |
@@ -1680,7 +1698,7 @@ iscsi_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask) | |||
1680 | if (mtask->data_count) | 1698 | if (mtask->data_count) |
1681 | mtask->xmstate |= XMSTATE_IMM_DATA; | 1699 | mtask->xmstate |= XMSTATE_IMM_DATA; |
1682 | if (conn->c_stage != ISCSI_CONN_INITIAL_STAGE && | 1700 | if (conn->c_stage != ISCSI_CONN_INITIAL_STAGE && |
1683 | conn->stop_stage != STOP_CONN_RECOVER && | 1701 | conn->stop_stage != STOP_CONN_RECOVER && |
1684 | conn->hdrdgst_en) | 1702 | conn->hdrdgst_en) |
1685 | iscsi_hdr_digest(conn, &mtask->headbuf, | 1703 | iscsi_hdr_digest(conn, &mtask->headbuf, |
1686 | (u8*)mtask->hdrext); | 1704 | (u8*)mtask->hdrext); |
@@ -2226,6 +2244,7 @@ iscsi_data_xmit(struct iscsi_conn *conn) | |||
2226 | /* process command queue */ | 2244 | /* process command queue */ |
2227 | while (__kfifo_get(conn->xmitqueue, (void*)&conn->ctask, | 2245 | while (__kfifo_get(conn->xmitqueue, (void*)&conn->ctask, |
2228 | sizeof(void*))) { | 2246 | sizeof(void*))) { |
2247 | list_add_tail(&conn->ctask->running, &conn->run_list); | ||
2229 | if (iscsi_ctask_xmit(conn, conn->ctask)) | 2248 | if (iscsi_ctask_xmit(conn, conn->ctask)) |
2230 | goto again; | 2249 | goto again; |
2231 | } | 2250 | } |
@@ -2277,11 +2296,14 @@ iscsi_xmitworker(void *data) | |||
2277 | mutex_unlock(&conn->xmitmutex); | 2296 | mutex_unlock(&conn->xmitmutex); |
2278 | } | 2297 | } |
2279 | 2298 | ||
2280 | #define FAILURE_BAD_HOST 1 | 2299 | enum { |
2281 | #define FAILURE_SESSION_FAILED 2 | 2300 | FAILURE_BAD_HOST = 1, |
2282 | #define FAILURE_SESSION_FREED 3 | 2301 | FAILURE_SESSION_FAILED, |
2283 | #define FAILURE_WINDOW_CLOSED 4 | 2302 | FAILURE_SESSION_FREED, |
2284 | #define FAILURE_SESSION_TERMINATE 5 | 2303 | FAILURE_WINDOW_CLOSED, |
2304 | FAILURE_SESSION_TERMINATE, | ||
2305 | FAILURE_SESSION_RECOVERY_TIMEOUT, | ||
2306 | }; | ||
2285 | 2307 | ||
2286 | static int | 2308 | static int |
2287 | iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) | 2309 | iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) |
@@ -2297,12 +2319,14 @@ iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) | |||
2297 | 2319 | ||
2298 | host = sc->device->host; | 2320 | host = sc->device->host; |
2299 | session = iscsi_hostdata(host->hostdata); | 2321 | session = iscsi_hostdata(host->hostdata); |
2300 | BUG_ON(host != session->host); | ||
2301 | 2322 | ||
2302 | spin_lock(&session->lock); | 2323 | spin_lock(&session->lock); |
2303 | 2324 | ||
2304 | if (session->state != ISCSI_STATE_LOGGED_IN) { | 2325 | if (session->state != ISCSI_STATE_LOGGED_IN) { |
2305 | if (session->state == ISCSI_STATE_FAILED) { | 2326 | if (session->recovery_failed) { |
2327 | reason = FAILURE_SESSION_RECOVERY_TIMEOUT; | ||
2328 | goto fault; | ||
2329 | } else if (session->state == ISCSI_STATE_FAILED) { | ||
2306 | reason = FAILURE_SESSION_FAILED; | 2330 | reason = FAILURE_SESSION_FAILED; |
2307 | goto reject; | 2331 | goto reject; |
2308 | } else if (session->state == ISCSI_STATE_TERMINATE) { | 2332 | } else if (session->state == ISCSI_STATE_TERMINATE) { |
@@ -2350,11 +2374,6 @@ fault: | |||
2350 | spin_unlock(&session->lock); | 2374 | spin_unlock(&session->lock); |
2351 | printk(KERN_ERR "iscsi_tcp: cmd 0x%x is not queued (%d)\n", | 2375 | printk(KERN_ERR "iscsi_tcp: cmd 0x%x is not queued (%d)\n", |
2352 | sc->cmnd[0], reason); | 2376 | sc->cmnd[0], reason); |
2353 | sc->sense_buffer[0] = 0x70; | ||
2354 | sc->sense_buffer[2] = NOT_READY; | ||
2355 | sc->sense_buffer[7] = 0x6; | ||
2356 | sc->sense_buffer[12] = 0x08; | ||
2357 | sc->sense_buffer[13] = 0x00; | ||
2358 | sc->result = (DID_NO_CONNECT << 16); | 2377 | sc->result = (DID_NO_CONNECT << 16); |
2359 | sc->resid = sc->request_bufflen; | 2378 | sc->resid = sc->request_bufflen; |
2360 | sc->scsi_done(sc); | 2379 | sc->scsi_done(sc); |
@@ -2445,6 +2464,7 @@ iscsi_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx) | |||
2445 | conn->id = conn_idx; | 2464 | conn->id = conn_idx; |
2446 | conn->exp_statsn = 0; | 2465 | conn->exp_statsn = 0; |
2447 | conn->tmabort_state = TMABORT_INITIAL; | 2466 | conn->tmabort_state = TMABORT_INITIAL; |
2467 | INIT_LIST_HEAD(&conn->run_list); | ||
2448 | 2468 | ||
2449 | /* initial operational parameters */ | 2469 | /* initial operational parameters */ |
2450 | conn->hdr_size = sizeof(struct iscsi_hdr); | 2470 | conn->hdr_size = sizeof(struct iscsi_hdr); |
@@ -2701,6 +2721,22 @@ iscsi_conn_bind(struct iscsi_cls_session *cls_session, | |||
2701 | return 0; | 2721 | return 0; |
2702 | } | 2722 | } |
2703 | 2723 | ||
2724 | static void | ||
2725 | iscsi_session_recovery_timedout(struct iscsi_cls_session *csession) | ||
2726 | { | ||
2727 | struct Scsi_Host *shost = iscsi_session_to_shost(csession); | ||
2728 | struct iscsi_session *session = iscsi_hostdata(shost->hostdata); | ||
2729 | struct iscsi_conn *conn = session->leadconn; | ||
2730 | |||
2731 | spin_lock_bh(&session->lock); | ||
2732 | if (session->state != ISCSI_STATE_LOGGED_IN) { | ||
2733 | session->recovery_failed = 1; | ||
2734 | if (conn) | ||
2735 | wake_up(&conn->ehwait); | ||
2736 | } | ||
2737 | spin_unlock_bh(&session->lock); | ||
2738 | } | ||
2739 | |||
2704 | static int | 2740 | static int |
2705 | iscsi_conn_start(struct iscsi_cls_conn *cls_conn) | 2741 | iscsi_conn_start(struct iscsi_cls_conn *cls_conn) |
2706 | { | 2742 | { |
@@ -2716,7 +2752,6 @@ iscsi_conn_start(struct iscsi_cls_conn *cls_conn) | |||
2716 | } | 2752 | } |
2717 | 2753 | ||
2718 | sk = conn->sock->sk; | 2754 | sk = conn->sock->sk; |
2719 | |||
2720 | write_lock_bh(&sk->sk_callback_lock); | 2755 | write_lock_bh(&sk->sk_callback_lock); |
2721 | spin_lock_bh(&session->lock); | 2756 | spin_lock_bh(&session->lock); |
2722 | conn->c_stage = ISCSI_CONN_STARTED; | 2757 | conn->c_stage = ISCSI_CONN_STARTED; |
@@ -2732,8 +2767,13 @@ iscsi_conn_start(struct iscsi_cls_conn *cls_conn) | |||
2732 | conn->stop_stage = 0; | 2767 | conn->stop_stage = 0; |
2733 | conn->tmabort_state = TMABORT_INITIAL; | 2768 | conn->tmabort_state = TMABORT_INITIAL; |
2734 | session->age++; | 2769 | session->age++; |
2770 | session->recovery_failed = 0; | ||
2771 | spin_unlock_bh(&session->lock); | ||
2772 | write_unlock_bh(&sk->sk_callback_lock); | ||
2773 | |||
2774 | iscsi_unblock_session(session_to_cls(session)); | ||
2735 | wake_up(&conn->ehwait); | 2775 | wake_up(&conn->ehwait); |
2736 | break; | 2776 | return 0; |
2737 | case STOP_CONN_TERM: | 2777 | case STOP_CONN_TERM: |
2738 | session->conn_cnt++; | 2778 | session->conn_cnt++; |
2739 | conn->stop_stage = 0; | 2779 | conn->stop_stage = 0; |
@@ -2752,105 +2792,199 @@ iscsi_conn_start(struct iscsi_cls_conn *cls_conn) | |||
2752 | return 0; | 2792 | return 0; |
2753 | } | 2793 | } |
2754 | 2794 | ||
2755 | static void | 2795 | static int |
2756 | iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) | 2796 | iscsi_ctask_mtask_cleanup(struct iscsi_cmd_task *ctask) |
2757 | { | 2797 | { |
2758 | struct iscsi_conn *conn = cls_conn->dd_data; | 2798 | struct iscsi_conn *conn = ctask->conn; |
2759 | struct iscsi_session *session = conn->session; | 2799 | struct iscsi_session *session = conn->session; |
2800 | struct iscsi_mgmt_task *mtask; | ||
2801 | |||
2802 | if (!ctask->mtask) | ||
2803 | return -EINVAL; | ||
2804 | |||
2805 | while (__kfifo_get(conn->immqueue, (void*)&mtask, sizeof(void*))) { | ||
2806 | if (mtask == ctask->mtask) | ||
2807 | break; | ||
2808 | __kfifo_put(conn->immqueue, (void*)&mtask, sizeof(void*)); | ||
2809 | } | ||
2810 | |||
2811 | __kfifo_put(session->mgmtpool.queue, (void*)&ctask->mtask, | ||
2812 | sizeof(void*)); | ||
2813 | ctask->mtask = NULL; | ||
2814 | return 0; | ||
2815 | } | ||
2816 | |||
2817 | static void | ||
2818 | fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, int err) | ||
2819 | { | ||
2820 | struct iscsi_r2t_info *r2t; | ||
2821 | struct scsi_cmnd *sc; | ||
2822 | |||
2823 | /* flush ctask's r2t queues */ | ||
2824 | while (__kfifo_get(ctask->r2tqueue, (void*)&r2t, sizeof(void*))) | ||
2825 | __kfifo_put(ctask->r2tpool.queue, (void*)&r2t, sizeof(void*)); | ||
2826 | |||
2827 | iscsi_ctask_mtask_cleanup(ctask); | ||
2828 | |||
2829 | sc = ctask->sc; | ||
2830 | if (!sc) | ||
2831 | return; | ||
2832 | |||
2833 | sc->result = err; | ||
2834 | sc->resid = sc->request_bufflen; | ||
2835 | |||
2836 | __iscsi_ctask_cleanup(conn, ctask); | ||
2837 | } | ||
2838 | |||
2839 | /* Fail commands. Mutex and session lock held */ | ||
2840 | static void | ||
2841 | fail_all_commands(struct iscsi_session *session, struct iscsi_conn *conn) | ||
2842 | { | ||
2843 | struct iscsi_cmd_task *ctask, *tmp; | ||
2844 | |||
2845 | /* flush pending */ | ||
2846 | while (__kfifo_get(conn->xmitqueue, (void*)&ctask, sizeof(void*))) { | ||
2847 | debug_scsi("failing pending sc %p itt 0x%x\n", ctask->sc, | ||
2848 | ctask->itt); | ||
2849 | fail_command(conn, ctask, DID_BUS_BUSY << 16); | ||
2850 | } | ||
2851 | |||
2852 | /* fail running */ | ||
2853 | list_for_each_entry_safe(ctask, tmp, &conn->run_list, running) { | ||
2854 | debug_scsi("failing in progress sc %p itt 0x%x\n", | ||
2855 | ctask->sc, ctask->itt); | ||
2856 | fail_command(conn, ctask, DID_BUS_BUSY << 16); | ||
2857 | } | ||
2858 | |||
2859 | conn->ctask = NULL; | ||
2860 | } | ||
2861 | |||
2862 | static void | ||
2863 | flush_control_queues(struct iscsi_session *session, struct iscsi_conn *conn) | ||
2864 | { | ||
2865 | struct iscsi_mgmt_task *mtask; | ||
2866 | |||
2867 | /* TODO: handle running pdus */ | ||
2868 | while (__kfifo_get(conn->immqueue, (void*)&mtask, sizeof(void*)) || | ||
2869 | __kfifo_get(conn->mgmtqueue, (void*)&mtask, sizeof(void*))) { | ||
2870 | if (mtask == conn->login_mtask) | ||
2871 | continue; | ||
2872 | __kfifo_put(session->mgmtpool.queue, (void*)&mtask, | ||
2873 | sizeof(void*)); | ||
2874 | } | ||
2875 | |||
2876 | if (conn->mtask && conn->mtask != conn->login_mtask) | ||
2877 | __kfifo_put(session->mgmtpool.queue, (void*)&conn->mtask, | ||
2878 | sizeof(void*)); | ||
2879 | conn->mtask = NULL; | ||
2880 | } | ||
2881 | |||
2882 | static void | ||
2883 | iscsi_suspend_conn_rx(struct iscsi_conn *conn) | ||
2884 | { | ||
2760 | struct sock *sk; | 2885 | struct sock *sk; |
2761 | unsigned long flags; | ||
2762 | 2886 | ||
2763 | BUG_ON(!conn->sock); | 2887 | BUG_ON(!conn->sock); |
2764 | sk = conn->sock->sk; | 2888 | sk = conn->sock->sk; |
2765 | write_lock_bh(&sk->sk_callback_lock); | 2889 | write_lock_bh(&sk->sk_callback_lock); |
2766 | set_bit(SUSPEND_BIT, &conn->suspend_rx); | 2890 | set_bit(SUSPEND_BIT, &conn->suspend_rx); |
2767 | write_unlock_bh(&sk->sk_callback_lock); | 2891 | write_unlock_bh(&sk->sk_callback_lock); |
2892 | } | ||
2768 | 2893 | ||
2769 | mutex_lock(&conn->xmitmutex); | 2894 | static void |
2770 | 2895 | iscsi_start_session_recovery(struct iscsi_session *session, | |
2771 | spin_lock_irqsave(session->host->host_lock, flags); | 2896 | struct iscsi_conn *conn, int flag) |
2772 | spin_lock(&session->lock); | 2897 | { |
2898 | spin_lock_bh(&session->lock); | ||
2899 | if (conn->stop_stage == STOP_CONN_RECOVER || | ||
2900 | conn->stop_stage == STOP_CONN_TERM) { | ||
2901 | spin_unlock_bh(&session->lock); | ||
2902 | return; | ||
2903 | } | ||
2773 | conn->stop_stage = flag; | 2904 | conn->stop_stage = flag; |
2905 | spin_unlock_bh(&session->lock); | ||
2906 | |||
2907 | iscsi_suspend_conn_rx(conn); | ||
2908 | |||
2909 | mutex_lock(&conn->xmitmutex); | ||
2910 | spin_lock_bh(&session->lock); | ||
2774 | conn->c_stage = ISCSI_CONN_STOPPED; | 2911 | conn->c_stage = ISCSI_CONN_STOPPED; |
2775 | set_bit(SUSPEND_BIT, &conn->suspend_tx); | 2912 | set_bit(SUSPEND_BIT, &conn->suspend_tx); |
2776 | 2913 | ||
2777 | if (flag != STOP_CONN_SUSPEND) | 2914 | session->conn_cnt--; |
2778 | session->conn_cnt--; | ||
2779 | |||
2780 | if (session->conn_cnt == 0 || session->leadconn == conn) | 2915 | if (session->conn_cnt == 0 || session->leadconn == conn) |
2781 | session->state = ISCSI_STATE_FAILED; | 2916 | session->state = ISCSI_STATE_FAILED; |
2782 | 2917 | ||
2783 | spin_unlock(&session->lock); | 2918 | spin_unlock_bh(&session->lock); |
2784 | spin_unlock_irqrestore(session->host->host_lock, flags); | ||
2785 | |||
2786 | if (flag == STOP_CONN_TERM || flag == STOP_CONN_RECOVER) { | ||
2787 | struct iscsi_cmd_task *ctask; | ||
2788 | struct iscsi_mgmt_task *mtask; | ||
2789 | 2919 | ||
2790 | /* | 2920 | /* |
2791 | * Socket must go now. | 2921 | * Socket must go now. |
2792 | */ | 2922 | */ |
2793 | sock_hold(conn->sock->sk); | 2923 | sock_hold(conn->sock->sk); |
2794 | iscsi_conn_restore_callbacks(conn); | 2924 | iscsi_conn_restore_callbacks(conn); |
2795 | sock_put(conn->sock->sk); | 2925 | sock_put(conn->sock->sk); |
2796 | 2926 | ||
2797 | /* | 2927 | /* |
2798 | * flush xmit queues. | 2928 | * flush queues. |
2799 | */ | 2929 | */ |
2800 | spin_lock_bh(&session->lock); | 2930 | spin_lock_bh(&session->lock); |
2801 | while (__kfifo_get(conn->writequeue, (void*)&ctask, | 2931 | fail_all_commands(session, conn); |
2802 | sizeof(void*)) || | 2932 | flush_control_queues(session, conn); |
2803 | __kfifo_get(conn->xmitqueue, (void*)&ctask, | 2933 | spin_unlock_bh(&session->lock); |
2804 | sizeof(void*))) { | ||
2805 | struct iscsi_r2t_info *r2t; | ||
2806 | |||
2807 | /* | ||
2808 | * flush ctask's r2t queues | ||
2809 | */ | ||
2810 | while (__kfifo_get(ctask->r2tqueue, (void*)&r2t, | ||
2811 | sizeof(void*))) | ||
2812 | __kfifo_put(ctask->r2tpool.queue, (void*)&r2t, | ||
2813 | sizeof(void*)); | ||
2814 | 2934 | ||
2815 | spin_unlock_bh(&session->lock); | 2935 | /* |
2816 | local_bh_disable(); | 2936 | * release socket only after we stopped data_xmit() |
2817 | iscsi_ctask_cleanup(conn, ctask); | 2937 | * activity and flushed all outstandings |
2818 | local_bh_enable(); | 2938 | */ |
2819 | spin_lock_bh(&session->lock); | 2939 | sock_release(conn->sock); |
2820 | } | 2940 | conn->sock = NULL; |
2821 | conn->ctask = NULL; | ||
2822 | while (__kfifo_get(conn->immqueue, (void*)&mtask, | ||
2823 | sizeof(void*)) || | ||
2824 | __kfifo_get(conn->mgmtqueue, (void*)&mtask, | ||
2825 | sizeof(void*))) { | ||
2826 | __kfifo_put(session->mgmtpool.queue, | ||
2827 | (void*)&mtask, sizeof(void*)); | ||
2828 | } | ||
2829 | conn->mtask = NULL; | ||
2830 | spin_unlock_bh(&session->lock); | ||
2831 | 2941 | ||
2832 | /* | 2942 | /* |
2833 | * release socket only after we stopped data_xmit() | 2943 | * for connection level recovery we should not calculate |
2834 | * activity and flushed all outstandings | 2944 | * header digest. conn->hdr_size used for optimization |
2835 | */ | 2945 | * in hdr_extract() and will be re-negotiated at |
2836 | sock_release(conn->sock); | 2946 | * set_param() time. |
2837 | conn->sock = NULL; | 2947 | */ |
2948 | if (flag == STOP_CONN_RECOVER) { | ||
2949 | conn->hdr_size = sizeof(struct iscsi_hdr); | ||
2950 | conn->hdrdgst_en = 0; | ||
2951 | conn->datadgst_en = 0; | ||
2838 | 2952 | ||
2839 | /* | 2953 | if (session->state == ISCSI_STATE_FAILED) |
2840 | * for connection level recovery we should not calculate | 2954 | iscsi_block_session(session_to_cls(session)); |
2841 | * header digest. conn->hdr_size used for optimization | ||
2842 | * in hdr_extract() and will be re-negotiated at | ||
2843 | * set_param() time. | ||
2844 | */ | ||
2845 | if (flag == STOP_CONN_RECOVER) { | ||
2846 | conn->hdr_size = sizeof(struct iscsi_hdr); | ||
2847 | conn->hdrdgst_en = 0; | ||
2848 | conn->datadgst_en = 0; | ||
2849 | } | ||
2850 | } | 2955 | } |
2851 | mutex_unlock(&conn->xmitmutex); | 2956 | mutex_unlock(&conn->xmitmutex); |
2852 | } | 2957 | } |
2853 | 2958 | ||
2959 | static void | ||
2960 | iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) | ||
2961 | { | ||
2962 | struct iscsi_conn *conn = cls_conn->dd_data; | ||
2963 | struct iscsi_session *session = conn->session; | ||
2964 | |||
2965 | switch (flag) { | ||
2966 | case STOP_CONN_RECOVER: | ||
2967 | case STOP_CONN_TERM: | ||
2968 | iscsi_start_session_recovery(session, conn, flag); | ||
2969 | return; | ||
2970 | case STOP_CONN_SUSPEND: | ||
2971 | iscsi_suspend_conn_rx(conn); | ||
2972 | |||
2973 | mutex_lock(&conn->xmitmutex); | ||
2974 | spin_lock_bh(&session->lock); | ||
2975 | |||
2976 | conn->stop_stage = flag; | ||
2977 | conn->c_stage = ISCSI_CONN_STOPPED; | ||
2978 | set_bit(SUSPEND_BIT, &conn->suspend_tx); | ||
2979 | |||
2980 | spin_unlock_bh(&session->lock); | ||
2981 | mutex_unlock(&conn->xmitmutex); | ||
2982 | break; | ||
2983 | default: | ||
2984 | printk(KERN_ERR "invalid stop flag %d\n", flag); | ||
2985 | } | ||
2986 | } | ||
2987 | |||
2854 | static int | 2988 | static int |
2855 | iscsi_conn_send_generic(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | 2989 | iscsi_conn_send_generic(struct iscsi_conn *conn, struct iscsi_hdr *hdr, |
2856 | char *data, uint32_t data_size) | 2990 | char *data, uint32_t data_size) |
@@ -2940,23 +3074,54 @@ iscsi_conn_send_generic(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
2940 | static int | 3074 | static int |
2941 | iscsi_eh_host_reset(struct scsi_cmnd *sc) | 3075 | iscsi_eh_host_reset(struct scsi_cmnd *sc) |
2942 | { | 3076 | { |
2943 | struct iscsi_cmd_task *ctask = (struct iscsi_cmd_task *)sc->SCp.ptr; | 3077 | struct Scsi_Host *host = sc->device->host; |
2944 | struct iscsi_conn *conn = ctask->conn; | 3078 | struct iscsi_session *session = iscsi_hostdata(host->hostdata); |
2945 | struct iscsi_session *session = conn->session; | 3079 | struct iscsi_conn *conn = session->leadconn; |
3080 | int fail_session = 0; | ||
2946 | 3081 | ||
2947 | spin_lock_bh(&session->lock); | 3082 | spin_lock_bh(&session->lock); |
2948 | if (session->state == ISCSI_STATE_TERMINATE) { | 3083 | if (session->state == ISCSI_STATE_TERMINATE) { |
3084 | failed: | ||
2949 | debug_scsi("failing host reset: session terminated " | 3085 | debug_scsi("failing host reset: session terminated " |
2950 | "[CID %d age %d]", conn->id, session->age); | 3086 | "[CID %d age %d]", conn->id, session->age); |
2951 | spin_unlock_bh(&session->lock); | 3087 | spin_unlock_bh(&session->lock); |
2952 | return FAILED; | 3088 | return FAILED; |
2953 | } | 3089 | } |
3090 | |||
3091 | if (sc->SCp.phase == session->age) { | ||
3092 | debug_scsi("failing connection CID %d due to SCSI host reset", | ||
3093 | conn->id); | ||
3094 | fail_session = 1; | ||
3095 | } | ||
2954 | spin_unlock_bh(&session->lock); | 3096 | spin_unlock_bh(&session->lock); |
2955 | 3097 | ||
2956 | debug_scsi("failing connection CID %d due to SCSI host reset " | 3098 | /* |
2957 | "[itt 0x%x age %d]", conn->id, ctask->itt, | 3099 | * we drop the lock here but the leadconn cannot be destoyed while |
2958 | session->age); | 3100 | * we are in the scsi eh |
2959 | iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); | 3101 | */ |
3102 | if (fail_session) { | ||
3103 | iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); | ||
3104 | /* | ||
3105 | * if userspace cannot respond then we must kick this off | ||
3106 | * here for it | ||
3107 | */ | ||
3108 | iscsi_start_session_recovery(session, conn, STOP_CONN_RECOVER); | ||
3109 | } | ||
3110 | |||
3111 | debug_scsi("iscsi_eh_host_reset wait for relogin\n"); | ||
3112 | wait_event_interruptible(conn->ehwait, | ||
3113 | session->state == ISCSI_STATE_TERMINATE || | ||
3114 | session->state == ISCSI_STATE_LOGGED_IN || | ||
3115 | session->recovery_failed); | ||
3116 | if (signal_pending(current)) | ||
3117 | flush_signals(current); | ||
3118 | |||
3119 | spin_lock_bh(&session->lock); | ||
3120 | if (session->state == ISCSI_STATE_LOGGED_IN) | ||
3121 | printk(KERN_INFO "host reset succeeded\n"); | ||
3122 | else | ||
3123 | goto failed; | ||
3124 | spin_unlock_bh(&session->lock); | ||
2960 | 3125 | ||
2961 | return SUCCESS; | 3126 | return SUCCESS; |
2962 | } | 3127 | } |
@@ -2970,8 +3135,6 @@ iscsi_tmabort_timedout(unsigned long data) | |||
2970 | 3135 | ||
2971 | spin_lock(&session->lock); | 3136 | spin_lock(&session->lock); |
2972 | if (conn->tmabort_state == TMABORT_INITIAL) { | 3137 | if (conn->tmabort_state == TMABORT_INITIAL) { |
2973 | __kfifo_put(session->mgmtpool.queue, | ||
2974 | (void*)&ctask->mtask, sizeof(void*)); | ||
2975 | conn->tmabort_state = TMABORT_TIMEDOUT; | 3138 | conn->tmabort_state = TMABORT_TIMEDOUT; |
2976 | debug_scsi("tmabort timedout [sc %lx itt 0x%x]\n", | 3139 | debug_scsi("tmabort timedout [sc %lx itt 0x%x]\n", |
2977 | (long)ctask->sc, ctask->itt); | 3140 | (long)ctask->sc, ctask->itt); |
@@ -2981,186 +3144,163 @@ iscsi_tmabort_timedout(unsigned long data) | |||
2981 | spin_unlock(&session->lock); | 3144 | spin_unlock(&session->lock); |
2982 | } | 3145 | } |
2983 | 3146 | ||
3147 | /* must be called with the mutex lock */ | ||
2984 | static int | 3148 | static int |
2985 | iscsi_eh_abort(struct scsi_cmnd *sc) | 3149 | iscsi_exec_abort_task(struct scsi_cmnd *sc, struct iscsi_cmd_task *ctask) |
2986 | { | 3150 | { |
2987 | int rc; | ||
2988 | struct iscsi_cmd_task *ctask = (struct iscsi_cmd_task *)sc->SCp.ptr; | ||
2989 | struct iscsi_conn *conn = ctask->conn; | 3151 | struct iscsi_conn *conn = ctask->conn; |
2990 | struct iscsi_session *session = conn->session; | 3152 | struct iscsi_session *session = conn->session; |
2991 | 3153 | struct iscsi_tm *hdr = &conn->tmhdr; | |
2992 | conn->eh_abort_cnt++; | 3154 | int rc; |
2993 | debug_scsi("aborting [sc %lx itt 0x%x]\n", (long)sc, ctask->itt); | ||
2994 | 3155 | ||
2995 | /* | 3156 | /* |
2996 | * two cases for ERL=0 here: | 3157 | * ctask timed out but session is OK requests must be serialized. |
2997 | * | ||
2998 | * 1) connection-level failure; | ||
2999 | * 2) recovery due protocol error; | ||
3000 | */ | 3158 | */ |
3001 | mutex_lock(&conn->xmitmutex); | 3159 | memset(hdr, 0, sizeof(struct iscsi_tm)); |
3002 | spin_lock_bh(&session->lock); | 3160 | hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE; |
3003 | if (session->state != ISCSI_STATE_LOGGED_IN) { | 3161 | hdr->flags = ISCSI_TM_FUNC_ABORT_TASK; |
3004 | if (session->state == ISCSI_STATE_TERMINATE) { | 3162 | hdr->flags |= ISCSI_FLAG_CMD_FINAL; |
3005 | spin_unlock_bh(&session->lock); | 3163 | memcpy(hdr->lun, ctask->hdr.lun, sizeof(hdr->lun)); |
3006 | mutex_unlock(&conn->xmitmutex); | 3164 | hdr->rtt = ctask->hdr.itt; |
3007 | goto failed; | 3165 | hdr->refcmdsn = ctask->hdr.cmdsn; |
3008 | } | ||
3009 | spin_unlock_bh(&session->lock); | ||
3010 | } else { | ||
3011 | struct iscsi_tm *hdr = &conn->tmhdr; | ||
3012 | 3166 | ||
3013 | /* | 3167 | rc = iscsi_conn_send_generic(conn, (struct iscsi_hdr *)hdr, |
3014 | * Still LOGGED_IN... | 3168 | NULL, 0); |
3015 | */ | 3169 | if (rc) { |
3170 | iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); | ||
3171 | debug_scsi("abort sent failure [itt 0x%x] %d", ctask->itt, rc); | ||
3172 | return rc; | ||
3173 | } | ||
3016 | 3174 | ||
3017 | if (!ctask->sc || sc->SCp.phase != session->age) { | 3175 | debug_scsi("abort sent [itt 0x%x]\n", ctask->itt); |
3018 | /* | ||
3019 | * 1) ctask completed before time out. But session | ||
3020 | * is still ok => Happy Retry. | ||
3021 | * 2) session was re-open during time out of ctask. | ||
3022 | */ | ||
3023 | spin_unlock_bh(&session->lock); | ||
3024 | mutex_unlock(&conn->xmitmutex); | ||
3025 | goto success; | ||
3026 | } | ||
3027 | conn->tmabort_state = TMABORT_INITIAL; | ||
3028 | spin_unlock_bh(&session->lock); | ||
3029 | 3176 | ||
3030 | /* | 3177 | spin_lock_bh(&session->lock); |
3031 | * ctask timed out but session is OK | 3178 | ctask->mtask = (struct iscsi_mgmt_task *) |
3032 | * ERL=0 requires task mgmt abort to be issued on each | 3179 | session->mgmt_cmds[(hdr->itt & ITT_MASK) - |
3033 | * failed command. requests must be serialized. | 3180 | ISCSI_MGMT_ITT_OFFSET]; |
3034 | */ | 3181 | |
3035 | memset(hdr, 0, sizeof(struct iscsi_tm)); | 3182 | if (conn->tmabort_state == TMABORT_INITIAL) { |
3036 | hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE; | 3183 | conn->tmfcmd_pdus_cnt++; |
3037 | hdr->flags = ISCSI_TM_FUNC_ABORT_TASK; | 3184 | conn->tmabort_timer.expires = 10*HZ + jiffies; |
3038 | hdr->flags |= ISCSI_FLAG_CMD_FINAL; | 3185 | conn->tmabort_timer.function = iscsi_tmabort_timedout; |
3039 | memcpy(hdr->lun, ctask->hdr.lun, sizeof(hdr->lun)); | 3186 | conn->tmabort_timer.data = (unsigned long)ctask; |
3040 | hdr->rtt = ctask->hdr.itt; | 3187 | add_timer(&conn->tmabort_timer); |
3041 | hdr->refcmdsn = ctask->hdr.cmdsn; | 3188 | debug_scsi("abort set timeout [itt 0x%x]", ctask->itt); |
3042 | |||
3043 | rc = iscsi_conn_send_generic(conn, (struct iscsi_hdr *)hdr, | ||
3044 | NULL, 0); | ||
3045 | if (rc) { | ||
3046 | iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); | ||
3047 | debug_scsi("abort sent failure [itt 0x%x]", ctask->itt); | ||
3048 | } else { | ||
3049 | struct iscsi_r2t_info *r2t; | ||
3050 | |||
3051 | /* | ||
3052 | * TMF abort vs. TMF response race logic | ||
3053 | */ | ||
3054 | spin_lock_bh(&session->lock); | ||
3055 | ctask->mtask = (struct iscsi_mgmt_task *) | ||
3056 | session->mgmt_cmds[(hdr->itt & ITT_MASK) - | ||
3057 | ISCSI_MGMT_ITT_OFFSET]; | ||
3058 | /* | ||
3059 | * have to flush r2tqueue to avoid r2t leaks | ||
3060 | */ | ||
3061 | while (__kfifo_get(ctask->r2tqueue, (void*)&r2t, | ||
3062 | sizeof(void*))) { | ||
3063 | __kfifo_put(ctask->r2tpool.queue, (void*)&r2t, | ||
3064 | sizeof(void*)); | ||
3065 | } | ||
3066 | if (conn->tmabort_state == TMABORT_INITIAL) { | ||
3067 | conn->tmfcmd_pdus_cnt++; | ||
3068 | conn->tmabort_timer.expires = 3*HZ + jiffies; | ||
3069 | conn->tmabort_timer.function = | ||
3070 | iscsi_tmabort_timedout; | ||
3071 | conn->tmabort_timer.data = (unsigned long)ctask; | ||
3072 | add_timer(&conn->tmabort_timer); | ||
3073 | debug_scsi("abort sent [itt 0x%x]", ctask->itt); | ||
3074 | } else { | ||
3075 | if (!ctask->sc || | ||
3076 | conn->tmabort_state == TMABORT_SUCCESS) { | ||
3077 | conn->tmabort_state = TMABORT_INITIAL; | ||
3078 | spin_unlock_bh(&session->lock); | ||
3079 | mutex_unlock(&conn->xmitmutex); | ||
3080 | goto success; | ||
3081 | } | ||
3082 | conn->tmabort_state = TMABORT_INITIAL; | ||
3083 | iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); | ||
3084 | } | ||
3085 | spin_unlock_bh(&session->lock); | ||
3086 | } | ||
3087 | } | 3189 | } |
3190 | spin_unlock_bh(&session->lock); | ||
3088 | mutex_unlock(&conn->xmitmutex); | 3191 | mutex_unlock(&conn->xmitmutex); |
3089 | 3192 | ||
3090 | |||
3091 | /* | 3193 | /* |
3092 | * block eh thread until: | 3194 | * block eh thread until: |
3093 | * | 3195 | * |
3094 | * 1) abort response; | 3196 | * 1) abort response |
3095 | * 2) abort timeout; | 3197 | * 2) abort timeout |
3096 | * 3) session re-opened; | 3198 | * 3) session is terminated or restarted or userspace has |
3097 | * 4) session terminated; | 3199 | * given up on recovery |
3098 | */ | 3200 | */ |
3099 | for (;;) { | 3201 | wait_event_interruptible(conn->ehwait, |
3100 | int p_state = session->state; | 3202 | sc->SCp.phase != session->age || |
3101 | 3203 | session->state != ISCSI_STATE_LOGGED_IN || | |
3102 | rc = wait_event_interruptible(conn->ehwait, | 3204 | conn->tmabort_state != TMABORT_INITIAL || |
3103 | (p_state == ISCSI_STATE_LOGGED_IN ? | 3205 | session->recovery_failed); |
3104 | (session->state == ISCSI_STATE_TERMINATE || | 3206 | if (signal_pending(current)) |
3105 | conn->tmabort_state != TMABORT_INITIAL) : | 3207 | flush_signals(current); |
3106 | (session->state == ISCSI_STATE_TERMINATE || | 3208 | del_timer_sync(&conn->tmabort_timer); |
3107 | session->state == ISCSI_STATE_LOGGED_IN))); | ||
3108 | if (rc) { | ||
3109 | /* shutdown.. */ | ||
3110 | session->state = ISCSI_STATE_TERMINATE; | ||
3111 | goto failed; | ||
3112 | } | ||
3113 | 3209 | ||
3114 | if (signal_pending(current)) | 3210 | mutex_lock(&conn->xmitmutex); |
3115 | flush_signals(current); | 3211 | return 0; |
3212 | } | ||
3116 | 3213 | ||
3117 | if (session->state == ISCSI_STATE_TERMINATE) | 3214 | static int |
3118 | goto failed; | 3215 | iscsi_eh_abort(struct scsi_cmnd *sc) |
3216 | { | ||
3217 | struct iscsi_cmd_task *ctask = (struct iscsi_cmd_task *)sc->SCp.ptr; | ||
3218 | struct iscsi_cmd_task *tmp_ctask; | ||
3219 | struct iscsi_conn *conn = ctask->conn; | ||
3220 | struct iscsi_session *session = conn->session; | ||
3221 | int rc; | ||
3119 | 3222 | ||
3120 | spin_lock_bh(&session->lock); | 3223 | conn->eh_abort_cnt++; |
3121 | if (sc->SCp.phase == session->age && | 3224 | debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt); |
3122 | (conn->tmabort_state == TMABORT_TIMEDOUT || | 3225 | |
3123 | conn->tmabort_state == TMABORT_FAILED)) { | 3226 | mutex_lock(&conn->xmitmutex); |
3124 | conn->tmabort_state = TMABORT_INITIAL; | 3227 | spin_lock_bh(&session->lock); |
3125 | if (!ctask->sc) { | 3228 | |
3126 | /* | 3229 | /* |
3127 | * ctask completed before tmf abort response or | 3230 | * If we are not logged in or we have started a new session |
3128 | * time out. | 3231 | * then let the host reset code handle this |
3129 | * But session is still ok => Happy Retry. | 3232 | */ |
3130 | */ | 3233 | if (session->state != ISCSI_STATE_LOGGED_IN || |
3131 | spin_unlock_bh(&session->lock); | 3234 | sc->SCp.phase != session->age) |
3132 | break; | 3235 | goto failed; |
3133 | } | 3236 | |
3134 | spin_unlock_bh(&session->lock); | 3237 | /* ctask completed before time out */ |
3135 | iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); | 3238 | if (!ctask->sc) |
3136 | continue; | 3239 | goto success; |
3240 | |||
3241 | /* what should we do here ? */ | ||
3242 | if (conn->ctask == ctask) { | ||
3243 | printk(KERN_INFO "sc %p itt 0x%x partially sent. Failing " | ||
3244 | "abort\n", sc, ctask->itt); | ||
3245 | goto failed; | ||
3246 | } | ||
3247 | |||
3248 | /* check for the easy pending cmd abort */ | ||
3249 | while (__kfifo_get(conn->xmitqueue, (void*)&tmp_ctask, sizeof(void*))) { | ||
3250 | if (tmp_ctask->itt == ctask->itt) { | ||
3251 | debug_scsi("found pending task\n"); | ||
3252 | goto success; | ||
3137 | } | 3253 | } |
3254 | __kfifo_put(conn->xmitqueue, (void*)&tmp_ctask, sizeof(void*)); | ||
3255 | } | ||
3256 | |||
3257 | conn->tmabort_state = TMABORT_INITIAL; | ||
3258 | |||
3259 | spin_unlock_bh(&session->lock); | ||
3260 | rc = iscsi_exec_abort_task(sc, ctask); | ||
3261 | spin_lock_bh(&session->lock); | ||
3262 | |||
3263 | iscsi_ctask_mtask_cleanup(ctask); | ||
3264 | if (rc || sc->SCp.phase != session->age || | ||
3265 | session->state != ISCSI_STATE_LOGGED_IN) | ||
3266 | goto failed; | ||
3267 | |||
3268 | /* ctask completed before tmf abort response */ | ||
3269 | if (!ctask->sc) { | ||
3270 | debug_scsi("sc completed while abort in progress\n"); | ||
3271 | goto success; | ||
3272 | } | ||
3273 | |||
3274 | if (conn->tmabort_state != TMABORT_SUCCESS) { | ||
3138 | spin_unlock_bh(&session->lock); | 3275 | spin_unlock_bh(&session->lock); |
3139 | break; | 3276 | iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); |
3277 | spin_lock_bh(&session->lock); | ||
3278 | goto failed; | ||
3140 | } | 3279 | } |
3141 | 3280 | ||
3142 | success: | 3281 | success: |
3143 | debug_scsi("abort success [sc %lx itt 0x%x]\n", (long)sc, ctask->itt); | 3282 | debug_scsi("abort success [sc %lx itt 0x%x]\n", (long)sc, ctask->itt); |
3144 | rc = SUCCESS; | 3283 | spin_unlock_bh(&session->lock); |
3145 | goto exit; | ||
3146 | |||
3147 | failed: | ||
3148 | debug_scsi("abort failed [sc %lx itt 0x%x]\n", (long)sc, ctask->itt); | ||
3149 | rc = FAILED; | ||
3150 | |||
3151 | exit: | ||
3152 | del_timer_sync(&conn->tmabort_timer); | ||
3153 | 3284 | ||
3154 | mutex_lock(&conn->xmitmutex); | 3285 | /* clean up task if aborted */ |
3155 | if (conn->sock) { | 3286 | if (conn->sock) { |
3156 | struct sock *sk = conn->sock->sk; | 3287 | struct sock *sk = conn->sock->sk; |
3157 | 3288 | ||
3158 | write_lock_bh(&sk->sk_callback_lock); | 3289 | write_lock_bh(&sk->sk_callback_lock); |
3159 | iscsi_ctask_cleanup(conn, ctask); | 3290 | spin_lock(&session->lock); |
3291 | fail_command(conn, ctask, DRIVER_TIMEOUT << 24); | ||
3292 | spin_unlock(&session->lock); | ||
3160 | write_unlock_bh(&sk->sk_callback_lock); | 3293 | write_unlock_bh(&sk->sk_callback_lock); |
3161 | } | 3294 | } |
3162 | mutex_unlock(&conn->xmitmutex); | 3295 | mutex_unlock(&conn->xmitmutex); |
3163 | return rc; | 3296 | return SUCCESS; |
3297 | |||
3298 | failed: | ||
3299 | spin_unlock_bh(&session->lock); | ||
3300 | mutex_unlock(&conn->xmitmutex); | ||
3301 | |||
3302 | debug_scsi("abort failed [sc %lx itt 0x%x]\n", (long)sc, ctask->itt); | ||
3303 | return FAILED; | ||
3164 | } | 3304 | } |
3165 | 3305 | ||
3166 | static int | 3306 | static int |
@@ -3359,16 +3499,6 @@ iscsi_conn_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param, | |||
3359 | struct iscsi_conn *conn = cls_conn->dd_data; | 3499 | struct iscsi_conn *conn = cls_conn->dd_data; |
3360 | struct iscsi_session *session = conn->session; | 3500 | struct iscsi_session *session = conn->session; |
3361 | 3501 | ||
3362 | spin_lock_bh(&session->lock); | ||
3363 | if (conn->c_stage != ISCSI_CONN_INITIAL_STAGE && | ||
3364 | conn->stop_stage != STOP_CONN_RECOVER) { | ||
3365 | printk(KERN_ERR "iscsi_tcp: can not change parameter [%d]\n", | ||
3366 | param); | ||
3367 | spin_unlock_bh(&session->lock); | ||
3368 | return 0; | ||
3369 | } | ||
3370 | spin_unlock_bh(&session->lock); | ||
3371 | |||
3372 | switch(param) { | 3502 | switch(param) { |
3373 | case ISCSI_PARAM_MAX_RECV_DLENGTH: { | 3503 | case ISCSI_PARAM_MAX_RECV_DLENGTH: { |
3374 | char *saveptr = conn->data; | 3504 | char *saveptr = conn->data; |
@@ -3691,6 +3821,7 @@ static struct iscsi_transport iscsi_tcp_transport = { | |||
3691 | .stop_conn = iscsi_conn_stop, | 3821 | .stop_conn = iscsi_conn_stop, |
3692 | .send_pdu = iscsi_conn_send_pdu, | 3822 | .send_pdu = iscsi_conn_send_pdu, |
3693 | .get_stats = iscsi_conn_get_stats, | 3823 | .get_stats = iscsi_conn_get_stats, |
3824 | .session_recovery_timedout = iscsi_session_recovery_timedout, | ||
3694 | }; | 3825 | }; |
3695 | 3826 | ||
3696 | static int __init | 3827 | static int __init |