diff options
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 |