1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /******************************************************************************* 3 * This file contains error recovery level two functions used by 4 * the iSCSI Target driver. 5 * 6 * (c) Copyright 2007-2013 Datera, Inc. 7 * 8 * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> 9 * 10 ******************************************************************************/ 11 12 #include <linux/slab.h> 13 #include <scsi/iscsi_proto.h> 14 #include <target/target_core_base.h> 15 #include <target/target_core_fabric.h> 16 17 #include <target/iscsi/iscsi_target_core.h> 18 #include "iscsi_target_datain_values.h" 19 #include "iscsi_target_util.h" 20 #include "iscsi_target_erl0.h" 21 #include "iscsi_target_erl1.h" 22 #include "iscsi_target_erl2.h" 23 #include "iscsi_target.h" 24 25 /* 26 * FIXME: Does RData SNACK apply here as well? 27 */ 28 static int iscsit_attach_active_connection_recovery_entry( 29 struct iscsit_session *sess, 30 struct iscsi_conn_recovery *cr) 31 { 32 spin_lock(&sess->cr_a_lock); 33 list_add_tail(&cr->cr_list, &sess->cr_active_list); 34 spin_unlock(&sess->cr_a_lock); 35 36 return 0; 37 } 38 39 static int iscsit_attach_inactive_connection_recovery_entry( 40 struct iscsit_session *sess, 41 struct iscsi_conn_recovery *cr) 42 { 43 spin_lock(&sess->cr_i_lock); 44 list_add_tail(&cr->cr_list, &sess->cr_inactive_list); 45 46 sess->conn_recovery_count++; 47 pr_debug("Incremented connection recovery count to %u for" 48 " SID: %u\n", sess->conn_recovery_count, sess->sid); 49 spin_unlock(&sess->cr_i_lock); 50 51 return 0; 52 } 53 54 struct iscsi_conn_recovery *iscsit_get_inactive_connection_recovery_entry( 55 struct iscsit_session *sess, 56 u16 cid) 57 { 58 struct iscsi_conn_recovery *cr; 59 60 spin_lock(&sess->cr_i_lock); 61 list_for_each_entry(cr, &sess->cr_inactive_list, cr_list) { 62 if (cr->cid == cid) { 63 spin_unlock(&sess->cr_i_lock); 64 return cr; 65 } 66 } 67 spin_unlock(&sess->cr_i_lock); 68 69 return NULL; 70 } 71 72 void iscsit_free_connection_recovery_entries(struct iscsit_session *sess) 73 { 74 struct iscsit_cmd *cmd, *cmd_tmp; 75 struct iscsi_conn_recovery *cr, *cr_tmp; 76 77 spin_lock(&sess->cr_a_lock); 78 list_for_each_entry_safe(cr, cr_tmp, &sess->cr_active_list, cr_list) { 79 list_del(&cr->cr_list); 80 spin_unlock(&sess->cr_a_lock); 81 82 spin_lock(&cr->conn_recovery_cmd_lock); 83 list_for_each_entry_safe(cmd, cmd_tmp, 84 &cr->conn_recovery_cmd_list, i_conn_node) { 85 86 list_del_init(&cmd->i_conn_node); 87 cmd->conn = NULL; 88 spin_unlock(&cr->conn_recovery_cmd_lock); 89 iscsit_free_cmd(cmd, true); 90 spin_lock(&cr->conn_recovery_cmd_lock); 91 } 92 spin_unlock(&cr->conn_recovery_cmd_lock); 93 spin_lock(&sess->cr_a_lock); 94 95 kfree(cr); 96 } 97 spin_unlock(&sess->cr_a_lock); 98 99 spin_lock(&sess->cr_i_lock); 100 list_for_each_entry_safe(cr, cr_tmp, &sess->cr_inactive_list, cr_list) { 101 list_del(&cr->cr_list); 102 spin_unlock(&sess->cr_i_lock); 103 104 spin_lock(&cr->conn_recovery_cmd_lock); 105 list_for_each_entry_safe(cmd, cmd_tmp, 106 &cr->conn_recovery_cmd_list, i_conn_node) { 107 108 list_del_init(&cmd->i_conn_node); 109 cmd->conn = NULL; 110 spin_unlock(&cr->conn_recovery_cmd_lock); 111 iscsit_free_cmd(cmd, true); 112 spin_lock(&cr->conn_recovery_cmd_lock); 113 } 114 spin_unlock(&cr->conn_recovery_cmd_lock); 115 spin_lock(&sess->cr_i_lock); 116 117 kfree(cr); 118 } 119 spin_unlock(&sess->cr_i_lock); 120 } 121 122 int iscsit_remove_active_connection_recovery_entry( 123 struct iscsi_conn_recovery *cr, 124 struct iscsit_session *sess) 125 { 126 spin_lock(&sess->cr_a_lock); 127 list_del(&cr->cr_list); 128 129 sess->conn_recovery_count--; 130 pr_debug("Decremented connection recovery count to %u for" 131 " SID: %u\n", sess->conn_recovery_count, sess->sid); 132 spin_unlock(&sess->cr_a_lock); 133 134 kfree(cr); 135 136 return 0; 137 } 138 139 static void iscsit_remove_inactive_connection_recovery_entry( 140 struct iscsi_conn_recovery *cr, 141 struct iscsit_session *sess) 142 { 143 spin_lock(&sess->cr_i_lock); 144 list_del(&cr->cr_list); 145 spin_unlock(&sess->cr_i_lock); 146 } 147 148 /* 149 * Called with cr->conn_recovery_cmd_lock help. 150 */ 151 int iscsit_remove_cmd_from_connection_recovery( 152 struct iscsit_cmd *cmd, 153 struct iscsit_session *sess) 154 { 155 struct iscsi_conn_recovery *cr; 156 157 if (!cmd->cr) { 158 pr_err("struct iscsi_conn_recovery pointer for ITT: 0x%08x" 159 " is NULL!\n", cmd->init_task_tag); 160 BUG(); 161 } 162 cr = cmd->cr; 163 164 list_del_init(&cmd->i_conn_node); 165 return --cr->cmd_count; 166 } 167 168 void iscsit_discard_cr_cmds_by_expstatsn( 169 struct iscsi_conn_recovery *cr, 170 u32 exp_statsn) 171 { 172 u32 dropped_count = 0; 173 struct iscsit_cmd *cmd, *cmd_tmp; 174 struct iscsit_session *sess = cr->sess; 175 176 spin_lock(&cr->conn_recovery_cmd_lock); 177 list_for_each_entry_safe(cmd, cmd_tmp, 178 &cr->conn_recovery_cmd_list, i_conn_node) { 179 180 if (((cmd->deferred_i_state != ISTATE_SENT_STATUS) && 181 (cmd->deferred_i_state != ISTATE_REMOVE)) || 182 (cmd->stat_sn >= exp_statsn)) { 183 continue; 184 } 185 186 dropped_count++; 187 pr_debug("Dropping Acknowledged ITT: 0x%08x, StatSN:" 188 " 0x%08x, CID: %hu.\n", cmd->init_task_tag, 189 cmd->stat_sn, cr->cid); 190 191 iscsit_remove_cmd_from_connection_recovery(cmd, sess); 192 193 spin_unlock(&cr->conn_recovery_cmd_lock); 194 iscsit_free_cmd(cmd, true); 195 spin_lock(&cr->conn_recovery_cmd_lock); 196 } 197 spin_unlock(&cr->conn_recovery_cmd_lock); 198 199 pr_debug("Dropped %u total acknowledged commands on" 200 " CID: %hu less than old ExpStatSN: 0x%08x\n", 201 dropped_count, cr->cid, exp_statsn); 202 203 if (!cr->cmd_count) { 204 pr_debug("No commands to be reassigned for failed" 205 " connection CID: %hu on SID: %u\n", 206 cr->cid, sess->sid); 207 iscsit_remove_inactive_connection_recovery_entry(cr, sess); 208 iscsit_attach_active_connection_recovery_entry(sess, cr); 209 pr_debug("iSCSI connection recovery successful for CID:" 210 " %hu on SID: %u\n", cr->cid, sess->sid); 211 iscsit_remove_active_connection_recovery_entry(cr, sess); 212 } else { 213 iscsit_remove_inactive_connection_recovery_entry(cr, sess); 214 iscsit_attach_active_connection_recovery_entry(sess, cr); 215 } 216 } 217 218 int iscsit_discard_unacknowledged_ooo_cmdsns_for_conn(struct iscsit_conn *conn) 219 { 220 u32 dropped_count = 0; 221 struct iscsit_cmd *cmd, *cmd_tmp; 222 struct iscsi_ooo_cmdsn *ooo_cmdsn, *ooo_cmdsn_tmp; 223 struct iscsit_session *sess = conn->sess; 224 225 mutex_lock(&sess->cmdsn_mutex); 226 list_for_each_entry_safe(ooo_cmdsn, ooo_cmdsn_tmp, 227 &sess->sess_ooo_cmdsn_list, ooo_list) { 228 229 if (ooo_cmdsn->cid != conn->cid) 230 continue; 231 232 dropped_count++; 233 pr_debug("Dropping unacknowledged CmdSN:" 234 " 0x%08x during connection recovery on CID: %hu\n", 235 ooo_cmdsn->cmdsn, conn->cid); 236 iscsit_remove_ooo_cmdsn(sess, ooo_cmdsn); 237 } 238 mutex_unlock(&sess->cmdsn_mutex); 239 240 spin_lock_bh(&conn->cmd_lock); 241 list_for_each_entry_safe(cmd, cmd_tmp, &conn->conn_cmd_list, i_conn_node) { 242 if (!(cmd->cmd_flags & ICF_OOO_CMDSN)) 243 continue; 244 245 list_del_init(&cmd->i_conn_node); 246 247 spin_unlock_bh(&conn->cmd_lock); 248 iscsit_free_cmd(cmd, true); 249 spin_lock_bh(&conn->cmd_lock); 250 } 251 spin_unlock_bh(&conn->cmd_lock); 252 253 pr_debug("Dropped %u total unacknowledged commands on CID:" 254 " %hu for ExpCmdSN: 0x%08x.\n", dropped_count, conn->cid, 255 sess->exp_cmd_sn); 256 return 0; 257 } 258 259 int iscsit_prepare_cmds_for_reallegiance(struct iscsit_conn *conn) 260 { 261 u32 cmd_count = 0; 262 struct iscsit_cmd *cmd, *cmd_tmp; 263 struct iscsi_conn_recovery *cr; 264 265 /* 266 * Allocate an struct iscsi_conn_recovery for this connection. 267 * Each struct iscsit_cmd contains an struct iscsi_conn_recovery pointer 268 * (struct iscsit_cmd->cr) so we need to allocate this before preparing the 269 * connection's command list for connection recovery. 270 */ 271 cr = kzalloc(sizeof(struct iscsi_conn_recovery), GFP_KERNEL); 272 if (!cr) { 273 pr_err("Unable to allocate memory for" 274 " struct iscsi_conn_recovery.\n"); 275 return -1; 276 } 277 INIT_LIST_HEAD(&cr->cr_list); 278 INIT_LIST_HEAD(&cr->conn_recovery_cmd_list); 279 spin_lock_init(&cr->conn_recovery_cmd_lock); 280 /* 281 * Only perform connection recovery on ISCSI_OP_SCSI_CMD or 282 * ISCSI_OP_NOOP_OUT opcodes. For all other opcodes call 283 * list_del_init(&cmd->i_conn_node); to release the command to the 284 * session pool and remove it from the connection's list. 285 * 286 * Also stop the DataOUT timer, which will be restarted after 287 * sending the TMR response. 288 */ 289 spin_lock_bh(&conn->cmd_lock); 290 list_for_each_entry_safe(cmd, cmd_tmp, &conn->conn_cmd_list, i_conn_node) { 291 292 if ((cmd->iscsi_opcode != ISCSI_OP_SCSI_CMD) && 293 (cmd->iscsi_opcode != ISCSI_OP_NOOP_OUT)) { 294 pr_debug("Not performing reallegiance on" 295 " Opcode: 0x%02x, ITT: 0x%08x, CmdSN: 0x%08x," 296 " CID: %hu\n", cmd->iscsi_opcode, 297 cmd->init_task_tag, cmd->cmd_sn, conn->cid); 298 299 list_del_init(&cmd->i_conn_node); 300 spin_unlock_bh(&conn->cmd_lock); 301 iscsit_free_cmd(cmd, true); 302 spin_lock_bh(&conn->cmd_lock); 303 continue; 304 } 305 306 /* 307 * Special case where commands greater than or equal to 308 * the session's ExpCmdSN are attached to the connection 309 * list but not to the out of order CmdSN list. The one 310 * obvious case is when a command with immediate data 311 * attached must only check the CmdSN against ExpCmdSN 312 * after the data is received. The special case below 313 * is when the connection fails before data is received, 314 * but also may apply to other PDUs, so it has been 315 * made generic here. 316 */ 317 if (!(cmd->cmd_flags & ICF_OOO_CMDSN) && !cmd->immediate_cmd && 318 iscsi_sna_gte(cmd->cmd_sn, conn->sess->exp_cmd_sn)) { 319 list_del_init(&cmd->i_conn_node); 320 spin_unlock_bh(&conn->cmd_lock); 321 iscsit_free_cmd(cmd, true); 322 spin_lock_bh(&conn->cmd_lock); 323 continue; 324 } 325 326 cmd_count++; 327 pr_debug("Preparing Opcode: 0x%02x, ITT: 0x%08x," 328 " CmdSN: 0x%08x, StatSN: 0x%08x, CID: %hu for" 329 " reallegiance.\n", cmd->iscsi_opcode, 330 cmd->init_task_tag, cmd->cmd_sn, cmd->stat_sn, 331 conn->cid); 332 333 cmd->deferred_i_state = cmd->i_state; 334 cmd->i_state = ISTATE_IN_CONNECTION_RECOVERY; 335 336 if (cmd->data_direction == DMA_TO_DEVICE) 337 iscsit_stop_dataout_timer(cmd); 338 339 cmd->sess = conn->sess; 340 341 list_del_init(&cmd->i_conn_node); 342 spin_unlock_bh(&conn->cmd_lock); 343 344 iscsit_free_all_datain_reqs(cmd); 345 346 transport_wait_for_tasks(&cmd->se_cmd); 347 /* 348 * Add the struct iscsit_cmd to the connection recovery cmd list 349 */ 350 spin_lock(&cr->conn_recovery_cmd_lock); 351 list_add_tail(&cmd->i_conn_node, &cr->conn_recovery_cmd_list); 352 spin_unlock(&cr->conn_recovery_cmd_lock); 353 354 spin_lock_bh(&conn->cmd_lock); 355 cmd->cr = cr; 356 cmd->conn = NULL; 357 } 358 spin_unlock_bh(&conn->cmd_lock); 359 /* 360 * Fill in the various values in the preallocated struct iscsi_conn_recovery. 361 */ 362 cr->cid = conn->cid; 363 cr->cmd_count = cmd_count; 364 cr->maxrecvdatasegmentlength = conn->conn_ops->MaxRecvDataSegmentLength; 365 cr->maxxmitdatasegmentlength = conn->conn_ops->MaxXmitDataSegmentLength; 366 cr->sess = conn->sess; 367 368 iscsit_attach_inactive_connection_recovery_entry(conn->sess, cr); 369 370 return 0; 371 } 372 373 int iscsit_connection_recovery_transport_reset(struct iscsit_conn *conn) 374 { 375 atomic_set(&conn->connection_recovery, 1); 376 377 if (iscsit_close_connection(conn) < 0) 378 return -1; 379 380 return 0; 381 } 382