diff options
author | Nicholas Bellinger <nab@linux-iscsi.org> | 2013-07-30 00:04:02 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-08-04 04:51:17 -0400 |
commit | adb97c299904814edb0bb26ae894139ca46ae446 (patch) | |
tree | 280a717a52abb15847e98d4e9f85b5c54b672d26 | |
parent | 1aa58ccd029fc75c115ae35c3fcb4d43043c0725 (diff) |
iscsi-target: Fix iscsit_sequence_cmd reject handling for iser
commit 561bf15892375597ee59d473a704a3e634c4f311 upstream
This patch moves ISCSI_OP_REJECT failures into iscsit_sequence_cmd()
in order to avoid external iscsit_reject_cmd() reject usage for all
PDU types.
It also updates PDU specific handlers for traditional iscsi-target
code to not reset the session after posting a ISCSI_OP_REJECT during
setup.
(v2: Fix CMDSN_LOWER_THAN_EXP for ISCSI_OP_SCSI to call
target_put_sess_cmd() after iscsit_sequence_cmd() failure)
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Cc: Or Gerlitz <ogerlitz@mellanox.com>
Cc: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/infiniband/ulp/isert/ib_isert.c | 2 | ||||
-rw-r--r-- | drivers/target/iscsi/iscsi_target.c | 50 | ||||
-rw-r--r-- | drivers/target/iscsi/iscsi_target_erl1.c | 6 | ||||
-rw-r--r-- | drivers/target/iscsi/iscsi_target_util.c | 26 | ||||
-rw-r--r-- | drivers/target/iscsi/iscsi_target_util.h | 3 | ||||
-rw-r--r-- | include/target/iscsi/iscsi_transport.h | 3 |
6 files changed, 60 insertions, 30 deletions
diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c index 4f6faf0915d5..5849dc0726b9 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.c +++ b/drivers/infiniband/ulp/isert/ib_isert.c | |||
@@ -952,7 +952,7 @@ isert_handle_scsi_cmd(struct isert_conn *isert_conn, | |||
952 | } | 952 | } |
953 | 953 | ||
954 | sequence_cmd: | 954 | sequence_cmd: |
955 | rc = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn); | 955 | rc = iscsit_sequence_cmd(conn, cmd, buf, hdr->cmdsn); |
956 | 956 | ||
957 | if (!rc && dump_payload == false && unsol_data) | 957 | if (!rc && dump_payload == false && unsol_data) |
958 | iscsit_set_unsoliticed_dataout(cmd); | 958 | iscsit_set_unsoliticed_dataout(cmd); |
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 03ccb610d2bb..012ff8bab0f8 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c | |||
@@ -1052,11 +1052,11 @@ int iscsit_process_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, | |||
1052 | * be acknowledged. (See below) | 1052 | * be acknowledged. (See below) |
1053 | */ | 1053 | */ |
1054 | if (!cmd->immediate_data) { | 1054 | if (!cmd->immediate_data) { |
1055 | cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn); | 1055 | cmdsn_ret = iscsit_sequence_cmd(conn, cmd, |
1056 | if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) { | 1056 | (unsigned char *)hdr, hdr->cmdsn); |
1057 | if (!cmd->sense_reason) | 1057 | if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) |
1058 | return 0; | 1058 | return -1; |
1059 | 1059 | else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) { | |
1060 | target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd); | 1060 | target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd); |
1061 | return 0; | 1061 | return 0; |
1062 | } | 1062 | } |
@@ -1083,6 +1083,9 @@ int iscsit_process_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, | |||
1083 | * iscsit_check_received_cmdsn() in iscsit_get_immediate_data() below. | 1083 | * iscsit_check_received_cmdsn() in iscsit_get_immediate_data() below. |
1084 | */ | 1084 | */ |
1085 | if (cmd->sense_reason) { | 1085 | if (cmd->sense_reason) { |
1086 | if (cmd->reject_reason) | ||
1087 | return 0; | ||
1088 | |||
1086 | target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd); | 1089 | target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd); |
1087 | return 1; | 1090 | return 1; |
1088 | } | 1091 | } |
@@ -1091,10 +1094,8 @@ int iscsit_process_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, | |||
1091 | * the backend memory allocation. | 1094 | * the backend memory allocation. |
1092 | */ | 1095 | */ |
1093 | cmd->sense_reason = transport_generic_new_cmd(&cmd->se_cmd); | 1096 | cmd->sense_reason = transport_generic_new_cmd(&cmd->se_cmd); |
1094 | if (cmd->sense_reason) { | 1097 | if (cmd->sense_reason) |
1095 | target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd); | ||
1096 | return 1; | 1098 | return 1; |
1097 | } | ||
1098 | 1099 | ||
1099 | return 0; | 1100 | return 0; |
1100 | } | 1101 | } |
@@ -1104,6 +1105,7 @@ static int | |||
1104 | iscsit_get_immediate_data(struct iscsi_cmd *cmd, struct iscsi_scsi_req *hdr, | 1105 | iscsit_get_immediate_data(struct iscsi_cmd *cmd, struct iscsi_scsi_req *hdr, |
1105 | bool dump_payload) | 1106 | bool dump_payload) |
1106 | { | 1107 | { |
1108 | struct iscsi_conn *conn = cmd->conn; | ||
1107 | int cmdsn_ret = 0, immed_ret = IMMEDIATE_DATA_NORMAL_OPERATION; | 1109 | int cmdsn_ret = 0, immed_ret = IMMEDIATE_DATA_NORMAL_OPERATION; |
1108 | /* | 1110 | /* |
1109 | * Special case for Unsupported SAM WRITE Opcodes and ImmediateData=Yes. | 1111 | * Special case for Unsupported SAM WRITE Opcodes and ImmediateData=Yes. |
@@ -1120,12 +1122,22 @@ after_immediate_data: | |||
1120 | * DataCRC, check against ExpCmdSN/MaxCmdSN if | 1122 | * DataCRC, check against ExpCmdSN/MaxCmdSN if |
1121 | * Immediate Bit is not set. | 1123 | * Immediate Bit is not set. |
1122 | */ | 1124 | */ |
1123 | cmdsn_ret = iscsit_sequence_cmd(cmd->conn, cmd, hdr->cmdsn); | 1125 | cmdsn_ret = iscsit_sequence_cmd(cmd->conn, cmd, |
1126 | (unsigned char *)hdr, hdr->cmdsn); | ||
1127 | if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) { | ||
1128 | return -1; | ||
1129 | } else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) { | ||
1130 | target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd); | ||
1131 | return 0; | ||
1132 | } | ||
1124 | 1133 | ||
1125 | if (cmd->sense_reason) { | 1134 | if (cmd->sense_reason) { |
1126 | if (iscsit_dump_data_payload(cmd->conn, | 1135 | int rc; |
1127 | cmd->first_burst_len, 1) < 0) | 1136 | |
1128 | return -1; | 1137 | rc = iscsit_dump_data_payload(cmd->conn, |
1138 | cmd->first_burst_len, 1); | ||
1139 | target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd); | ||
1140 | return rc; | ||
1129 | } else if (cmd->unsolicited_data) | 1141 | } else if (cmd->unsolicited_data) |
1130 | iscsit_set_unsoliticed_dataout(cmd); | 1142 | iscsit_set_unsoliticed_dataout(cmd); |
1131 | 1143 | ||
@@ -1159,7 +1171,7 @@ iscsit_handle_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, | |||
1159 | 1171 | ||
1160 | rc = iscsit_setup_scsi_cmd(conn, cmd, buf); | 1172 | rc = iscsit_setup_scsi_cmd(conn, cmd, buf); |
1161 | if (rc < 0) | 1173 | if (rc < 0) |
1162 | return rc; | 1174 | return 0; |
1163 | /* | 1175 | /* |
1164 | * Allocation iovecs needed for struct socket operations for | 1176 | * Allocation iovecs needed for struct socket operations for |
1165 | * traditional iSCSI block I/O. | 1177 | * traditional iSCSI block I/O. |
@@ -1500,7 +1512,7 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf) | |||
1500 | 1512 | ||
1501 | rc = iscsit_check_dataout_hdr(conn, buf, &cmd); | 1513 | rc = iscsit_check_dataout_hdr(conn, buf, &cmd); |
1502 | if (rc < 0) | 1514 | if (rc < 0) |
1503 | return rc; | 1515 | return 0; |
1504 | else if (!cmd) | 1516 | else if (!cmd) |
1505 | return 0; | 1517 | return 0; |
1506 | 1518 | ||
@@ -1672,7 +1684,8 @@ int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd, | |||
1672 | return 0; | 1684 | return 0; |
1673 | } | 1685 | } |
1674 | 1686 | ||
1675 | cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn); | 1687 | cmdsn_ret = iscsit_sequence_cmd(conn, cmd, |
1688 | (unsigned char *)hdr, hdr->cmdsn); | ||
1676 | if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) { | 1689 | if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) { |
1677 | ret = 0; | 1690 | ret = 0; |
1678 | goto ping_out; | 1691 | goto ping_out; |
@@ -1898,7 +1911,7 @@ attach: | |||
1898 | spin_unlock_bh(&conn->cmd_lock); | 1911 | spin_unlock_bh(&conn->cmd_lock); |
1899 | 1912 | ||
1900 | if (!(hdr->opcode & ISCSI_OP_IMMEDIATE)) { | 1913 | if (!(hdr->opcode & ISCSI_OP_IMMEDIATE)) { |
1901 | int cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn); | 1914 | int cmdsn_ret = iscsit_sequence_cmd(conn, cmd, buf, hdr->cmdsn); |
1902 | if (cmdsn_ret == CMDSN_HIGHER_THAN_EXP) | 1915 | if (cmdsn_ret == CMDSN_HIGHER_THAN_EXP) |
1903 | out_of_order_cmdsn = 1; | 1916 | out_of_order_cmdsn = 1; |
1904 | else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) | 1917 | else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) |
@@ -2075,7 +2088,8 @@ static int iscsit_handle_text_cmd( | |||
2075 | iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn)); | 2088 | iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn)); |
2076 | 2089 | ||
2077 | if (!(hdr->opcode & ISCSI_OP_IMMEDIATE)) { | 2090 | if (!(hdr->opcode & ISCSI_OP_IMMEDIATE)) { |
2078 | cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn); | 2091 | cmdsn_ret = iscsit_sequence_cmd(conn, cmd, |
2092 | (unsigned char *)hdr, hdr->cmdsn); | ||
2079 | if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) | 2093 | if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) |
2080 | return -1; | 2094 | return -1; |
2081 | 2095 | ||
@@ -2262,7 +2276,7 @@ iscsit_handle_logout_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, | |||
2262 | if (ret < 0) | 2276 | if (ret < 0) |
2263 | return ret; | 2277 | return ret; |
2264 | } else { | 2278 | } else { |
2265 | cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn); | 2279 | cmdsn_ret = iscsit_sequence_cmd(conn, cmd, buf, hdr->cmdsn); |
2266 | if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) | 2280 | if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) |
2267 | logout_remove = 0; | 2281 | logout_remove = 0; |
2268 | else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) | 2282 | else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) |
diff --git a/drivers/target/iscsi/iscsi_target_erl1.c b/drivers/target/iscsi/iscsi_target_erl1.c index d00f1326f0c8..586c268679a4 100644 --- a/drivers/target/iscsi/iscsi_target_erl1.c +++ b/drivers/target/iscsi/iscsi_target_erl1.c | |||
@@ -1088,7 +1088,7 @@ int iscsit_handle_ooo_cmdsn( | |||
1088 | 1088 | ||
1089 | ooo_cmdsn = iscsit_allocate_ooo_cmdsn(); | 1089 | ooo_cmdsn = iscsit_allocate_ooo_cmdsn(); |
1090 | if (!ooo_cmdsn) | 1090 | if (!ooo_cmdsn) |
1091 | return CMDSN_ERROR_CANNOT_RECOVER; | 1091 | return -ENOMEM; |
1092 | 1092 | ||
1093 | ooo_cmdsn->cmd = cmd; | 1093 | ooo_cmdsn->cmd = cmd; |
1094 | ooo_cmdsn->batch_count = (batch) ? | 1094 | ooo_cmdsn->batch_count = (batch) ? |
@@ -1099,10 +1099,10 @@ int iscsit_handle_ooo_cmdsn( | |||
1099 | 1099 | ||
1100 | if (iscsit_attach_ooo_cmdsn(sess, ooo_cmdsn) < 0) { | 1100 | if (iscsit_attach_ooo_cmdsn(sess, ooo_cmdsn) < 0) { |
1101 | kmem_cache_free(lio_ooo_cache, ooo_cmdsn); | 1101 | kmem_cache_free(lio_ooo_cache, ooo_cmdsn); |
1102 | return CMDSN_ERROR_CANNOT_RECOVER; | 1102 | return -ENOMEM; |
1103 | } | 1103 | } |
1104 | 1104 | ||
1105 | return CMDSN_HIGHER_THAN_EXP; | 1105 | return 0; |
1106 | } | 1106 | } |
1107 | 1107 | ||
1108 | static int iscsit_set_dataout_timeout_values( | 1108 | static int iscsit_set_dataout_timeout_values( |
diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index 6374a1a98d6b..96e7fdbba9fc 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c | |||
@@ -283,13 +283,12 @@ static inline int iscsit_check_received_cmdsn(struct iscsi_session *sess, u32 cm | |||
283 | * Commands may be received out of order if MC/S is in use. | 283 | * Commands may be received out of order if MC/S is in use. |
284 | * Ensure they are executed in CmdSN order. | 284 | * Ensure they are executed in CmdSN order. |
285 | */ | 285 | */ |
286 | int iscsit_sequence_cmd( | 286 | int iscsit_sequence_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, |
287 | struct iscsi_conn *conn, | 287 | unsigned char *buf, __be32 cmdsn) |
288 | struct iscsi_cmd *cmd, | ||
289 | __be32 cmdsn) | ||
290 | { | 288 | { |
291 | int ret; | 289 | int ret, cmdsn_ret; |
292 | int cmdsn_ret; | 290 | bool reject = false; |
291 | u8 reason = ISCSI_REASON_BOOKMARK_NO_RESOURCES; | ||
293 | 292 | ||
294 | mutex_lock(&conn->sess->cmdsn_mutex); | 293 | mutex_lock(&conn->sess->cmdsn_mutex); |
295 | 294 | ||
@@ -299,9 +298,19 @@ int iscsit_sequence_cmd( | |||
299 | ret = iscsit_execute_cmd(cmd, 0); | 298 | ret = iscsit_execute_cmd(cmd, 0); |
300 | if ((ret >= 0) && !list_empty(&conn->sess->sess_ooo_cmdsn_list)) | 299 | if ((ret >= 0) && !list_empty(&conn->sess->sess_ooo_cmdsn_list)) |
301 | iscsit_execute_ooo_cmdsns(conn->sess); | 300 | iscsit_execute_ooo_cmdsns(conn->sess); |
301 | else if (ret < 0) { | ||
302 | reject = true; | ||
303 | ret = CMDSN_ERROR_CANNOT_RECOVER; | ||
304 | } | ||
302 | break; | 305 | break; |
303 | case CMDSN_HIGHER_THAN_EXP: | 306 | case CMDSN_HIGHER_THAN_EXP: |
304 | ret = iscsit_handle_ooo_cmdsn(conn->sess, cmd, be32_to_cpu(cmdsn)); | 307 | ret = iscsit_handle_ooo_cmdsn(conn->sess, cmd, be32_to_cpu(cmdsn)); |
308 | if (ret < 0) { | ||
309 | reject = true; | ||
310 | ret = CMDSN_ERROR_CANNOT_RECOVER; | ||
311 | break; | ||
312 | } | ||
313 | ret = CMDSN_HIGHER_THAN_EXP; | ||
305 | break; | 314 | break; |
306 | case CMDSN_LOWER_THAN_EXP: | 315 | case CMDSN_LOWER_THAN_EXP: |
307 | cmd->i_state = ISTATE_REMOVE; | 316 | cmd->i_state = ISTATE_REMOVE; |
@@ -309,11 +318,16 @@ int iscsit_sequence_cmd( | |||
309 | ret = cmdsn_ret; | 318 | ret = cmdsn_ret; |
310 | break; | 319 | break; |
311 | default: | 320 | default: |
321 | reason = ISCSI_REASON_PROTOCOL_ERROR; | ||
322 | reject = true; | ||
312 | ret = cmdsn_ret; | 323 | ret = cmdsn_ret; |
313 | break; | 324 | break; |
314 | } | 325 | } |
315 | mutex_unlock(&conn->sess->cmdsn_mutex); | 326 | mutex_unlock(&conn->sess->cmdsn_mutex); |
316 | 327 | ||
328 | if (reject) | ||
329 | iscsit_reject_cmd(cmd, reason, buf); | ||
330 | |||
317 | return ret; | 331 | return ret; |
318 | } | 332 | } |
319 | EXPORT_SYMBOL(iscsit_sequence_cmd); | 333 | EXPORT_SYMBOL(iscsit_sequence_cmd); |
diff --git a/drivers/target/iscsi/iscsi_target_util.h b/drivers/target/iscsi/iscsi_target_util.h index a4422659d049..e4fc34a02f57 100644 --- a/drivers/target/iscsi/iscsi_target_util.h +++ b/drivers/target/iscsi/iscsi_target_util.h | |||
@@ -13,7 +13,8 @@ extern struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *, gfp_t); | |||
13 | extern struct iscsi_seq *iscsit_get_seq_holder_for_datain(struct iscsi_cmd *, u32); | 13 | extern struct iscsi_seq *iscsit_get_seq_holder_for_datain(struct iscsi_cmd *, u32); |
14 | extern struct iscsi_seq *iscsit_get_seq_holder_for_r2t(struct iscsi_cmd *); | 14 | extern struct iscsi_seq *iscsit_get_seq_holder_for_r2t(struct iscsi_cmd *); |
15 | extern struct iscsi_r2t *iscsit_get_holder_for_r2tsn(struct iscsi_cmd *, u32); | 15 | extern struct iscsi_r2t *iscsit_get_holder_for_r2tsn(struct iscsi_cmd *, u32); |
16 | int iscsit_sequence_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, __be32 cmdsn); | 16 | extern int iscsit_sequence_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, |
17 | unsigned char * ,__be32 cmdsn); | ||
17 | extern int iscsit_check_unsolicited_dataout(struct iscsi_cmd *, unsigned char *); | 18 | extern int iscsit_check_unsolicited_dataout(struct iscsi_cmd *, unsigned char *); |
18 | extern struct iscsi_cmd *iscsit_find_cmd_from_itt(struct iscsi_conn *, itt_t); | 19 | extern struct iscsi_cmd *iscsit_find_cmd_from_itt(struct iscsi_conn *, itt_t); |
19 | extern struct iscsi_cmd *iscsit_find_cmd_from_itt_or_dump(struct iscsi_conn *, | 20 | extern struct iscsi_cmd *iscsit_find_cmd_from_itt_or_dump(struct iscsi_conn *, |
diff --git a/include/target/iscsi/iscsi_transport.h b/include/target/iscsi/iscsi_transport.h index c8da4dd11d26..c5aade523863 100644 --- a/include/target/iscsi/iscsi_transport.h +++ b/include/target/iscsi/iscsi_transport.h | |||
@@ -82,4 +82,5 @@ extern int iscsit_tmr_post_handler(struct iscsi_cmd *, struct iscsi_conn *); | |||
82 | * From iscsi_target_util.c | 82 | * From iscsi_target_util.c |
83 | */ | 83 | */ |
84 | extern struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *, gfp_t); | 84 | extern struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *, gfp_t); |
85 | extern int iscsit_sequence_cmd(struct iscsi_conn *, struct iscsi_cmd *, __be32); | 85 | extern int iscsit_sequence_cmd(struct iscsi_conn *, struct iscsi_cmd *, |
86 | unsigned char *, __be32); | ||