| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * iSCSI lib functions |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 6 | 7 | * Copyright (C) 2004 - 2005 Dmitry Yusupov |
|---|
| 7 | 8 | * Copyright (C) 2004 - 2005 Alex Aizman |
|---|
| 8 | 9 | * maintained by open-iscsi@googlegroups.com |
|---|
| 9 | | - * |
|---|
| 10 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 11 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 12 | | - * the Free Software Foundation; either version 2 of the License, or |
|---|
| 13 | | - * (at your option) any later version. |
|---|
| 14 | | - * |
|---|
| 15 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 16 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 17 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 18 | | - * GNU General Public License for more details. |
|---|
| 19 | | - * |
|---|
| 20 | | - * You should have received a copy of the GNU General Public License |
|---|
| 21 | | - * along with this program; if not, write to the Free Software |
|---|
| 22 | | - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
|---|
| 23 | 10 | */ |
|---|
| 24 | 11 | #include <linux/types.h> |
|---|
| 25 | 12 | #include <linux/kfifo.h> |
|---|
| .. | .. |
|---|
| 40 | 27 | #include <scsi/scsi_transport.h> |
|---|
| 41 | 28 | #include <scsi/scsi_transport_iscsi.h> |
|---|
| 42 | 29 | #include <scsi/libiscsi.h> |
|---|
| 30 | +#include <trace/events/iscsi.h> |
|---|
| 43 | 31 | |
|---|
| 44 | 32 | static int iscsi_dbg_lib_conn; |
|---|
| 45 | 33 | module_param_named(debug_libiscsi_conn, iscsi_dbg_lib_conn, int, |
|---|
| .. | .. |
|---|
| 68 | 56 | iscsi_conn_printk(KERN_INFO, _conn, \ |
|---|
| 69 | 57 | "%s " dbg_fmt, \ |
|---|
| 70 | 58 | __func__, ##arg); \ |
|---|
| 59 | + iscsi_dbg_trace(trace_iscsi_dbg_conn, \ |
|---|
| 60 | + &(_conn)->cls_conn->dev, \ |
|---|
| 61 | + "%s " dbg_fmt, __func__, ##arg);\ |
|---|
| 71 | 62 | } while (0); |
|---|
| 72 | 63 | |
|---|
| 73 | 64 | #define ISCSI_DBG_SESSION(_session, dbg_fmt, arg...) \ |
|---|
| .. | .. |
|---|
| 76 | 67 | iscsi_session_printk(KERN_INFO, _session, \ |
|---|
| 77 | 68 | "%s " dbg_fmt, \ |
|---|
| 78 | 69 | __func__, ##arg); \ |
|---|
| 70 | + iscsi_dbg_trace(trace_iscsi_dbg_session, \ |
|---|
| 71 | + &(_session)->cls_session->dev, \ |
|---|
| 72 | + "%s " dbg_fmt, __func__, ##arg); \ |
|---|
| 79 | 73 | } while (0); |
|---|
| 80 | 74 | |
|---|
| 81 | 75 | #define ISCSI_DBG_EH(_session, dbg_fmt, arg...) \ |
|---|
| .. | .. |
|---|
| 84 | 78 | iscsi_session_printk(KERN_INFO, _session, \ |
|---|
| 85 | 79 | "%s " dbg_fmt, \ |
|---|
| 86 | 80 | __func__, ##arg); \ |
|---|
| 81 | + iscsi_dbg_trace(trace_iscsi_dbg_eh, \ |
|---|
| 82 | + &(_session)->cls_session->dev, \ |
|---|
| 83 | + "%s " dbg_fmt, __func__, ##arg); \ |
|---|
| 87 | 84 | } while (0); |
|---|
| 88 | 85 | |
|---|
| 89 | 86 | inline void iscsi_conn_queue_work(struct iscsi_conn *conn) |
|---|
| .. | .. |
|---|
| 218 | 215 | return 0; |
|---|
| 219 | 216 | } |
|---|
| 220 | 217 | |
|---|
| 221 | | -static int iscsi_prep_bidi_ahs(struct iscsi_task *task) |
|---|
| 222 | | -{ |
|---|
| 223 | | - struct scsi_cmnd *sc = task->sc; |
|---|
| 224 | | - struct iscsi_rlength_ahdr *rlen_ahdr; |
|---|
| 225 | | - int rc; |
|---|
| 226 | | - |
|---|
| 227 | | - rlen_ahdr = iscsi_next_hdr(task); |
|---|
| 228 | | - rc = iscsi_add_hdr(task, sizeof(*rlen_ahdr)); |
|---|
| 229 | | - if (rc) |
|---|
| 230 | | - return rc; |
|---|
| 231 | | - |
|---|
| 232 | | - rlen_ahdr->ahslength = |
|---|
| 233 | | - cpu_to_be16(sizeof(rlen_ahdr->read_length) + |
|---|
| 234 | | - sizeof(rlen_ahdr->reserved)); |
|---|
| 235 | | - rlen_ahdr->ahstype = ISCSI_AHSTYPE_RLENGTH; |
|---|
| 236 | | - rlen_ahdr->reserved = 0; |
|---|
| 237 | | - rlen_ahdr->read_length = cpu_to_be32(scsi_in(sc)->length); |
|---|
| 238 | | - |
|---|
| 239 | | - ISCSI_DBG_SESSION(task->conn->session, |
|---|
| 240 | | - "bidi-in rlen_ahdr->read_length(%d) " |
|---|
| 241 | | - "rlen_ahdr->ahslength(%d)\n", |
|---|
| 242 | | - be32_to_cpu(rlen_ahdr->read_length), |
|---|
| 243 | | - be16_to_cpu(rlen_ahdr->ahslength)); |
|---|
| 244 | | - return 0; |
|---|
| 245 | | -} |
|---|
| 246 | | - |
|---|
| 247 | 218 | /** |
|---|
| 248 | 219 | * iscsi_check_tmf_restrictions - check if a task is affected by TMF |
|---|
| 249 | 220 | * @task: iscsi task |
|---|
| .. | .. |
|---|
| 277 | 248 | hdr_lun = scsilun_to_int(&tmf->lun); |
|---|
| 278 | 249 | if (hdr_lun != task->sc->device->lun) |
|---|
| 279 | 250 | return 0; |
|---|
| 280 | | - /* fall through */ |
|---|
| 251 | + fallthrough; |
|---|
| 281 | 252 | case ISCSI_TM_FUNC_TARGET_WARM_RESET: |
|---|
| 282 | 253 | /* |
|---|
| 283 | 254 | * Fail all SCSI cmd PDUs |
|---|
| .. | .. |
|---|
| 377 | 348 | memcpy(hdr->cdb, sc->cmnd, cmd_len); |
|---|
| 378 | 349 | |
|---|
| 379 | 350 | task->imm_count = 0; |
|---|
| 380 | | - if (scsi_bidi_cmnd(sc)) { |
|---|
| 381 | | - hdr->flags |= ISCSI_FLAG_CMD_READ; |
|---|
| 382 | | - rc = iscsi_prep_bidi_ahs(task); |
|---|
| 383 | | - if (rc) |
|---|
| 384 | | - return rc; |
|---|
| 385 | | - } |
|---|
| 386 | | - |
|---|
| 387 | 351 | if (scsi_get_prot_op(sc) != SCSI_PROT_NORMAL) |
|---|
| 388 | 352 | task->protected = true; |
|---|
| 389 | 353 | |
|---|
| .. | .. |
|---|
| 458 | 422 | |
|---|
| 459 | 423 | conn->scsicmd_pdus_cnt++; |
|---|
| 460 | 424 | ISCSI_DBG_SESSION(session, "iscsi prep [%s cid %d sc %p cdb 0x%x " |
|---|
| 461 | | - "itt 0x%x len %d bidi_len %d cmdsn %d win %d]\n", |
|---|
| 462 | | - scsi_bidi_cmnd(sc) ? "bidirectional" : |
|---|
| 425 | + "itt 0x%x len %d cmdsn %d win %d]\n", |
|---|
| 463 | 426 | sc->sc_data_direction == DMA_TO_DEVICE ? |
|---|
| 464 | 427 | "write" : "read", conn->id, sc, sc->cmnd[0], |
|---|
| 465 | 428 | task->itt, transfer_length, |
|---|
| 466 | | - scsi_bidi_cmnd(sc) ? scsi_in(sc)->length : 0, |
|---|
| 467 | 429 | session->cmdsn, |
|---|
| 468 | 430 | session->max_cmdsn - session->exp_cmdsn + 1); |
|---|
| 469 | 431 | return 0; |
|---|
| .. | .. |
|---|
| 632 | 594 | state = ISCSI_TASK_ABRT_TMF; |
|---|
| 633 | 595 | |
|---|
| 634 | 596 | sc->result = err << 16; |
|---|
| 635 | | - if (!scsi_bidi_cmnd(sc)) |
|---|
| 636 | | - scsi_set_resid(sc, scsi_bufflen(sc)); |
|---|
| 637 | | - else { |
|---|
| 638 | | - scsi_out(sc)->resid = scsi_out(sc)->length; |
|---|
| 639 | | - scsi_in(sc)->resid = scsi_in(sc)->length; |
|---|
| 640 | | - } |
|---|
| 597 | + scsi_set_resid(sc, scsi_bufflen(sc)); |
|---|
| 641 | 598 | |
|---|
| 642 | 599 | /* regular RX path uses back_lock */ |
|---|
| 643 | 600 | spin_lock_bh(&conn->session->back_lock); |
|---|
| .. | .. |
|---|
| 826 | 783 | * @datalen: len of buffer |
|---|
| 827 | 784 | * |
|---|
| 828 | 785 | * iscsi_cmd_rsp sets up the scsi_cmnd fields based on the PDU and |
|---|
| 829 | | - * then completes the command and task. |
|---|
| 786 | + * then completes the command and task. called under back_lock |
|---|
| 830 | 787 | **/ |
|---|
| 831 | 788 | static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr, |
|---|
| 832 | 789 | struct iscsi_task *task, char *data, |
|---|
| .. | .. |
|---|
| 895 | 852 | |
|---|
| 896 | 853 | if (rhdr->flags & (ISCSI_FLAG_CMD_BIDI_UNDERFLOW | |
|---|
| 897 | 854 | ISCSI_FLAG_CMD_BIDI_OVERFLOW)) { |
|---|
| 898 | | - int res_count = be32_to_cpu(rhdr->bi_residual_count); |
|---|
| 899 | | - |
|---|
| 900 | | - if (scsi_bidi_cmnd(sc) && res_count > 0 && |
|---|
| 901 | | - (rhdr->flags & ISCSI_FLAG_CMD_BIDI_OVERFLOW || |
|---|
| 902 | | - res_count <= scsi_in(sc)->length)) |
|---|
| 903 | | - scsi_in(sc)->resid = res_count; |
|---|
| 904 | | - else |
|---|
| 905 | | - sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; |
|---|
| 855 | + sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; |
|---|
| 906 | 856 | } |
|---|
| 907 | 857 | |
|---|
| 908 | 858 | if (rhdr->flags & (ISCSI_FLAG_CMD_UNDERFLOW | |
|---|
| .. | .. |
|---|
| 929 | 879 | * @conn: iscsi connection |
|---|
| 930 | 880 | * @hdr: iscsi pdu |
|---|
| 931 | 881 | * @task: scsi command task |
|---|
| 882 | + * |
|---|
| 883 | + * iscsi_data_in_rsp sets up the scsi_cmnd fields based on the data received |
|---|
| 884 | + * then completes the command and task. called under back_lock |
|---|
| 932 | 885 | **/ |
|---|
| 933 | 886 | static void |
|---|
| 934 | 887 | iscsi_data_in_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr, |
|---|
| .. | .. |
|---|
| 949 | 902 | |
|---|
| 950 | 903 | if (res_count > 0 && |
|---|
| 951 | 904 | (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW || |
|---|
| 952 | | - res_count <= scsi_in(sc)->length)) |
|---|
| 953 | | - scsi_in(sc)->resid = res_count; |
|---|
| 905 | + res_count <= sc->sdb.length)) |
|---|
| 906 | + scsi_set_resid(sc, res_count); |
|---|
| 954 | 907 | else |
|---|
| 955 | 908 | sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; |
|---|
| 956 | 909 | } |
|---|
| .. | .. |
|---|
| 1018 | 971 | return 0; |
|---|
| 1019 | 972 | } |
|---|
| 1020 | 973 | |
|---|
| 974 | +/** |
|---|
| 975 | + * iscsi_nop_out_rsp - SCSI NOP Response processing |
|---|
| 976 | + * @task: scsi command task |
|---|
| 977 | + * @nop: the nop structure |
|---|
| 978 | + * @data: where to put the data |
|---|
| 979 | + * @datalen: length of data |
|---|
| 980 | + * |
|---|
| 981 | + * iscsi_nop_out_rsp handles nop response from use or |
|---|
| 982 | + * from user space. called under back_lock |
|---|
| 983 | + **/ |
|---|
| 1021 | 984 | static int iscsi_nop_out_rsp(struct iscsi_task *task, |
|---|
| 1022 | 985 | struct iscsi_nopin *nop, char *data, int datalen) |
|---|
| 1023 | 986 | { |
|---|
| .. | .. |
|---|
| 1404 | 1367 | } |
|---|
| 1405 | 1368 | EXPORT_SYMBOL_GPL(iscsi_session_failure); |
|---|
| 1406 | 1369 | |
|---|
| 1407 | | -void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err) |
|---|
| 1370 | +static bool iscsi_set_conn_failed(struct iscsi_conn *conn) |
|---|
| 1408 | 1371 | { |
|---|
| 1409 | 1372 | struct iscsi_session *session = conn->session; |
|---|
| 1410 | 1373 | |
|---|
| 1411 | | - spin_lock_bh(&session->frwd_lock); |
|---|
| 1412 | | - if (session->state == ISCSI_STATE_FAILED) { |
|---|
| 1413 | | - spin_unlock_bh(&session->frwd_lock); |
|---|
| 1414 | | - return; |
|---|
| 1415 | | - } |
|---|
| 1374 | + if (session->state == ISCSI_STATE_FAILED) |
|---|
| 1375 | + return false; |
|---|
| 1416 | 1376 | |
|---|
| 1417 | 1377 | if (conn->stop_stage == 0) |
|---|
| 1418 | 1378 | session->state = ISCSI_STATE_FAILED; |
|---|
| 1419 | | - spin_unlock_bh(&session->frwd_lock); |
|---|
| 1420 | 1379 | |
|---|
| 1421 | 1380 | set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); |
|---|
| 1422 | 1381 | set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx); |
|---|
| 1423 | | - iscsi_conn_error_event(conn->cls_conn, err); |
|---|
| 1382 | + return true; |
|---|
| 1383 | +} |
|---|
| 1384 | + |
|---|
| 1385 | +void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err) |
|---|
| 1386 | +{ |
|---|
| 1387 | + struct iscsi_session *session = conn->session; |
|---|
| 1388 | + bool needs_evt; |
|---|
| 1389 | + |
|---|
| 1390 | + spin_lock_bh(&session->frwd_lock); |
|---|
| 1391 | + needs_evt = iscsi_set_conn_failed(conn); |
|---|
| 1392 | + spin_unlock_bh(&session->frwd_lock); |
|---|
| 1393 | + |
|---|
| 1394 | + if (needs_evt) |
|---|
| 1395 | + iscsi_conn_error_event(conn->cls_conn, err); |
|---|
| 1424 | 1396 | } |
|---|
| 1425 | 1397 | EXPORT_SYMBOL_GPL(iscsi_conn_failure); |
|---|
| 1426 | 1398 | |
|---|
| .. | .. |
|---|
| 1706 | 1678 | sc->result = DID_NO_CONNECT << 16; |
|---|
| 1707 | 1679 | break; |
|---|
| 1708 | 1680 | } |
|---|
| 1709 | | - /* fall through */ |
|---|
| 1681 | + fallthrough; |
|---|
| 1710 | 1682 | case ISCSI_STATE_IN_RECOVERY: |
|---|
| 1711 | 1683 | reason = FAILURE_SESSION_IN_RECOVERY; |
|---|
| 1712 | 1684 | sc->result = DID_IMM_RETRY << 16; |
|---|
| .. | .. |
|---|
| 1782 | 1754 | return 0; |
|---|
| 1783 | 1755 | |
|---|
| 1784 | 1756 | prepd_reject: |
|---|
| 1757 | + spin_lock_bh(&session->back_lock); |
|---|
| 1785 | 1758 | iscsi_complete_task(task, ISCSI_TASK_REQUEUE_SCSIQ); |
|---|
| 1759 | + spin_unlock_bh(&session->back_lock); |
|---|
| 1786 | 1760 | reject: |
|---|
| 1787 | 1761 | spin_unlock_bh(&session->frwd_lock); |
|---|
| 1788 | 1762 | ISCSI_DBG_SESSION(session, "cmd 0x%x rejected (%d)\n", |
|---|
| .. | .. |
|---|
| 1790 | 1764 | return SCSI_MLQUEUE_TARGET_BUSY; |
|---|
| 1791 | 1765 | |
|---|
| 1792 | 1766 | prepd_fault: |
|---|
| 1767 | + spin_lock_bh(&session->back_lock); |
|---|
| 1793 | 1768 | iscsi_complete_task(task, ISCSI_TASK_REQUEUE_SCSIQ); |
|---|
| 1769 | + spin_unlock_bh(&session->back_lock); |
|---|
| 1794 | 1770 | fault: |
|---|
| 1795 | 1771 | spin_unlock_bh(&session->frwd_lock); |
|---|
| 1796 | 1772 | ISCSI_DBG_SESSION(session, "iscsi: cmd 0x%x is not queued (%d)\n", |
|---|
| 1797 | 1773 | sc->cmnd[0], reason); |
|---|
| 1798 | | - if (!scsi_bidi_cmnd(sc)) |
|---|
| 1799 | | - scsi_set_resid(sc, scsi_bufflen(sc)); |
|---|
| 1800 | | - else { |
|---|
| 1801 | | - scsi_out(sc)->resid = scsi_out(sc)->length; |
|---|
| 1802 | | - scsi_in(sc)->resid = scsi_in(sc)->length; |
|---|
| 1803 | | - } |
|---|
| 1774 | + scsi_set_resid(sc, scsi_bufflen(sc)); |
|---|
| 1804 | 1775 | sc->scsi_done(sc); |
|---|
| 1805 | 1776 | return 0; |
|---|
| 1806 | 1777 | } |
|---|
| .. | .. |
|---|
| 2155 | 2126 | spin_unlock(&session->frwd_lock); |
|---|
| 2156 | 2127 | } |
|---|
| 2157 | 2128 | |
|---|
| 2129 | +/** |
|---|
| 2130 | + * iscsi_conn_unbind - prevent queueing to conn. |
|---|
| 2131 | + * @cls_conn: iscsi conn ep is bound to. |
|---|
| 2132 | + * @is_active: is the conn in use for boot or is this for EH/termination |
|---|
| 2133 | + * |
|---|
| 2134 | + * This must be called by drivers implementing the ep_disconnect callout. |
|---|
| 2135 | + * It disables queueing to the connection from libiscsi in preparation for |
|---|
| 2136 | + * an ep_disconnect call. |
|---|
| 2137 | + */ |
|---|
| 2138 | +void iscsi_conn_unbind(struct iscsi_cls_conn *cls_conn, bool is_active) |
|---|
| 2139 | +{ |
|---|
| 2140 | + struct iscsi_session *session; |
|---|
| 2141 | + struct iscsi_conn *conn; |
|---|
| 2142 | + |
|---|
| 2143 | + if (!cls_conn) |
|---|
| 2144 | + return; |
|---|
| 2145 | + |
|---|
| 2146 | + conn = cls_conn->dd_data; |
|---|
| 2147 | + session = conn->session; |
|---|
| 2148 | + /* |
|---|
| 2149 | + * Wait for iscsi_eh calls to exit. We don't wait for the tmf to |
|---|
| 2150 | + * complete or timeout. The caller just wants to know what's running |
|---|
| 2151 | + * is everything that needs to be cleaned up, and no cmds will be |
|---|
| 2152 | + * queued. |
|---|
| 2153 | + */ |
|---|
| 2154 | + mutex_lock(&session->eh_mutex); |
|---|
| 2155 | + |
|---|
| 2156 | + iscsi_suspend_queue(conn); |
|---|
| 2157 | + iscsi_suspend_tx(conn); |
|---|
| 2158 | + |
|---|
| 2159 | + spin_lock_bh(&session->frwd_lock); |
|---|
| 2160 | + if (!is_active) { |
|---|
| 2161 | + /* |
|---|
| 2162 | + * if logout timed out before userspace could even send a PDU |
|---|
| 2163 | + * the state might still be in ISCSI_STATE_LOGGED_IN and |
|---|
| 2164 | + * allowing new cmds and TMFs. |
|---|
| 2165 | + */ |
|---|
| 2166 | + if (session->state == ISCSI_STATE_LOGGED_IN) |
|---|
| 2167 | + iscsi_set_conn_failed(conn); |
|---|
| 2168 | + } |
|---|
| 2169 | + spin_unlock_bh(&session->frwd_lock); |
|---|
| 2170 | + mutex_unlock(&session->eh_mutex); |
|---|
| 2171 | +} |
|---|
| 2172 | +EXPORT_SYMBOL_GPL(iscsi_conn_unbind); |
|---|
| 2173 | + |
|---|
| 2158 | 2174 | static void iscsi_prep_abort_task_pdu(struct iscsi_task *task, |
|---|
| 2159 | 2175 | struct iscsi_tm *hdr) |
|---|
| 2160 | 2176 | { |
|---|
| .. | .. |
|---|
| 2271 | 2287 | "progress\n"); |
|---|
| 2272 | 2288 | goto success; |
|---|
| 2273 | 2289 | } |
|---|
| 2274 | | - /* fall through */ |
|---|
| 2290 | + fallthrough; |
|---|
| 2275 | 2291 | default: |
|---|
| 2276 | 2292 | session->tmf_state = TMF_INITIAL; |
|---|
| 2277 | 2293 | goto failed; |
|---|
| .. | .. |
|---|
| 2658 | 2674 | if (xmit_can_sleep) { |
|---|
| 2659 | 2675 | snprintf(ihost->workq_name, sizeof(ihost->workq_name), |
|---|
| 2660 | 2676 | "iscsi_q_%d", shost->host_no); |
|---|
| 2661 | | - ihost->workq = create_singlethread_workqueue(ihost->workq_name); |
|---|
| 2677 | + ihost->workq = alloc_workqueue("%s", |
|---|
| 2678 | + WQ_SYSFS | __WQ_LEGACY | WQ_MEM_RECLAIM | WQ_UNBOUND, |
|---|
| 2679 | + 1, ihost->workq_name); |
|---|
| 2662 | 2680 | if (!ihost->workq) |
|---|
| 2663 | 2681 | goto free_host; |
|---|
| 2664 | 2682 | } |
|---|
| .. | .. |
|---|
| 2802 | 2820 | "must be a power of 2.\n", total_cmds); |
|---|
| 2803 | 2821 | total_cmds = rounddown_pow_of_two(total_cmds); |
|---|
| 2804 | 2822 | if (total_cmds < ISCSI_TOTAL_CMDS_MIN) |
|---|
| 2805 | | - return NULL; |
|---|
| 2823 | + goto dec_session_count; |
|---|
| 2806 | 2824 | printk(KERN_INFO "iscsi: Rounding can_queue to %d.\n", |
|---|
| 2807 | 2825 | total_cmds); |
|---|
| 2808 | 2826 | } |
|---|
| .. | .. |
|---|
| 3113 | 3131 | state = ISCSI_TASK_ABRT_SESS_RECOV; |
|---|
| 3114 | 3132 | if (task->state == ISCSI_TASK_PENDING) |
|---|
| 3115 | 3133 | state = ISCSI_TASK_COMPLETED; |
|---|
| 3134 | + spin_lock_bh(&session->back_lock); |
|---|
| 3116 | 3135 | iscsi_complete_task(task, state); |
|---|
| 3117 | | - |
|---|
| 3136 | + spin_unlock_bh(&session->back_lock); |
|---|
| 3118 | 3137 | } |
|---|
| 3119 | 3138 | } |
|---|
| 3120 | 3139 | |
|---|
| 3121 | | -static void iscsi_start_session_recovery(struct iscsi_session *session, |
|---|
| 3122 | | - struct iscsi_conn *conn, int flag) |
|---|
| 3140 | +void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) |
|---|
| 3123 | 3141 | { |
|---|
| 3142 | + struct iscsi_conn *conn = cls_conn->dd_data; |
|---|
| 3143 | + struct iscsi_session *session = conn->session; |
|---|
| 3124 | 3144 | int old_stop_stage; |
|---|
| 3125 | 3145 | |
|---|
| 3126 | 3146 | mutex_lock(&session->eh_mutex); |
|---|
| .. | .. |
|---|
| 3177 | 3197 | memset(&session->tmhdr, 0, sizeof(session->tmhdr)); |
|---|
| 3178 | 3198 | spin_unlock_bh(&session->frwd_lock); |
|---|
| 3179 | 3199 | mutex_unlock(&session->eh_mutex); |
|---|
| 3180 | | -} |
|---|
| 3181 | | - |
|---|
| 3182 | | -void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) |
|---|
| 3183 | | -{ |
|---|
| 3184 | | - struct iscsi_conn *conn = cls_conn->dd_data; |
|---|
| 3185 | | - struct iscsi_session *session = conn->session; |
|---|
| 3186 | | - |
|---|
| 3187 | | - switch (flag) { |
|---|
| 3188 | | - case STOP_CONN_RECOVER: |
|---|
| 3189 | | - case STOP_CONN_TERM: |
|---|
| 3190 | | - iscsi_start_session_recovery(session, conn, flag); |
|---|
| 3191 | | - break; |
|---|
| 3192 | | - default: |
|---|
| 3193 | | - iscsi_conn_printk(KERN_ERR, conn, |
|---|
| 3194 | | - "invalid stop flag %d\n", flag); |
|---|
| 3195 | | - } |
|---|
| 3196 | 3200 | } |
|---|
| 3197 | 3201 | EXPORT_SYMBOL_GPL(iscsi_conn_stop); |
|---|
| 3198 | 3202 | |
|---|