diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/infiniband/ulp/iser/iscsi_iser.c | 18 | ||||
-rw-r--r-- | drivers/scsi/iscsi_tcp.c | 33 | ||||
-rw-r--r-- | drivers/scsi/libiscsi.c | 491 |
3 files changed, 247 insertions, 295 deletions
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index 6c8cd09c58f0..9782190a9ee5 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c | |||
@@ -134,19 +134,9 @@ iscsi_iser_cmd_init(struct iscsi_cmd_task *ctask) | |||
134 | { | 134 | { |
135 | struct iscsi_iser_conn *iser_conn = ctask->conn->dd_data; | 135 | struct iscsi_iser_conn *iser_conn = ctask->conn->dd_data; |
136 | struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data; | 136 | struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data; |
137 | struct scsi_cmnd *sc = ctask->sc; | ||
138 | 137 | ||
139 | iser_ctask->command_sent = 0; | 138 | iser_ctask->command_sent = 0; |
140 | iser_ctask->iser_conn = iser_conn; | 139 | iser_ctask->iser_conn = iser_conn; |
141 | |||
142 | if (sc->sc_data_direction == DMA_TO_DEVICE) { | ||
143 | BUG_ON(sc->request_bufflen == 0); | ||
144 | |||
145 | debug_scsi("cmd [itt %x total %d imm %d unsol_data %d\n", | ||
146 | ctask->itt, sc->request_bufflen, ctask->imm_count, | ||
147 | ctask->unsol_count); | ||
148 | } | ||
149 | |||
150 | iser_ctask_rdma_init(iser_ctask); | 140 | iser_ctask_rdma_init(iser_ctask); |
151 | } | 141 | } |
152 | 142 | ||
@@ -219,6 +209,14 @@ iscsi_iser_ctask_xmit(struct iscsi_conn *conn, | |||
219 | struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data; | 209 | struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data; |
220 | int error = 0; | 210 | int error = 0; |
221 | 211 | ||
212 | if (ctask->sc->sc_data_direction == DMA_TO_DEVICE) { | ||
213 | BUG_ON(ctask->sc->request_bufflen == 0); | ||
214 | |||
215 | debug_scsi("cmd [itt %x total %d imm %d unsol_data %d\n", | ||
216 | ctask->itt, ctask->sc->request_bufflen, | ||
217 | ctask->imm_count, ctask->unsol_count); | ||
218 | } | ||
219 | |||
222 | debug_scsi("ctask deq [cid %d itt 0x%x]\n", | 220 | debug_scsi("ctask deq [cid %d itt 0x%x]\n", |
223 | conn->id, ctask->itt); | 221 | conn->id, ctask->itt); |
224 | 222 | ||
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 0afdca2224c2..8edcfddc0baf 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c | |||
@@ -34,7 +34,6 @@ | |||
34 | #include <linux/delay.h> | 34 | #include <linux/delay.h> |
35 | #include <linux/kfifo.h> | 35 | #include <linux/kfifo.h> |
36 | #include <linux/scatterlist.h> | 36 | #include <linux/scatterlist.h> |
37 | #include <linux/mutex.h> | ||
38 | #include <net/tcp.h> | 37 | #include <net/tcp.h> |
39 | #include <scsi/scsi_cmnd.h> | 38 | #include <scsi/scsi_cmnd.h> |
40 | #include <scsi/scsi_host.h> | 39 | #include <scsi/scsi_host.h> |
@@ -211,7 +210,6 @@ iscsi_tcp_cleanup_ctask(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | |||
211 | static int | 210 | static int |
212 | iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | 211 | iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) |
213 | { | 212 | { |
214 | int rc; | ||
215 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; | 213 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; |
216 | struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; | 214 | struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; |
217 | struct iscsi_data_rsp *rhdr = (struct iscsi_data_rsp *)tcp_conn->in.hdr; | 215 | struct iscsi_data_rsp *rhdr = (struct iscsi_data_rsp *)tcp_conn->in.hdr; |
@@ -219,9 +217,7 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | |||
219 | struct scsi_cmnd *sc = ctask->sc; | 217 | struct scsi_cmnd *sc = ctask->sc; |
220 | int datasn = be32_to_cpu(rhdr->datasn); | 218 | int datasn = be32_to_cpu(rhdr->datasn); |
221 | 219 | ||
222 | rc = iscsi_check_assign_cmdsn(session, (struct iscsi_nopin*)rhdr); | 220 | iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr); |
223 | if (rc) | ||
224 | return rc; | ||
225 | /* | 221 | /* |
226 | * setup Data-In byte counter (gets decremented..) | 222 | * setup Data-In byte counter (gets decremented..) |
227 | */ | 223 | */ |
@@ -377,12 +373,10 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | |||
377 | return ISCSI_ERR_R2TSN; | 373 | return ISCSI_ERR_R2TSN; |
378 | } | 374 | } |
379 | 375 | ||
380 | rc = iscsi_check_assign_cmdsn(session, (struct iscsi_nopin*)rhdr); | ||
381 | if (rc) | ||
382 | return rc; | ||
383 | |||
384 | /* fill-in new R2T associated with the task */ | 376 | /* fill-in new R2T associated with the task */ |
385 | spin_lock(&session->lock); | 377 | spin_lock(&session->lock); |
378 | iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr); | ||
379 | |||
386 | if (!ctask->sc || ctask->mtask || | 380 | if (!ctask->sc || ctask->mtask || |
387 | session->state != ISCSI_STATE_LOGGED_IN) { | 381 | session->state != ISCSI_STATE_LOGGED_IN) { |
388 | printk(KERN_INFO "iscsi_tcp: dropping R2T itt %d in " | 382 | printk(KERN_INFO "iscsi_tcp: dropping R2T itt %d in " |
@@ -1762,12 +1756,6 @@ iscsi_tcp_ctask_xmit(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | |||
1762 | debug_scsi("ctask deq [cid %d xmstate %x itt 0x%x]\n", | 1756 | debug_scsi("ctask deq [cid %d xmstate %x itt 0x%x]\n", |
1763 | conn->id, tcp_ctask->xmstate, ctask->itt); | 1757 | conn->id, tcp_ctask->xmstate, ctask->itt); |
1764 | 1758 | ||
1765 | /* | ||
1766 | * serialize with TMF AbortTask | ||
1767 | */ | ||
1768 | if (ctask->mtask) | ||
1769 | return rc; | ||
1770 | |||
1771 | rc = iscsi_send_cmd_hdr(conn, ctask); | 1759 | rc = iscsi_send_cmd_hdr(conn, ctask); |
1772 | if (rc) | 1760 | if (rc) |
1773 | return rc; | 1761 | return rc; |
@@ -1949,8 +1937,7 @@ iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session, | |||
1949 | 1937 | ||
1950 | /* called with host lock */ | 1938 | /* called with host lock */ |
1951 | static void | 1939 | static void |
1952 | iscsi_tcp_mgmt_init(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask, | 1940 | iscsi_tcp_mgmt_init(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask) |
1953 | char *data, uint32_t data_size) | ||
1954 | { | 1941 | { |
1955 | struct iscsi_tcp_mgmt_task *tcp_mtask = mtask->dd_data; | 1942 | struct iscsi_tcp_mgmt_task *tcp_mtask = mtask->dd_data; |
1956 | tcp_mtask->xmstate = XMSTATE_IMM_HDR_INIT; | 1943 | tcp_mtask->xmstate = XMSTATE_IMM_HDR_INIT; |
@@ -2073,22 +2060,15 @@ iscsi_tcp_conn_get_param(struct iscsi_cls_conn *cls_conn, | |||
2073 | 2060 | ||
2074 | switch(param) { | 2061 | switch(param) { |
2075 | case ISCSI_PARAM_CONN_PORT: | 2062 | case ISCSI_PARAM_CONN_PORT: |
2076 | mutex_lock(&conn->xmitmutex); | 2063 | if (!tcp_conn->sock) |
2077 | if (!tcp_conn->sock) { | ||
2078 | mutex_unlock(&conn->xmitmutex); | ||
2079 | return -EINVAL; | 2064 | return -EINVAL; |
2080 | } | ||
2081 | 2065 | ||
2082 | inet = inet_sk(tcp_conn->sock->sk); | 2066 | inet = inet_sk(tcp_conn->sock->sk); |
2083 | len = sprintf(buf, "%hu\n", be16_to_cpu(inet->dport)); | 2067 | len = sprintf(buf, "%hu\n", be16_to_cpu(inet->dport)); |
2084 | mutex_unlock(&conn->xmitmutex); | ||
2085 | break; | 2068 | break; |
2086 | case ISCSI_PARAM_CONN_ADDRESS: | 2069 | case ISCSI_PARAM_CONN_ADDRESS: |
2087 | mutex_lock(&conn->xmitmutex); | 2070 | if (!tcp_conn->sock) |
2088 | if (!tcp_conn->sock) { | ||
2089 | mutex_unlock(&conn->xmitmutex); | ||
2090 | return -EINVAL; | 2071 | return -EINVAL; |
2091 | } | ||
2092 | 2072 | ||
2093 | sk = tcp_conn->sock->sk; | 2073 | sk = tcp_conn->sock->sk; |
2094 | if (sk->sk_family == PF_INET) { | 2074 | if (sk->sk_family == PF_INET) { |
@@ -2099,7 +2079,6 @@ iscsi_tcp_conn_get_param(struct iscsi_cls_conn *cls_conn, | |||
2099 | np = inet6_sk(sk); | 2079 | np = inet6_sk(sk); |
2100 | len = sprintf(buf, NIP6_FMT "\n", NIP6(np->daddr)); | 2080 | len = sprintf(buf, NIP6_FMT "\n", NIP6(np->daddr)); |
2101 | } | 2081 | } |
2102 | mutex_unlock(&conn->xmitmutex); | ||
2103 | break; | 2082 | break; |
2104 | default: | 2083 | default: |
2105 | return iscsi_conn_get_param(cls_conn, param, buf); | 2084 | return iscsi_conn_get_param(cls_conn, param, buf); |
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 63f0a15d9887..938f527cd81a 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c | |||
@@ -22,7 +22,6 @@ | |||
22 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | 22 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
23 | */ | 23 | */ |
24 | #include <linux/types.h> | 24 | #include <linux/types.h> |
25 | #include <linux/mutex.h> | ||
26 | #include <linux/kfifo.h> | 25 | #include <linux/kfifo.h> |
27 | #include <linux/delay.h> | 26 | #include <linux/delay.h> |
28 | #include <asm/unaligned.h> | 27 | #include <asm/unaligned.h> |
@@ -46,27 +45,53 @@ class_to_transport_session(struct iscsi_cls_session *cls_session) | |||
46 | } | 45 | } |
47 | EXPORT_SYMBOL_GPL(class_to_transport_session); | 46 | EXPORT_SYMBOL_GPL(class_to_transport_session); |
48 | 47 | ||
49 | #define INVALID_SN_DELTA 0xffff | 48 | /* Serial Number Arithmetic, 32 bits, less than, RFC1982 */ |
49 | #define SNA32_CHECK 2147483648UL | ||
50 | 50 | ||
51 | int | 51 | static int iscsi_sna_lt(u32 n1, u32 n2) |
52 | iscsi_check_assign_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr) | 52 | { |
53 | return n1 != n2 && ((n1 < n2 && (n2 - n1 < SNA32_CHECK)) || | ||
54 | (n1 > n2 && (n2 - n1 < SNA32_CHECK))); | ||
55 | } | ||
56 | |||
57 | /* Serial Number Arithmetic, 32 bits, less than, RFC1982 */ | ||
58 | static int iscsi_sna_lte(u32 n1, u32 n2) | ||
59 | { | ||
60 | return n1 == n2 || ((n1 < n2 && (n2 - n1 < SNA32_CHECK)) || | ||
61 | (n1 > n2 && (n2 - n1 < SNA32_CHECK))); | ||
62 | } | ||
63 | |||
64 | void | ||
65 | iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr) | ||
53 | { | 66 | { |
54 | uint32_t max_cmdsn = be32_to_cpu(hdr->max_cmdsn); | 67 | uint32_t max_cmdsn = be32_to_cpu(hdr->max_cmdsn); |
55 | uint32_t exp_cmdsn = be32_to_cpu(hdr->exp_cmdsn); | 68 | uint32_t exp_cmdsn = be32_to_cpu(hdr->exp_cmdsn); |
56 | 69 | ||
57 | if (max_cmdsn < exp_cmdsn -1 && | 70 | /* |
58 | max_cmdsn > exp_cmdsn - INVALID_SN_DELTA) | 71 | * standard specifies this check for when to update expected and |
59 | return ISCSI_ERR_MAX_CMDSN; | 72 | * max sequence numbers |
60 | if (max_cmdsn > session->max_cmdsn || | 73 | */ |
61 | max_cmdsn < session->max_cmdsn - INVALID_SN_DELTA) | 74 | if (iscsi_sna_lt(max_cmdsn, exp_cmdsn - 1)) |
62 | session->max_cmdsn = max_cmdsn; | 75 | return; |
63 | if (exp_cmdsn > session->exp_cmdsn || | 76 | |
64 | exp_cmdsn < session->exp_cmdsn - INVALID_SN_DELTA) | 77 | if (exp_cmdsn != session->exp_cmdsn && |
78 | !iscsi_sna_lt(exp_cmdsn, session->exp_cmdsn)) | ||
65 | session->exp_cmdsn = exp_cmdsn; | 79 | session->exp_cmdsn = exp_cmdsn; |
66 | 80 | ||
67 | return 0; | 81 | if (max_cmdsn != session->max_cmdsn && |
82 | !iscsi_sna_lt(max_cmdsn, session->max_cmdsn)) { | ||
83 | session->max_cmdsn = max_cmdsn; | ||
84 | /* | ||
85 | * if the window closed with IO queued, then kick the | ||
86 | * xmit thread | ||
87 | */ | ||
88 | if (!list_empty(&session->leadconn->xmitqueue) || | ||
89 | __kfifo_len(session->leadconn->mgmtqueue)) | ||
90 | scsi_queue_work(session->host, | ||
91 | &session->leadconn->xmitwork); | ||
92 | } | ||
68 | } | 93 | } |
69 | EXPORT_SYMBOL_GPL(iscsi_check_assign_cmdsn); | 94 | EXPORT_SYMBOL_GPL(iscsi_update_cmdsn); |
70 | 95 | ||
71 | void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *ctask, | 96 | void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *ctask, |
72 | struct iscsi_data *hdr) | 97 | struct iscsi_data *hdr) |
@@ -175,8 +200,13 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) | |||
175 | } | 200 | } |
176 | 201 | ||
177 | conn->scsicmd_pdus_cnt++; | 202 | conn->scsicmd_pdus_cnt++; |
203 | |||
204 | debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x len %d " | ||
205 | "cmdsn %d win %d]\n", | ||
206 | sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read", | ||
207 | conn->id, sc, sc->cmnd[0], ctask->itt, sc->request_bufflen, | ||
208 | session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1); | ||
178 | } | 209 | } |
179 | EXPORT_SYMBOL_GPL(iscsi_prep_scsi_cmd_pdu); | ||
180 | 210 | ||
181 | /** | 211 | /** |
182 | * iscsi_complete_command - return command back to scsi-ml | 212 | * iscsi_complete_command - return command back to scsi-ml |
@@ -205,26 +235,12 @@ static void __iscsi_get_ctask(struct iscsi_cmd_task *ctask) | |||
205 | atomic_inc(&ctask->refcount); | 235 | atomic_inc(&ctask->refcount); |
206 | } | 236 | } |
207 | 237 | ||
208 | static void iscsi_get_ctask(struct iscsi_cmd_task *ctask) | ||
209 | { | ||
210 | spin_lock_bh(&ctask->conn->session->lock); | ||
211 | __iscsi_get_ctask(ctask); | ||
212 | spin_unlock_bh(&ctask->conn->session->lock); | ||
213 | } | ||
214 | |||
215 | static void __iscsi_put_ctask(struct iscsi_cmd_task *ctask) | 238 | static void __iscsi_put_ctask(struct iscsi_cmd_task *ctask) |
216 | { | 239 | { |
217 | if (atomic_dec_and_test(&ctask->refcount)) | 240 | if (atomic_dec_and_test(&ctask->refcount)) |
218 | iscsi_complete_command(ctask); | 241 | iscsi_complete_command(ctask); |
219 | } | 242 | } |
220 | 243 | ||
221 | static void iscsi_put_ctask(struct iscsi_cmd_task *ctask) | ||
222 | { | ||
223 | spin_lock_bh(&ctask->conn->session->lock); | ||
224 | __iscsi_put_ctask(ctask); | ||
225 | spin_unlock_bh(&ctask->conn->session->lock); | ||
226 | } | ||
227 | |||
228 | /** | 244 | /** |
229 | * iscsi_cmd_rsp - SCSI Command Response processing | 245 | * iscsi_cmd_rsp - SCSI Command Response processing |
230 | * @conn: iscsi connection | 246 | * @conn: iscsi connection |
@@ -236,21 +252,15 @@ static void iscsi_put_ctask(struct iscsi_cmd_task *ctask) | |||
236 | * iscsi_cmd_rsp sets up the scsi_cmnd fields based on the PDU and | 252 | * iscsi_cmd_rsp sets up the scsi_cmnd fields based on the PDU and |
237 | * then completes the command and task. | 253 | * then completes the command and task. |
238 | **/ | 254 | **/ |
239 | static int iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | 255 | static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr, |
240 | struct iscsi_cmd_task *ctask, char *data, | 256 | struct iscsi_cmd_task *ctask, char *data, |
241 | int datalen) | 257 | int datalen) |
242 | { | 258 | { |
243 | int rc; | ||
244 | struct iscsi_cmd_rsp *rhdr = (struct iscsi_cmd_rsp *)hdr; | 259 | struct iscsi_cmd_rsp *rhdr = (struct iscsi_cmd_rsp *)hdr; |
245 | struct iscsi_session *session = conn->session; | 260 | struct iscsi_session *session = conn->session; |
246 | struct scsi_cmnd *sc = ctask->sc; | 261 | struct scsi_cmnd *sc = ctask->sc; |
247 | 262 | ||
248 | rc = iscsi_check_assign_cmdsn(session, (struct iscsi_nopin*)rhdr); | 263 | iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr); |
249 | if (rc) { | ||
250 | sc->result = DID_ERROR << 16; | ||
251 | goto out; | ||
252 | } | ||
253 | |||
254 | conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1; | 264 | conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1; |
255 | 265 | ||
256 | sc->result = (DID_OK << 16) | rhdr->cmd_status; | 266 | sc->result = (DID_OK << 16) | rhdr->cmd_status; |
@@ -302,7 +312,6 @@ out: | |||
302 | conn->scsirsp_pdus_cnt++; | 312 | conn->scsirsp_pdus_cnt++; |
303 | 313 | ||
304 | __iscsi_put_ctask(ctask); | 314 | __iscsi_put_ctask(ctask); |
305 | return rc; | ||
306 | } | 315 | } |
307 | 316 | ||
308 | static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr) | 317 | static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr) |
@@ -382,8 +391,8 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
382 | switch(opcode) { | 391 | switch(opcode) { |
383 | case ISCSI_OP_SCSI_CMD_RSP: | 392 | case ISCSI_OP_SCSI_CMD_RSP: |
384 | BUG_ON((void*)ctask != ctask->sc->SCp.ptr); | 393 | BUG_ON((void*)ctask != ctask->sc->SCp.ptr); |
385 | rc = iscsi_scsi_cmd_rsp(conn, hdr, ctask, data, | 394 | iscsi_scsi_cmd_rsp(conn, hdr, ctask, data, |
386 | datalen); | 395 | datalen); |
387 | break; | 396 | break; |
388 | case ISCSI_OP_SCSI_DATA_IN: | 397 | case ISCSI_OP_SCSI_DATA_IN: |
389 | BUG_ON((void*)ctask != ctask->sc->SCp.ptr); | 398 | BUG_ON((void*)ctask != ctask->sc->SCp.ptr); |
@@ -406,11 +415,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
406 | debug_scsi("immrsp [op 0x%x cid %d itt 0x%x len %d]\n", | 415 | debug_scsi("immrsp [op 0x%x cid %d itt 0x%x len %d]\n", |
407 | opcode, conn->id, mtask->itt, datalen); | 416 | opcode, conn->id, mtask->itt, datalen); |
408 | 417 | ||
409 | rc = iscsi_check_assign_cmdsn(session, | 418 | iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr); |
410 | (struct iscsi_nopin*)hdr); | ||
411 | if (rc) | ||
412 | goto done; | ||
413 | |||
414 | switch(opcode) { | 419 | switch(opcode) { |
415 | case ISCSI_OP_LOGOUT_RSP: | 420 | case ISCSI_OP_LOGOUT_RSP: |
416 | if (datalen) { | 421 | if (datalen) { |
@@ -459,10 +464,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
459 | break; | 464 | break; |
460 | } | 465 | } |
461 | } else if (itt == ~0U) { | 466 | } else if (itt == ~0U) { |
462 | rc = iscsi_check_assign_cmdsn(session, | 467 | iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr); |
463 | (struct iscsi_nopin*)hdr); | ||
464 | if (rc) | ||
465 | goto done; | ||
466 | 468 | ||
467 | switch(opcode) { | 469 | switch(opcode) { |
468 | case ISCSI_OP_NOOP_IN: | 470 | case ISCSI_OP_NOOP_IN: |
@@ -492,7 +494,6 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
492 | } else | 494 | } else |
493 | rc = ISCSI_ERR_BAD_ITT; | 495 | rc = ISCSI_ERR_BAD_ITT; |
494 | 496 | ||
495 | done: | ||
496 | return rc; | 497 | return rc; |
497 | } | 498 | } |
498 | EXPORT_SYMBOL_GPL(__iscsi_complete_pdu); | 499 | EXPORT_SYMBOL_GPL(__iscsi_complete_pdu); |
@@ -579,17 +580,47 @@ void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err) | |||
579 | } | 580 | } |
580 | EXPORT_SYMBOL_GPL(iscsi_conn_failure); | 581 | EXPORT_SYMBOL_GPL(iscsi_conn_failure); |
581 | 582 | ||
583 | static void iscsi_prep_mtask(struct iscsi_conn *conn, | ||
584 | struct iscsi_mgmt_task *mtask) | ||
585 | { | ||
586 | struct iscsi_session *session = conn->session; | ||
587 | struct iscsi_hdr *hdr = mtask->hdr; | ||
588 | struct iscsi_nopout *nop = (struct iscsi_nopout *)hdr; | ||
589 | |||
590 | if (hdr->opcode != (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) && | ||
591 | hdr->opcode != (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE)) | ||
592 | nop->exp_statsn = cpu_to_be32(conn->exp_statsn); | ||
593 | /* | ||
594 | * pre-format CmdSN for outgoing PDU. | ||
595 | */ | ||
596 | nop->cmdsn = cpu_to_be32(session->cmdsn); | ||
597 | if (hdr->itt != RESERVED_ITT) { | ||
598 | hdr->itt = build_itt(mtask->itt, conn->id, session->age); | ||
599 | if (conn->c_stage == ISCSI_CONN_STARTED && | ||
600 | !(hdr->opcode & ISCSI_OP_IMMEDIATE)) | ||
601 | session->cmdsn++; | ||
602 | } | ||
603 | |||
604 | if (session->tt->init_mgmt_task) | ||
605 | session->tt->init_mgmt_task(conn, mtask); | ||
606 | |||
607 | debug_scsi("mgmtpdu [op 0x%x hdr->itt 0x%x datalen %d]\n", | ||
608 | hdr->opcode, hdr->itt, mtask->data_count); | ||
609 | } | ||
610 | |||
582 | static int iscsi_xmit_mtask(struct iscsi_conn *conn) | 611 | static int iscsi_xmit_mtask(struct iscsi_conn *conn) |
583 | { | 612 | { |
584 | struct iscsi_hdr *hdr = conn->mtask->hdr; | 613 | struct iscsi_hdr *hdr = conn->mtask->hdr; |
585 | int rc, was_logout = 0; | 614 | int rc, was_logout = 0; |
586 | 615 | ||
616 | spin_unlock_bh(&conn->session->lock); | ||
587 | if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT) { | 617 | if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT) { |
588 | conn->session->state = ISCSI_STATE_IN_RECOVERY; | 618 | conn->session->state = ISCSI_STATE_IN_RECOVERY; |
589 | iscsi_block_session(session_to_cls(conn->session)); | 619 | iscsi_block_session(session_to_cls(conn->session)); |
590 | was_logout = 1; | 620 | was_logout = 1; |
591 | } | 621 | } |
592 | rc = conn->session->tt->xmit_mgmt_task(conn, conn->mtask); | 622 | rc = conn->session->tt->xmit_mgmt_task(conn, conn->mtask); |
623 | spin_lock_bh(&conn->session->lock); | ||
593 | if (rc) | 624 | if (rc) |
594 | return rc; | 625 | return rc; |
595 | 626 | ||
@@ -603,6 +634,45 @@ static int iscsi_xmit_mtask(struct iscsi_conn *conn) | |||
603 | return 0; | 634 | return 0; |
604 | } | 635 | } |
605 | 636 | ||
637 | static int iscsi_check_cmdsn_window_closed(struct iscsi_conn *conn) | ||
638 | { | ||
639 | struct iscsi_session *session = conn->session; | ||
640 | |||
641 | /* | ||
642 | * Check for iSCSI window and take care of CmdSN wrap-around | ||
643 | */ | ||
644 | if (!iscsi_sna_lte(session->cmdsn, session->max_cmdsn)) { | ||
645 | debug_scsi("iSCSI CmdSN closed. MaxCmdSN %u CmdSN %u\n", | ||
646 | session->max_cmdsn, session->cmdsn); | ||
647 | return -ENOSPC; | ||
648 | } | ||
649 | return 0; | ||
650 | } | ||
651 | |||
652 | static int iscsi_xmit_ctask(struct iscsi_conn *conn) | ||
653 | { | ||
654 | struct iscsi_cmd_task *ctask = conn->ctask; | ||
655 | int rc = 0; | ||
656 | |||
657 | /* | ||
658 | * serialize with TMF AbortTask | ||
659 | */ | ||
660 | if (ctask->state == ISCSI_TASK_ABORTING) | ||
661 | goto done; | ||
662 | |||
663 | __iscsi_get_ctask(ctask); | ||
664 | spin_unlock_bh(&conn->session->lock); | ||
665 | rc = conn->session->tt->xmit_cmd_task(conn, ctask); | ||
666 | spin_lock_bh(&conn->session->lock); | ||
667 | __iscsi_put_ctask(ctask); | ||
668 | |||
669 | done: | ||
670 | if (!rc) | ||
671 | /* done with this ctask */ | ||
672 | conn->ctask = NULL; | ||
673 | return rc; | ||
674 | } | ||
675 | |||
606 | /** | 676 | /** |
607 | * iscsi_data_xmit - xmit any command into the scheduled connection | 677 | * iscsi_data_xmit - xmit any command into the scheduled connection |
608 | * @conn: iscsi connection | 678 | * @conn: iscsi connection |
@@ -614,106 +684,79 @@ static int iscsi_xmit_mtask(struct iscsi_conn *conn) | |||
614 | **/ | 684 | **/ |
615 | static int iscsi_data_xmit(struct iscsi_conn *conn) | 685 | static int iscsi_data_xmit(struct iscsi_conn *conn) |
616 | { | 686 | { |
617 | struct iscsi_transport *tt; | ||
618 | int rc = 0; | 687 | int rc = 0; |
619 | 688 | ||
689 | spin_lock_bh(&conn->session->lock); | ||
620 | if (unlikely(conn->suspend_tx)) { | 690 | if (unlikely(conn->suspend_tx)) { |
621 | debug_scsi("conn %d Tx suspended!\n", conn->id); | 691 | debug_scsi("conn %d Tx suspended!\n", conn->id); |
692 | spin_unlock_bh(&conn->session->lock); | ||
622 | return -ENODATA; | 693 | return -ENODATA; |
623 | } | 694 | } |
624 | tt = conn->session->tt; | ||
625 | |||
626 | /* | ||
627 | * Transmit in the following order: | ||
628 | * | ||
629 | * 1) un-finished xmit (ctask or mtask) | ||
630 | * 2) immediate control PDUs | ||
631 | * 3) write data | ||
632 | * 4) SCSI commands | ||
633 | * 5) non-immediate control PDUs | ||
634 | * | ||
635 | * No need to lock around __kfifo_get as long as | ||
636 | * there's one producer and one consumer. | ||
637 | */ | ||
638 | |||
639 | BUG_ON(conn->ctask && conn->mtask); | ||
640 | 695 | ||
641 | if (conn->ctask) { | 696 | if (conn->ctask) { |
642 | iscsi_get_ctask(conn->ctask); | 697 | rc = iscsi_xmit_ctask(conn); |
643 | rc = tt->xmit_cmd_task(conn, conn->ctask); | ||
644 | iscsi_put_ctask(conn->ctask); | ||
645 | if (rc) | 698 | if (rc) |
646 | goto again; | 699 | goto again; |
647 | /* done with this in-progress ctask */ | ||
648 | conn->ctask = NULL; | ||
649 | } | 700 | } |
701 | |||
650 | if (conn->mtask) { | 702 | if (conn->mtask) { |
651 | rc = iscsi_xmit_mtask(conn); | 703 | rc = iscsi_xmit_mtask(conn); |
652 | if (rc) | 704 | if (rc) |
653 | goto again; | 705 | goto again; |
654 | } | 706 | } |
655 | 707 | ||
656 | /* process immediate first */ | 708 | /* |
657 | if (unlikely(__kfifo_len(conn->immqueue))) { | 709 | * process mgmt pdus like nops before commands since we should |
658 | while (__kfifo_get(conn->immqueue, (void*)&conn->mtask, | 710 | * only have one nop-out as a ping from us and targets should not |
659 | sizeof(void*))) { | 711 | * overflow us with nop-ins |
660 | spin_lock_bh(&conn->session->lock); | 712 | */ |
661 | list_add_tail(&conn->mtask->running, | 713 | check_mgmt: |
662 | &conn->mgmt_run_list); | 714 | while (__kfifo_get(conn->mgmtqueue, (void*)&conn->mtask, |
663 | spin_unlock_bh(&conn->session->lock); | 715 | sizeof(void*))) { |
664 | rc = iscsi_xmit_mtask(conn); | 716 | iscsi_prep_mtask(conn, conn->mtask); |
665 | if (rc) | 717 | list_add_tail(&conn->mtask->running, &conn->mgmt_run_list); |
666 | goto again; | 718 | rc = iscsi_xmit_mtask(conn); |
667 | } | 719 | if (rc) |
720 | goto again; | ||
668 | } | 721 | } |
669 | 722 | ||
670 | /* process command queue */ | 723 | /* process command queue */ |
671 | spin_lock_bh(&conn->session->lock); | ||
672 | while (!list_empty(&conn->xmitqueue)) { | 724 | while (!list_empty(&conn->xmitqueue)) { |
725 | rc = iscsi_check_cmdsn_window_closed(conn); | ||
726 | if (rc) { | ||
727 | spin_unlock_bh(&conn->session->lock); | ||
728 | return rc; | ||
729 | } | ||
673 | /* | 730 | /* |
674 | * iscsi tcp may readd the task to the xmitqueue to send | 731 | * iscsi tcp may readd the task to the xmitqueue to send |
675 | * write data | 732 | * write data |
676 | */ | 733 | */ |
677 | conn->ctask = list_entry(conn->xmitqueue.next, | 734 | conn->ctask = list_entry(conn->xmitqueue.next, |
678 | struct iscsi_cmd_task, running); | 735 | struct iscsi_cmd_task, running); |
736 | if (conn->ctask->state == ISCSI_TASK_PENDING) { | ||
737 | iscsi_prep_scsi_cmd_pdu(conn->ctask); | ||
738 | conn->session->tt->init_cmd_task(conn->ctask); | ||
739 | } | ||
679 | conn->ctask->state = ISCSI_TASK_RUNNING; | 740 | conn->ctask->state = ISCSI_TASK_RUNNING; |
680 | list_move_tail(conn->xmitqueue.next, &conn->run_list); | 741 | list_move_tail(conn->xmitqueue.next, &conn->run_list); |
681 | __iscsi_get_ctask(conn->ctask); | 742 | rc = iscsi_xmit_ctask(conn); |
682 | spin_unlock_bh(&conn->session->lock); | 743 | if (rc) |
683 | |||
684 | rc = tt->xmit_cmd_task(conn, conn->ctask); | ||
685 | |||
686 | spin_lock_bh(&conn->session->lock); | ||
687 | __iscsi_put_ctask(conn->ctask); | ||
688 | if (rc) { | ||
689 | spin_unlock_bh(&conn->session->lock); | ||
690 | goto again; | 744 | goto again; |
691 | } | 745 | /* |
746 | * we could continuously get new ctask requests so | ||
747 | * we need to check the mgmt queue for nops that need to | ||
748 | * be sent to aviod starvation | ||
749 | */ | ||
750 | if (__kfifo_len(conn->mgmtqueue)) | ||
751 | goto check_mgmt; | ||
692 | } | 752 | } |
693 | spin_unlock_bh(&conn->session->lock); | 753 | spin_unlock_bh(&conn->session->lock); |
694 | /* done with this ctask */ | ||
695 | conn->ctask = NULL; | ||
696 | |||
697 | /* process the rest control plane PDUs, if any */ | ||
698 | if (unlikely(__kfifo_len(conn->mgmtqueue))) { | ||
699 | while (__kfifo_get(conn->mgmtqueue, (void*)&conn->mtask, | ||
700 | sizeof(void*))) { | ||
701 | spin_lock_bh(&conn->session->lock); | ||
702 | list_add_tail(&conn->mtask->running, | ||
703 | &conn->mgmt_run_list); | ||
704 | spin_unlock_bh(&conn->session->lock); | ||
705 | rc = iscsi_xmit_mtask(conn); | ||
706 | if (rc) | ||
707 | goto again; | ||
708 | } | ||
709 | } | ||
710 | |||
711 | return -ENODATA; | 754 | return -ENODATA; |
712 | 755 | ||
713 | again: | 756 | again: |
714 | if (unlikely(conn->suspend_tx)) | 757 | if (unlikely(conn->suspend_tx)) |
715 | return -ENODATA; | 758 | rc = -ENODATA; |
716 | 759 | spin_unlock_bh(&conn->session->lock); | |
717 | return rc; | 760 | return rc; |
718 | } | 761 | } |
719 | 762 | ||
@@ -725,11 +768,9 @@ static void iscsi_xmitworker(struct work_struct *work) | |||
725 | /* | 768 | /* |
726 | * serialize Xmit worker on a per-connection basis. | 769 | * serialize Xmit worker on a per-connection basis. |
727 | */ | 770 | */ |
728 | mutex_lock(&conn->xmitmutex); | ||
729 | do { | 771 | do { |
730 | rc = iscsi_data_xmit(conn); | 772 | rc = iscsi_data_xmit(conn); |
731 | } while (rc >= 0 || rc == -EAGAIN); | 773 | } while (rc >= 0 || rc == -EAGAIN); |
732 | mutex_unlock(&conn->xmitmutex); | ||
733 | } | 774 | } |
734 | 775 | ||
735 | enum { | 776 | enum { |
@@ -787,20 +828,23 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) | |||
787 | goto fault; | 828 | goto fault; |
788 | } | 829 | } |
789 | 830 | ||
790 | /* | ||
791 | * Check for iSCSI window and take care of CmdSN wrap-around | ||
792 | */ | ||
793 | if ((int)(session->max_cmdsn - session->cmdsn) < 0) { | ||
794 | reason = FAILURE_WINDOW_CLOSED; | ||
795 | goto reject; | ||
796 | } | ||
797 | |||
798 | conn = session->leadconn; | 831 | conn = session->leadconn; |
799 | if (!conn) { | 832 | if (!conn) { |
800 | reason = FAILURE_SESSION_FREED; | 833 | reason = FAILURE_SESSION_FREED; |
801 | goto fault; | 834 | goto fault; |
802 | } | 835 | } |
803 | 836 | ||
837 | /* | ||
838 | * We check this here and in data xmit, because if we get to the point | ||
839 | * that this check is hitting the window then we have enough IO in | ||
840 | * flight and enough IO waiting to be transmitted it is better | ||
841 | * to let the scsi/block layer queue up. | ||
842 | */ | ||
843 | if (iscsi_check_cmdsn_window_closed(conn)) { | ||
844 | reason = FAILURE_WINDOW_CLOSED; | ||
845 | goto reject; | ||
846 | } | ||
847 | |||
804 | if (!__kfifo_get(session->cmdpool.queue, (void*)&ctask, | 848 | if (!__kfifo_get(session->cmdpool.queue, (void*)&ctask, |
805 | sizeof(void*))) { | 849 | sizeof(void*))) { |
806 | reason = FAILURE_OOM; | 850 | reason = FAILURE_OOM; |
@@ -815,17 +859,8 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) | |||
815 | ctask->conn = conn; | 859 | ctask->conn = conn; |
816 | ctask->sc = sc; | 860 | ctask->sc = sc; |
817 | INIT_LIST_HEAD(&ctask->running); | 861 | INIT_LIST_HEAD(&ctask->running); |
818 | iscsi_prep_scsi_cmd_pdu(ctask); | ||
819 | |||
820 | session->tt->init_cmd_task(ctask); | ||
821 | 862 | ||
822 | list_add_tail(&ctask->running, &conn->xmitqueue); | 863 | list_add_tail(&ctask->running, &conn->xmitqueue); |
823 | debug_scsi( | ||
824 | "ctask enq [%s cid %d sc %p cdb 0x%x itt 0x%x len %d cmdsn %d " | ||
825 | "win %d]\n", | ||
826 | sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read", | ||
827 | conn->id, sc, sc->cmnd[0], ctask->itt, sc->request_bufflen, | ||
828 | session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1); | ||
829 | spin_unlock(&session->lock); | 864 | spin_unlock(&session->lock); |
830 | 865 | ||
831 | scsi_queue_work(host, &conn->xmitwork); | 866 | scsi_queue_work(host, &conn->xmitwork); |
@@ -856,19 +891,16 @@ int iscsi_change_queue_depth(struct scsi_device *sdev, int depth) | |||
856 | } | 891 | } |
857 | EXPORT_SYMBOL_GPL(iscsi_change_queue_depth); | 892 | EXPORT_SYMBOL_GPL(iscsi_change_queue_depth); |
858 | 893 | ||
859 | static int | 894 | static struct iscsi_mgmt_task * |
860 | iscsi_conn_send_generic(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | 895 | __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, |
861 | char *data, uint32_t data_size) | 896 | char *data, uint32_t data_size) |
862 | { | 897 | { |
863 | struct iscsi_session *session = conn->session; | 898 | struct iscsi_session *session = conn->session; |
864 | struct iscsi_nopout *nop = (struct iscsi_nopout *)hdr; | ||
865 | struct iscsi_mgmt_task *mtask; | 899 | struct iscsi_mgmt_task *mtask; |
866 | 900 | ||
867 | spin_lock_bh(&session->lock); | 901 | if (session->state == ISCSI_STATE_TERMINATE) |
868 | if (session->state == ISCSI_STATE_TERMINATE) { | 902 | return NULL; |
869 | spin_unlock_bh(&session->lock); | 903 | |
870 | return -EPERM; | ||
871 | } | ||
872 | if (hdr->opcode == (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) || | 904 | if (hdr->opcode == (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) || |
873 | hdr->opcode == (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE)) | 905 | hdr->opcode == (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE)) |
874 | /* | 906 | /* |
@@ -882,27 +914,11 @@ iscsi_conn_send_generic(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
882 | BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE); | 914 | BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE); |
883 | BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED); | 915 | BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED); |
884 | 916 | ||
885 | nop->exp_statsn = cpu_to_be32(conn->exp_statsn); | ||
886 | if (!__kfifo_get(session->mgmtpool.queue, | 917 | if (!__kfifo_get(session->mgmtpool.queue, |
887 | (void*)&mtask, sizeof(void*))) { | 918 | (void*)&mtask, sizeof(void*))) |
888 | spin_unlock_bh(&session->lock); | 919 | return NULL; |
889 | return -ENOSPC; | ||
890 | } | ||
891 | } | 920 | } |
892 | 921 | ||
893 | /* | ||
894 | * pre-format CmdSN for outgoing PDU. | ||
895 | */ | ||
896 | if (hdr->itt != RESERVED_ITT) { | ||
897 | hdr->itt = build_itt(mtask->itt, conn->id, session->age); | ||
898 | nop->cmdsn = cpu_to_be32(session->cmdsn); | ||
899 | if (conn->c_stage == ISCSI_CONN_STARTED && | ||
900 | !(hdr->opcode & ISCSI_OP_IMMEDIATE)) | ||
901 | session->cmdsn++; | ||
902 | } else | ||
903 | /* do not advance CmdSN */ | ||
904 | nop->cmdsn = cpu_to_be32(session->cmdsn); | ||
905 | |||
906 | if (data_size) { | 922 | if (data_size) { |
907 | memcpy(mtask->data, data, data_size); | 923 | memcpy(mtask->data, data, data_size); |
908 | mtask->data_count = data_size; | 924 | mtask->data_count = data_size; |
@@ -911,38 +927,23 @@ iscsi_conn_send_generic(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
911 | 927 | ||
912 | INIT_LIST_HEAD(&mtask->running); | 928 | INIT_LIST_HEAD(&mtask->running); |
913 | memcpy(mtask->hdr, hdr, sizeof(struct iscsi_hdr)); | 929 | memcpy(mtask->hdr, hdr, sizeof(struct iscsi_hdr)); |
914 | if (session->tt->init_mgmt_task) | 930 | __kfifo_put(conn->mgmtqueue, (void*)&mtask, sizeof(void*)); |
915 | session->tt->init_mgmt_task(conn, mtask, data, data_size); | 931 | return mtask; |
916 | spin_unlock_bh(&session->lock); | ||
917 | |||
918 | debug_scsi("mgmtpdu [op 0x%x hdr->itt 0x%x datalen %d]\n", | ||
919 | hdr->opcode, hdr->itt, data_size); | ||
920 | |||
921 | /* | ||
922 | * since send_pdu() could be called at least from two contexts, | ||
923 | * we need to serialize __kfifo_put, so we don't have to take | ||
924 | * additional lock on fast data-path | ||
925 | */ | ||
926 | if (hdr->opcode & ISCSI_OP_IMMEDIATE) | ||
927 | __kfifo_put(conn->immqueue, (void*)&mtask, sizeof(void*)); | ||
928 | else | ||
929 | __kfifo_put(conn->mgmtqueue, (void*)&mtask, sizeof(void*)); | ||
930 | |||
931 | scsi_queue_work(session->host, &conn->xmitwork); | ||
932 | return 0; | ||
933 | } | 932 | } |
934 | 933 | ||
935 | int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr, | 934 | int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr, |
936 | char *data, uint32_t data_size) | 935 | char *data, uint32_t data_size) |
937 | { | 936 | { |
938 | struct iscsi_conn *conn = cls_conn->dd_data; | 937 | struct iscsi_conn *conn = cls_conn->dd_data; |
939 | int rc; | 938 | struct iscsi_session *session = conn->session; |
940 | 939 | int err = 0; | |
941 | mutex_lock(&conn->xmitmutex); | ||
942 | rc = iscsi_conn_send_generic(conn, hdr, data, data_size); | ||
943 | mutex_unlock(&conn->xmitmutex); | ||
944 | 940 | ||
945 | return rc; | 941 | spin_lock_bh(&session->lock); |
942 | if (!__iscsi_conn_send_pdu(conn, hdr, data, data_size)) | ||
943 | err = -EPERM; | ||
944 | spin_unlock_bh(&session->lock); | ||
945 | scsi_queue_work(session->host, &conn->xmitwork); | ||
946 | return err; | ||
946 | } | 947 | } |
947 | EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu); | 948 | EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu); |
948 | 949 | ||
@@ -1027,14 +1028,12 @@ static void iscsi_tmabort_timedout(unsigned long data) | |||
1027 | spin_unlock(&session->lock); | 1028 | spin_unlock(&session->lock); |
1028 | } | 1029 | } |
1029 | 1030 | ||
1030 | /* must be called with the mutex lock */ | ||
1031 | static int iscsi_exec_abort_task(struct scsi_cmnd *sc, | 1031 | static int iscsi_exec_abort_task(struct scsi_cmnd *sc, |
1032 | struct iscsi_cmd_task *ctask) | 1032 | struct iscsi_cmd_task *ctask) |
1033 | { | 1033 | { |
1034 | struct iscsi_conn *conn = ctask->conn; | 1034 | struct iscsi_conn *conn = ctask->conn; |
1035 | struct iscsi_session *session = conn->session; | 1035 | struct iscsi_session *session = conn->session; |
1036 | struct iscsi_tm *hdr = &conn->tmhdr; | 1036 | struct iscsi_tm *hdr = &conn->tmhdr; |
1037 | int rc; | ||
1038 | 1037 | ||
1039 | /* | 1038 | /* |
1040 | * ctask timed out but session is OK requests must be serialized. | 1039 | * ctask timed out but session is OK requests must be serialized. |
@@ -1047,32 +1046,27 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc, | |||
1047 | hdr->rtt = ctask->hdr->itt; | 1046 | hdr->rtt = ctask->hdr->itt; |
1048 | hdr->refcmdsn = ctask->hdr->cmdsn; | 1047 | hdr->refcmdsn = ctask->hdr->cmdsn; |
1049 | 1048 | ||
1050 | rc = iscsi_conn_send_generic(conn, (struct iscsi_hdr *)hdr, | 1049 | ctask->mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr, |
1051 | NULL, 0); | 1050 | NULL, 0); |
1052 | if (rc) { | 1051 | if (!ctask->mtask) { |
1053 | iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); | 1052 | iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); |
1054 | debug_scsi("abort sent failure [itt 0x%x] %d\n", ctask->itt, | 1053 | debug_scsi("abort sent failure [itt 0x%x]\n", ctask->itt); |
1055 | rc); | 1054 | return -EPERM; |
1056 | return rc; | ||
1057 | } | 1055 | } |
1056 | ctask->state = ISCSI_TASK_ABORTING; | ||
1058 | 1057 | ||
1059 | debug_scsi("abort sent [itt 0x%x]\n", ctask->itt); | 1058 | debug_scsi("abort sent [itt 0x%x]\n", ctask->itt); |
1060 | 1059 | ||
1061 | spin_lock_bh(&session->lock); | ||
1062 | ctask->mtask = (struct iscsi_mgmt_task *) | ||
1063 | session->mgmt_cmds[get_itt(hdr->itt) - | ||
1064 | ISCSI_MGMT_ITT_OFFSET]; | ||
1065 | |||
1066 | if (conn->tmabort_state == TMABORT_INITIAL) { | 1060 | if (conn->tmabort_state == TMABORT_INITIAL) { |
1067 | conn->tmfcmd_pdus_cnt++; | 1061 | conn->tmfcmd_pdus_cnt++; |
1068 | conn->tmabort_timer.expires = 10*HZ + jiffies; | 1062 | conn->tmabort_timer.expires = 20*HZ + jiffies; |
1069 | conn->tmabort_timer.function = iscsi_tmabort_timedout; | 1063 | conn->tmabort_timer.function = iscsi_tmabort_timedout; |
1070 | conn->tmabort_timer.data = (unsigned long)ctask; | 1064 | conn->tmabort_timer.data = (unsigned long)ctask; |
1071 | add_timer(&conn->tmabort_timer); | 1065 | add_timer(&conn->tmabort_timer); |
1072 | debug_scsi("abort set timeout [itt 0x%x]\n", ctask->itt); | 1066 | debug_scsi("abort set timeout [itt 0x%x]\n", ctask->itt); |
1073 | } | 1067 | } |
1074 | spin_unlock_bh(&session->lock); | 1068 | spin_unlock_bh(&session->lock); |
1075 | mutex_unlock(&conn->xmitmutex); | 1069 | scsi_queue_work(session->host, &conn->xmitwork); |
1076 | 1070 | ||
1077 | /* | 1071 | /* |
1078 | * block eh thread until: | 1072 | * block eh thread until: |
@@ -1089,13 +1083,12 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc, | |||
1089 | if (signal_pending(current)) | 1083 | if (signal_pending(current)) |
1090 | flush_signals(current); | 1084 | flush_signals(current); |
1091 | del_timer_sync(&conn->tmabort_timer); | 1085 | del_timer_sync(&conn->tmabort_timer); |
1092 | 1086 | spin_lock_bh(&session->lock); | |
1093 | mutex_lock(&conn->xmitmutex); | ||
1094 | return 0; | 1087 | return 0; |
1095 | } | 1088 | } |
1096 | 1089 | ||
1097 | /* | 1090 | /* |
1098 | * xmit mutex and session lock must be held | 1091 | * session lock must be held |
1099 | */ | 1092 | */ |
1100 | static struct iscsi_mgmt_task * | 1093 | static struct iscsi_mgmt_task * |
1101 | iscsi_remove_mgmt_task(struct kfifo *fifo, uint32_t itt) | 1094 | iscsi_remove_mgmt_task(struct kfifo *fifo, uint32_t itt) |
@@ -1127,7 +1120,7 @@ static int iscsi_ctask_mtask_cleanup(struct iscsi_cmd_task *ctask) | |||
1127 | if (!ctask->mtask) | 1120 | if (!ctask->mtask) |
1128 | return -EINVAL; | 1121 | return -EINVAL; |
1129 | 1122 | ||
1130 | if (!iscsi_remove_mgmt_task(conn->immqueue, ctask->mtask->itt)) | 1123 | if (!iscsi_remove_mgmt_task(conn->mgmtqueue, ctask->mtask->itt)) |
1131 | list_del(&ctask->mtask->running); | 1124 | list_del(&ctask->mtask->running); |
1132 | __kfifo_put(session->mgmtpool.queue, (void*)&ctask->mtask, | 1125 | __kfifo_put(session->mgmtpool.queue, (void*)&ctask->mtask, |
1133 | sizeof(void*)); | 1126 | sizeof(void*)); |
@@ -1136,7 +1129,7 @@ static int iscsi_ctask_mtask_cleanup(struct iscsi_cmd_task *ctask) | |||
1136 | } | 1129 | } |
1137 | 1130 | ||
1138 | /* | 1131 | /* |
1139 | * session lock and xmitmutex must be held | 1132 | * session lock must be held |
1140 | */ | 1133 | */ |
1141 | static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, | 1134 | static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, |
1142 | int err) | 1135 | int err) |
@@ -1147,11 +1140,14 @@ static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, | |||
1147 | if (!sc) | 1140 | if (!sc) |
1148 | return; | 1141 | return; |
1149 | 1142 | ||
1150 | conn->session->tt->cleanup_cmd_task(conn, ctask); | 1143 | if (ctask->state != ISCSI_TASK_PENDING) |
1144 | conn->session->tt->cleanup_cmd_task(conn, ctask); | ||
1151 | iscsi_ctask_mtask_cleanup(ctask); | 1145 | iscsi_ctask_mtask_cleanup(ctask); |
1152 | 1146 | ||
1153 | sc->result = err; | 1147 | sc->result = err; |
1154 | sc->resid = sc->request_bufflen; | 1148 | sc->resid = sc->request_bufflen; |
1149 | if (conn->ctask == ctask) | ||
1150 | conn->ctask = NULL; | ||
1155 | /* release ref from queuecommand */ | 1151 | /* release ref from queuecommand */ |
1156 | __iscsi_put_ctask(ctask); | 1152 | __iscsi_put_ctask(ctask); |
1157 | } | 1153 | } |
@@ -1179,7 +1175,6 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) | |||
1179 | conn->eh_abort_cnt++; | 1175 | conn->eh_abort_cnt++; |
1180 | debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt); | 1176 | debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt); |
1181 | 1177 | ||
1182 | mutex_lock(&conn->xmitmutex); | ||
1183 | spin_lock_bh(&session->lock); | 1178 | spin_lock_bh(&session->lock); |
1184 | 1179 | ||
1185 | /* | 1180 | /* |
@@ -1192,9 +1187,8 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) | |||
1192 | 1187 | ||
1193 | /* ctask completed before time out */ | 1188 | /* ctask completed before time out */ |
1194 | if (!ctask->sc) { | 1189 | if (!ctask->sc) { |
1195 | spin_unlock_bh(&session->lock); | ||
1196 | debug_scsi("sc completed while abort in progress\n"); | 1190 | debug_scsi("sc completed while abort in progress\n"); |
1197 | goto success_rel_mutex; | 1191 | goto success; |
1198 | } | 1192 | } |
1199 | 1193 | ||
1200 | /* what should we do here ? */ | 1194 | /* what should we do here ? */ |
@@ -1204,15 +1198,13 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) | |||
1204 | goto failed; | 1198 | goto failed; |
1205 | } | 1199 | } |
1206 | 1200 | ||
1207 | if (ctask->state == ISCSI_TASK_PENDING) | 1201 | if (ctask->state == ISCSI_TASK_PENDING) { |
1208 | goto success_cleanup; | 1202 | fail_command(conn, ctask, DID_ABORT << 16); |
1203 | goto success; | ||
1204 | } | ||
1209 | 1205 | ||
1210 | conn->tmabort_state = TMABORT_INITIAL; | 1206 | conn->tmabort_state = TMABORT_INITIAL; |
1211 | |||
1212 | spin_unlock_bh(&session->lock); | ||
1213 | rc = iscsi_exec_abort_task(sc, ctask); | 1207 | rc = iscsi_exec_abort_task(sc, ctask); |
1214 | spin_lock_bh(&session->lock); | ||
1215 | |||
1216 | if (rc || sc->SCp.phase != session->age || | 1208 | if (rc || sc->SCp.phase != session->age || |
1217 | session->state != ISCSI_STATE_LOGGED_IN) | 1209 | session->state != ISCSI_STATE_LOGGED_IN) |
1218 | goto failed; | 1210 | goto failed; |
@@ -1220,45 +1212,44 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) | |||
1220 | 1212 | ||
1221 | switch (conn->tmabort_state) { | 1213 | switch (conn->tmabort_state) { |
1222 | case TMABORT_SUCCESS: | 1214 | case TMABORT_SUCCESS: |
1223 | goto success_cleanup; | 1215 | spin_unlock_bh(&session->lock); |
1216 | /* | ||
1217 | * clean up task if aborted. grab the recv lock as a writer | ||
1218 | */ | ||
1219 | write_lock_bh(conn->recv_lock); | ||
1220 | spin_lock(&session->lock); | ||
1221 | fail_command(conn, ctask, DID_ABORT << 16); | ||
1222 | spin_unlock(&session->lock); | ||
1223 | write_unlock_bh(conn->recv_lock); | ||
1224 | /* | ||
1225 | * make sure xmit thread is not still touching the | ||
1226 | * ctask/scsi_cmnd | ||
1227 | */ | ||
1228 | scsi_flush_work(session->host); | ||
1229 | goto success_unlocked; | ||
1224 | case TMABORT_NOT_FOUND: | 1230 | case TMABORT_NOT_FOUND: |
1225 | if (!ctask->sc) { | 1231 | if (!ctask->sc) { |
1226 | /* ctask completed before tmf abort response */ | 1232 | /* ctask completed before tmf abort response */ |
1227 | spin_unlock_bh(&session->lock); | ||
1228 | debug_scsi("sc completed while abort in progress\n"); | 1233 | debug_scsi("sc completed while abort in progress\n"); |
1229 | goto success_rel_mutex; | 1234 | goto success; |
1230 | } | 1235 | } |
1231 | /* fall through */ | 1236 | /* fall through */ |
1232 | default: | 1237 | default: |
1233 | /* timedout or failed */ | 1238 | /* timedout or failed */ |
1234 | spin_unlock_bh(&session->lock); | 1239 | spin_unlock_bh(&session->lock); |
1235 | iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); | 1240 | iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); |
1236 | spin_lock_bh(&session->lock); | 1241 | goto failed_unlocked; |
1237 | goto failed; | ||
1238 | } | 1242 | } |
1239 | 1243 | ||
1240 | success_cleanup: | 1244 | success: |
1241 | debug_scsi("abort success [sc %lx itt 0x%x]\n", (long)sc, ctask->itt); | ||
1242 | spin_unlock_bh(&session->lock); | 1245 | spin_unlock_bh(&session->lock); |
1243 | 1246 | success_unlocked: | |
1244 | /* | 1247 | debug_scsi("abort success [sc %lx itt 0x%x]\n", (long)sc, ctask->itt); |
1245 | * clean up task if aborted. we have the xmitmutex so grab | ||
1246 | * the recv lock as a writer | ||
1247 | */ | ||
1248 | write_lock_bh(conn->recv_lock); | ||
1249 | spin_lock(&session->lock); | ||
1250 | fail_command(conn, ctask, DID_ABORT << 16); | ||
1251 | spin_unlock(&session->lock); | ||
1252 | write_unlock_bh(conn->recv_lock); | ||
1253 | |||
1254 | success_rel_mutex: | ||
1255 | mutex_unlock(&conn->xmitmutex); | ||
1256 | return SUCCESS; | 1248 | return SUCCESS; |
1257 | 1249 | ||
1258 | failed: | 1250 | failed: |
1259 | spin_unlock_bh(&session->lock); | 1251 | spin_unlock_bh(&session->lock); |
1260 | mutex_unlock(&conn->xmitmutex); | 1252 | failed_unlocked: |
1261 | |||
1262 | debug_scsi("abort failed [sc %lx itt 0x%x]\n", (long)sc, ctask->itt); | 1253 | debug_scsi("abort failed [sc %lx itt 0x%x]\n", (long)sc, ctask->itt); |
1263 | return FAILED; | 1254 | return FAILED; |
1264 | } | 1255 | } |
@@ -1505,11 +1496,6 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx) | |||
1505 | INIT_LIST_HEAD(&conn->xmitqueue); | 1496 | INIT_LIST_HEAD(&conn->xmitqueue); |
1506 | 1497 | ||
1507 | /* initialize general immediate & non-immediate PDU commands queue */ | 1498 | /* initialize general immediate & non-immediate PDU commands queue */ |
1508 | conn->immqueue = kfifo_alloc(session->mgmtpool_max * sizeof(void*), | ||
1509 | GFP_KERNEL, NULL); | ||
1510 | if (conn->immqueue == ERR_PTR(-ENOMEM)) | ||
1511 | goto immqueue_alloc_fail; | ||
1512 | |||
1513 | conn->mgmtqueue = kfifo_alloc(session->mgmtpool_max * sizeof(void*), | 1499 | conn->mgmtqueue = kfifo_alloc(session->mgmtpool_max * sizeof(void*), |
1514 | GFP_KERNEL, NULL); | 1500 | GFP_KERNEL, NULL); |
1515 | if (conn->mgmtqueue == ERR_PTR(-ENOMEM)) | 1501 | if (conn->mgmtqueue == ERR_PTR(-ENOMEM)) |
@@ -1533,7 +1519,6 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx) | |||
1533 | conn->login_mtask->data = conn->data = data; | 1519 | conn->login_mtask->data = conn->data = data; |
1534 | 1520 | ||
1535 | init_timer(&conn->tmabort_timer); | 1521 | init_timer(&conn->tmabort_timer); |
1536 | mutex_init(&conn->xmitmutex); | ||
1537 | init_waitqueue_head(&conn->ehwait); | 1522 | init_waitqueue_head(&conn->ehwait); |
1538 | 1523 | ||
1539 | return cls_conn; | 1524 | return cls_conn; |
@@ -1544,8 +1529,6 @@ login_mtask_data_alloc_fail: | |||
1544 | login_mtask_alloc_fail: | 1529 | login_mtask_alloc_fail: |
1545 | kfifo_free(conn->mgmtqueue); | 1530 | kfifo_free(conn->mgmtqueue); |
1546 | mgmtqueue_alloc_fail: | 1531 | mgmtqueue_alloc_fail: |
1547 | kfifo_free(conn->immqueue); | ||
1548 | immqueue_alloc_fail: | ||
1549 | iscsi_destroy_conn(cls_conn); | 1532 | iscsi_destroy_conn(cls_conn); |
1550 | return NULL; | 1533 | return NULL; |
1551 | } | 1534 | } |
@@ -1564,10 +1547,8 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) | |||
1564 | struct iscsi_session *session = conn->session; | 1547 | struct iscsi_session *session = conn->session; |
1565 | unsigned long flags; | 1548 | unsigned long flags; |
1566 | 1549 | ||
1567 | set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); | ||
1568 | mutex_lock(&conn->xmitmutex); | ||
1569 | |||
1570 | spin_lock_bh(&session->lock); | 1550 | spin_lock_bh(&session->lock); |
1551 | set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); | ||
1571 | conn->c_stage = ISCSI_CONN_CLEANUP_WAIT; | 1552 | conn->c_stage = ISCSI_CONN_CLEANUP_WAIT; |
1572 | if (session->leadconn == conn) { | 1553 | if (session->leadconn == conn) { |
1573 | /* | 1554 | /* |
@@ -1578,8 +1559,6 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) | |||
1578 | } | 1559 | } |
1579 | spin_unlock_bh(&session->lock); | 1560 | spin_unlock_bh(&session->lock); |
1580 | 1561 | ||
1581 | mutex_unlock(&conn->xmitmutex); | ||
1582 | |||
1583 | /* | 1562 | /* |
1584 | * Block until all in-progress commands for this connection | 1563 | * Block until all in-progress commands for this connection |
1585 | * time out or fail. | 1564 | * time out or fail. |
@@ -1616,7 +1595,6 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) | |||
1616 | } | 1595 | } |
1617 | spin_unlock_bh(&session->lock); | 1596 | spin_unlock_bh(&session->lock); |
1618 | 1597 | ||
1619 | kfifo_free(conn->immqueue); | ||
1620 | kfifo_free(conn->mgmtqueue); | 1598 | kfifo_free(conn->mgmtqueue); |
1621 | 1599 | ||
1622 | iscsi_destroy_conn(cls_conn); | 1600 | iscsi_destroy_conn(cls_conn); |
@@ -1677,8 +1655,7 @@ flush_control_queues(struct iscsi_session *session, struct iscsi_conn *conn) | |||
1677 | struct iscsi_mgmt_task *mtask, *tmp; | 1655 | struct iscsi_mgmt_task *mtask, *tmp; |
1678 | 1656 | ||
1679 | /* handle pending */ | 1657 | /* handle pending */ |
1680 | while (__kfifo_get(conn->immqueue, (void*)&mtask, sizeof(void*)) || | 1658 | while (__kfifo_get(conn->mgmtqueue, (void*)&mtask, sizeof(void*))) { |
1681 | __kfifo_get(conn->mgmtqueue, (void*)&mtask, sizeof(void*))) { | ||
1682 | if (mtask == conn->login_mtask) | 1659 | if (mtask == conn->login_mtask) |
1683 | continue; | 1660 | continue; |
1684 | debug_scsi("flushing pending mgmt task itt 0x%x\n", mtask->itt); | 1661 | debug_scsi("flushing pending mgmt task itt 0x%x\n", mtask->itt); |
@@ -1748,12 +1725,12 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, | |||
1748 | conn->c_stage = ISCSI_CONN_STOPPED; | 1725 | conn->c_stage = ISCSI_CONN_STOPPED; |
1749 | set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); | 1726 | set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); |
1750 | spin_unlock_bh(&session->lock); | 1727 | spin_unlock_bh(&session->lock); |
1728 | scsi_flush_work(session->host); | ||
1751 | 1729 | ||
1752 | write_lock_bh(conn->recv_lock); | 1730 | write_lock_bh(conn->recv_lock); |
1753 | set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx); | 1731 | set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx); |
1754 | write_unlock_bh(conn->recv_lock); | 1732 | write_unlock_bh(conn->recv_lock); |
1755 | 1733 | ||
1756 | mutex_lock(&conn->xmitmutex); | ||
1757 | /* | 1734 | /* |
1758 | * for connection level recovery we should not calculate | 1735 | * for connection level recovery we should not calculate |
1759 | * header digest. conn->hdr_size used for optimization | 1736 | * header digest. conn->hdr_size used for optimization |
@@ -1777,8 +1754,6 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, | |||
1777 | fail_all_commands(conn); | 1754 | fail_all_commands(conn); |
1778 | flush_control_queues(session, conn); | 1755 | flush_control_queues(session, conn); |
1779 | spin_unlock_bh(&session->lock); | 1756 | spin_unlock_bh(&session->lock); |
1780 | |||
1781 | mutex_unlock(&conn->xmitmutex); | ||
1782 | } | 1757 | } |
1783 | 1758 | ||
1784 | void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) | 1759 | void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) |