iscsi_target_erl2.c 13 KB

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