diff options
-rw-r--r-- | drivers/infiniband/ulp/iser/iser_initiator.c | 4 | ||||
-rw-r--r-- | drivers/scsi/iscsi_tcp.c | 4 | ||||
-rw-r--r-- | drivers/scsi/libiscsi.c | 153 | ||||
-rw-r--r-- | include/scsi/libiscsi.h | 2 | ||||
-rw-r--r-- | include/scsi/scsi_transport_iscsi.h | 1 |
5 files changed, 88 insertions, 76 deletions
diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c index a6f2303ed14a..47f716ca0026 100644 --- a/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/drivers/infiniband/ulp/iser/iser_initiator.c | |||
@@ -621,9 +621,7 @@ void iser_snd_completion(struct iser_desc *tx_desc) | |||
621 | struct iscsi_session *session = conn->session; | 621 | struct iscsi_session *session = conn->session; |
622 | 622 | ||
623 | spin_lock(&conn->session->lock); | 623 | spin_lock(&conn->session->lock); |
624 | list_del(&mtask->running); | 624 | iscsi_free_mgmt_task(conn, mtask); |
625 | __kfifo_put(session->mgmtpool.queue, (void*)&mtask, | ||
626 | sizeof(void*)); | ||
627 | spin_unlock(&session->lock); | 625 | spin_unlock(&session->lock); |
628 | } | 626 | } |
629 | } | 627 | } |
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index f79a457099e6..90eae8e0d978 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c | |||
@@ -1349,9 +1349,7 @@ iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask) | |||
1349 | struct iscsi_session *session = conn->session; | 1349 | struct iscsi_session *session = conn->session; |
1350 | 1350 | ||
1351 | spin_lock_bh(&session->lock); | 1351 | spin_lock_bh(&session->lock); |
1352 | list_del(&conn->mtask->running); | 1352 | iscsi_free_mgmt_task(conn, mtask); |
1353 | __kfifo_put(session->mgmtpool.queue, (void*)&conn->mtask, | ||
1354 | sizeof(void*)); | ||
1355 | spin_unlock_bh(&session->lock); | 1353 | spin_unlock_bh(&session->lock); |
1356 | } | 1354 | } |
1357 | return 0; | 1355 | return 0; |
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index d43f909a022c..b7a2b9ad3a97 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c | |||
@@ -37,9 +37,6 @@ | |||
37 | #include <scsi/scsi_transport_iscsi.h> | 37 | #include <scsi/scsi_transport_iscsi.h> |
38 | #include <scsi/libiscsi.h> | 38 | #include <scsi/libiscsi.h> |
39 | 39 | ||
40 | static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, | ||
41 | int err); | ||
42 | |||
43 | struct iscsi_session * | 40 | struct iscsi_session * |
44 | class_to_transport_session(struct iscsi_cls_session *cls_session) | 41 | class_to_transport_session(struct iscsi_cls_session *cls_session) |
45 | { | 42 | { |
@@ -274,6 +271,53 @@ static void __iscsi_put_ctask(struct iscsi_cmd_task *ctask) | |||
274 | iscsi_complete_command(ctask); | 271 | iscsi_complete_command(ctask); |
275 | } | 272 | } |
276 | 273 | ||
274 | /* | ||
275 | * session lock must be held | ||
276 | */ | ||
277 | static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, | ||
278 | int err) | ||
279 | { | ||
280 | struct scsi_cmnd *sc; | ||
281 | |||
282 | sc = ctask->sc; | ||
283 | if (!sc) | ||
284 | return; | ||
285 | |||
286 | if (ctask->state == ISCSI_TASK_PENDING) | ||
287 | /* | ||
288 | * cmd never made it to the xmit thread, so we should not count | ||
289 | * the cmd in the sequencing | ||
290 | */ | ||
291 | conn->session->queued_cmdsn--; | ||
292 | else | ||
293 | conn->session->tt->cleanup_cmd_task(conn, ctask); | ||
294 | |||
295 | sc->result = err; | ||
296 | scsi_set_resid(sc, scsi_bufflen(sc)); | ||
297 | if (conn->ctask == ctask) | ||
298 | conn->ctask = NULL; | ||
299 | /* release ref from queuecommand */ | ||
300 | __iscsi_put_ctask(ctask); | ||
301 | } | ||
302 | |||
303 | /** | ||
304 | * iscsi_free_mgmt_task - return mgmt task back to pool | ||
305 | * @conn: iscsi connection | ||
306 | * @mtask: mtask | ||
307 | * | ||
308 | * Must be called with session lock. | ||
309 | */ | ||
310 | void iscsi_free_mgmt_task(struct iscsi_conn *conn, | ||
311 | struct iscsi_mgmt_task *mtask) | ||
312 | { | ||
313 | list_del_init(&mtask->running); | ||
314 | if (conn->login_mtask == mtask) | ||
315 | return; | ||
316 | __kfifo_put(conn->session->mgmtpool.queue, | ||
317 | (void*)&mtask, sizeof(void*)); | ||
318 | } | ||
319 | EXPORT_SYMBOL_GPL(iscsi_free_mgmt_task); | ||
320 | |||
277 | /** | 321 | /** |
278 | * iscsi_cmd_rsp - SCSI Command Response processing | 322 | * iscsi_cmd_rsp - SCSI Command Response processing |
279 | * @conn: iscsi connection | 323 | * @conn: iscsi connection |
@@ -464,10 +508,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
464 | */ | 508 | */ |
465 | if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen)) | 509 | if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen)) |
466 | rc = ISCSI_ERR_CONN_FAILED; | 510 | rc = ISCSI_ERR_CONN_FAILED; |
467 | list_del_init(&mtask->running); | 511 | iscsi_free_mgmt_task(conn, mtask); |
468 | if (conn->login_mtask != mtask) | ||
469 | __kfifo_put(session->mgmtpool.queue, | ||
470 | (void*)&mtask, sizeof(void*)); | ||
471 | break; | 512 | break; |
472 | case ISCSI_OP_SCSI_TMFUNC_RSP: | 513 | case ISCSI_OP_SCSI_TMFUNC_RSP: |
473 | if (datalen) { | 514 | if (datalen) { |
@@ -476,6 +517,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
476 | } | 517 | } |
477 | 518 | ||
478 | iscsi_tmf_rsp(conn, hdr); | 519 | iscsi_tmf_rsp(conn, hdr); |
520 | iscsi_free_mgmt_task(conn, mtask); | ||
479 | break; | 521 | break; |
480 | case ISCSI_OP_NOOP_IN: | 522 | case ISCSI_OP_NOOP_IN: |
481 | if (hdr->ttt != cpu_to_be32(ISCSI_RESERVED_TAG) || datalen) { | 523 | if (hdr->ttt != cpu_to_be32(ISCSI_RESERVED_TAG) || datalen) { |
@@ -486,9 +528,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
486 | 528 | ||
487 | if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen)) | 529 | if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen)) |
488 | rc = ISCSI_ERR_CONN_FAILED; | 530 | rc = ISCSI_ERR_CONN_FAILED; |
489 | list_del_init(&mtask->running); | 531 | iscsi_free_mgmt_task(conn, mtask); |
490 | __kfifo_put(session->mgmtpool.queue, | ||
491 | (void*)&mtask, sizeof(void*)); | ||
492 | break; | 532 | break; |
493 | default: | 533 | default: |
494 | rc = ISCSI_ERR_BAD_OPCODE; | 534 | rc = ISCSI_ERR_BAD_OPCODE; |
@@ -650,14 +690,12 @@ static void iscsi_prep_mtask(struct iscsi_conn *conn, | |||
650 | static int iscsi_xmit_mtask(struct iscsi_conn *conn) | 690 | static int iscsi_xmit_mtask(struct iscsi_conn *conn) |
651 | { | 691 | { |
652 | struct iscsi_hdr *hdr = conn->mtask->hdr; | 692 | struct iscsi_hdr *hdr = conn->mtask->hdr; |
653 | int rc, was_logout = 0; | 693 | int rc; |
654 | 694 | ||
695 | if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT) | ||
696 | conn->session->state = ISCSI_STATE_LOGGING_OUT; | ||
655 | spin_unlock_bh(&conn->session->lock); | 697 | spin_unlock_bh(&conn->session->lock); |
656 | if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT) { | 698 | |
657 | conn->session->state = ISCSI_STATE_IN_RECOVERY; | ||
658 | iscsi_block_session(session_to_cls(conn->session)); | ||
659 | was_logout = 1; | ||
660 | } | ||
661 | rc = conn->session->tt->xmit_mgmt_task(conn, conn->mtask); | 699 | rc = conn->session->tt->xmit_mgmt_task(conn, conn->mtask); |
662 | spin_lock_bh(&conn->session->lock); | 700 | spin_lock_bh(&conn->session->lock); |
663 | if (rc) | 701 | if (rc) |
@@ -665,11 +703,6 @@ static int iscsi_xmit_mtask(struct iscsi_conn *conn) | |||
665 | 703 | ||
666 | /* done with this in-progress mtask */ | 704 | /* done with this in-progress mtask */ |
667 | conn->mtask = NULL; | 705 | conn->mtask = NULL; |
668 | |||
669 | if (was_logout) { | ||
670 | set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); | ||
671 | return -ENODATA; | ||
672 | } | ||
673 | return 0; | 706 | return 0; |
674 | } | 707 | } |
675 | 708 | ||
@@ -763,6 +796,12 @@ check_mgmt: | |||
763 | while (!list_empty(&conn->mgmtqueue)) { | 796 | while (!list_empty(&conn->mgmtqueue)) { |
764 | conn->mtask = list_entry(conn->mgmtqueue.next, | 797 | conn->mtask = list_entry(conn->mgmtqueue.next, |
765 | struct iscsi_mgmt_task, running); | 798 | struct iscsi_mgmt_task, running); |
799 | if (conn->session->state == ISCSI_STATE_LOGGING_OUT) { | ||
800 | iscsi_free_mgmt_task(conn, conn->mtask); | ||
801 | conn->mtask = NULL; | ||
802 | continue; | ||
803 | } | ||
804 | |||
766 | iscsi_prep_mtask(conn, conn->mtask); | 805 | iscsi_prep_mtask(conn, conn->mtask); |
767 | list_move_tail(conn->mgmtqueue.next, &conn->mgmt_run_list); | 806 | list_move_tail(conn->mgmtqueue.next, &conn->mgmt_run_list); |
768 | rc = iscsi_xmit_mtask(conn); | 807 | rc = iscsi_xmit_mtask(conn); |
@@ -777,6 +816,10 @@ check_mgmt: | |||
777 | 816 | ||
778 | conn->ctask = list_entry(conn->xmitqueue.next, | 817 | conn->ctask = list_entry(conn->xmitqueue.next, |
779 | struct iscsi_cmd_task, running); | 818 | struct iscsi_cmd_task, running); |
819 | if (conn->session->state == ISCSI_STATE_LOGGING_OUT) { | ||
820 | fail_command(conn, conn->ctask, DID_NO_CONNECT << 16); | ||
821 | continue; | ||
822 | } | ||
780 | if (iscsi_prep_scsi_cmd_pdu(conn->ctask)) { | 823 | if (iscsi_prep_scsi_cmd_pdu(conn->ctask)) { |
781 | fail_command(conn, conn->ctask, DID_ABORT << 16); | 824 | fail_command(conn, conn->ctask, DID_ABORT << 16); |
782 | continue; | 825 | continue; |
@@ -800,6 +843,12 @@ check_mgmt: | |||
800 | if (conn->session->fast_abort && conn->tmf_state != TMF_INITIAL) | 843 | if (conn->session->fast_abort && conn->tmf_state != TMF_INITIAL) |
801 | break; | 844 | break; |
802 | 845 | ||
846 | /* | ||
847 | * we always do fastlogout - conn stop code will clean up. | ||
848 | */ | ||
849 | if (conn->session->state == ISCSI_STATE_LOGGING_OUT) | ||
850 | break; | ||
851 | |||
803 | conn->ctask = list_entry(conn->requeue.next, | 852 | conn->ctask = list_entry(conn->requeue.next, |
804 | struct iscsi_cmd_task, running); | 853 | struct iscsi_cmd_task, running); |
805 | conn->ctask->state = ISCSI_TASK_RUNNING; | 854 | conn->ctask->state = ISCSI_TASK_RUNNING; |
@@ -842,6 +891,7 @@ enum { | |||
842 | FAILURE_SESSION_TERMINATE, | 891 | FAILURE_SESSION_TERMINATE, |
843 | FAILURE_SESSION_IN_RECOVERY, | 892 | FAILURE_SESSION_IN_RECOVERY, |
844 | FAILURE_SESSION_RECOVERY_TIMEOUT, | 893 | FAILURE_SESSION_RECOVERY_TIMEOUT, |
894 | FAILURE_SESSION_LOGGING_OUT, | ||
845 | }; | 895 | }; |
846 | 896 | ||
847 | int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) | 897 | int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) |
@@ -879,12 +929,19 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) | |||
879 | goto reject; | 929 | goto reject; |
880 | } | 930 | } |
881 | 931 | ||
882 | if (session->state == ISCSI_STATE_RECOVERY_FAILED) | 932 | switch (session->state) { |
933 | case ISCSI_STATE_RECOVERY_FAILED: | ||
883 | reason = FAILURE_SESSION_RECOVERY_TIMEOUT; | 934 | reason = FAILURE_SESSION_RECOVERY_TIMEOUT; |
884 | else if (session->state == ISCSI_STATE_TERMINATE) | 935 | break; |
936 | case ISCSI_STATE_TERMINATE: | ||
885 | reason = FAILURE_SESSION_TERMINATE; | 937 | reason = FAILURE_SESSION_TERMINATE; |
886 | else | 938 | break; |
939 | case ISCSI_STATE_LOGGING_OUT: | ||
940 | reason = FAILURE_SESSION_LOGGING_OUT; | ||
941 | break; | ||
942 | default: | ||
887 | reason = FAILURE_SESSION_FREED; | 943 | reason = FAILURE_SESSION_FREED; |
944 | } | ||
888 | goto fault; | 945 | goto fault; |
889 | } | 946 | } |
890 | 947 | ||
@@ -1120,45 +1177,10 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn, | |||
1120 | if (age != session->age || | 1177 | if (age != session->age || |
1121 | session->state != ISCSI_STATE_LOGGED_IN) | 1178 | session->state != ISCSI_STATE_LOGGED_IN) |
1122 | return -ENOTCONN; | 1179 | return -ENOTCONN; |
1123 | |||
1124 | if (!list_empty(&mtask->running)) { | ||
1125 | list_del_init(&mtask->running); | ||
1126 | __kfifo_put(session->mgmtpool.queue, (void*)&mtask, | ||
1127 | sizeof(void*)); | ||
1128 | } | ||
1129 | return 0; | 1180 | return 0; |
1130 | } | 1181 | } |
1131 | 1182 | ||
1132 | /* | 1183 | /* |
1133 | * session lock must be held | ||
1134 | */ | ||
1135 | static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, | ||
1136 | int err) | ||
1137 | { | ||
1138 | struct scsi_cmnd *sc; | ||
1139 | |||
1140 | sc = ctask->sc; | ||
1141 | if (!sc) | ||
1142 | return; | ||
1143 | |||
1144 | if (ctask->state == ISCSI_TASK_PENDING) | ||
1145 | /* | ||
1146 | * cmd never made it to the xmit thread, so we should not count | ||
1147 | * the cmd in the sequencing | ||
1148 | */ | ||
1149 | conn->session->queued_cmdsn--; | ||
1150 | else | ||
1151 | conn->session->tt->cleanup_cmd_task(conn, ctask); | ||
1152 | |||
1153 | sc->result = err; | ||
1154 | scsi_set_resid(sc, scsi_bufflen(sc)); | ||
1155 | if (conn->ctask == ctask) | ||
1156 | conn->ctask = NULL; | ||
1157 | /* release ref from queuecommand */ | ||
1158 | __iscsi_put_ctask(ctask); | ||
1159 | } | ||
1160 | |||
1161 | /* | ||
1162 | * Fail commands. session lock held and recv side suspended and xmit | 1184 | * Fail commands. session lock held and recv side suspended and xmit |
1163 | * thread flushed | 1185 | * thread flushed |
1164 | */ | 1186 | */ |
@@ -1837,22 +1859,13 @@ flush_control_queues(struct iscsi_session *session, struct iscsi_conn *conn) | |||
1837 | /* handle pending */ | 1859 | /* handle pending */ |
1838 | list_for_each_entry_safe(mtask, tmp, &conn->mgmtqueue, running) { | 1860 | list_for_each_entry_safe(mtask, tmp, &conn->mgmtqueue, running) { |
1839 | debug_scsi("flushing pending mgmt task itt 0x%x\n", mtask->itt); | 1861 | debug_scsi("flushing pending mgmt task itt 0x%x\n", mtask->itt); |
1840 | list_del_init(&mtask->running); | 1862 | iscsi_free_mgmt_task(conn, mtask); |
1841 | if (mtask == conn->login_mtask) | ||
1842 | continue; | ||
1843 | __kfifo_put(session->mgmtpool.queue, (void*)&mtask, | ||
1844 | sizeof(void*)); | ||
1845 | } | 1863 | } |
1846 | 1864 | ||
1847 | /* handle running */ | 1865 | /* handle running */ |
1848 | list_for_each_entry_safe(mtask, tmp, &conn->mgmt_run_list, running) { | 1866 | list_for_each_entry_safe(mtask, tmp, &conn->mgmt_run_list, running) { |
1849 | debug_scsi("flushing running mgmt task itt 0x%x\n", mtask->itt); | 1867 | debug_scsi("flushing running mgmt task itt 0x%x\n", mtask->itt); |
1850 | list_del_init(&mtask->running); | 1868 | iscsi_free_mgmt_task(conn, mtask); |
1851 | |||
1852 | if (mtask == conn->login_mtask) | ||
1853 | continue; | ||
1854 | __kfifo_put(session->mgmtpool.queue, (void*)&mtask, | ||
1855 | sizeof(void*)); | ||
1856 | } | 1869 | } |
1857 | 1870 | ||
1858 | conn->mtask = NULL; | 1871 | conn->mtask = NULL; |
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h index 4b3e3c15121a..d68f74523f2e 100644 --- a/include/scsi/libiscsi.h +++ b/include/scsi/libiscsi.h | |||
@@ -346,6 +346,8 @@ extern int __iscsi_complete_pdu(struct iscsi_conn *, struct iscsi_hdr *, | |||
346 | extern int iscsi_verify_itt(struct iscsi_conn *, struct iscsi_hdr *, | 346 | extern int iscsi_verify_itt(struct iscsi_conn *, struct iscsi_hdr *, |
347 | uint32_t *); | 347 | uint32_t *); |
348 | extern void iscsi_requeue_ctask(struct iscsi_cmd_task *ctask); | 348 | extern void iscsi_requeue_ctask(struct iscsi_cmd_task *ctask); |
349 | extern void iscsi_free_mgmt_task(struct iscsi_conn *conn, | ||
350 | struct iscsi_mgmt_task *mtask); | ||
349 | 351 | ||
350 | /* | 352 | /* |
351 | * generic helpers | 353 | * generic helpers |
diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h index 7ff6199cbd55..b8d97bd20f6e 100644 --- a/include/scsi/scsi_transport_iscsi.h +++ b/include/scsi/scsi_transport_iscsi.h | |||
@@ -176,6 +176,7 @@ struct iscsi_cls_conn { | |||
176 | #define ISCSI_STATE_TERMINATE 4 | 176 | #define ISCSI_STATE_TERMINATE 4 |
177 | #define ISCSI_STATE_IN_RECOVERY 5 | 177 | #define ISCSI_STATE_IN_RECOVERY 5 |
178 | #define ISCSI_STATE_RECOVERY_FAILED 6 | 178 | #define ISCSI_STATE_RECOVERY_FAILED 6 |
179 | #define ISCSI_STATE_LOGGING_OUT 7 | ||
179 | 180 | ||
180 | struct iscsi_cls_session { | 181 | struct iscsi_cls_session { |
181 | struct list_head sess_list; /* item in session_list */ | 182 | struct list_head sess_list; /* item in session_list */ |