.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /******************************************************************************* |
---|
2 | 3 | * This file contains error recovery level one used by the iSCSI Target driver. |
---|
3 | 4 | * |
---|
.. | .. |
---|
5 | 6 | * |
---|
6 | 7 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> |
---|
7 | 8 | * |
---|
8 | | - * This program is free software; you can redistribute it and/or modify |
---|
9 | | - * it under the terms of the GNU General Public License as published by |
---|
10 | | - * the Free Software Foundation; either version 2 of the License, or |
---|
11 | | - * (at your option) any later version. |
---|
12 | | - * |
---|
13 | | - * This program is distributed in the hope that it will be useful, |
---|
14 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
15 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
16 | | - * GNU General Public License for more details. |
---|
17 | 9 | ******************************************************************************/ |
---|
18 | 10 | |
---|
19 | 11 | #include <linux/list.h> |
---|
.. | .. |
---|
48 | 40 | u32 buf_len, |
---|
49 | 41 | int dump_padding_digest) |
---|
50 | 42 | { |
---|
51 | | - char *buf, pad_bytes[4]; |
---|
| 43 | + char *buf; |
---|
52 | 44 | int ret = DATAOUT_WITHIN_COMMAND_RECOVERY, rx_got; |
---|
53 | | - u32 length, padding, offset = 0, size; |
---|
| 45 | + u32 length, offset = 0, size; |
---|
54 | 46 | struct kvec iov; |
---|
55 | 47 | |
---|
56 | 48 | if (conn->sess->sess_ops->RDMAExtensions) |
---|
57 | 49 | return 0; |
---|
| 50 | + |
---|
| 51 | + if (dump_padding_digest) { |
---|
| 52 | + buf_len = ALIGN(buf_len, 4); |
---|
| 53 | + if (conn->conn_ops->DataDigest) |
---|
| 54 | + buf_len += ISCSI_CRC_LEN; |
---|
| 55 | + } |
---|
58 | 56 | |
---|
59 | 57 | length = min(buf_len, OFFLOAD_BUF_SIZE); |
---|
60 | 58 | |
---|
.. | .. |
---|
75 | 73 | rx_got = rx_data(conn, &iov, 1, size); |
---|
76 | 74 | if (rx_got != size) { |
---|
77 | 75 | ret = DATAOUT_CANNOT_RECOVER; |
---|
78 | | - goto out; |
---|
| 76 | + break; |
---|
79 | 77 | } |
---|
80 | 78 | |
---|
81 | 79 | offset += size; |
---|
82 | 80 | } |
---|
83 | 81 | |
---|
84 | | - if (!dump_padding_digest) |
---|
85 | | - goto out; |
---|
86 | | - |
---|
87 | | - padding = ((-buf_len) & 3); |
---|
88 | | - if (padding != 0) { |
---|
89 | | - iov.iov_len = padding; |
---|
90 | | - iov.iov_base = pad_bytes; |
---|
91 | | - |
---|
92 | | - rx_got = rx_data(conn, &iov, 1, padding); |
---|
93 | | - if (rx_got != padding) { |
---|
94 | | - ret = DATAOUT_CANNOT_RECOVER; |
---|
95 | | - goto out; |
---|
96 | | - } |
---|
97 | | - } |
---|
98 | | - |
---|
99 | | - if (conn->conn_ops->DataDigest) { |
---|
100 | | - u32 data_crc; |
---|
101 | | - |
---|
102 | | - iov.iov_len = ISCSI_CRC_LEN; |
---|
103 | | - iov.iov_base = &data_crc; |
---|
104 | | - |
---|
105 | | - rx_got = rx_data(conn, &iov, 1, ISCSI_CRC_LEN); |
---|
106 | | - if (rx_got != ISCSI_CRC_LEN) { |
---|
107 | | - ret = DATAOUT_CANNOT_RECOVER; |
---|
108 | | - goto out; |
---|
109 | | - } |
---|
110 | | - } |
---|
111 | | - |
---|
112 | | -out: |
---|
113 | 82 | kfree(buf); |
---|
114 | 83 | return ret; |
---|
115 | 84 | } |
---|
.. | .. |
---|
797 | 766 | return ooo_cmdsn; |
---|
798 | 767 | } |
---|
799 | 768 | |
---|
800 | | -/* |
---|
801 | | - * Called with sess->cmdsn_mutex held. |
---|
802 | | - */ |
---|
803 | 769 | static int iscsit_attach_ooo_cmdsn( |
---|
804 | 770 | struct iscsi_session *sess, |
---|
805 | 771 | struct iscsi_ooo_cmdsn *ooo_cmdsn) |
---|
806 | 772 | { |
---|
807 | 773 | struct iscsi_ooo_cmdsn *ooo_tail, *ooo_tmp; |
---|
| 774 | + |
---|
| 775 | + lockdep_assert_held(&sess->cmdsn_mutex); |
---|
| 776 | + |
---|
808 | 777 | /* |
---|
809 | 778 | * We attach the struct iscsi_ooo_cmdsn entry to the out of order |
---|
810 | 779 | * list in increasing CmdSN order. |
---|
.. | .. |
---|
871 | 840 | mutex_unlock(&sess->cmdsn_mutex); |
---|
872 | 841 | } |
---|
873 | 842 | |
---|
874 | | -/* |
---|
875 | | - * Called with sess->cmdsn_mutex held. |
---|
876 | | - */ |
---|
877 | 843 | int iscsit_execute_ooo_cmdsns(struct iscsi_session *sess) |
---|
878 | 844 | { |
---|
879 | 845 | int ooo_count = 0; |
---|
880 | 846 | struct iscsi_cmd *cmd = NULL; |
---|
881 | 847 | struct iscsi_ooo_cmdsn *ooo_cmdsn, *ooo_cmdsn_tmp; |
---|
| 848 | + |
---|
| 849 | + lockdep_assert_held(&sess->cmdsn_mutex); |
---|
882 | 850 | |
---|
883 | 851 | list_for_each_entry_safe(ooo_cmdsn, ooo_cmdsn_tmp, |
---|
884 | 852 | &sess->sess_ooo_cmdsn_list, ooo_list) { |
---|
.. | .. |
---|
943 | 911 | return 0; |
---|
944 | 912 | } |
---|
945 | 913 | spin_unlock_bh(&cmd->istate_lock); |
---|
946 | | - /* |
---|
947 | | - * Determine if delayed TASK_ABORTED status for WRITEs |
---|
948 | | - * should be sent now if no unsolicited data out |
---|
949 | | - * payloads are expected, or if the delayed status |
---|
950 | | - * should be sent after unsolicited data out with |
---|
951 | | - * ISCSI_FLAG_CMD_FINAL set in iscsi_handle_data_out() |
---|
952 | | - */ |
---|
953 | | - if (transport_check_aborted_status(se_cmd, |
---|
954 | | - (cmd->unsolicited_data == 0)) != 0) |
---|
| 914 | + if (cmd->se_cmd.transport_state & CMD_T_ABORTED) |
---|
955 | 915 | return 0; |
---|
956 | | - /* |
---|
957 | | - * Otherwise send CHECK_CONDITION and sense for |
---|
958 | | - * exception |
---|
959 | | - */ |
---|
960 | 916 | return transport_send_check_condition_and_sense(se_cmd, |
---|
961 | 917 | cmd->sense_reason, 0); |
---|
962 | 918 | } |
---|
.. | .. |
---|
974 | 930 | |
---|
975 | 931 | if (!(cmd->cmd_flags & |
---|
976 | 932 | ICF_NON_IMMEDIATE_UNSOLICITED_DATA)) { |
---|
977 | | - /* |
---|
978 | | - * Send the delayed TASK_ABORTED status for |
---|
979 | | - * WRITEs if no more unsolicitied data is |
---|
980 | | - * expected. |
---|
981 | | - */ |
---|
982 | | - if (transport_check_aborted_status(se_cmd, 1) |
---|
983 | | - != 0) |
---|
| 933 | + if (cmd->se_cmd.transport_state & CMD_T_ABORTED) |
---|
984 | 934 | return 0; |
---|
985 | 935 | |
---|
986 | 936 | iscsit_set_dataout_sequence_values(cmd); |
---|
.. | .. |
---|
995 | 945 | |
---|
996 | 946 | if ((cmd->data_direction == DMA_TO_DEVICE) && |
---|
997 | 947 | !(cmd->cmd_flags & ICF_NON_IMMEDIATE_UNSOLICITED_DATA)) { |
---|
998 | | - /* |
---|
999 | | - * Send the delayed TASK_ABORTED status for WRITEs if |
---|
1000 | | - * no more nsolicitied data is expected. |
---|
1001 | | - */ |
---|
1002 | | - if (transport_check_aborted_status(se_cmd, 1) != 0) |
---|
| 948 | + if (cmd->se_cmd.transport_state & CMD_T_ABORTED) |
---|
1003 | 949 | return 0; |
---|
1004 | 950 | |
---|
1005 | | - iscsit_set_unsoliticed_dataout(cmd); |
---|
| 951 | + iscsit_set_unsolicited_dataout(cmd); |
---|
1006 | 952 | } |
---|
1007 | 953 | return transport_handle_cdb_direct(&cmd->se_cmd); |
---|
1008 | 954 | |
---|
.. | .. |
---|
1169 | 1115 | na = iscsit_tpg_get_node_attrib(sess); |
---|
1170 | 1116 | |
---|
1171 | 1117 | if (!sess->sess_ops->ErrorRecoveryLevel) { |
---|
1172 | | - pr_debug("Unable to recover from DataOut timeout while" |
---|
1173 | | - " in ERL=0.\n"); |
---|
| 1118 | + pr_err("Unable to recover from DataOut timeout while" |
---|
| 1119 | + " in ERL=0, closing iSCSI connection for I_T Nexus" |
---|
| 1120 | + " %s,i,0x%6phN,%s,t,0x%02x\n", |
---|
| 1121 | + sess->sess_ops->InitiatorName, sess->isid, |
---|
| 1122 | + sess->tpg->tpg_tiqn->tiqn, (u32)sess->tpg->tpgt); |
---|
1174 | 1123 | goto failure; |
---|
1175 | 1124 | } |
---|
1176 | 1125 | |
---|
1177 | 1126 | if (++cmd->dataout_timeout_retries == na->dataout_timeout_retries) { |
---|
1178 | | - pr_debug("Command ITT: 0x%08x exceeded max retries" |
---|
1179 | | - " for DataOUT timeout %u, closing iSCSI connection.\n", |
---|
1180 | | - cmd->init_task_tag, na->dataout_timeout_retries); |
---|
| 1127 | + pr_err("Command ITT: 0x%08x exceeded max retries" |
---|
| 1128 | + " for DataOUT timeout %u, closing iSCSI connection for" |
---|
| 1129 | + " I_T Nexus %s,i,0x%6phN,%s,t,0x%02x\n", |
---|
| 1130 | + cmd->init_task_tag, na->dataout_timeout_retries, |
---|
| 1131 | + sess->sess_ops->InitiatorName, sess->isid, |
---|
| 1132 | + sess->tpg->tpg_tiqn->tiqn, (u32)sess->tpg->tpgt); |
---|
1181 | 1133 | goto failure; |
---|
1182 | 1134 | } |
---|
1183 | 1135 | |
---|
.. | .. |
---|
1224 | 1176 | |
---|
1225 | 1177 | failure: |
---|
1226 | 1178 | spin_unlock_bh(&cmd->dataout_timeout_lock); |
---|
| 1179 | + iscsit_fill_cxn_timeout_err_stats(sess); |
---|
1227 | 1180 | iscsit_cause_connection_reinstatement(conn, 0); |
---|
1228 | 1181 | iscsit_dec_conn_usage_count(conn); |
---|
1229 | 1182 | } |
---|
.. | .. |
---|
1247 | 1200 | spin_unlock_bh(&cmd->dataout_timeout_lock); |
---|
1248 | 1201 | } |
---|
1249 | 1202 | |
---|
1250 | | -/* |
---|
1251 | | - * Called with cmd->dataout_timeout_lock held. |
---|
1252 | | - */ |
---|
1253 | 1203 | void iscsit_start_dataout_timer( |
---|
1254 | 1204 | struct iscsi_cmd *cmd, |
---|
1255 | 1205 | struct iscsi_conn *conn) |
---|
.. | .. |
---|
1257 | 1207 | struct iscsi_session *sess = conn->sess; |
---|
1258 | 1208 | struct iscsi_node_attrib *na = iscsit_tpg_get_node_attrib(sess); |
---|
1259 | 1209 | |
---|
| 1210 | + lockdep_assert_held(&cmd->dataout_timeout_lock); |
---|
| 1211 | + |
---|
1260 | 1212 | if (cmd->dataout_timer_flags & ISCSI_TF_RUNNING) |
---|
1261 | 1213 | return; |
---|
1262 | 1214 | |
---|