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