Commit 683497566d48f86e04d026de1ee658dd74fc1077
1 parent
83ff42fcce
Exists in
ti-lsk-linux-4.1.y
and in
10 other branches
iscsi-target: Explicily clear login response PDU in exception path
This patch adds a explicit memset to the login response PDU exception path in iscsit_tx_login_rsp(). This addresses a regression bug introduced in commit baa4d64b where the initiator would end up not receiving the login response and associated status class + detail, before closing the login connection. Reported-by: Christophe Vu-Brugier <cvubrugier@yahoo.fr> Tested-by: Christophe Vu-Brugier <cvubrugier@yahoo.fr> Cc: stable@vger.kernel.org # 3.10+ Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Showing 1 changed file with 2 additions and 0 deletions Inline Diff
drivers/target/iscsi/iscsi_target_util.c
1 | /******************************************************************************* | 1 | /******************************************************************************* |
2 | * This file contains the iSCSI Target specific utility functions. | 2 | * This file contains the iSCSI Target specific utility functions. |
3 | * | 3 | * |
4 | * (c) Copyright 2007-2013 Datera, Inc. | 4 | * (c) Copyright 2007-2013 Datera, Inc. |
5 | * | 5 | * |
6 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> | 6 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify | 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 | 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 | 10 | * the Free Software Foundation; either version 2 of the License, or |
11 | * (at your option) any later version. | 11 | * (at your option) any later version. |
12 | * | 12 | * |
13 | * This program is distributed in the hope that it will be useful, | 13 | * This program is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | * GNU General Public License for more details. | 16 | * GNU General Public License for more details. |
17 | ******************************************************************************/ | 17 | ******************************************************************************/ |
18 | 18 | ||
19 | #include <linux/list.h> | 19 | #include <linux/list.h> |
20 | #include <linux/percpu_ida.h> | 20 | #include <linux/percpu_ida.h> |
21 | #include <scsi/scsi_tcq.h> | 21 | #include <scsi/scsi_tcq.h> |
22 | #include <scsi/iscsi_proto.h> | 22 | #include <scsi/iscsi_proto.h> |
23 | #include <target/target_core_base.h> | 23 | #include <target/target_core_base.h> |
24 | #include <target/target_core_fabric.h> | 24 | #include <target/target_core_fabric.h> |
25 | #include <target/target_core_configfs.h> | 25 | #include <target/target_core_configfs.h> |
26 | #include <target/iscsi/iscsi_transport.h> | 26 | #include <target/iscsi/iscsi_transport.h> |
27 | 27 | ||
28 | #include "iscsi_target_core.h" | 28 | #include "iscsi_target_core.h" |
29 | #include "iscsi_target_parameters.h" | 29 | #include "iscsi_target_parameters.h" |
30 | #include "iscsi_target_seq_pdu_list.h" | 30 | #include "iscsi_target_seq_pdu_list.h" |
31 | #include "iscsi_target_datain_values.h" | 31 | #include "iscsi_target_datain_values.h" |
32 | #include "iscsi_target_erl0.h" | 32 | #include "iscsi_target_erl0.h" |
33 | #include "iscsi_target_erl1.h" | 33 | #include "iscsi_target_erl1.h" |
34 | #include "iscsi_target_erl2.h" | 34 | #include "iscsi_target_erl2.h" |
35 | #include "iscsi_target_tpg.h" | 35 | #include "iscsi_target_tpg.h" |
36 | #include "iscsi_target_tq.h" | 36 | #include "iscsi_target_tq.h" |
37 | #include "iscsi_target_util.h" | 37 | #include "iscsi_target_util.h" |
38 | #include "iscsi_target.h" | 38 | #include "iscsi_target.h" |
39 | 39 | ||
40 | #define PRINT_BUFF(buff, len) \ | 40 | #define PRINT_BUFF(buff, len) \ |
41 | { \ | 41 | { \ |
42 | int zzz; \ | 42 | int zzz; \ |
43 | \ | 43 | \ |
44 | pr_debug("%d:\n", __LINE__); \ | 44 | pr_debug("%d:\n", __LINE__); \ |
45 | for (zzz = 0; zzz < len; zzz++) { \ | 45 | for (zzz = 0; zzz < len; zzz++) { \ |
46 | if (zzz % 16 == 0) { \ | 46 | if (zzz % 16 == 0) { \ |
47 | if (zzz) \ | 47 | if (zzz) \ |
48 | pr_debug("\n"); \ | 48 | pr_debug("\n"); \ |
49 | pr_debug("%4i: ", zzz); \ | 49 | pr_debug("%4i: ", zzz); \ |
50 | } \ | 50 | } \ |
51 | pr_debug("%02x ", (unsigned char) (buff)[zzz]); \ | 51 | pr_debug("%02x ", (unsigned char) (buff)[zzz]); \ |
52 | } \ | 52 | } \ |
53 | if ((len + 1) % 16) \ | 53 | if ((len + 1) % 16) \ |
54 | pr_debug("\n"); \ | 54 | pr_debug("\n"); \ |
55 | } | 55 | } |
56 | 56 | ||
57 | extern struct list_head g_tiqn_list; | 57 | extern struct list_head g_tiqn_list; |
58 | extern spinlock_t tiqn_lock; | 58 | extern spinlock_t tiqn_lock; |
59 | 59 | ||
60 | /* | 60 | /* |
61 | * Called with cmd->r2t_lock held. | 61 | * Called with cmd->r2t_lock held. |
62 | */ | 62 | */ |
63 | int iscsit_add_r2t_to_list( | 63 | int iscsit_add_r2t_to_list( |
64 | struct iscsi_cmd *cmd, | 64 | struct iscsi_cmd *cmd, |
65 | u32 offset, | 65 | u32 offset, |
66 | u32 xfer_len, | 66 | u32 xfer_len, |
67 | int recovery, | 67 | int recovery, |
68 | u32 r2t_sn) | 68 | u32 r2t_sn) |
69 | { | 69 | { |
70 | struct iscsi_r2t *r2t; | 70 | struct iscsi_r2t *r2t; |
71 | 71 | ||
72 | r2t = kmem_cache_zalloc(lio_r2t_cache, GFP_ATOMIC); | 72 | r2t = kmem_cache_zalloc(lio_r2t_cache, GFP_ATOMIC); |
73 | if (!r2t) { | 73 | if (!r2t) { |
74 | pr_err("Unable to allocate memory for struct iscsi_r2t.\n"); | 74 | pr_err("Unable to allocate memory for struct iscsi_r2t.\n"); |
75 | return -1; | 75 | return -1; |
76 | } | 76 | } |
77 | INIT_LIST_HEAD(&r2t->r2t_list); | 77 | INIT_LIST_HEAD(&r2t->r2t_list); |
78 | 78 | ||
79 | r2t->recovery_r2t = recovery; | 79 | r2t->recovery_r2t = recovery; |
80 | r2t->r2t_sn = (!r2t_sn) ? cmd->r2t_sn++ : r2t_sn; | 80 | r2t->r2t_sn = (!r2t_sn) ? cmd->r2t_sn++ : r2t_sn; |
81 | r2t->offset = offset; | 81 | r2t->offset = offset; |
82 | r2t->xfer_len = xfer_len; | 82 | r2t->xfer_len = xfer_len; |
83 | list_add_tail(&r2t->r2t_list, &cmd->cmd_r2t_list); | 83 | list_add_tail(&r2t->r2t_list, &cmd->cmd_r2t_list); |
84 | spin_unlock_bh(&cmd->r2t_lock); | 84 | spin_unlock_bh(&cmd->r2t_lock); |
85 | 85 | ||
86 | iscsit_add_cmd_to_immediate_queue(cmd, cmd->conn, ISTATE_SEND_R2T); | 86 | iscsit_add_cmd_to_immediate_queue(cmd, cmd->conn, ISTATE_SEND_R2T); |
87 | 87 | ||
88 | spin_lock_bh(&cmd->r2t_lock); | 88 | spin_lock_bh(&cmd->r2t_lock); |
89 | return 0; | 89 | return 0; |
90 | } | 90 | } |
91 | 91 | ||
92 | struct iscsi_r2t *iscsit_get_r2t_for_eos( | 92 | struct iscsi_r2t *iscsit_get_r2t_for_eos( |
93 | struct iscsi_cmd *cmd, | 93 | struct iscsi_cmd *cmd, |
94 | u32 offset, | 94 | u32 offset, |
95 | u32 length) | 95 | u32 length) |
96 | { | 96 | { |
97 | struct iscsi_r2t *r2t; | 97 | struct iscsi_r2t *r2t; |
98 | 98 | ||
99 | spin_lock_bh(&cmd->r2t_lock); | 99 | spin_lock_bh(&cmd->r2t_lock); |
100 | list_for_each_entry(r2t, &cmd->cmd_r2t_list, r2t_list) { | 100 | list_for_each_entry(r2t, &cmd->cmd_r2t_list, r2t_list) { |
101 | if ((r2t->offset <= offset) && | 101 | if ((r2t->offset <= offset) && |
102 | (r2t->offset + r2t->xfer_len) >= (offset + length)) { | 102 | (r2t->offset + r2t->xfer_len) >= (offset + length)) { |
103 | spin_unlock_bh(&cmd->r2t_lock); | 103 | spin_unlock_bh(&cmd->r2t_lock); |
104 | return r2t; | 104 | return r2t; |
105 | } | 105 | } |
106 | } | 106 | } |
107 | spin_unlock_bh(&cmd->r2t_lock); | 107 | spin_unlock_bh(&cmd->r2t_lock); |
108 | 108 | ||
109 | pr_err("Unable to locate R2T for Offset: %u, Length:" | 109 | pr_err("Unable to locate R2T for Offset: %u, Length:" |
110 | " %u\n", offset, length); | 110 | " %u\n", offset, length); |
111 | return NULL; | 111 | return NULL; |
112 | } | 112 | } |
113 | 113 | ||
114 | struct iscsi_r2t *iscsit_get_r2t_from_list(struct iscsi_cmd *cmd) | 114 | struct iscsi_r2t *iscsit_get_r2t_from_list(struct iscsi_cmd *cmd) |
115 | { | 115 | { |
116 | struct iscsi_r2t *r2t; | 116 | struct iscsi_r2t *r2t; |
117 | 117 | ||
118 | spin_lock_bh(&cmd->r2t_lock); | 118 | spin_lock_bh(&cmd->r2t_lock); |
119 | list_for_each_entry(r2t, &cmd->cmd_r2t_list, r2t_list) { | 119 | list_for_each_entry(r2t, &cmd->cmd_r2t_list, r2t_list) { |
120 | if (!r2t->sent_r2t) { | 120 | if (!r2t->sent_r2t) { |
121 | spin_unlock_bh(&cmd->r2t_lock); | 121 | spin_unlock_bh(&cmd->r2t_lock); |
122 | return r2t; | 122 | return r2t; |
123 | } | 123 | } |
124 | } | 124 | } |
125 | spin_unlock_bh(&cmd->r2t_lock); | 125 | spin_unlock_bh(&cmd->r2t_lock); |
126 | 126 | ||
127 | pr_err("Unable to locate next R2T to send for ITT:" | 127 | pr_err("Unable to locate next R2T to send for ITT:" |
128 | " 0x%08x.\n", cmd->init_task_tag); | 128 | " 0x%08x.\n", cmd->init_task_tag); |
129 | return NULL; | 129 | return NULL; |
130 | } | 130 | } |
131 | 131 | ||
132 | /* | 132 | /* |
133 | * Called with cmd->r2t_lock held. | 133 | * Called with cmd->r2t_lock held. |
134 | */ | 134 | */ |
135 | void iscsit_free_r2t(struct iscsi_r2t *r2t, struct iscsi_cmd *cmd) | 135 | void iscsit_free_r2t(struct iscsi_r2t *r2t, struct iscsi_cmd *cmd) |
136 | { | 136 | { |
137 | list_del(&r2t->r2t_list); | 137 | list_del(&r2t->r2t_list); |
138 | kmem_cache_free(lio_r2t_cache, r2t); | 138 | kmem_cache_free(lio_r2t_cache, r2t); |
139 | } | 139 | } |
140 | 140 | ||
141 | void iscsit_free_r2ts_from_list(struct iscsi_cmd *cmd) | 141 | void iscsit_free_r2ts_from_list(struct iscsi_cmd *cmd) |
142 | { | 142 | { |
143 | struct iscsi_r2t *r2t, *r2t_tmp; | 143 | struct iscsi_r2t *r2t, *r2t_tmp; |
144 | 144 | ||
145 | spin_lock_bh(&cmd->r2t_lock); | 145 | spin_lock_bh(&cmd->r2t_lock); |
146 | list_for_each_entry_safe(r2t, r2t_tmp, &cmd->cmd_r2t_list, r2t_list) | 146 | list_for_each_entry_safe(r2t, r2t_tmp, &cmd->cmd_r2t_list, r2t_list) |
147 | iscsit_free_r2t(r2t, cmd); | 147 | iscsit_free_r2t(r2t, cmd); |
148 | spin_unlock_bh(&cmd->r2t_lock); | 148 | spin_unlock_bh(&cmd->r2t_lock); |
149 | } | 149 | } |
150 | 150 | ||
151 | /* | 151 | /* |
152 | * May be called from software interrupt (timer) context for allocating | 152 | * May be called from software interrupt (timer) context for allocating |
153 | * iSCSI NopINs. | 153 | * iSCSI NopINs. |
154 | */ | 154 | */ |
155 | struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *conn, int state) | 155 | struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *conn, int state) |
156 | { | 156 | { |
157 | struct iscsi_cmd *cmd; | 157 | struct iscsi_cmd *cmd; |
158 | struct se_session *se_sess = conn->sess->se_sess; | 158 | struct se_session *se_sess = conn->sess->se_sess; |
159 | int size, tag; | 159 | int size, tag; |
160 | 160 | ||
161 | tag = percpu_ida_alloc(&se_sess->sess_tag_pool, state); | 161 | tag = percpu_ida_alloc(&se_sess->sess_tag_pool, state); |
162 | if (tag < 0) | 162 | if (tag < 0) |
163 | return NULL; | 163 | return NULL; |
164 | 164 | ||
165 | size = sizeof(struct iscsi_cmd) + conn->conn_transport->priv_size; | 165 | size = sizeof(struct iscsi_cmd) + conn->conn_transport->priv_size; |
166 | cmd = (struct iscsi_cmd *)(se_sess->sess_cmd_map + (tag * size)); | 166 | cmd = (struct iscsi_cmd *)(se_sess->sess_cmd_map + (tag * size)); |
167 | memset(cmd, 0, size); | 167 | memset(cmd, 0, size); |
168 | 168 | ||
169 | cmd->se_cmd.map_tag = tag; | 169 | cmd->se_cmd.map_tag = tag; |
170 | cmd->conn = conn; | 170 | cmd->conn = conn; |
171 | INIT_LIST_HEAD(&cmd->i_conn_node); | 171 | INIT_LIST_HEAD(&cmd->i_conn_node); |
172 | INIT_LIST_HEAD(&cmd->datain_list); | 172 | INIT_LIST_HEAD(&cmd->datain_list); |
173 | INIT_LIST_HEAD(&cmd->cmd_r2t_list); | 173 | INIT_LIST_HEAD(&cmd->cmd_r2t_list); |
174 | spin_lock_init(&cmd->datain_lock); | 174 | spin_lock_init(&cmd->datain_lock); |
175 | spin_lock_init(&cmd->dataout_timeout_lock); | 175 | spin_lock_init(&cmd->dataout_timeout_lock); |
176 | spin_lock_init(&cmd->istate_lock); | 176 | spin_lock_init(&cmd->istate_lock); |
177 | spin_lock_init(&cmd->error_lock); | 177 | spin_lock_init(&cmd->error_lock); |
178 | spin_lock_init(&cmd->r2t_lock); | 178 | spin_lock_init(&cmd->r2t_lock); |
179 | 179 | ||
180 | return cmd; | 180 | return cmd; |
181 | } | 181 | } |
182 | EXPORT_SYMBOL(iscsit_allocate_cmd); | 182 | EXPORT_SYMBOL(iscsit_allocate_cmd); |
183 | 183 | ||
184 | struct iscsi_seq *iscsit_get_seq_holder_for_datain( | 184 | struct iscsi_seq *iscsit_get_seq_holder_for_datain( |
185 | struct iscsi_cmd *cmd, | 185 | struct iscsi_cmd *cmd, |
186 | u32 seq_send_order) | 186 | u32 seq_send_order) |
187 | { | 187 | { |
188 | u32 i; | 188 | u32 i; |
189 | 189 | ||
190 | for (i = 0; i < cmd->seq_count; i++) | 190 | for (i = 0; i < cmd->seq_count; i++) |
191 | if (cmd->seq_list[i].seq_send_order == seq_send_order) | 191 | if (cmd->seq_list[i].seq_send_order == seq_send_order) |
192 | return &cmd->seq_list[i]; | 192 | return &cmd->seq_list[i]; |
193 | 193 | ||
194 | return NULL; | 194 | return NULL; |
195 | } | 195 | } |
196 | 196 | ||
197 | struct iscsi_seq *iscsit_get_seq_holder_for_r2t(struct iscsi_cmd *cmd) | 197 | struct iscsi_seq *iscsit_get_seq_holder_for_r2t(struct iscsi_cmd *cmd) |
198 | { | 198 | { |
199 | u32 i; | 199 | u32 i; |
200 | 200 | ||
201 | if (!cmd->seq_list) { | 201 | if (!cmd->seq_list) { |
202 | pr_err("struct iscsi_cmd->seq_list is NULL!\n"); | 202 | pr_err("struct iscsi_cmd->seq_list is NULL!\n"); |
203 | return NULL; | 203 | return NULL; |
204 | } | 204 | } |
205 | 205 | ||
206 | for (i = 0; i < cmd->seq_count; i++) { | 206 | for (i = 0; i < cmd->seq_count; i++) { |
207 | if (cmd->seq_list[i].type != SEQTYPE_NORMAL) | 207 | if (cmd->seq_list[i].type != SEQTYPE_NORMAL) |
208 | continue; | 208 | continue; |
209 | if (cmd->seq_list[i].seq_send_order == cmd->seq_send_order) { | 209 | if (cmd->seq_list[i].seq_send_order == cmd->seq_send_order) { |
210 | cmd->seq_send_order++; | 210 | cmd->seq_send_order++; |
211 | return &cmd->seq_list[i]; | 211 | return &cmd->seq_list[i]; |
212 | } | 212 | } |
213 | } | 213 | } |
214 | 214 | ||
215 | return NULL; | 215 | return NULL; |
216 | } | 216 | } |
217 | 217 | ||
218 | struct iscsi_r2t *iscsit_get_holder_for_r2tsn( | 218 | struct iscsi_r2t *iscsit_get_holder_for_r2tsn( |
219 | struct iscsi_cmd *cmd, | 219 | struct iscsi_cmd *cmd, |
220 | u32 r2t_sn) | 220 | u32 r2t_sn) |
221 | { | 221 | { |
222 | struct iscsi_r2t *r2t; | 222 | struct iscsi_r2t *r2t; |
223 | 223 | ||
224 | spin_lock_bh(&cmd->r2t_lock); | 224 | spin_lock_bh(&cmd->r2t_lock); |
225 | list_for_each_entry(r2t, &cmd->cmd_r2t_list, r2t_list) { | 225 | list_for_each_entry(r2t, &cmd->cmd_r2t_list, r2t_list) { |
226 | if (r2t->r2t_sn == r2t_sn) { | 226 | if (r2t->r2t_sn == r2t_sn) { |
227 | spin_unlock_bh(&cmd->r2t_lock); | 227 | spin_unlock_bh(&cmd->r2t_lock); |
228 | return r2t; | 228 | return r2t; |
229 | } | 229 | } |
230 | } | 230 | } |
231 | spin_unlock_bh(&cmd->r2t_lock); | 231 | spin_unlock_bh(&cmd->r2t_lock); |
232 | 232 | ||
233 | return NULL; | 233 | return NULL; |
234 | } | 234 | } |
235 | 235 | ||
236 | static inline int iscsit_check_received_cmdsn(struct iscsi_session *sess, u32 cmdsn) | 236 | static inline int iscsit_check_received_cmdsn(struct iscsi_session *sess, u32 cmdsn) |
237 | { | 237 | { |
238 | int ret; | 238 | int ret; |
239 | 239 | ||
240 | /* | 240 | /* |
241 | * This is the proper method of checking received CmdSN against | 241 | * This is the proper method of checking received CmdSN against |
242 | * ExpCmdSN and MaxCmdSN values, as well as accounting for out | 242 | * ExpCmdSN and MaxCmdSN values, as well as accounting for out |
243 | * or order CmdSNs due to multiple connection sessions and/or | 243 | * or order CmdSNs due to multiple connection sessions and/or |
244 | * CRC failures. | 244 | * CRC failures. |
245 | */ | 245 | */ |
246 | if (iscsi_sna_gt(cmdsn, sess->max_cmd_sn)) { | 246 | if (iscsi_sna_gt(cmdsn, sess->max_cmd_sn)) { |
247 | pr_err("Received CmdSN: 0x%08x is greater than" | 247 | pr_err("Received CmdSN: 0x%08x is greater than" |
248 | " MaxCmdSN: 0x%08x, ignoring.\n", cmdsn, | 248 | " MaxCmdSN: 0x%08x, ignoring.\n", cmdsn, |
249 | sess->max_cmd_sn); | 249 | sess->max_cmd_sn); |
250 | ret = CMDSN_MAXCMDSN_OVERRUN; | 250 | ret = CMDSN_MAXCMDSN_OVERRUN; |
251 | 251 | ||
252 | } else if (cmdsn == sess->exp_cmd_sn) { | 252 | } else if (cmdsn == sess->exp_cmd_sn) { |
253 | sess->exp_cmd_sn++; | 253 | sess->exp_cmd_sn++; |
254 | pr_debug("Received CmdSN matches ExpCmdSN," | 254 | pr_debug("Received CmdSN matches ExpCmdSN," |
255 | " incremented ExpCmdSN to: 0x%08x\n", | 255 | " incremented ExpCmdSN to: 0x%08x\n", |
256 | sess->exp_cmd_sn); | 256 | sess->exp_cmd_sn); |
257 | ret = CMDSN_NORMAL_OPERATION; | 257 | ret = CMDSN_NORMAL_OPERATION; |
258 | 258 | ||
259 | } else if (iscsi_sna_gt(cmdsn, sess->exp_cmd_sn)) { | 259 | } else if (iscsi_sna_gt(cmdsn, sess->exp_cmd_sn)) { |
260 | pr_debug("Received CmdSN: 0x%08x is greater" | 260 | pr_debug("Received CmdSN: 0x%08x is greater" |
261 | " than ExpCmdSN: 0x%08x, not acknowledging.\n", | 261 | " than ExpCmdSN: 0x%08x, not acknowledging.\n", |
262 | cmdsn, sess->exp_cmd_sn); | 262 | cmdsn, sess->exp_cmd_sn); |
263 | ret = CMDSN_HIGHER_THAN_EXP; | 263 | ret = CMDSN_HIGHER_THAN_EXP; |
264 | 264 | ||
265 | } else { | 265 | } else { |
266 | pr_err("Received CmdSN: 0x%08x is less than" | 266 | pr_err("Received CmdSN: 0x%08x is less than" |
267 | " ExpCmdSN: 0x%08x, ignoring.\n", cmdsn, | 267 | " ExpCmdSN: 0x%08x, ignoring.\n", cmdsn, |
268 | sess->exp_cmd_sn); | 268 | sess->exp_cmd_sn); |
269 | ret = CMDSN_LOWER_THAN_EXP; | 269 | ret = CMDSN_LOWER_THAN_EXP; |
270 | } | 270 | } |
271 | 271 | ||
272 | return ret; | 272 | return ret; |
273 | } | 273 | } |
274 | 274 | ||
275 | /* | 275 | /* |
276 | * Commands may be received out of order if MC/S is in use. | 276 | * Commands may be received out of order if MC/S is in use. |
277 | * Ensure they are executed in CmdSN order. | 277 | * Ensure they are executed in CmdSN order. |
278 | */ | 278 | */ |
279 | int iscsit_sequence_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, | 279 | int iscsit_sequence_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, |
280 | unsigned char *buf, __be32 cmdsn) | 280 | unsigned char *buf, __be32 cmdsn) |
281 | { | 281 | { |
282 | int ret, cmdsn_ret; | 282 | int ret, cmdsn_ret; |
283 | bool reject = false; | 283 | bool reject = false; |
284 | u8 reason = ISCSI_REASON_BOOKMARK_NO_RESOURCES; | 284 | u8 reason = ISCSI_REASON_BOOKMARK_NO_RESOURCES; |
285 | 285 | ||
286 | mutex_lock(&conn->sess->cmdsn_mutex); | 286 | mutex_lock(&conn->sess->cmdsn_mutex); |
287 | 287 | ||
288 | cmdsn_ret = iscsit_check_received_cmdsn(conn->sess, be32_to_cpu(cmdsn)); | 288 | cmdsn_ret = iscsit_check_received_cmdsn(conn->sess, be32_to_cpu(cmdsn)); |
289 | switch (cmdsn_ret) { | 289 | switch (cmdsn_ret) { |
290 | case CMDSN_NORMAL_OPERATION: | 290 | case CMDSN_NORMAL_OPERATION: |
291 | ret = iscsit_execute_cmd(cmd, 0); | 291 | ret = iscsit_execute_cmd(cmd, 0); |
292 | if ((ret >= 0) && !list_empty(&conn->sess->sess_ooo_cmdsn_list)) | 292 | if ((ret >= 0) && !list_empty(&conn->sess->sess_ooo_cmdsn_list)) |
293 | iscsit_execute_ooo_cmdsns(conn->sess); | 293 | iscsit_execute_ooo_cmdsns(conn->sess); |
294 | else if (ret < 0) { | 294 | else if (ret < 0) { |
295 | reject = true; | 295 | reject = true; |
296 | ret = CMDSN_ERROR_CANNOT_RECOVER; | 296 | ret = CMDSN_ERROR_CANNOT_RECOVER; |
297 | } | 297 | } |
298 | break; | 298 | break; |
299 | case CMDSN_HIGHER_THAN_EXP: | 299 | case CMDSN_HIGHER_THAN_EXP: |
300 | ret = iscsit_handle_ooo_cmdsn(conn->sess, cmd, be32_to_cpu(cmdsn)); | 300 | ret = iscsit_handle_ooo_cmdsn(conn->sess, cmd, be32_to_cpu(cmdsn)); |
301 | if (ret < 0) { | 301 | if (ret < 0) { |
302 | reject = true; | 302 | reject = true; |
303 | ret = CMDSN_ERROR_CANNOT_RECOVER; | 303 | ret = CMDSN_ERROR_CANNOT_RECOVER; |
304 | break; | 304 | break; |
305 | } | 305 | } |
306 | ret = CMDSN_HIGHER_THAN_EXP; | 306 | ret = CMDSN_HIGHER_THAN_EXP; |
307 | break; | 307 | break; |
308 | case CMDSN_LOWER_THAN_EXP: | 308 | case CMDSN_LOWER_THAN_EXP: |
309 | case CMDSN_MAXCMDSN_OVERRUN: | 309 | case CMDSN_MAXCMDSN_OVERRUN: |
310 | default: | 310 | default: |
311 | cmd->i_state = ISTATE_REMOVE; | 311 | cmd->i_state = ISTATE_REMOVE; |
312 | iscsit_add_cmd_to_immediate_queue(cmd, conn, cmd->i_state); | 312 | iscsit_add_cmd_to_immediate_queue(cmd, conn, cmd->i_state); |
313 | /* | 313 | /* |
314 | * Existing callers for iscsit_sequence_cmd() will silently | 314 | * Existing callers for iscsit_sequence_cmd() will silently |
315 | * ignore commands with CMDSN_LOWER_THAN_EXP, so force this | 315 | * ignore commands with CMDSN_LOWER_THAN_EXP, so force this |
316 | * return for CMDSN_MAXCMDSN_OVERRUN as well.. | 316 | * return for CMDSN_MAXCMDSN_OVERRUN as well.. |
317 | */ | 317 | */ |
318 | ret = CMDSN_LOWER_THAN_EXP; | 318 | ret = CMDSN_LOWER_THAN_EXP; |
319 | break; | 319 | break; |
320 | } | 320 | } |
321 | mutex_unlock(&conn->sess->cmdsn_mutex); | 321 | mutex_unlock(&conn->sess->cmdsn_mutex); |
322 | 322 | ||
323 | if (reject) | 323 | if (reject) |
324 | iscsit_reject_cmd(cmd, reason, buf); | 324 | iscsit_reject_cmd(cmd, reason, buf); |
325 | 325 | ||
326 | return ret; | 326 | return ret; |
327 | } | 327 | } |
328 | EXPORT_SYMBOL(iscsit_sequence_cmd); | 328 | EXPORT_SYMBOL(iscsit_sequence_cmd); |
329 | 329 | ||
330 | int iscsit_check_unsolicited_dataout(struct iscsi_cmd *cmd, unsigned char *buf) | 330 | int iscsit_check_unsolicited_dataout(struct iscsi_cmd *cmd, unsigned char *buf) |
331 | { | 331 | { |
332 | struct iscsi_conn *conn = cmd->conn; | 332 | struct iscsi_conn *conn = cmd->conn; |
333 | struct se_cmd *se_cmd = &cmd->se_cmd; | 333 | struct se_cmd *se_cmd = &cmd->se_cmd; |
334 | struct iscsi_data *hdr = (struct iscsi_data *) buf; | 334 | struct iscsi_data *hdr = (struct iscsi_data *) buf; |
335 | u32 payload_length = ntoh24(hdr->dlength); | 335 | u32 payload_length = ntoh24(hdr->dlength); |
336 | 336 | ||
337 | if (conn->sess->sess_ops->InitialR2T) { | 337 | if (conn->sess->sess_ops->InitialR2T) { |
338 | pr_err("Received unexpected unsolicited data" | 338 | pr_err("Received unexpected unsolicited data" |
339 | " while InitialR2T=Yes, protocol error.\n"); | 339 | " while InitialR2T=Yes, protocol error.\n"); |
340 | transport_send_check_condition_and_sense(se_cmd, | 340 | transport_send_check_condition_and_sense(se_cmd, |
341 | TCM_UNEXPECTED_UNSOLICITED_DATA, 0); | 341 | TCM_UNEXPECTED_UNSOLICITED_DATA, 0); |
342 | return -1; | 342 | return -1; |
343 | } | 343 | } |
344 | 344 | ||
345 | if ((cmd->first_burst_len + payload_length) > | 345 | if ((cmd->first_burst_len + payload_length) > |
346 | conn->sess->sess_ops->FirstBurstLength) { | 346 | conn->sess->sess_ops->FirstBurstLength) { |
347 | pr_err("Total %u bytes exceeds FirstBurstLength: %u" | 347 | pr_err("Total %u bytes exceeds FirstBurstLength: %u" |
348 | " for this Unsolicited DataOut Burst.\n", | 348 | " for this Unsolicited DataOut Burst.\n", |
349 | (cmd->first_burst_len + payload_length), | 349 | (cmd->first_burst_len + payload_length), |
350 | conn->sess->sess_ops->FirstBurstLength); | 350 | conn->sess->sess_ops->FirstBurstLength); |
351 | transport_send_check_condition_and_sense(se_cmd, | 351 | transport_send_check_condition_and_sense(se_cmd, |
352 | TCM_INCORRECT_AMOUNT_OF_DATA, 0); | 352 | TCM_INCORRECT_AMOUNT_OF_DATA, 0); |
353 | return -1; | 353 | return -1; |
354 | } | 354 | } |
355 | 355 | ||
356 | if (!(hdr->flags & ISCSI_FLAG_CMD_FINAL)) | 356 | if (!(hdr->flags & ISCSI_FLAG_CMD_FINAL)) |
357 | return 0; | 357 | return 0; |
358 | 358 | ||
359 | if (((cmd->first_burst_len + payload_length) != cmd->se_cmd.data_length) && | 359 | if (((cmd->first_burst_len + payload_length) != cmd->se_cmd.data_length) && |
360 | ((cmd->first_burst_len + payload_length) != | 360 | ((cmd->first_burst_len + payload_length) != |
361 | conn->sess->sess_ops->FirstBurstLength)) { | 361 | conn->sess->sess_ops->FirstBurstLength)) { |
362 | pr_err("Unsolicited non-immediate data received %u" | 362 | pr_err("Unsolicited non-immediate data received %u" |
363 | " does not equal FirstBurstLength: %u, and does" | 363 | " does not equal FirstBurstLength: %u, and does" |
364 | " not equal ExpXferLen %u.\n", | 364 | " not equal ExpXferLen %u.\n", |
365 | (cmd->first_burst_len + payload_length), | 365 | (cmd->first_burst_len + payload_length), |
366 | conn->sess->sess_ops->FirstBurstLength, cmd->se_cmd.data_length); | 366 | conn->sess->sess_ops->FirstBurstLength, cmd->se_cmd.data_length); |
367 | transport_send_check_condition_and_sense(se_cmd, | 367 | transport_send_check_condition_and_sense(se_cmd, |
368 | TCM_INCORRECT_AMOUNT_OF_DATA, 0); | 368 | TCM_INCORRECT_AMOUNT_OF_DATA, 0); |
369 | return -1; | 369 | return -1; |
370 | } | 370 | } |
371 | return 0; | 371 | return 0; |
372 | } | 372 | } |
373 | 373 | ||
374 | struct iscsi_cmd *iscsit_find_cmd_from_itt( | 374 | struct iscsi_cmd *iscsit_find_cmd_from_itt( |
375 | struct iscsi_conn *conn, | 375 | struct iscsi_conn *conn, |
376 | itt_t init_task_tag) | 376 | itt_t init_task_tag) |
377 | { | 377 | { |
378 | struct iscsi_cmd *cmd; | 378 | struct iscsi_cmd *cmd; |
379 | 379 | ||
380 | spin_lock_bh(&conn->cmd_lock); | 380 | spin_lock_bh(&conn->cmd_lock); |
381 | list_for_each_entry(cmd, &conn->conn_cmd_list, i_conn_node) { | 381 | list_for_each_entry(cmd, &conn->conn_cmd_list, i_conn_node) { |
382 | if (cmd->init_task_tag == init_task_tag) { | 382 | if (cmd->init_task_tag == init_task_tag) { |
383 | spin_unlock_bh(&conn->cmd_lock); | 383 | spin_unlock_bh(&conn->cmd_lock); |
384 | return cmd; | 384 | return cmd; |
385 | } | 385 | } |
386 | } | 386 | } |
387 | spin_unlock_bh(&conn->cmd_lock); | 387 | spin_unlock_bh(&conn->cmd_lock); |
388 | 388 | ||
389 | pr_err("Unable to locate ITT: 0x%08x on CID: %hu", | 389 | pr_err("Unable to locate ITT: 0x%08x on CID: %hu", |
390 | init_task_tag, conn->cid); | 390 | init_task_tag, conn->cid); |
391 | return NULL; | 391 | return NULL; |
392 | } | 392 | } |
393 | 393 | ||
394 | struct iscsi_cmd *iscsit_find_cmd_from_itt_or_dump( | 394 | struct iscsi_cmd *iscsit_find_cmd_from_itt_or_dump( |
395 | struct iscsi_conn *conn, | 395 | struct iscsi_conn *conn, |
396 | itt_t init_task_tag, | 396 | itt_t init_task_tag, |
397 | u32 length) | 397 | u32 length) |
398 | { | 398 | { |
399 | struct iscsi_cmd *cmd; | 399 | struct iscsi_cmd *cmd; |
400 | 400 | ||
401 | spin_lock_bh(&conn->cmd_lock); | 401 | spin_lock_bh(&conn->cmd_lock); |
402 | list_for_each_entry(cmd, &conn->conn_cmd_list, i_conn_node) { | 402 | list_for_each_entry(cmd, &conn->conn_cmd_list, i_conn_node) { |
403 | if (cmd->init_task_tag == init_task_tag) { | 403 | if (cmd->init_task_tag == init_task_tag) { |
404 | spin_unlock_bh(&conn->cmd_lock); | 404 | spin_unlock_bh(&conn->cmd_lock); |
405 | return cmd; | 405 | return cmd; |
406 | } | 406 | } |
407 | } | 407 | } |
408 | spin_unlock_bh(&conn->cmd_lock); | 408 | spin_unlock_bh(&conn->cmd_lock); |
409 | 409 | ||
410 | pr_err("Unable to locate ITT: 0x%08x on CID: %hu," | 410 | pr_err("Unable to locate ITT: 0x%08x on CID: %hu," |
411 | " dumping payload\n", init_task_tag, conn->cid); | 411 | " dumping payload\n", init_task_tag, conn->cid); |
412 | if (length) | 412 | if (length) |
413 | iscsit_dump_data_payload(conn, length, 1); | 413 | iscsit_dump_data_payload(conn, length, 1); |
414 | 414 | ||
415 | return NULL; | 415 | return NULL; |
416 | } | 416 | } |
417 | 417 | ||
418 | struct iscsi_cmd *iscsit_find_cmd_from_ttt( | 418 | struct iscsi_cmd *iscsit_find_cmd_from_ttt( |
419 | struct iscsi_conn *conn, | 419 | struct iscsi_conn *conn, |
420 | u32 targ_xfer_tag) | 420 | u32 targ_xfer_tag) |
421 | { | 421 | { |
422 | struct iscsi_cmd *cmd = NULL; | 422 | struct iscsi_cmd *cmd = NULL; |
423 | 423 | ||
424 | spin_lock_bh(&conn->cmd_lock); | 424 | spin_lock_bh(&conn->cmd_lock); |
425 | list_for_each_entry(cmd, &conn->conn_cmd_list, i_conn_node) { | 425 | list_for_each_entry(cmd, &conn->conn_cmd_list, i_conn_node) { |
426 | if (cmd->targ_xfer_tag == targ_xfer_tag) { | 426 | if (cmd->targ_xfer_tag == targ_xfer_tag) { |
427 | spin_unlock_bh(&conn->cmd_lock); | 427 | spin_unlock_bh(&conn->cmd_lock); |
428 | return cmd; | 428 | return cmd; |
429 | } | 429 | } |
430 | } | 430 | } |
431 | spin_unlock_bh(&conn->cmd_lock); | 431 | spin_unlock_bh(&conn->cmd_lock); |
432 | 432 | ||
433 | pr_err("Unable to locate TTT: 0x%08x on CID: %hu\n", | 433 | pr_err("Unable to locate TTT: 0x%08x on CID: %hu\n", |
434 | targ_xfer_tag, conn->cid); | 434 | targ_xfer_tag, conn->cid); |
435 | return NULL; | 435 | return NULL; |
436 | } | 436 | } |
437 | 437 | ||
438 | int iscsit_find_cmd_for_recovery( | 438 | int iscsit_find_cmd_for_recovery( |
439 | struct iscsi_session *sess, | 439 | struct iscsi_session *sess, |
440 | struct iscsi_cmd **cmd_ptr, | 440 | struct iscsi_cmd **cmd_ptr, |
441 | struct iscsi_conn_recovery **cr_ptr, | 441 | struct iscsi_conn_recovery **cr_ptr, |
442 | itt_t init_task_tag) | 442 | itt_t init_task_tag) |
443 | { | 443 | { |
444 | struct iscsi_cmd *cmd = NULL; | 444 | struct iscsi_cmd *cmd = NULL; |
445 | struct iscsi_conn_recovery *cr; | 445 | struct iscsi_conn_recovery *cr; |
446 | /* | 446 | /* |
447 | * Scan through the inactive connection recovery list's command list. | 447 | * Scan through the inactive connection recovery list's command list. |
448 | * If init_task_tag matches the command is still alligent. | 448 | * If init_task_tag matches the command is still alligent. |
449 | */ | 449 | */ |
450 | spin_lock(&sess->cr_i_lock); | 450 | spin_lock(&sess->cr_i_lock); |
451 | list_for_each_entry(cr, &sess->cr_inactive_list, cr_list) { | 451 | list_for_each_entry(cr, &sess->cr_inactive_list, cr_list) { |
452 | spin_lock(&cr->conn_recovery_cmd_lock); | 452 | spin_lock(&cr->conn_recovery_cmd_lock); |
453 | list_for_each_entry(cmd, &cr->conn_recovery_cmd_list, i_conn_node) { | 453 | list_for_each_entry(cmd, &cr->conn_recovery_cmd_list, i_conn_node) { |
454 | if (cmd->init_task_tag == init_task_tag) { | 454 | if (cmd->init_task_tag == init_task_tag) { |
455 | spin_unlock(&cr->conn_recovery_cmd_lock); | 455 | spin_unlock(&cr->conn_recovery_cmd_lock); |
456 | spin_unlock(&sess->cr_i_lock); | 456 | spin_unlock(&sess->cr_i_lock); |
457 | 457 | ||
458 | *cr_ptr = cr; | 458 | *cr_ptr = cr; |
459 | *cmd_ptr = cmd; | 459 | *cmd_ptr = cmd; |
460 | return -2; | 460 | return -2; |
461 | } | 461 | } |
462 | } | 462 | } |
463 | spin_unlock(&cr->conn_recovery_cmd_lock); | 463 | spin_unlock(&cr->conn_recovery_cmd_lock); |
464 | } | 464 | } |
465 | spin_unlock(&sess->cr_i_lock); | 465 | spin_unlock(&sess->cr_i_lock); |
466 | /* | 466 | /* |
467 | * Scan through the active connection recovery list's command list. | 467 | * Scan through the active connection recovery list's command list. |
468 | * If init_task_tag matches the command is ready to be reassigned. | 468 | * If init_task_tag matches the command is ready to be reassigned. |
469 | */ | 469 | */ |
470 | spin_lock(&sess->cr_a_lock); | 470 | spin_lock(&sess->cr_a_lock); |
471 | list_for_each_entry(cr, &sess->cr_active_list, cr_list) { | 471 | list_for_each_entry(cr, &sess->cr_active_list, cr_list) { |
472 | spin_lock(&cr->conn_recovery_cmd_lock); | 472 | spin_lock(&cr->conn_recovery_cmd_lock); |
473 | list_for_each_entry(cmd, &cr->conn_recovery_cmd_list, i_conn_node) { | 473 | list_for_each_entry(cmd, &cr->conn_recovery_cmd_list, i_conn_node) { |
474 | if (cmd->init_task_tag == init_task_tag) { | 474 | if (cmd->init_task_tag == init_task_tag) { |
475 | spin_unlock(&cr->conn_recovery_cmd_lock); | 475 | spin_unlock(&cr->conn_recovery_cmd_lock); |
476 | spin_unlock(&sess->cr_a_lock); | 476 | spin_unlock(&sess->cr_a_lock); |
477 | 477 | ||
478 | *cr_ptr = cr; | 478 | *cr_ptr = cr; |
479 | *cmd_ptr = cmd; | 479 | *cmd_ptr = cmd; |
480 | return 0; | 480 | return 0; |
481 | } | 481 | } |
482 | } | 482 | } |
483 | spin_unlock(&cr->conn_recovery_cmd_lock); | 483 | spin_unlock(&cr->conn_recovery_cmd_lock); |
484 | } | 484 | } |
485 | spin_unlock(&sess->cr_a_lock); | 485 | spin_unlock(&sess->cr_a_lock); |
486 | 486 | ||
487 | return -1; | 487 | return -1; |
488 | } | 488 | } |
489 | 489 | ||
490 | void iscsit_add_cmd_to_immediate_queue( | 490 | void iscsit_add_cmd_to_immediate_queue( |
491 | struct iscsi_cmd *cmd, | 491 | struct iscsi_cmd *cmd, |
492 | struct iscsi_conn *conn, | 492 | struct iscsi_conn *conn, |
493 | u8 state) | 493 | u8 state) |
494 | { | 494 | { |
495 | struct iscsi_queue_req *qr; | 495 | struct iscsi_queue_req *qr; |
496 | 496 | ||
497 | qr = kmem_cache_zalloc(lio_qr_cache, GFP_ATOMIC); | 497 | qr = kmem_cache_zalloc(lio_qr_cache, GFP_ATOMIC); |
498 | if (!qr) { | 498 | if (!qr) { |
499 | pr_err("Unable to allocate memory for" | 499 | pr_err("Unable to allocate memory for" |
500 | " struct iscsi_queue_req\n"); | 500 | " struct iscsi_queue_req\n"); |
501 | return; | 501 | return; |
502 | } | 502 | } |
503 | INIT_LIST_HEAD(&qr->qr_list); | 503 | INIT_LIST_HEAD(&qr->qr_list); |
504 | qr->cmd = cmd; | 504 | qr->cmd = cmd; |
505 | qr->state = state; | 505 | qr->state = state; |
506 | 506 | ||
507 | spin_lock_bh(&conn->immed_queue_lock); | 507 | spin_lock_bh(&conn->immed_queue_lock); |
508 | list_add_tail(&qr->qr_list, &conn->immed_queue_list); | 508 | list_add_tail(&qr->qr_list, &conn->immed_queue_list); |
509 | atomic_inc(&cmd->immed_queue_count); | 509 | atomic_inc(&cmd->immed_queue_count); |
510 | atomic_set(&conn->check_immediate_queue, 1); | 510 | atomic_set(&conn->check_immediate_queue, 1); |
511 | spin_unlock_bh(&conn->immed_queue_lock); | 511 | spin_unlock_bh(&conn->immed_queue_lock); |
512 | 512 | ||
513 | wake_up(&conn->queues_wq); | 513 | wake_up(&conn->queues_wq); |
514 | } | 514 | } |
515 | 515 | ||
516 | struct iscsi_queue_req *iscsit_get_cmd_from_immediate_queue(struct iscsi_conn *conn) | 516 | struct iscsi_queue_req *iscsit_get_cmd_from_immediate_queue(struct iscsi_conn *conn) |
517 | { | 517 | { |
518 | struct iscsi_queue_req *qr; | 518 | struct iscsi_queue_req *qr; |
519 | 519 | ||
520 | spin_lock_bh(&conn->immed_queue_lock); | 520 | spin_lock_bh(&conn->immed_queue_lock); |
521 | if (list_empty(&conn->immed_queue_list)) { | 521 | if (list_empty(&conn->immed_queue_list)) { |
522 | spin_unlock_bh(&conn->immed_queue_lock); | 522 | spin_unlock_bh(&conn->immed_queue_lock); |
523 | return NULL; | 523 | return NULL; |
524 | } | 524 | } |
525 | qr = list_first_entry(&conn->immed_queue_list, | 525 | qr = list_first_entry(&conn->immed_queue_list, |
526 | struct iscsi_queue_req, qr_list); | 526 | struct iscsi_queue_req, qr_list); |
527 | 527 | ||
528 | list_del(&qr->qr_list); | 528 | list_del(&qr->qr_list); |
529 | if (qr->cmd) | 529 | if (qr->cmd) |
530 | atomic_dec(&qr->cmd->immed_queue_count); | 530 | atomic_dec(&qr->cmd->immed_queue_count); |
531 | spin_unlock_bh(&conn->immed_queue_lock); | 531 | spin_unlock_bh(&conn->immed_queue_lock); |
532 | 532 | ||
533 | return qr; | 533 | return qr; |
534 | } | 534 | } |
535 | 535 | ||
536 | static void iscsit_remove_cmd_from_immediate_queue( | 536 | static void iscsit_remove_cmd_from_immediate_queue( |
537 | struct iscsi_cmd *cmd, | 537 | struct iscsi_cmd *cmd, |
538 | struct iscsi_conn *conn) | 538 | struct iscsi_conn *conn) |
539 | { | 539 | { |
540 | struct iscsi_queue_req *qr, *qr_tmp; | 540 | struct iscsi_queue_req *qr, *qr_tmp; |
541 | 541 | ||
542 | spin_lock_bh(&conn->immed_queue_lock); | 542 | spin_lock_bh(&conn->immed_queue_lock); |
543 | if (!atomic_read(&cmd->immed_queue_count)) { | 543 | if (!atomic_read(&cmd->immed_queue_count)) { |
544 | spin_unlock_bh(&conn->immed_queue_lock); | 544 | spin_unlock_bh(&conn->immed_queue_lock); |
545 | return; | 545 | return; |
546 | } | 546 | } |
547 | 547 | ||
548 | list_for_each_entry_safe(qr, qr_tmp, &conn->immed_queue_list, qr_list) { | 548 | list_for_each_entry_safe(qr, qr_tmp, &conn->immed_queue_list, qr_list) { |
549 | if (qr->cmd != cmd) | 549 | if (qr->cmd != cmd) |
550 | continue; | 550 | continue; |
551 | 551 | ||
552 | atomic_dec(&qr->cmd->immed_queue_count); | 552 | atomic_dec(&qr->cmd->immed_queue_count); |
553 | list_del(&qr->qr_list); | 553 | list_del(&qr->qr_list); |
554 | kmem_cache_free(lio_qr_cache, qr); | 554 | kmem_cache_free(lio_qr_cache, qr); |
555 | } | 555 | } |
556 | spin_unlock_bh(&conn->immed_queue_lock); | 556 | spin_unlock_bh(&conn->immed_queue_lock); |
557 | 557 | ||
558 | if (atomic_read(&cmd->immed_queue_count)) { | 558 | if (atomic_read(&cmd->immed_queue_count)) { |
559 | pr_err("ITT: 0x%08x immed_queue_count: %d\n", | 559 | pr_err("ITT: 0x%08x immed_queue_count: %d\n", |
560 | cmd->init_task_tag, | 560 | cmd->init_task_tag, |
561 | atomic_read(&cmd->immed_queue_count)); | 561 | atomic_read(&cmd->immed_queue_count)); |
562 | } | 562 | } |
563 | } | 563 | } |
564 | 564 | ||
565 | void iscsit_add_cmd_to_response_queue( | 565 | void iscsit_add_cmd_to_response_queue( |
566 | struct iscsi_cmd *cmd, | 566 | struct iscsi_cmd *cmd, |
567 | struct iscsi_conn *conn, | 567 | struct iscsi_conn *conn, |
568 | u8 state) | 568 | u8 state) |
569 | { | 569 | { |
570 | struct iscsi_queue_req *qr; | 570 | struct iscsi_queue_req *qr; |
571 | 571 | ||
572 | qr = kmem_cache_zalloc(lio_qr_cache, GFP_ATOMIC); | 572 | qr = kmem_cache_zalloc(lio_qr_cache, GFP_ATOMIC); |
573 | if (!qr) { | 573 | if (!qr) { |
574 | pr_err("Unable to allocate memory for" | 574 | pr_err("Unable to allocate memory for" |
575 | " struct iscsi_queue_req\n"); | 575 | " struct iscsi_queue_req\n"); |
576 | return; | 576 | return; |
577 | } | 577 | } |
578 | INIT_LIST_HEAD(&qr->qr_list); | 578 | INIT_LIST_HEAD(&qr->qr_list); |
579 | qr->cmd = cmd; | 579 | qr->cmd = cmd; |
580 | qr->state = state; | 580 | qr->state = state; |
581 | 581 | ||
582 | spin_lock_bh(&conn->response_queue_lock); | 582 | spin_lock_bh(&conn->response_queue_lock); |
583 | list_add_tail(&qr->qr_list, &conn->response_queue_list); | 583 | list_add_tail(&qr->qr_list, &conn->response_queue_list); |
584 | atomic_inc(&cmd->response_queue_count); | 584 | atomic_inc(&cmd->response_queue_count); |
585 | spin_unlock_bh(&conn->response_queue_lock); | 585 | spin_unlock_bh(&conn->response_queue_lock); |
586 | 586 | ||
587 | wake_up(&conn->queues_wq); | 587 | wake_up(&conn->queues_wq); |
588 | } | 588 | } |
589 | 589 | ||
590 | struct iscsi_queue_req *iscsit_get_cmd_from_response_queue(struct iscsi_conn *conn) | 590 | struct iscsi_queue_req *iscsit_get_cmd_from_response_queue(struct iscsi_conn *conn) |
591 | { | 591 | { |
592 | struct iscsi_queue_req *qr; | 592 | struct iscsi_queue_req *qr; |
593 | 593 | ||
594 | spin_lock_bh(&conn->response_queue_lock); | 594 | spin_lock_bh(&conn->response_queue_lock); |
595 | if (list_empty(&conn->response_queue_list)) { | 595 | if (list_empty(&conn->response_queue_list)) { |
596 | spin_unlock_bh(&conn->response_queue_lock); | 596 | spin_unlock_bh(&conn->response_queue_lock); |
597 | return NULL; | 597 | return NULL; |
598 | } | 598 | } |
599 | 599 | ||
600 | qr = list_first_entry(&conn->response_queue_list, | 600 | qr = list_first_entry(&conn->response_queue_list, |
601 | struct iscsi_queue_req, qr_list); | 601 | struct iscsi_queue_req, qr_list); |
602 | 602 | ||
603 | list_del(&qr->qr_list); | 603 | list_del(&qr->qr_list); |
604 | if (qr->cmd) | 604 | if (qr->cmd) |
605 | atomic_dec(&qr->cmd->response_queue_count); | 605 | atomic_dec(&qr->cmd->response_queue_count); |
606 | spin_unlock_bh(&conn->response_queue_lock); | 606 | spin_unlock_bh(&conn->response_queue_lock); |
607 | 607 | ||
608 | return qr; | 608 | return qr; |
609 | } | 609 | } |
610 | 610 | ||
611 | static void iscsit_remove_cmd_from_response_queue( | 611 | static void iscsit_remove_cmd_from_response_queue( |
612 | struct iscsi_cmd *cmd, | 612 | struct iscsi_cmd *cmd, |
613 | struct iscsi_conn *conn) | 613 | struct iscsi_conn *conn) |
614 | { | 614 | { |
615 | struct iscsi_queue_req *qr, *qr_tmp; | 615 | struct iscsi_queue_req *qr, *qr_tmp; |
616 | 616 | ||
617 | spin_lock_bh(&conn->response_queue_lock); | 617 | spin_lock_bh(&conn->response_queue_lock); |
618 | if (!atomic_read(&cmd->response_queue_count)) { | 618 | if (!atomic_read(&cmd->response_queue_count)) { |
619 | spin_unlock_bh(&conn->response_queue_lock); | 619 | spin_unlock_bh(&conn->response_queue_lock); |
620 | return; | 620 | return; |
621 | } | 621 | } |
622 | 622 | ||
623 | list_for_each_entry_safe(qr, qr_tmp, &conn->response_queue_list, | 623 | list_for_each_entry_safe(qr, qr_tmp, &conn->response_queue_list, |
624 | qr_list) { | 624 | qr_list) { |
625 | if (qr->cmd != cmd) | 625 | if (qr->cmd != cmd) |
626 | continue; | 626 | continue; |
627 | 627 | ||
628 | atomic_dec(&qr->cmd->response_queue_count); | 628 | atomic_dec(&qr->cmd->response_queue_count); |
629 | list_del(&qr->qr_list); | 629 | list_del(&qr->qr_list); |
630 | kmem_cache_free(lio_qr_cache, qr); | 630 | kmem_cache_free(lio_qr_cache, qr); |
631 | } | 631 | } |
632 | spin_unlock_bh(&conn->response_queue_lock); | 632 | spin_unlock_bh(&conn->response_queue_lock); |
633 | 633 | ||
634 | if (atomic_read(&cmd->response_queue_count)) { | 634 | if (atomic_read(&cmd->response_queue_count)) { |
635 | pr_err("ITT: 0x%08x response_queue_count: %d\n", | 635 | pr_err("ITT: 0x%08x response_queue_count: %d\n", |
636 | cmd->init_task_tag, | 636 | cmd->init_task_tag, |
637 | atomic_read(&cmd->response_queue_count)); | 637 | atomic_read(&cmd->response_queue_count)); |
638 | } | 638 | } |
639 | } | 639 | } |
640 | 640 | ||
641 | bool iscsit_conn_all_queues_empty(struct iscsi_conn *conn) | 641 | bool iscsit_conn_all_queues_empty(struct iscsi_conn *conn) |
642 | { | 642 | { |
643 | bool empty; | 643 | bool empty; |
644 | 644 | ||
645 | spin_lock_bh(&conn->immed_queue_lock); | 645 | spin_lock_bh(&conn->immed_queue_lock); |
646 | empty = list_empty(&conn->immed_queue_list); | 646 | empty = list_empty(&conn->immed_queue_list); |
647 | spin_unlock_bh(&conn->immed_queue_lock); | 647 | spin_unlock_bh(&conn->immed_queue_lock); |
648 | 648 | ||
649 | if (!empty) | 649 | if (!empty) |
650 | return empty; | 650 | return empty; |
651 | 651 | ||
652 | spin_lock_bh(&conn->response_queue_lock); | 652 | spin_lock_bh(&conn->response_queue_lock); |
653 | empty = list_empty(&conn->response_queue_list); | 653 | empty = list_empty(&conn->response_queue_list); |
654 | spin_unlock_bh(&conn->response_queue_lock); | 654 | spin_unlock_bh(&conn->response_queue_lock); |
655 | 655 | ||
656 | return empty; | 656 | return empty; |
657 | } | 657 | } |
658 | 658 | ||
659 | void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *conn) | 659 | void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *conn) |
660 | { | 660 | { |
661 | struct iscsi_queue_req *qr, *qr_tmp; | 661 | struct iscsi_queue_req *qr, *qr_tmp; |
662 | 662 | ||
663 | spin_lock_bh(&conn->immed_queue_lock); | 663 | spin_lock_bh(&conn->immed_queue_lock); |
664 | list_for_each_entry_safe(qr, qr_tmp, &conn->immed_queue_list, qr_list) { | 664 | list_for_each_entry_safe(qr, qr_tmp, &conn->immed_queue_list, qr_list) { |
665 | list_del(&qr->qr_list); | 665 | list_del(&qr->qr_list); |
666 | if (qr->cmd) | 666 | if (qr->cmd) |
667 | atomic_dec(&qr->cmd->immed_queue_count); | 667 | atomic_dec(&qr->cmd->immed_queue_count); |
668 | 668 | ||
669 | kmem_cache_free(lio_qr_cache, qr); | 669 | kmem_cache_free(lio_qr_cache, qr); |
670 | } | 670 | } |
671 | spin_unlock_bh(&conn->immed_queue_lock); | 671 | spin_unlock_bh(&conn->immed_queue_lock); |
672 | 672 | ||
673 | spin_lock_bh(&conn->response_queue_lock); | 673 | spin_lock_bh(&conn->response_queue_lock); |
674 | list_for_each_entry_safe(qr, qr_tmp, &conn->response_queue_list, | 674 | list_for_each_entry_safe(qr, qr_tmp, &conn->response_queue_list, |
675 | qr_list) { | 675 | qr_list) { |
676 | list_del(&qr->qr_list); | 676 | list_del(&qr->qr_list); |
677 | if (qr->cmd) | 677 | if (qr->cmd) |
678 | atomic_dec(&qr->cmd->response_queue_count); | 678 | atomic_dec(&qr->cmd->response_queue_count); |
679 | 679 | ||
680 | kmem_cache_free(lio_qr_cache, qr); | 680 | kmem_cache_free(lio_qr_cache, qr); |
681 | } | 681 | } |
682 | spin_unlock_bh(&conn->response_queue_lock); | 682 | spin_unlock_bh(&conn->response_queue_lock); |
683 | } | 683 | } |
684 | 684 | ||
685 | void iscsit_release_cmd(struct iscsi_cmd *cmd) | 685 | void iscsit_release_cmd(struct iscsi_cmd *cmd) |
686 | { | 686 | { |
687 | struct iscsi_session *sess; | 687 | struct iscsi_session *sess; |
688 | struct se_cmd *se_cmd = &cmd->se_cmd; | 688 | struct se_cmd *se_cmd = &cmd->se_cmd; |
689 | 689 | ||
690 | if (cmd->conn) | 690 | if (cmd->conn) |
691 | sess = cmd->conn->sess; | 691 | sess = cmd->conn->sess; |
692 | else | 692 | else |
693 | sess = cmd->sess; | 693 | sess = cmd->sess; |
694 | 694 | ||
695 | BUG_ON(!sess || !sess->se_sess); | 695 | BUG_ON(!sess || !sess->se_sess); |
696 | 696 | ||
697 | kfree(cmd->buf_ptr); | 697 | kfree(cmd->buf_ptr); |
698 | kfree(cmd->pdu_list); | 698 | kfree(cmd->pdu_list); |
699 | kfree(cmd->seq_list); | 699 | kfree(cmd->seq_list); |
700 | kfree(cmd->tmr_req); | 700 | kfree(cmd->tmr_req); |
701 | kfree(cmd->iov_data); | 701 | kfree(cmd->iov_data); |
702 | kfree(cmd->text_in_ptr); | 702 | kfree(cmd->text_in_ptr); |
703 | 703 | ||
704 | percpu_ida_free(&sess->se_sess->sess_tag_pool, se_cmd->map_tag); | 704 | percpu_ida_free(&sess->se_sess->sess_tag_pool, se_cmd->map_tag); |
705 | } | 705 | } |
706 | EXPORT_SYMBOL(iscsit_release_cmd); | 706 | EXPORT_SYMBOL(iscsit_release_cmd); |
707 | 707 | ||
708 | void __iscsit_free_cmd(struct iscsi_cmd *cmd, bool scsi_cmd, | 708 | void __iscsit_free_cmd(struct iscsi_cmd *cmd, bool scsi_cmd, |
709 | bool check_queues) | 709 | bool check_queues) |
710 | { | 710 | { |
711 | struct iscsi_conn *conn = cmd->conn; | 711 | struct iscsi_conn *conn = cmd->conn; |
712 | 712 | ||
713 | if (scsi_cmd) { | 713 | if (scsi_cmd) { |
714 | if (cmd->data_direction == DMA_TO_DEVICE) { | 714 | if (cmd->data_direction == DMA_TO_DEVICE) { |
715 | iscsit_stop_dataout_timer(cmd); | 715 | iscsit_stop_dataout_timer(cmd); |
716 | iscsit_free_r2ts_from_list(cmd); | 716 | iscsit_free_r2ts_from_list(cmd); |
717 | } | 717 | } |
718 | if (cmd->data_direction == DMA_FROM_DEVICE) | 718 | if (cmd->data_direction == DMA_FROM_DEVICE) |
719 | iscsit_free_all_datain_reqs(cmd); | 719 | iscsit_free_all_datain_reqs(cmd); |
720 | } | 720 | } |
721 | 721 | ||
722 | if (conn && check_queues) { | 722 | if (conn && check_queues) { |
723 | iscsit_remove_cmd_from_immediate_queue(cmd, conn); | 723 | iscsit_remove_cmd_from_immediate_queue(cmd, conn); |
724 | iscsit_remove_cmd_from_response_queue(cmd, conn); | 724 | iscsit_remove_cmd_from_response_queue(cmd, conn); |
725 | } | 725 | } |
726 | } | 726 | } |
727 | 727 | ||
728 | void iscsit_free_cmd(struct iscsi_cmd *cmd, bool shutdown) | 728 | void iscsit_free_cmd(struct iscsi_cmd *cmd, bool shutdown) |
729 | { | 729 | { |
730 | struct se_cmd *se_cmd = NULL; | 730 | struct se_cmd *se_cmd = NULL; |
731 | int rc; | 731 | int rc; |
732 | /* | 732 | /* |
733 | * Determine if a struct se_cmd is associated with | 733 | * Determine if a struct se_cmd is associated with |
734 | * this struct iscsi_cmd. | 734 | * this struct iscsi_cmd. |
735 | */ | 735 | */ |
736 | switch (cmd->iscsi_opcode) { | 736 | switch (cmd->iscsi_opcode) { |
737 | case ISCSI_OP_SCSI_CMD: | 737 | case ISCSI_OP_SCSI_CMD: |
738 | se_cmd = &cmd->se_cmd; | 738 | se_cmd = &cmd->se_cmd; |
739 | __iscsit_free_cmd(cmd, true, shutdown); | 739 | __iscsit_free_cmd(cmd, true, shutdown); |
740 | /* | 740 | /* |
741 | * Fallthrough | 741 | * Fallthrough |
742 | */ | 742 | */ |
743 | case ISCSI_OP_SCSI_TMFUNC: | 743 | case ISCSI_OP_SCSI_TMFUNC: |
744 | rc = transport_generic_free_cmd(&cmd->se_cmd, shutdown); | 744 | rc = transport_generic_free_cmd(&cmd->se_cmd, shutdown); |
745 | if (!rc && shutdown && se_cmd && se_cmd->se_sess) { | 745 | if (!rc && shutdown && se_cmd && se_cmd->se_sess) { |
746 | __iscsit_free_cmd(cmd, true, shutdown); | 746 | __iscsit_free_cmd(cmd, true, shutdown); |
747 | target_put_sess_cmd(se_cmd->se_sess, se_cmd); | 747 | target_put_sess_cmd(se_cmd->se_sess, se_cmd); |
748 | } | 748 | } |
749 | break; | 749 | break; |
750 | case ISCSI_OP_REJECT: | 750 | case ISCSI_OP_REJECT: |
751 | /* | 751 | /* |
752 | * Handle special case for REJECT when iscsi_add_reject*() has | 752 | * Handle special case for REJECT when iscsi_add_reject*() has |
753 | * overwritten the original iscsi_opcode assignment, and the | 753 | * overwritten the original iscsi_opcode assignment, and the |
754 | * associated cmd->se_cmd needs to be released. | 754 | * associated cmd->se_cmd needs to be released. |
755 | */ | 755 | */ |
756 | if (cmd->se_cmd.se_tfo != NULL) { | 756 | if (cmd->se_cmd.se_tfo != NULL) { |
757 | se_cmd = &cmd->se_cmd; | 757 | se_cmd = &cmd->se_cmd; |
758 | __iscsit_free_cmd(cmd, true, shutdown); | 758 | __iscsit_free_cmd(cmd, true, shutdown); |
759 | 759 | ||
760 | rc = transport_generic_free_cmd(&cmd->se_cmd, shutdown); | 760 | rc = transport_generic_free_cmd(&cmd->se_cmd, shutdown); |
761 | if (!rc && shutdown && se_cmd->se_sess) { | 761 | if (!rc && shutdown && se_cmd->se_sess) { |
762 | __iscsit_free_cmd(cmd, true, shutdown); | 762 | __iscsit_free_cmd(cmd, true, shutdown); |
763 | target_put_sess_cmd(se_cmd->se_sess, se_cmd); | 763 | target_put_sess_cmd(se_cmd->se_sess, se_cmd); |
764 | } | 764 | } |
765 | break; | 765 | break; |
766 | } | 766 | } |
767 | /* Fall-through */ | 767 | /* Fall-through */ |
768 | default: | 768 | default: |
769 | __iscsit_free_cmd(cmd, false, shutdown); | 769 | __iscsit_free_cmd(cmd, false, shutdown); |
770 | iscsit_release_cmd(cmd); | 770 | iscsit_release_cmd(cmd); |
771 | break; | 771 | break; |
772 | } | 772 | } |
773 | } | 773 | } |
774 | 774 | ||
775 | int iscsit_check_session_usage_count(struct iscsi_session *sess) | 775 | int iscsit_check_session_usage_count(struct iscsi_session *sess) |
776 | { | 776 | { |
777 | spin_lock_bh(&sess->session_usage_lock); | 777 | spin_lock_bh(&sess->session_usage_lock); |
778 | if (sess->session_usage_count != 0) { | 778 | if (sess->session_usage_count != 0) { |
779 | sess->session_waiting_on_uc = 1; | 779 | sess->session_waiting_on_uc = 1; |
780 | spin_unlock_bh(&sess->session_usage_lock); | 780 | spin_unlock_bh(&sess->session_usage_lock); |
781 | if (in_interrupt()) | 781 | if (in_interrupt()) |
782 | return 2; | 782 | return 2; |
783 | 783 | ||
784 | wait_for_completion(&sess->session_waiting_on_uc_comp); | 784 | wait_for_completion(&sess->session_waiting_on_uc_comp); |
785 | return 1; | 785 | return 1; |
786 | } | 786 | } |
787 | spin_unlock_bh(&sess->session_usage_lock); | 787 | spin_unlock_bh(&sess->session_usage_lock); |
788 | 788 | ||
789 | return 0; | 789 | return 0; |
790 | } | 790 | } |
791 | 791 | ||
792 | void iscsit_dec_session_usage_count(struct iscsi_session *sess) | 792 | void iscsit_dec_session_usage_count(struct iscsi_session *sess) |
793 | { | 793 | { |
794 | spin_lock_bh(&sess->session_usage_lock); | 794 | spin_lock_bh(&sess->session_usage_lock); |
795 | sess->session_usage_count--; | 795 | sess->session_usage_count--; |
796 | 796 | ||
797 | if (!sess->session_usage_count && sess->session_waiting_on_uc) | 797 | if (!sess->session_usage_count && sess->session_waiting_on_uc) |
798 | complete(&sess->session_waiting_on_uc_comp); | 798 | complete(&sess->session_waiting_on_uc_comp); |
799 | 799 | ||
800 | spin_unlock_bh(&sess->session_usage_lock); | 800 | spin_unlock_bh(&sess->session_usage_lock); |
801 | } | 801 | } |
802 | 802 | ||
803 | void iscsit_inc_session_usage_count(struct iscsi_session *sess) | 803 | void iscsit_inc_session_usage_count(struct iscsi_session *sess) |
804 | { | 804 | { |
805 | spin_lock_bh(&sess->session_usage_lock); | 805 | spin_lock_bh(&sess->session_usage_lock); |
806 | sess->session_usage_count++; | 806 | sess->session_usage_count++; |
807 | spin_unlock_bh(&sess->session_usage_lock); | 807 | spin_unlock_bh(&sess->session_usage_lock); |
808 | } | 808 | } |
809 | 809 | ||
810 | /* | 810 | /* |
811 | * Setup conn->if_marker and conn->of_marker values based upon | 811 | * Setup conn->if_marker and conn->of_marker values based upon |
812 | * the initial marker-less interval. (see iSCSI v19 A.2) | 812 | * the initial marker-less interval. (see iSCSI v19 A.2) |
813 | */ | 813 | */ |
814 | int iscsit_set_sync_and_steering_values(struct iscsi_conn *conn) | 814 | int iscsit_set_sync_and_steering_values(struct iscsi_conn *conn) |
815 | { | 815 | { |
816 | int login_ifmarker_count = 0, login_ofmarker_count = 0, next_marker = 0; | 816 | int login_ifmarker_count = 0, login_ofmarker_count = 0, next_marker = 0; |
817 | /* | 817 | /* |
818 | * IFMarkInt and OFMarkInt are negotiated as 32-bit words. | 818 | * IFMarkInt and OFMarkInt are negotiated as 32-bit words. |
819 | */ | 819 | */ |
820 | u32 IFMarkInt = (conn->conn_ops->IFMarkInt * 4); | 820 | u32 IFMarkInt = (conn->conn_ops->IFMarkInt * 4); |
821 | u32 OFMarkInt = (conn->conn_ops->OFMarkInt * 4); | 821 | u32 OFMarkInt = (conn->conn_ops->OFMarkInt * 4); |
822 | 822 | ||
823 | if (conn->conn_ops->OFMarker) { | 823 | if (conn->conn_ops->OFMarker) { |
824 | /* | 824 | /* |
825 | * Account for the first Login Command received not | 825 | * Account for the first Login Command received not |
826 | * via iscsi_recv_msg(). | 826 | * via iscsi_recv_msg(). |
827 | */ | 827 | */ |
828 | conn->of_marker += ISCSI_HDR_LEN; | 828 | conn->of_marker += ISCSI_HDR_LEN; |
829 | if (conn->of_marker <= OFMarkInt) { | 829 | if (conn->of_marker <= OFMarkInt) { |
830 | conn->of_marker = (OFMarkInt - conn->of_marker); | 830 | conn->of_marker = (OFMarkInt - conn->of_marker); |
831 | } else { | 831 | } else { |
832 | login_ofmarker_count = (conn->of_marker / OFMarkInt); | 832 | login_ofmarker_count = (conn->of_marker / OFMarkInt); |
833 | next_marker = (OFMarkInt * (login_ofmarker_count + 1)) + | 833 | next_marker = (OFMarkInt * (login_ofmarker_count + 1)) + |
834 | (login_ofmarker_count * MARKER_SIZE); | 834 | (login_ofmarker_count * MARKER_SIZE); |
835 | conn->of_marker = (next_marker - conn->of_marker); | 835 | conn->of_marker = (next_marker - conn->of_marker); |
836 | } | 836 | } |
837 | conn->of_marker_offset = 0; | 837 | conn->of_marker_offset = 0; |
838 | pr_debug("Setting OFMarker value to %u based on Initial" | 838 | pr_debug("Setting OFMarker value to %u based on Initial" |
839 | " Markerless Interval.\n", conn->of_marker); | 839 | " Markerless Interval.\n", conn->of_marker); |
840 | } | 840 | } |
841 | 841 | ||
842 | if (conn->conn_ops->IFMarker) { | 842 | if (conn->conn_ops->IFMarker) { |
843 | if (conn->if_marker <= IFMarkInt) { | 843 | if (conn->if_marker <= IFMarkInt) { |
844 | conn->if_marker = (IFMarkInt - conn->if_marker); | 844 | conn->if_marker = (IFMarkInt - conn->if_marker); |
845 | } else { | 845 | } else { |
846 | login_ifmarker_count = (conn->if_marker / IFMarkInt); | 846 | login_ifmarker_count = (conn->if_marker / IFMarkInt); |
847 | next_marker = (IFMarkInt * (login_ifmarker_count + 1)) + | 847 | next_marker = (IFMarkInt * (login_ifmarker_count + 1)) + |
848 | (login_ifmarker_count * MARKER_SIZE); | 848 | (login_ifmarker_count * MARKER_SIZE); |
849 | conn->if_marker = (next_marker - conn->if_marker); | 849 | conn->if_marker = (next_marker - conn->if_marker); |
850 | } | 850 | } |
851 | pr_debug("Setting IFMarker value to %u based on Initial" | 851 | pr_debug("Setting IFMarker value to %u based on Initial" |
852 | " Markerless Interval.\n", conn->if_marker); | 852 | " Markerless Interval.\n", conn->if_marker); |
853 | } | 853 | } |
854 | 854 | ||
855 | return 0; | 855 | return 0; |
856 | } | 856 | } |
857 | 857 | ||
858 | struct iscsi_conn *iscsit_get_conn_from_cid(struct iscsi_session *sess, u16 cid) | 858 | struct iscsi_conn *iscsit_get_conn_from_cid(struct iscsi_session *sess, u16 cid) |
859 | { | 859 | { |
860 | struct iscsi_conn *conn; | 860 | struct iscsi_conn *conn; |
861 | 861 | ||
862 | spin_lock_bh(&sess->conn_lock); | 862 | spin_lock_bh(&sess->conn_lock); |
863 | list_for_each_entry(conn, &sess->sess_conn_list, conn_list) { | 863 | list_for_each_entry(conn, &sess->sess_conn_list, conn_list) { |
864 | if ((conn->cid == cid) && | 864 | if ((conn->cid == cid) && |
865 | (conn->conn_state == TARG_CONN_STATE_LOGGED_IN)) { | 865 | (conn->conn_state == TARG_CONN_STATE_LOGGED_IN)) { |
866 | iscsit_inc_conn_usage_count(conn); | 866 | iscsit_inc_conn_usage_count(conn); |
867 | spin_unlock_bh(&sess->conn_lock); | 867 | spin_unlock_bh(&sess->conn_lock); |
868 | return conn; | 868 | return conn; |
869 | } | 869 | } |
870 | } | 870 | } |
871 | spin_unlock_bh(&sess->conn_lock); | 871 | spin_unlock_bh(&sess->conn_lock); |
872 | 872 | ||
873 | return NULL; | 873 | return NULL; |
874 | } | 874 | } |
875 | 875 | ||
876 | struct iscsi_conn *iscsit_get_conn_from_cid_rcfr(struct iscsi_session *sess, u16 cid) | 876 | struct iscsi_conn *iscsit_get_conn_from_cid_rcfr(struct iscsi_session *sess, u16 cid) |
877 | { | 877 | { |
878 | struct iscsi_conn *conn; | 878 | struct iscsi_conn *conn; |
879 | 879 | ||
880 | spin_lock_bh(&sess->conn_lock); | 880 | spin_lock_bh(&sess->conn_lock); |
881 | list_for_each_entry(conn, &sess->sess_conn_list, conn_list) { | 881 | list_for_each_entry(conn, &sess->sess_conn_list, conn_list) { |
882 | if (conn->cid == cid) { | 882 | if (conn->cid == cid) { |
883 | iscsit_inc_conn_usage_count(conn); | 883 | iscsit_inc_conn_usage_count(conn); |
884 | spin_lock(&conn->state_lock); | 884 | spin_lock(&conn->state_lock); |
885 | atomic_set(&conn->connection_wait_rcfr, 1); | 885 | atomic_set(&conn->connection_wait_rcfr, 1); |
886 | spin_unlock(&conn->state_lock); | 886 | spin_unlock(&conn->state_lock); |
887 | spin_unlock_bh(&sess->conn_lock); | 887 | spin_unlock_bh(&sess->conn_lock); |
888 | return conn; | 888 | return conn; |
889 | } | 889 | } |
890 | } | 890 | } |
891 | spin_unlock_bh(&sess->conn_lock); | 891 | spin_unlock_bh(&sess->conn_lock); |
892 | 892 | ||
893 | return NULL; | 893 | return NULL; |
894 | } | 894 | } |
895 | 895 | ||
896 | void iscsit_check_conn_usage_count(struct iscsi_conn *conn) | 896 | void iscsit_check_conn_usage_count(struct iscsi_conn *conn) |
897 | { | 897 | { |
898 | spin_lock_bh(&conn->conn_usage_lock); | 898 | spin_lock_bh(&conn->conn_usage_lock); |
899 | if (conn->conn_usage_count != 0) { | 899 | if (conn->conn_usage_count != 0) { |
900 | conn->conn_waiting_on_uc = 1; | 900 | conn->conn_waiting_on_uc = 1; |
901 | spin_unlock_bh(&conn->conn_usage_lock); | 901 | spin_unlock_bh(&conn->conn_usage_lock); |
902 | 902 | ||
903 | wait_for_completion(&conn->conn_waiting_on_uc_comp); | 903 | wait_for_completion(&conn->conn_waiting_on_uc_comp); |
904 | return; | 904 | return; |
905 | } | 905 | } |
906 | spin_unlock_bh(&conn->conn_usage_lock); | 906 | spin_unlock_bh(&conn->conn_usage_lock); |
907 | } | 907 | } |
908 | 908 | ||
909 | void iscsit_dec_conn_usage_count(struct iscsi_conn *conn) | 909 | void iscsit_dec_conn_usage_count(struct iscsi_conn *conn) |
910 | { | 910 | { |
911 | spin_lock_bh(&conn->conn_usage_lock); | 911 | spin_lock_bh(&conn->conn_usage_lock); |
912 | conn->conn_usage_count--; | 912 | conn->conn_usage_count--; |
913 | 913 | ||
914 | if (!conn->conn_usage_count && conn->conn_waiting_on_uc) | 914 | if (!conn->conn_usage_count && conn->conn_waiting_on_uc) |
915 | complete(&conn->conn_waiting_on_uc_comp); | 915 | complete(&conn->conn_waiting_on_uc_comp); |
916 | 916 | ||
917 | spin_unlock_bh(&conn->conn_usage_lock); | 917 | spin_unlock_bh(&conn->conn_usage_lock); |
918 | } | 918 | } |
919 | 919 | ||
920 | void iscsit_inc_conn_usage_count(struct iscsi_conn *conn) | 920 | void iscsit_inc_conn_usage_count(struct iscsi_conn *conn) |
921 | { | 921 | { |
922 | spin_lock_bh(&conn->conn_usage_lock); | 922 | spin_lock_bh(&conn->conn_usage_lock); |
923 | conn->conn_usage_count++; | 923 | conn->conn_usage_count++; |
924 | spin_unlock_bh(&conn->conn_usage_lock); | 924 | spin_unlock_bh(&conn->conn_usage_lock); |
925 | } | 925 | } |
926 | 926 | ||
927 | static int iscsit_add_nopin(struct iscsi_conn *conn, int want_response) | 927 | static int iscsit_add_nopin(struct iscsi_conn *conn, int want_response) |
928 | { | 928 | { |
929 | u8 state; | 929 | u8 state; |
930 | struct iscsi_cmd *cmd; | 930 | struct iscsi_cmd *cmd; |
931 | 931 | ||
932 | cmd = iscsit_allocate_cmd(conn, TASK_RUNNING); | 932 | cmd = iscsit_allocate_cmd(conn, TASK_RUNNING); |
933 | if (!cmd) | 933 | if (!cmd) |
934 | return -1; | 934 | return -1; |
935 | 935 | ||
936 | cmd->iscsi_opcode = ISCSI_OP_NOOP_IN; | 936 | cmd->iscsi_opcode = ISCSI_OP_NOOP_IN; |
937 | state = (want_response) ? ISTATE_SEND_NOPIN_WANT_RESPONSE : | 937 | state = (want_response) ? ISTATE_SEND_NOPIN_WANT_RESPONSE : |
938 | ISTATE_SEND_NOPIN_NO_RESPONSE; | 938 | ISTATE_SEND_NOPIN_NO_RESPONSE; |
939 | cmd->init_task_tag = RESERVED_ITT; | 939 | cmd->init_task_tag = RESERVED_ITT; |
940 | spin_lock_bh(&conn->sess->ttt_lock); | 940 | spin_lock_bh(&conn->sess->ttt_lock); |
941 | cmd->targ_xfer_tag = (want_response) ? conn->sess->targ_xfer_tag++ : | 941 | cmd->targ_xfer_tag = (want_response) ? conn->sess->targ_xfer_tag++ : |
942 | 0xFFFFFFFF; | 942 | 0xFFFFFFFF; |
943 | if (want_response && (cmd->targ_xfer_tag == 0xFFFFFFFF)) | 943 | if (want_response && (cmd->targ_xfer_tag == 0xFFFFFFFF)) |
944 | cmd->targ_xfer_tag = conn->sess->targ_xfer_tag++; | 944 | cmd->targ_xfer_tag = conn->sess->targ_xfer_tag++; |
945 | spin_unlock_bh(&conn->sess->ttt_lock); | 945 | spin_unlock_bh(&conn->sess->ttt_lock); |
946 | 946 | ||
947 | spin_lock_bh(&conn->cmd_lock); | 947 | spin_lock_bh(&conn->cmd_lock); |
948 | list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list); | 948 | list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list); |
949 | spin_unlock_bh(&conn->cmd_lock); | 949 | spin_unlock_bh(&conn->cmd_lock); |
950 | 950 | ||
951 | if (want_response) | 951 | if (want_response) |
952 | iscsit_start_nopin_response_timer(conn); | 952 | iscsit_start_nopin_response_timer(conn); |
953 | iscsit_add_cmd_to_immediate_queue(cmd, conn, state); | 953 | iscsit_add_cmd_to_immediate_queue(cmd, conn, state); |
954 | 954 | ||
955 | return 0; | 955 | return 0; |
956 | } | 956 | } |
957 | 957 | ||
958 | static void iscsit_handle_nopin_response_timeout(unsigned long data) | 958 | static void iscsit_handle_nopin_response_timeout(unsigned long data) |
959 | { | 959 | { |
960 | struct iscsi_conn *conn = (struct iscsi_conn *) data; | 960 | struct iscsi_conn *conn = (struct iscsi_conn *) data; |
961 | 961 | ||
962 | iscsit_inc_conn_usage_count(conn); | 962 | iscsit_inc_conn_usage_count(conn); |
963 | 963 | ||
964 | spin_lock_bh(&conn->nopin_timer_lock); | 964 | spin_lock_bh(&conn->nopin_timer_lock); |
965 | if (conn->nopin_response_timer_flags & ISCSI_TF_STOP) { | 965 | if (conn->nopin_response_timer_flags & ISCSI_TF_STOP) { |
966 | spin_unlock_bh(&conn->nopin_timer_lock); | 966 | spin_unlock_bh(&conn->nopin_timer_lock); |
967 | iscsit_dec_conn_usage_count(conn); | 967 | iscsit_dec_conn_usage_count(conn); |
968 | return; | 968 | return; |
969 | } | 969 | } |
970 | 970 | ||
971 | pr_debug("Did not receive response to NOPIN on CID: %hu on" | 971 | pr_debug("Did not receive response to NOPIN on CID: %hu on" |
972 | " SID: %u, failing connection.\n", conn->cid, | 972 | " SID: %u, failing connection.\n", conn->cid, |
973 | conn->sess->sid); | 973 | conn->sess->sid); |
974 | conn->nopin_response_timer_flags &= ~ISCSI_TF_RUNNING; | 974 | conn->nopin_response_timer_flags &= ~ISCSI_TF_RUNNING; |
975 | spin_unlock_bh(&conn->nopin_timer_lock); | 975 | spin_unlock_bh(&conn->nopin_timer_lock); |
976 | 976 | ||
977 | { | 977 | { |
978 | struct iscsi_portal_group *tpg = conn->sess->tpg; | 978 | struct iscsi_portal_group *tpg = conn->sess->tpg; |
979 | struct iscsi_tiqn *tiqn = tpg->tpg_tiqn; | 979 | struct iscsi_tiqn *tiqn = tpg->tpg_tiqn; |
980 | 980 | ||
981 | if (tiqn) { | 981 | if (tiqn) { |
982 | spin_lock_bh(&tiqn->sess_err_stats.lock); | 982 | spin_lock_bh(&tiqn->sess_err_stats.lock); |
983 | strcpy(tiqn->sess_err_stats.last_sess_fail_rem_name, | 983 | strcpy(tiqn->sess_err_stats.last_sess_fail_rem_name, |
984 | conn->sess->sess_ops->InitiatorName); | 984 | conn->sess->sess_ops->InitiatorName); |
985 | tiqn->sess_err_stats.last_sess_failure_type = | 985 | tiqn->sess_err_stats.last_sess_failure_type = |
986 | ISCSI_SESS_ERR_CXN_TIMEOUT; | 986 | ISCSI_SESS_ERR_CXN_TIMEOUT; |
987 | tiqn->sess_err_stats.cxn_timeout_errors++; | 987 | tiqn->sess_err_stats.cxn_timeout_errors++; |
988 | atomic_long_inc(&conn->sess->conn_timeout_errors); | 988 | atomic_long_inc(&conn->sess->conn_timeout_errors); |
989 | spin_unlock_bh(&tiqn->sess_err_stats.lock); | 989 | spin_unlock_bh(&tiqn->sess_err_stats.lock); |
990 | } | 990 | } |
991 | } | 991 | } |
992 | 992 | ||
993 | iscsit_cause_connection_reinstatement(conn, 0); | 993 | iscsit_cause_connection_reinstatement(conn, 0); |
994 | iscsit_dec_conn_usage_count(conn); | 994 | iscsit_dec_conn_usage_count(conn); |
995 | } | 995 | } |
996 | 996 | ||
997 | void iscsit_mod_nopin_response_timer(struct iscsi_conn *conn) | 997 | void iscsit_mod_nopin_response_timer(struct iscsi_conn *conn) |
998 | { | 998 | { |
999 | struct iscsi_session *sess = conn->sess; | 999 | struct iscsi_session *sess = conn->sess; |
1000 | struct iscsi_node_attrib *na = iscsit_tpg_get_node_attrib(sess); | 1000 | struct iscsi_node_attrib *na = iscsit_tpg_get_node_attrib(sess); |
1001 | 1001 | ||
1002 | spin_lock_bh(&conn->nopin_timer_lock); | 1002 | spin_lock_bh(&conn->nopin_timer_lock); |
1003 | if (!(conn->nopin_response_timer_flags & ISCSI_TF_RUNNING)) { | 1003 | if (!(conn->nopin_response_timer_flags & ISCSI_TF_RUNNING)) { |
1004 | spin_unlock_bh(&conn->nopin_timer_lock); | 1004 | spin_unlock_bh(&conn->nopin_timer_lock); |
1005 | return; | 1005 | return; |
1006 | } | 1006 | } |
1007 | 1007 | ||
1008 | mod_timer(&conn->nopin_response_timer, | 1008 | mod_timer(&conn->nopin_response_timer, |
1009 | (get_jiffies_64() + na->nopin_response_timeout * HZ)); | 1009 | (get_jiffies_64() + na->nopin_response_timeout * HZ)); |
1010 | spin_unlock_bh(&conn->nopin_timer_lock); | 1010 | spin_unlock_bh(&conn->nopin_timer_lock); |
1011 | } | 1011 | } |
1012 | 1012 | ||
1013 | /* | 1013 | /* |
1014 | * Called with conn->nopin_timer_lock held. | 1014 | * Called with conn->nopin_timer_lock held. |
1015 | */ | 1015 | */ |
1016 | void iscsit_start_nopin_response_timer(struct iscsi_conn *conn) | 1016 | void iscsit_start_nopin_response_timer(struct iscsi_conn *conn) |
1017 | { | 1017 | { |
1018 | struct iscsi_session *sess = conn->sess; | 1018 | struct iscsi_session *sess = conn->sess; |
1019 | struct iscsi_node_attrib *na = iscsit_tpg_get_node_attrib(sess); | 1019 | struct iscsi_node_attrib *na = iscsit_tpg_get_node_attrib(sess); |
1020 | 1020 | ||
1021 | spin_lock_bh(&conn->nopin_timer_lock); | 1021 | spin_lock_bh(&conn->nopin_timer_lock); |
1022 | if (conn->nopin_response_timer_flags & ISCSI_TF_RUNNING) { | 1022 | if (conn->nopin_response_timer_flags & ISCSI_TF_RUNNING) { |
1023 | spin_unlock_bh(&conn->nopin_timer_lock); | 1023 | spin_unlock_bh(&conn->nopin_timer_lock); |
1024 | return; | 1024 | return; |
1025 | } | 1025 | } |
1026 | 1026 | ||
1027 | init_timer(&conn->nopin_response_timer); | 1027 | init_timer(&conn->nopin_response_timer); |
1028 | conn->nopin_response_timer.expires = | 1028 | conn->nopin_response_timer.expires = |
1029 | (get_jiffies_64() + na->nopin_response_timeout * HZ); | 1029 | (get_jiffies_64() + na->nopin_response_timeout * HZ); |
1030 | conn->nopin_response_timer.data = (unsigned long)conn; | 1030 | conn->nopin_response_timer.data = (unsigned long)conn; |
1031 | conn->nopin_response_timer.function = iscsit_handle_nopin_response_timeout; | 1031 | conn->nopin_response_timer.function = iscsit_handle_nopin_response_timeout; |
1032 | conn->nopin_response_timer_flags &= ~ISCSI_TF_STOP; | 1032 | conn->nopin_response_timer_flags &= ~ISCSI_TF_STOP; |
1033 | conn->nopin_response_timer_flags |= ISCSI_TF_RUNNING; | 1033 | conn->nopin_response_timer_flags |= ISCSI_TF_RUNNING; |
1034 | add_timer(&conn->nopin_response_timer); | 1034 | add_timer(&conn->nopin_response_timer); |
1035 | 1035 | ||
1036 | pr_debug("Started NOPIN Response Timer on CID: %d to %u" | 1036 | pr_debug("Started NOPIN Response Timer on CID: %d to %u" |
1037 | " seconds\n", conn->cid, na->nopin_response_timeout); | 1037 | " seconds\n", conn->cid, na->nopin_response_timeout); |
1038 | spin_unlock_bh(&conn->nopin_timer_lock); | 1038 | spin_unlock_bh(&conn->nopin_timer_lock); |
1039 | } | 1039 | } |
1040 | 1040 | ||
1041 | void iscsit_stop_nopin_response_timer(struct iscsi_conn *conn) | 1041 | void iscsit_stop_nopin_response_timer(struct iscsi_conn *conn) |
1042 | { | 1042 | { |
1043 | spin_lock_bh(&conn->nopin_timer_lock); | 1043 | spin_lock_bh(&conn->nopin_timer_lock); |
1044 | if (!(conn->nopin_response_timer_flags & ISCSI_TF_RUNNING)) { | 1044 | if (!(conn->nopin_response_timer_flags & ISCSI_TF_RUNNING)) { |
1045 | spin_unlock_bh(&conn->nopin_timer_lock); | 1045 | spin_unlock_bh(&conn->nopin_timer_lock); |
1046 | return; | 1046 | return; |
1047 | } | 1047 | } |
1048 | conn->nopin_response_timer_flags |= ISCSI_TF_STOP; | 1048 | conn->nopin_response_timer_flags |= ISCSI_TF_STOP; |
1049 | spin_unlock_bh(&conn->nopin_timer_lock); | 1049 | spin_unlock_bh(&conn->nopin_timer_lock); |
1050 | 1050 | ||
1051 | del_timer_sync(&conn->nopin_response_timer); | 1051 | del_timer_sync(&conn->nopin_response_timer); |
1052 | 1052 | ||
1053 | spin_lock_bh(&conn->nopin_timer_lock); | 1053 | spin_lock_bh(&conn->nopin_timer_lock); |
1054 | conn->nopin_response_timer_flags &= ~ISCSI_TF_RUNNING; | 1054 | conn->nopin_response_timer_flags &= ~ISCSI_TF_RUNNING; |
1055 | spin_unlock_bh(&conn->nopin_timer_lock); | 1055 | spin_unlock_bh(&conn->nopin_timer_lock); |
1056 | } | 1056 | } |
1057 | 1057 | ||
1058 | static void iscsit_handle_nopin_timeout(unsigned long data) | 1058 | static void iscsit_handle_nopin_timeout(unsigned long data) |
1059 | { | 1059 | { |
1060 | struct iscsi_conn *conn = (struct iscsi_conn *) data; | 1060 | struct iscsi_conn *conn = (struct iscsi_conn *) data; |
1061 | 1061 | ||
1062 | iscsit_inc_conn_usage_count(conn); | 1062 | iscsit_inc_conn_usage_count(conn); |
1063 | 1063 | ||
1064 | spin_lock_bh(&conn->nopin_timer_lock); | 1064 | spin_lock_bh(&conn->nopin_timer_lock); |
1065 | if (conn->nopin_timer_flags & ISCSI_TF_STOP) { | 1065 | if (conn->nopin_timer_flags & ISCSI_TF_STOP) { |
1066 | spin_unlock_bh(&conn->nopin_timer_lock); | 1066 | spin_unlock_bh(&conn->nopin_timer_lock); |
1067 | iscsit_dec_conn_usage_count(conn); | 1067 | iscsit_dec_conn_usage_count(conn); |
1068 | return; | 1068 | return; |
1069 | } | 1069 | } |
1070 | conn->nopin_timer_flags &= ~ISCSI_TF_RUNNING; | 1070 | conn->nopin_timer_flags &= ~ISCSI_TF_RUNNING; |
1071 | spin_unlock_bh(&conn->nopin_timer_lock); | 1071 | spin_unlock_bh(&conn->nopin_timer_lock); |
1072 | 1072 | ||
1073 | iscsit_add_nopin(conn, 1); | 1073 | iscsit_add_nopin(conn, 1); |
1074 | iscsit_dec_conn_usage_count(conn); | 1074 | iscsit_dec_conn_usage_count(conn); |
1075 | } | 1075 | } |
1076 | 1076 | ||
1077 | /* | 1077 | /* |
1078 | * Called with conn->nopin_timer_lock held. | 1078 | * Called with conn->nopin_timer_lock held. |
1079 | */ | 1079 | */ |
1080 | void __iscsit_start_nopin_timer(struct iscsi_conn *conn) | 1080 | void __iscsit_start_nopin_timer(struct iscsi_conn *conn) |
1081 | { | 1081 | { |
1082 | struct iscsi_session *sess = conn->sess; | 1082 | struct iscsi_session *sess = conn->sess; |
1083 | struct iscsi_node_attrib *na = iscsit_tpg_get_node_attrib(sess); | 1083 | struct iscsi_node_attrib *na = iscsit_tpg_get_node_attrib(sess); |
1084 | /* | 1084 | /* |
1085 | * NOPIN timeout is disabled. | 1085 | * NOPIN timeout is disabled. |
1086 | */ | 1086 | */ |
1087 | if (!na->nopin_timeout) | 1087 | if (!na->nopin_timeout) |
1088 | return; | 1088 | return; |
1089 | 1089 | ||
1090 | if (conn->nopin_timer_flags & ISCSI_TF_RUNNING) | 1090 | if (conn->nopin_timer_flags & ISCSI_TF_RUNNING) |
1091 | return; | 1091 | return; |
1092 | 1092 | ||
1093 | init_timer(&conn->nopin_timer); | 1093 | init_timer(&conn->nopin_timer); |
1094 | conn->nopin_timer.expires = (get_jiffies_64() + na->nopin_timeout * HZ); | 1094 | conn->nopin_timer.expires = (get_jiffies_64() + na->nopin_timeout * HZ); |
1095 | conn->nopin_timer.data = (unsigned long)conn; | 1095 | conn->nopin_timer.data = (unsigned long)conn; |
1096 | conn->nopin_timer.function = iscsit_handle_nopin_timeout; | 1096 | conn->nopin_timer.function = iscsit_handle_nopin_timeout; |
1097 | conn->nopin_timer_flags &= ~ISCSI_TF_STOP; | 1097 | conn->nopin_timer_flags &= ~ISCSI_TF_STOP; |
1098 | conn->nopin_timer_flags |= ISCSI_TF_RUNNING; | 1098 | conn->nopin_timer_flags |= ISCSI_TF_RUNNING; |
1099 | add_timer(&conn->nopin_timer); | 1099 | add_timer(&conn->nopin_timer); |
1100 | 1100 | ||
1101 | pr_debug("Started NOPIN Timer on CID: %d at %u second" | 1101 | pr_debug("Started NOPIN Timer on CID: %d at %u second" |
1102 | " interval\n", conn->cid, na->nopin_timeout); | 1102 | " interval\n", conn->cid, na->nopin_timeout); |
1103 | } | 1103 | } |
1104 | 1104 | ||
1105 | void iscsit_start_nopin_timer(struct iscsi_conn *conn) | 1105 | void iscsit_start_nopin_timer(struct iscsi_conn *conn) |
1106 | { | 1106 | { |
1107 | struct iscsi_session *sess = conn->sess; | 1107 | struct iscsi_session *sess = conn->sess; |
1108 | struct iscsi_node_attrib *na = iscsit_tpg_get_node_attrib(sess); | 1108 | struct iscsi_node_attrib *na = iscsit_tpg_get_node_attrib(sess); |
1109 | /* | 1109 | /* |
1110 | * NOPIN timeout is disabled.. | 1110 | * NOPIN timeout is disabled.. |
1111 | */ | 1111 | */ |
1112 | if (!na->nopin_timeout) | 1112 | if (!na->nopin_timeout) |
1113 | return; | 1113 | return; |
1114 | 1114 | ||
1115 | spin_lock_bh(&conn->nopin_timer_lock); | 1115 | spin_lock_bh(&conn->nopin_timer_lock); |
1116 | if (conn->nopin_timer_flags & ISCSI_TF_RUNNING) { | 1116 | if (conn->nopin_timer_flags & ISCSI_TF_RUNNING) { |
1117 | spin_unlock_bh(&conn->nopin_timer_lock); | 1117 | spin_unlock_bh(&conn->nopin_timer_lock); |
1118 | return; | 1118 | return; |
1119 | } | 1119 | } |
1120 | 1120 | ||
1121 | init_timer(&conn->nopin_timer); | 1121 | init_timer(&conn->nopin_timer); |
1122 | conn->nopin_timer.expires = (get_jiffies_64() + na->nopin_timeout * HZ); | 1122 | conn->nopin_timer.expires = (get_jiffies_64() + na->nopin_timeout * HZ); |
1123 | conn->nopin_timer.data = (unsigned long)conn; | 1123 | conn->nopin_timer.data = (unsigned long)conn; |
1124 | conn->nopin_timer.function = iscsit_handle_nopin_timeout; | 1124 | conn->nopin_timer.function = iscsit_handle_nopin_timeout; |
1125 | conn->nopin_timer_flags &= ~ISCSI_TF_STOP; | 1125 | conn->nopin_timer_flags &= ~ISCSI_TF_STOP; |
1126 | conn->nopin_timer_flags |= ISCSI_TF_RUNNING; | 1126 | conn->nopin_timer_flags |= ISCSI_TF_RUNNING; |
1127 | add_timer(&conn->nopin_timer); | 1127 | add_timer(&conn->nopin_timer); |
1128 | 1128 | ||
1129 | pr_debug("Started NOPIN Timer on CID: %d at %u second" | 1129 | pr_debug("Started NOPIN Timer on CID: %d at %u second" |
1130 | " interval\n", conn->cid, na->nopin_timeout); | 1130 | " interval\n", conn->cid, na->nopin_timeout); |
1131 | spin_unlock_bh(&conn->nopin_timer_lock); | 1131 | spin_unlock_bh(&conn->nopin_timer_lock); |
1132 | } | 1132 | } |
1133 | 1133 | ||
1134 | void iscsit_stop_nopin_timer(struct iscsi_conn *conn) | 1134 | void iscsit_stop_nopin_timer(struct iscsi_conn *conn) |
1135 | { | 1135 | { |
1136 | spin_lock_bh(&conn->nopin_timer_lock); | 1136 | spin_lock_bh(&conn->nopin_timer_lock); |
1137 | if (!(conn->nopin_timer_flags & ISCSI_TF_RUNNING)) { | 1137 | if (!(conn->nopin_timer_flags & ISCSI_TF_RUNNING)) { |
1138 | spin_unlock_bh(&conn->nopin_timer_lock); | 1138 | spin_unlock_bh(&conn->nopin_timer_lock); |
1139 | return; | 1139 | return; |
1140 | } | 1140 | } |
1141 | conn->nopin_timer_flags |= ISCSI_TF_STOP; | 1141 | conn->nopin_timer_flags |= ISCSI_TF_STOP; |
1142 | spin_unlock_bh(&conn->nopin_timer_lock); | 1142 | spin_unlock_bh(&conn->nopin_timer_lock); |
1143 | 1143 | ||
1144 | del_timer_sync(&conn->nopin_timer); | 1144 | del_timer_sync(&conn->nopin_timer); |
1145 | 1145 | ||
1146 | spin_lock_bh(&conn->nopin_timer_lock); | 1146 | spin_lock_bh(&conn->nopin_timer_lock); |
1147 | conn->nopin_timer_flags &= ~ISCSI_TF_RUNNING; | 1147 | conn->nopin_timer_flags &= ~ISCSI_TF_RUNNING; |
1148 | spin_unlock_bh(&conn->nopin_timer_lock); | 1148 | spin_unlock_bh(&conn->nopin_timer_lock); |
1149 | } | 1149 | } |
1150 | 1150 | ||
1151 | int iscsit_send_tx_data( | 1151 | int iscsit_send_tx_data( |
1152 | struct iscsi_cmd *cmd, | 1152 | struct iscsi_cmd *cmd, |
1153 | struct iscsi_conn *conn, | 1153 | struct iscsi_conn *conn, |
1154 | int use_misc) | 1154 | int use_misc) |
1155 | { | 1155 | { |
1156 | int tx_sent, tx_size; | 1156 | int tx_sent, tx_size; |
1157 | u32 iov_count; | 1157 | u32 iov_count; |
1158 | struct kvec *iov; | 1158 | struct kvec *iov; |
1159 | 1159 | ||
1160 | send_data: | 1160 | send_data: |
1161 | tx_size = cmd->tx_size; | 1161 | tx_size = cmd->tx_size; |
1162 | 1162 | ||
1163 | if (!use_misc) { | 1163 | if (!use_misc) { |
1164 | iov = &cmd->iov_data[0]; | 1164 | iov = &cmd->iov_data[0]; |
1165 | iov_count = cmd->iov_data_count; | 1165 | iov_count = cmd->iov_data_count; |
1166 | } else { | 1166 | } else { |
1167 | iov = &cmd->iov_misc[0]; | 1167 | iov = &cmd->iov_misc[0]; |
1168 | iov_count = cmd->iov_misc_count; | 1168 | iov_count = cmd->iov_misc_count; |
1169 | } | 1169 | } |
1170 | 1170 | ||
1171 | tx_sent = tx_data(conn, &iov[0], iov_count, tx_size); | 1171 | tx_sent = tx_data(conn, &iov[0], iov_count, tx_size); |
1172 | if (tx_size != tx_sent) { | 1172 | if (tx_size != tx_sent) { |
1173 | if (tx_sent == -EAGAIN) { | 1173 | if (tx_sent == -EAGAIN) { |
1174 | pr_err("tx_data() returned -EAGAIN\n"); | 1174 | pr_err("tx_data() returned -EAGAIN\n"); |
1175 | goto send_data; | 1175 | goto send_data; |
1176 | } else | 1176 | } else |
1177 | return -1; | 1177 | return -1; |
1178 | } | 1178 | } |
1179 | cmd->tx_size = 0; | 1179 | cmd->tx_size = 0; |
1180 | 1180 | ||
1181 | return 0; | 1181 | return 0; |
1182 | } | 1182 | } |
1183 | 1183 | ||
1184 | int iscsit_fe_sendpage_sg( | 1184 | int iscsit_fe_sendpage_sg( |
1185 | struct iscsi_cmd *cmd, | 1185 | struct iscsi_cmd *cmd, |
1186 | struct iscsi_conn *conn) | 1186 | struct iscsi_conn *conn) |
1187 | { | 1187 | { |
1188 | struct scatterlist *sg = cmd->first_data_sg; | 1188 | struct scatterlist *sg = cmd->first_data_sg; |
1189 | struct kvec iov; | 1189 | struct kvec iov; |
1190 | u32 tx_hdr_size, data_len; | 1190 | u32 tx_hdr_size, data_len; |
1191 | u32 offset = cmd->first_data_sg_off; | 1191 | u32 offset = cmd->first_data_sg_off; |
1192 | int tx_sent, iov_off; | 1192 | int tx_sent, iov_off; |
1193 | 1193 | ||
1194 | send_hdr: | 1194 | send_hdr: |
1195 | tx_hdr_size = ISCSI_HDR_LEN; | 1195 | tx_hdr_size = ISCSI_HDR_LEN; |
1196 | if (conn->conn_ops->HeaderDigest) | 1196 | if (conn->conn_ops->HeaderDigest) |
1197 | tx_hdr_size += ISCSI_CRC_LEN; | 1197 | tx_hdr_size += ISCSI_CRC_LEN; |
1198 | 1198 | ||
1199 | iov.iov_base = cmd->pdu; | 1199 | iov.iov_base = cmd->pdu; |
1200 | iov.iov_len = tx_hdr_size; | 1200 | iov.iov_len = tx_hdr_size; |
1201 | 1201 | ||
1202 | tx_sent = tx_data(conn, &iov, 1, tx_hdr_size); | 1202 | tx_sent = tx_data(conn, &iov, 1, tx_hdr_size); |
1203 | if (tx_hdr_size != tx_sent) { | 1203 | if (tx_hdr_size != tx_sent) { |
1204 | if (tx_sent == -EAGAIN) { | 1204 | if (tx_sent == -EAGAIN) { |
1205 | pr_err("tx_data() returned -EAGAIN\n"); | 1205 | pr_err("tx_data() returned -EAGAIN\n"); |
1206 | goto send_hdr; | 1206 | goto send_hdr; |
1207 | } | 1207 | } |
1208 | return -1; | 1208 | return -1; |
1209 | } | 1209 | } |
1210 | 1210 | ||
1211 | data_len = cmd->tx_size - tx_hdr_size - cmd->padding; | 1211 | data_len = cmd->tx_size - tx_hdr_size - cmd->padding; |
1212 | /* | 1212 | /* |
1213 | * Set iov_off used by padding and data digest tx_data() calls below | 1213 | * Set iov_off used by padding and data digest tx_data() calls below |
1214 | * in order to determine proper offset into cmd->iov_data[] | 1214 | * in order to determine proper offset into cmd->iov_data[] |
1215 | */ | 1215 | */ |
1216 | if (conn->conn_ops->DataDigest) { | 1216 | if (conn->conn_ops->DataDigest) { |
1217 | data_len -= ISCSI_CRC_LEN; | 1217 | data_len -= ISCSI_CRC_LEN; |
1218 | if (cmd->padding) | 1218 | if (cmd->padding) |
1219 | iov_off = (cmd->iov_data_count - 2); | 1219 | iov_off = (cmd->iov_data_count - 2); |
1220 | else | 1220 | else |
1221 | iov_off = (cmd->iov_data_count - 1); | 1221 | iov_off = (cmd->iov_data_count - 1); |
1222 | } else { | 1222 | } else { |
1223 | iov_off = (cmd->iov_data_count - 1); | 1223 | iov_off = (cmd->iov_data_count - 1); |
1224 | } | 1224 | } |
1225 | /* | 1225 | /* |
1226 | * Perform sendpage() for each page in the scatterlist | 1226 | * Perform sendpage() for each page in the scatterlist |
1227 | */ | 1227 | */ |
1228 | while (data_len) { | 1228 | while (data_len) { |
1229 | u32 space = (sg->length - offset); | 1229 | u32 space = (sg->length - offset); |
1230 | u32 sub_len = min_t(u32, data_len, space); | 1230 | u32 sub_len = min_t(u32, data_len, space); |
1231 | send_pg: | 1231 | send_pg: |
1232 | tx_sent = conn->sock->ops->sendpage(conn->sock, | 1232 | tx_sent = conn->sock->ops->sendpage(conn->sock, |
1233 | sg_page(sg), sg->offset + offset, sub_len, 0); | 1233 | sg_page(sg), sg->offset + offset, sub_len, 0); |
1234 | if (tx_sent != sub_len) { | 1234 | if (tx_sent != sub_len) { |
1235 | if (tx_sent == -EAGAIN) { | 1235 | if (tx_sent == -EAGAIN) { |
1236 | pr_err("tcp_sendpage() returned" | 1236 | pr_err("tcp_sendpage() returned" |
1237 | " -EAGAIN\n"); | 1237 | " -EAGAIN\n"); |
1238 | goto send_pg; | 1238 | goto send_pg; |
1239 | } | 1239 | } |
1240 | 1240 | ||
1241 | pr_err("tcp_sendpage() failure: %d\n", | 1241 | pr_err("tcp_sendpage() failure: %d\n", |
1242 | tx_sent); | 1242 | tx_sent); |
1243 | return -1; | 1243 | return -1; |
1244 | } | 1244 | } |
1245 | 1245 | ||
1246 | data_len -= sub_len; | 1246 | data_len -= sub_len; |
1247 | offset = 0; | 1247 | offset = 0; |
1248 | sg = sg_next(sg); | 1248 | sg = sg_next(sg); |
1249 | } | 1249 | } |
1250 | 1250 | ||
1251 | send_padding: | 1251 | send_padding: |
1252 | if (cmd->padding) { | 1252 | if (cmd->padding) { |
1253 | struct kvec *iov_p = &cmd->iov_data[iov_off++]; | 1253 | struct kvec *iov_p = &cmd->iov_data[iov_off++]; |
1254 | 1254 | ||
1255 | tx_sent = tx_data(conn, iov_p, 1, cmd->padding); | 1255 | tx_sent = tx_data(conn, iov_p, 1, cmd->padding); |
1256 | if (cmd->padding != tx_sent) { | 1256 | if (cmd->padding != tx_sent) { |
1257 | if (tx_sent == -EAGAIN) { | 1257 | if (tx_sent == -EAGAIN) { |
1258 | pr_err("tx_data() returned -EAGAIN\n"); | 1258 | pr_err("tx_data() returned -EAGAIN\n"); |
1259 | goto send_padding; | 1259 | goto send_padding; |
1260 | } | 1260 | } |
1261 | return -1; | 1261 | return -1; |
1262 | } | 1262 | } |
1263 | } | 1263 | } |
1264 | 1264 | ||
1265 | send_datacrc: | 1265 | send_datacrc: |
1266 | if (conn->conn_ops->DataDigest) { | 1266 | if (conn->conn_ops->DataDigest) { |
1267 | struct kvec *iov_d = &cmd->iov_data[iov_off]; | 1267 | struct kvec *iov_d = &cmd->iov_data[iov_off]; |
1268 | 1268 | ||
1269 | tx_sent = tx_data(conn, iov_d, 1, ISCSI_CRC_LEN); | 1269 | tx_sent = tx_data(conn, iov_d, 1, ISCSI_CRC_LEN); |
1270 | if (ISCSI_CRC_LEN != tx_sent) { | 1270 | if (ISCSI_CRC_LEN != tx_sent) { |
1271 | if (tx_sent == -EAGAIN) { | 1271 | if (tx_sent == -EAGAIN) { |
1272 | pr_err("tx_data() returned -EAGAIN\n"); | 1272 | pr_err("tx_data() returned -EAGAIN\n"); |
1273 | goto send_datacrc; | 1273 | goto send_datacrc; |
1274 | } | 1274 | } |
1275 | return -1; | 1275 | return -1; |
1276 | } | 1276 | } |
1277 | } | 1277 | } |
1278 | 1278 | ||
1279 | return 0; | 1279 | return 0; |
1280 | } | 1280 | } |
1281 | 1281 | ||
1282 | /* | 1282 | /* |
1283 | * This function is used for mainly sending a ISCSI_TARG_LOGIN_RSP PDU | 1283 | * This function is used for mainly sending a ISCSI_TARG_LOGIN_RSP PDU |
1284 | * back to the Initiator when an expection condition occurs with the | 1284 | * back to the Initiator when an expection condition occurs with the |
1285 | * errors set in status_class and status_detail. | 1285 | * errors set in status_class and status_detail. |
1286 | * | 1286 | * |
1287 | * Parameters: iSCSI Connection, Status Class, Status Detail. | 1287 | * Parameters: iSCSI Connection, Status Class, Status Detail. |
1288 | * Returns: 0 on success, -1 on error. | 1288 | * Returns: 0 on success, -1 on error. |
1289 | */ | 1289 | */ |
1290 | int iscsit_tx_login_rsp(struct iscsi_conn *conn, u8 status_class, u8 status_detail) | 1290 | int iscsit_tx_login_rsp(struct iscsi_conn *conn, u8 status_class, u8 status_detail) |
1291 | { | 1291 | { |
1292 | struct iscsi_login_rsp *hdr; | 1292 | struct iscsi_login_rsp *hdr; |
1293 | struct iscsi_login *login = conn->conn_login; | 1293 | struct iscsi_login *login = conn->conn_login; |
1294 | 1294 | ||
1295 | login->login_failed = 1; | 1295 | login->login_failed = 1; |
1296 | iscsit_collect_login_stats(conn, status_class, status_detail); | 1296 | iscsit_collect_login_stats(conn, status_class, status_detail); |
1297 | 1297 | ||
1298 | memset(&login->rsp[0], 0, ISCSI_HDR_LEN); | ||
1299 | |||
1298 | hdr = (struct iscsi_login_rsp *)&login->rsp[0]; | 1300 | hdr = (struct iscsi_login_rsp *)&login->rsp[0]; |
1299 | hdr->opcode = ISCSI_OP_LOGIN_RSP; | 1301 | hdr->opcode = ISCSI_OP_LOGIN_RSP; |
1300 | hdr->status_class = status_class; | 1302 | hdr->status_class = status_class; |
1301 | hdr->status_detail = status_detail; | 1303 | hdr->status_detail = status_detail; |
1302 | hdr->itt = conn->login_itt; | 1304 | hdr->itt = conn->login_itt; |
1303 | 1305 | ||
1304 | return conn->conn_transport->iscsit_put_login_tx(conn, login, 0); | 1306 | return conn->conn_transport->iscsit_put_login_tx(conn, login, 0); |
1305 | } | 1307 | } |
1306 | 1308 | ||
1307 | void iscsit_print_session_params(struct iscsi_session *sess) | 1309 | void iscsit_print_session_params(struct iscsi_session *sess) |
1308 | { | 1310 | { |
1309 | struct iscsi_conn *conn; | 1311 | struct iscsi_conn *conn; |
1310 | 1312 | ||
1311 | pr_debug("-----------------------------[Session Params for" | 1313 | pr_debug("-----------------------------[Session Params for" |
1312 | " SID: %u]-----------------------------\n", sess->sid); | 1314 | " SID: %u]-----------------------------\n", sess->sid); |
1313 | spin_lock_bh(&sess->conn_lock); | 1315 | spin_lock_bh(&sess->conn_lock); |
1314 | list_for_each_entry(conn, &sess->sess_conn_list, conn_list) | 1316 | list_for_each_entry(conn, &sess->sess_conn_list, conn_list) |
1315 | iscsi_dump_conn_ops(conn->conn_ops); | 1317 | iscsi_dump_conn_ops(conn->conn_ops); |
1316 | spin_unlock_bh(&sess->conn_lock); | 1318 | spin_unlock_bh(&sess->conn_lock); |
1317 | 1319 | ||
1318 | iscsi_dump_sess_ops(sess->sess_ops); | 1320 | iscsi_dump_sess_ops(sess->sess_ops); |
1319 | } | 1321 | } |
1320 | 1322 | ||
1321 | static int iscsit_do_rx_data( | 1323 | static int iscsit_do_rx_data( |
1322 | struct iscsi_conn *conn, | 1324 | struct iscsi_conn *conn, |
1323 | struct iscsi_data_count *count) | 1325 | struct iscsi_data_count *count) |
1324 | { | 1326 | { |
1325 | int data = count->data_length, rx_loop = 0, total_rx = 0, iov_len; | 1327 | int data = count->data_length, rx_loop = 0, total_rx = 0, iov_len; |
1326 | struct kvec *iov_p; | 1328 | struct kvec *iov_p; |
1327 | struct msghdr msg; | 1329 | struct msghdr msg; |
1328 | 1330 | ||
1329 | if (!conn || !conn->sock || !conn->conn_ops) | 1331 | if (!conn || !conn->sock || !conn->conn_ops) |
1330 | return -1; | 1332 | return -1; |
1331 | 1333 | ||
1332 | memset(&msg, 0, sizeof(struct msghdr)); | 1334 | memset(&msg, 0, sizeof(struct msghdr)); |
1333 | 1335 | ||
1334 | iov_p = count->iov; | 1336 | iov_p = count->iov; |
1335 | iov_len = count->iov_count; | 1337 | iov_len = count->iov_count; |
1336 | 1338 | ||
1337 | while (total_rx < data) { | 1339 | while (total_rx < data) { |
1338 | rx_loop = kernel_recvmsg(conn->sock, &msg, iov_p, iov_len, | 1340 | rx_loop = kernel_recvmsg(conn->sock, &msg, iov_p, iov_len, |
1339 | (data - total_rx), MSG_WAITALL); | 1341 | (data - total_rx), MSG_WAITALL); |
1340 | if (rx_loop <= 0) { | 1342 | if (rx_loop <= 0) { |
1341 | pr_debug("rx_loop: %d total_rx: %d\n", | 1343 | pr_debug("rx_loop: %d total_rx: %d\n", |
1342 | rx_loop, total_rx); | 1344 | rx_loop, total_rx); |
1343 | return rx_loop; | 1345 | return rx_loop; |
1344 | } | 1346 | } |
1345 | total_rx += rx_loop; | 1347 | total_rx += rx_loop; |
1346 | pr_debug("rx_loop: %d, total_rx: %d, data: %d\n", | 1348 | pr_debug("rx_loop: %d, total_rx: %d, data: %d\n", |
1347 | rx_loop, total_rx, data); | 1349 | rx_loop, total_rx, data); |
1348 | } | 1350 | } |
1349 | 1351 | ||
1350 | return total_rx; | 1352 | return total_rx; |
1351 | } | 1353 | } |
1352 | 1354 | ||
1353 | static int iscsit_do_tx_data( | 1355 | static int iscsit_do_tx_data( |
1354 | struct iscsi_conn *conn, | 1356 | struct iscsi_conn *conn, |
1355 | struct iscsi_data_count *count) | 1357 | struct iscsi_data_count *count) |
1356 | { | 1358 | { |
1357 | int data = count->data_length, total_tx = 0, tx_loop = 0, iov_len; | 1359 | int data = count->data_length, total_tx = 0, tx_loop = 0, iov_len; |
1358 | struct kvec *iov_p; | 1360 | struct kvec *iov_p; |
1359 | struct msghdr msg; | 1361 | struct msghdr msg; |
1360 | 1362 | ||
1361 | if (!conn || !conn->sock || !conn->conn_ops) | 1363 | if (!conn || !conn->sock || !conn->conn_ops) |
1362 | return -1; | 1364 | return -1; |
1363 | 1365 | ||
1364 | if (data <= 0) { | 1366 | if (data <= 0) { |
1365 | pr_err("Data length is: %d\n", data); | 1367 | pr_err("Data length is: %d\n", data); |
1366 | return -1; | 1368 | return -1; |
1367 | } | 1369 | } |
1368 | 1370 | ||
1369 | memset(&msg, 0, sizeof(struct msghdr)); | 1371 | memset(&msg, 0, sizeof(struct msghdr)); |
1370 | 1372 | ||
1371 | iov_p = count->iov; | 1373 | iov_p = count->iov; |
1372 | iov_len = count->iov_count; | 1374 | iov_len = count->iov_count; |
1373 | 1375 | ||
1374 | while (total_tx < data) { | 1376 | while (total_tx < data) { |
1375 | tx_loop = kernel_sendmsg(conn->sock, &msg, iov_p, iov_len, | 1377 | tx_loop = kernel_sendmsg(conn->sock, &msg, iov_p, iov_len, |
1376 | (data - total_tx)); | 1378 | (data - total_tx)); |
1377 | if (tx_loop <= 0) { | 1379 | if (tx_loop <= 0) { |
1378 | pr_debug("tx_loop: %d total_tx %d\n", | 1380 | pr_debug("tx_loop: %d total_tx %d\n", |
1379 | tx_loop, total_tx); | 1381 | tx_loop, total_tx); |
1380 | return tx_loop; | 1382 | return tx_loop; |
1381 | } | 1383 | } |
1382 | total_tx += tx_loop; | 1384 | total_tx += tx_loop; |
1383 | pr_debug("tx_loop: %d, total_tx: %d, data: %d\n", | 1385 | pr_debug("tx_loop: %d, total_tx: %d, data: %d\n", |
1384 | tx_loop, total_tx, data); | 1386 | tx_loop, total_tx, data); |
1385 | } | 1387 | } |
1386 | 1388 | ||
1387 | return total_tx; | 1389 | return total_tx; |
1388 | } | 1390 | } |
1389 | 1391 | ||
1390 | int rx_data( | 1392 | int rx_data( |
1391 | struct iscsi_conn *conn, | 1393 | struct iscsi_conn *conn, |
1392 | struct kvec *iov, | 1394 | struct kvec *iov, |
1393 | int iov_count, | 1395 | int iov_count, |
1394 | int data) | 1396 | int data) |
1395 | { | 1397 | { |
1396 | struct iscsi_data_count c; | 1398 | struct iscsi_data_count c; |
1397 | 1399 | ||
1398 | if (!conn || !conn->sock || !conn->conn_ops) | 1400 | if (!conn || !conn->sock || !conn->conn_ops) |
1399 | return -1; | 1401 | return -1; |
1400 | 1402 | ||
1401 | memset(&c, 0, sizeof(struct iscsi_data_count)); | 1403 | memset(&c, 0, sizeof(struct iscsi_data_count)); |
1402 | c.iov = iov; | 1404 | c.iov = iov; |
1403 | c.iov_count = iov_count; | 1405 | c.iov_count = iov_count; |
1404 | c.data_length = data; | 1406 | c.data_length = data; |
1405 | c.type = ISCSI_RX_DATA; | 1407 | c.type = ISCSI_RX_DATA; |
1406 | 1408 | ||
1407 | return iscsit_do_rx_data(conn, &c); | 1409 | return iscsit_do_rx_data(conn, &c); |
1408 | } | 1410 | } |
1409 | 1411 | ||
1410 | int tx_data( | 1412 | int tx_data( |
1411 | struct iscsi_conn *conn, | 1413 | struct iscsi_conn *conn, |
1412 | struct kvec *iov, | 1414 | struct kvec *iov, |
1413 | int iov_count, | 1415 | int iov_count, |
1414 | int data) | 1416 | int data) |
1415 | { | 1417 | { |
1416 | struct iscsi_data_count c; | 1418 | struct iscsi_data_count c; |
1417 | 1419 | ||
1418 | if (!conn || !conn->sock || !conn->conn_ops) | 1420 | if (!conn || !conn->sock || !conn->conn_ops) |
1419 | return -1; | 1421 | return -1; |
1420 | 1422 | ||
1421 | memset(&c, 0, sizeof(struct iscsi_data_count)); | 1423 | memset(&c, 0, sizeof(struct iscsi_data_count)); |
1422 | c.iov = iov; | 1424 | c.iov = iov; |
1423 | c.iov_count = iov_count; | 1425 | c.iov_count = iov_count; |
1424 | c.data_length = data; | 1426 | c.data_length = data; |
1425 | c.type = ISCSI_TX_DATA; | 1427 | c.type = ISCSI_TX_DATA; |
1426 | 1428 | ||
1427 | return iscsit_do_tx_data(conn, &c); | 1429 | return iscsit_do_tx_data(conn, &c); |
1428 | } | 1430 | } |
1429 | 1431 | ||
1430 | void iscsit_collect_login_stats( | 1432 | void iscsit_collect_login_stats( |
1431 | struct iscsi_conn *conn, | 1433 | struct iscsi_conn *conn, |
1432 | u8 status_class, | 1434 | u8 status_class, |
1433 | u8 status_detail) | 1435 | u8 status_detail) |
1434 | { | 1436 | { |
1435 | struct iscsi_param *intrname = NULL; | 1437 | struct iscsi_param *intrname = NULL; |
1436 | struct iscsi_tiqn *tiqn; | 1438 | struct iscsi_tiqn *tiqn; |
1437 | struct iscsi_login_stats *ls; | 1439 | struct iscsi_login_stats *ls; |
1438 | 1440 | ||
1439 | tiqn = iscsit_snmp_get_tiqn(conn); | 1441 | tiqn = iscsit_snmp_get_tiqn(conn); |
1440 | if (!tiqn) | 1442 | if (!tiqn) |
1441 | return; | 1443 | return; |
1442 | 1444 | ||
1443 | ls = &tiqn->login_stats; | 1445 | ls = &tiqn->login_stats; |
1444 | 1446 | ||
1445 | spin_lock(&ls->lock); | 1447 | spin_lock(&ls->lock); |
1446 | if (!strcmp(conn->login_ip, ls->last_intr_fail_ip_addr) && | 1448 | if (!strcmp(conn->login_ip, ls->last_intr_fail_ip_addr) && |
1447 | ((get_jiffies_64() - ls->last_fail_time) < 10)) { | 1449 | ((get_jiffies_64() - ls->last_fail_time) < 10)) { |
1448 | /* We already have the failure info for this login */ | 1450 | /* We already have the failure info for this login */ |
1449 | spin_unlock(&ls->lock); | 1451 | spin_unlock(&ls->lock); |
1450 | return; | 1452 | return; |
1451 | } | 1453 | } |
1452 | 1454 | ||
1453 | if (status_class == ISCSI_STATUS_CLS_SUCCESS) | 1455 | if (status_class == ISCSI_STATUS_CLS_SUCCESS) |
1454 | ls->accepts++; | 1456 | ls->accepts++; |
1455 | else if (status_class == ISCSI_STATUS_CLS_REDIRECT) { | 1457 | else if (status_class == ISCSI_STATUS_CLS_REDIRECT) { |
1456 | ls->redirects++; | 1458 | ls->redirects++; |
1457 | ls->last_fail_type = ISCSI_LOGIN_FAIL_REDIRECT; | 1459 | ls->last_fail_type = ISCSI_LOGIN_FAIL_REDIRECT; |
1458 | } else if ((status_class == ISCSI_STATUS_CLS_INITIATOR_ERR) && | 1460 | } else if ((status_class == ISCSI_STATUS_CLS_INITIATOR_ERR) && |
1459 | (status_detail == ISCSI_LOGIN_STATUS_AUTH_FAILED)) { | 1461 | (status_detail == ISCSI_LOGIN_STATUS_AUTH_FAILED)) { |
1460 | ls->authenticate_fails++; | 1462 | ls->authenticate_fails++; |
1461 | ls->last_fail_type = ISCSI_LOGIN_FAIL_AUTHENTICATE; | 1463 | ls->last_fail_type = ISCSI_LOGIN_FAIL_AUTHENTICATE; |
1462 | } else if ((status_class == ISCSI_STATUS_CLS_INITIATOR_ERR) && | 1464 | } else if ((status_class == ISCSI_STATUS_CLS_INITIATOR_ERR) && |
1463 | (status_detail == ISCSI_LOGIN_STATUS_TGT_FORBIDDEN)) { | 1465 | (status_detail == ISCSI_LOGIN_STATUS_TGT_FORBIDDEN)) { |
1464 | ls->authorize_fails++; | 1466 | ls->authorize_fails++; |
1465 | ls->last_fail_type = ISCSI_LOGIN_FAIL_AUTHORIZE; | 1467 | ls->last_fail_type = ISCSI_LOGIN_FAIL_AUTHORIZE; |
1466 | } else if ((status_class == ISCSI_STATUS_CLS_INITIATOR_ERR) && | 1468 | } else if ((status_class == ISCSI_STATUS_CLS_INITIATOR_ERR) && |
1467 | (status_detail == ISCSI_LOGIN_STATUS_INIT_ERR)) { | 1469 | (status_detail == ISCSI_LOGIN_STATUS_INIT_ERR)) { |
1468 | ls->negotiate_fails++; | 1470 | ls->negotiate_fails++; |
1469 | ls->last_fail_type = ISCSI_LOGIN_FAIL_NEGOTIATE; | 1471 | ls->last_fail_type = ISCSI_LOGIN_FAIL_NEGOTIATE; |
1470 | } else { | 1472 | } else { |
1471 | ls->other_fails++; | 1473 | ls->other_fails++; |
1472 | ls->last_fail_type = ISCSI_LOGIN_FAIL_OTHER; | 1474 | ls->last_fail_type = ISCSI_LOGIN_FAIL_OTHER; |
1473 | } | 1475 | } |
1474 | 1476 | ||
1475 | /* Save initiator name, ip address and time, if it is a failed login */ | 1477 | /* Save initiator name, ip address and time, if it is a failed login */ |
1476 | if (status_class != ISCSI_STATUS_CLS_SUCCESS) { | 1478 | if (status_class != ISCSI_STATUS_CLS_SUCCESS) { |
1477 | if (conn->param_list) | 1479 | if (conn->param_list) |
1478 | intrname = iscsi_find_param_from_key(INITIATORNAME, | 1480 | intrname = iscsi_find_param_from_key(INITIATORNAME, |
1479 | conn->param_list); | 1481 | conn->param_list); |
1480 | strcpy(ls->last_intr_fail_name, | 1482 | strcpy(ls->last_intr_fail_name, |
1481 | (intrname ? intrname->value : "Unknown")); | 1483 | (intrname ? intrname->value : "Unknown")); |
1482 | 1484 | ||
1483 | ls->last_intr_fail_ip_family = conn->login_family; | 1485 | ls->last_intr_fail_ip_family = conn->login_family; |
1484 | 1486 | ||
1485 | snprintf(ls->last_intr_fail_ip_addr, IPV6_ADDRESS_SPACE, | 1487 | snprintf(ls->last_intr_fail_ip_addr, IPV6_ADDRESS_SPACE, |
1486 | "%s", conn->login_ip); | 1488 | "%s", conn->login_ip); |
1487 | ls->last_fail_time = get_jiffies_64(); | 1489 | ls->last_fail_time = get_jiffies_64(); |
1488 | } | 1490 | } |
1489 | 1491 | ||
1490 | spin_unlock(&ls->lock); | 1492 | spin_unlock(&ls->lock); |
1491 | } | 1493 | } |
1492 | 1494 | ||
1493 | struct iscsi_tiqn *iscsit_snmp_get_tiqn(struct iscsi_conn *conn) | 1495 | struct iscsi_tiqn *iscsit_snmp_get_tiqn(struct iscsi_conn *conn) |
1494 | { | 1496 | { |
1495 | struct iscsi_portal_group *tpg; | 1497 | struct iscsi_portal_group *tpg; |
1496 | 1498 | ||
1497 | if (!conn || !conn->sess) | 1499 | if (!conn || !conn->sess) |
1498 | return NULL; | 1500 | return NULL; |
1499 | 1501 | ||
1500 | tpg = conn->sess->tpg; | 1502 | tpg = conn->sess->tpg; |
1501 | if (!tpg) | 1503 | if (!tpg) |
1502 | return NULL; | 1504 | return NULL; |
1503 | 1505 | ||
1504 | if (!tpg->tpg_tiqn) | 1506 | if (!tpg->tpg_tiqn) |
1505 | return NULL; | 1507 | return NULL; |
1506 | 1508 | ||
1507 | return tpg->tpg_tiqn; | 1509 | return tpg->tpg_tiqn; |
1508 | } | 1510 | } |
1509 | 1511 |