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