| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /******************************************************************************* |
|---|
| 2 | 3 | * This file contains main functions related to the iSCSI Target Core Driver. |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 5 | 6 | * |
|---|
| 6 | 7 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> |
|---|
| 7 | 8 | * |
|---|
| 8 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 9 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 10 | | - * the Free Software Foundation; either version 2 of the License, or |
|---|
| 11 | | - * (at your option) any later version. |
|---|
| 12 | | - * |
|---|
| 13 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 14 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 15 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 16 | | - * GNU General Public License for more details. |
|---|
| 17 | 9 | ******************************************************************************/ |
|---|
| 18 | 10 | |
|---|
| 19 | 11 | #include <crypto/hash.h> |
|---|
| .. | .. |
|---|
| 308 | 300 | return false; |
|---|
| 309 | 301 | } |
|---|
| 310 | 302 | |
|---|
| 311 | | -/* |
|---|
| 312 | | - * Called with mutex np_lock held |
|---|
| 313 | | - */ |
|---|
| 314 | 303 | static struct iscsi_np *iscsit_get_np( |
|---|
| 315 | 304 | struct sockaddr_storage *sockaddr, |
|---|
| 316 | 305 | int network_transport) |
|---|
| 317 | 306 | { |
|---|
| 318 | 307 | struct iscsi_np *np; |
|---|
| 319 | 308 | bool match; |
|---|
| 309 | + |
|---|
| 310 | + lockdep_assert_held(&np_lock); |
|---|
| 320 | 311 | |
|---|
| 321 | 312 | list_for_each_entry(np, &g_np_list, np_list) { |
|---|
| 322 | 313 | spin_lock_bh(&np->np_thread_lock); |
|---|
| .. | .. |
|---|
| 573 | 564 | return 0; |
|---|
| 574 | 565 | } |
|---|
| 575 | 566 | |
|---|
| 576 | | -static int iscsit_map_iovec(struct iscsi_cmd *, struct kvec *, u32, u32); |
|---|
| 567 | +static int iscsit_map_iovec(struct iscsi_cmd *cmd, struct kvec *iov, int nvec, |
|---|
| 568 | + u32 data_offset, u32 data_length); |
|---|
| 577 | 569 | static void iscsit_unmap_iovec(struct iscsi_cmd *); |
|---|
| 578 | 570 | static u32 iscsit_do_crypto_hash_sg(struct ahash_request *, struct iscsi_cmd *, |
|---|
| 579 | 571 | u32, u32, u32, u8 *); |
|---|
| .. | .. |
|---|
| 604 | 596 | *header_digest); |
|---|
| 605 | 597 | } |
|---|
| 606 | 598 | |
|---|
| 607 | | - iov_ret = iscsit_map_iovec(cmd, &cmd->iov_data[1], |
|---|
| 599 | + iov_ret = iscsit_map_iovec(cmd, &cmd->iov_data[iov_count], |
|---|
| 600 | + cmd->orig_iov_data_count - (iov_count + 2), |
|---|
| 608 | 601 | datain->offset, datain->length); |
|---|
| 609 | 602 | if (iov_ret < 0) |
|---|
| 610 | 603 | return -1; |
|---|
| .. | .. |
|---|
| 713 | 706 | sizeof(struct iscsi_queue_req), |
|---|
| 714 | 707 | __alignof__(struct iscsi_queue_req), 0, NULL); |
|---|
| 715 | 708 | if (!lio_qr_cache) { |
|---|
| 716 | | - pr_err("nable to kmem_cache_create() for" |
|---|
| 709 | + pr_err("Unable to kmem_cache_create() for" |
|---|
| 717 | 710 | " lio_qr_cache\n"); |
|---|
| 718 | 711 | goto bitmap_out; |
|---|
| 719 | 712 | } |
|---|
| .. | .. |
|---|
| 886 | 879 | * Map some portion of the allocated scatterlist to an iovec, suitable for |
|---|
| 887 | 880 | * kernel sockets to copy data in/out. |
|---|
| 888 | 881 | */ |
|---|
| 889 | | -static int iscsit_map_iovec( |
|---|
| 890 | | - struct iscsi_cmd *cmd, |
|---|
| 891 | | - struct kvec *iov, |
|---|
| 892 | | - u32 data_offset, |
|---|
| 893 | | - u32 data_length) |
|---|
| 882 | +static int iscsit_map_iovec(struct iscsi_cmd *cmd, struct kvec *iov, int nvec, |
|---|
| 883 | + u32 data_offset, u32 data_length) |
|---|
| 894 | 884 | { |
|---|
| 895 | | - u32 i = 0; |
|---|
| 885 | + u32 i = 0, orig_data_length = data_length; |
|---|
| 896 | 886 | struct scatterlist *sg; |
|---|
| 897 | 887 | unsigned int page_off; |
|---|
| 898 | 888 | |
|---|
| .. | .. |
|---|
| 901 | 891 | */ |
|---|
| 902 | 892 | u32 ent = data_offset / PAGE_SIZE; |
|---|
| 903 | 893 | |
|---|
| 894 | + if (!data_length) |
|---|
| 895 | + return 0; |
|---|
| 896 | + |
|---|
| 904 | 897 | if (ent >= cmd->se_cmd.t_data_nents) { |
|---|
| 905 | 898 | pr_err("Initial page entry out-of-bounds\n"); |
|---|
| 906 | | - return -1; |
|---|
| 899 | + goto overflow; |
|---|
| 907 | 900 | } |
|---|
| 908 | 901 | |
|---|
| 909 | 902 | sg = &cmd->se_cmd.t_data_sg[ent]; |
|---|
| .. | .. |
|---|
| 913 | 906 | cmd->first_data_sg_off = page_off; |
|---|
| 914 | 907 | |
|---|
| 915 | 908 | while (data_length) { |
|---|
| 916 | | - u32 cur_len = min_t(u32, data_length, sg->length - page_off); |
|---|
| 909 | + u32 cur_len; |
|---|
| 910 | + |
|---|
| 911 | + if (WARN_ON_ONCE(!sg || i >= nvec)) |
|---|
| 912 | + goto overflow; |
|---|
| 913 | + |
|---|
| 914 | + cur_len = min_t(u32, data_length, sg->length - page_off); |
|---|
| 917 | 915 | |
|---|
| 918 | 916 | iov[i].iov_base = kmap(sg_page(sg)) + sg->offset + page_off; |
|---|
| 919 | 917 | iov[i].iov_len = cur_len; |
|---|
| .. | .. |
|---|
| 927 | 925 | cmd->kmapped_nents = i; |
|---|
| 928 | 926 | |
|---|
| 929 | 927 | return i; |
|---|
| 928 | + |
|---|
| 929 | +overflow: |
|---|
| 930 | + pr_err("offset %d + length %d overflow; %d/%d; sg-list:\n", |
|---|
| 931 | + data_offset, orig_data_length, i, nvec); |
|---|
| 932 | + for_each_sg(cmd->se_cmd.t_data_sg, sg, |
|---|
| 933 | + cmd->se_cmd.t_data_nents, i) { |
|---|
| 934 | + pr_err("[%d] off %d len %d\n", |
|---|
| 935 | + i, sg->offset, sg->length); |
|---|
| 936 | + } |
|---|
| 937 | + return -1; |
|---|
| 930 | 938 | } |
|---|
| 931 | 939 | |
|---|
| 932 | 940 | static void iscsit_unmap_iovec(struct iscsi_cmd *cmd) |
|---|
| .. | .. |
|---|
| 1149 | 1157 | transport_init_se_cmd(&cmd->se_cmd, &iscsi_ops, |
|---|
| 1150 | 1158 | conn->sess->se_sess, be32_to_cpu(hdr->data_length), |
|---|
| 1151 | 1159 | cmd->data_direction, sam_task_attr, |
|---|
| 1152 | | - cmd->sense_buffer + 2); |
|---|
| 1160 | + cmd->sense_buffer + 2, scsilun_to_int(&hdr->lun)); |
|---|
| 1153 | 1161 | |
|---|
| 1154 | 1162 | pr_debug("Got SCSI Command, ITT: 0x%08x, CmdSN: 0x%08x," |
|---|
| 1155 | 1163 | " ExpXferLen: %u, Length: %u, CID: %hu\n", hdr->itt, |
|---|
| .. | .. |
|---|
| 1158 | 1166 | |
|---|
| 1159 | 1167 | target_get_sess_cmd(&cmd->se_cmd, true); |
|---|
| 1160 | 1168 | |
|---|
| 1161 | | - cmd->sense_reason = transport_lookup_cmd_lun(&cmd->se_cmd, |
|---|
| 1162 | | - scsilun_to_int(&hdr->lun)); |
|---|
| 1163 | | - if (cmd->sense_reason) |
|---|
| 1164 | | - goto attach_cmd; |
|---|
| 1165 | | - |
|---|
| 1166 | | - /* only used for printks or comparing with ->ref_task_tag */ |
|---|
| 1167 | 1169 | cmd->se_cmd.tag = (__force u32)cmd->init_task_tag; |
|---|
| 1168 | | - cmd->sense_reason = target_setup_cmd_from_cdb(&cmd->se_cmd, hdr->cdb); |
|---|
| 1170 | + cmd->sense_reason = target_cmd_init_cdb(&cmd->se_cmd, hdr->cdb); |
|---|
| 1169 | 1171 | if (cmd->sense_reason) { |
|---|
| 1170 | 1172 | if (cmd->sense_reason == TCM_OUT_OF_RESOURCES) { |
|---|
| 1171 | 1173 | return iscsit_add_reject_cmd(cmd, |
|---|
| 1172 | | - ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf); |
|---|
| 1174 | + ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf); |
|---|
| 1173 | 1175 | } |
|---|
| 1174 | 1176 | |
|---|
| 1175 | 1177 | goto attach_cmd; |
|---|
| 1176 | 1178 | } |
|---|
| 1179 | + |
|---|
| 1180 | + cmd->sense_reason = transport_lookup_cmd_lun(&cmd->se_cmd); |
|---|
| 1181 | + if (cmd->sense_reason) |
|---|
| 1182 | + goto attach_cmd; |
|---|
| 1183 | + |
|---|
| 1184 | + cmd->sense_reason = target_cmd_parse_cdb(&cmd->se_cmd); |
|---|
| 1185 | + if (cmd->sense_reason) |
|---|
| 1186 | + goto attach_cmd; |
|---|
| 1177 | 1187 | |
|---|
| 1178 | 1188 | if (iscsit_build_pdu_and_seq_lists(cmd, payload_length) < 0) { |
|---|
| 1179 | 1189 | return iscsit_add_reject_cmd(cmd, |
|---|
| .. | .. |
|---|
| 1194 | 1204 | } |
|---|
| 1195 | 1205 | EXPORT_SYMBOL(iscsit_setup_scsi_cmd); |
|---|
| 1196 | 1206 | |
|---|
| 1197 | | -void iscsit_set_unsoliticed_dataout(struct iscsi_cmd *cmd) |
|---|
| 1207 | +void iscsit_set_unsolicited_dataout(struct iscsi_cmd *cmd) |
|---|
| 1198 | 1208 | { |
|---|
| 1199 | 1209 | iscsit_set_dataout_sequence_values(cmd); |
|---|
| 1200 | 1210 | |
|---|
| .. | .. |
|---|
| 1202 | 1212 | iscsit_start_dataout_timer(cmd, cmd->conn); |
|---|
| 1203 | 1213 | spin_unlock_bh(&cmd->dataout_timeout_lock); |
|---|
| 1204 | 1214 | } |
|---|
| 1205 | | -EXPORT_SYMBOL(iscsit_set_unsoliticed_dataout); |
|---|
| 1215 | +EXPORT_SYMBOL(iscsit_set_unsolicited_dataout); |
|---|
| 1206 | 1216 | |
|---|
| 1207 | 1217 | int iscsit_process_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, |
|---|
| 1208 | 1218 | struct iscsi_scsi_req *hdr) |
|---|
| .. | .. |
|---|
| 1236 | 1246 | */ |
|---|
| 1237 | 1247 | if (!cmd->immediate_data) { |
|---|
| 1238 | 1248 | if (!cmd->sense_reason && cmd->unsolicited_data) |
|---|
| 1239 | | - iscsit_set_unsoliticed_dataout(cmd); |
|---|
| 1249 | + iscsit_set_unsolicited_dataout(cmd); |
|---|
| 1240 | 1250 | if (!cmd->sense_reason) |
|---|
| 1241 | 1251 | return 0; |
|---|
| 1242 | 1252 | |
|---|
| .. | .. |
|---|
| 1268 | 1278 | bool dump_payload) |
|---|
| 1269 | 1279 | { |
|---|
| 1270 | 1280 | int cmdsn_ret = 0, immed_ret = IMMEDIATE_DATA_NORMAL_OPERATION; |
|---|
| 1281 | + int rc; |
|---|
| 1282 | + |
|---|
| 1271 | 1283 | /* |
|---|
| 1272 | 1284 | * Special case for Unsupported SAM WRITE Opcodes and ImmediateData=Yes. |
|---|
| 1273 | 1285 | */ |
|---|
| 1274 | | - if (dump_payload) |
|---|
| 1275 | | - goto after_immediate_data; |
|---|
| 1276 | | - /* |
|---|
| 1277 | | - * Check for underflow case where both EDTL and immediate data payload |
|---|
| 1278 | | - * exceeds what is presented by CDB's TRANSFER LENGTH, and what has |
|---|
| 1279 | | - * already been set in target_cmd_size_check() as se_cmd->data_length. |
|---|
| 1280 | | - * |
|---|
| 1281 | | - * For this special case, fail the command and dump the immediate data |
|---|
| 1282 | | - * payload. |
|---|
| 1283 | | - */ |
|---|
| 1284 | | - if (cmd->first_burst_len > cmd->se_cmd.data_length) { |
|---|
| 1285 | | - cmd->sense_reason = TCM_INVALID_CDB_FIELD; |
|---|
| 1286 | | - goto after_immediate_data; |
|---|
| 1286 | + if (dump_payload) { |
|---|
| 1287 | + u32 length = min(cmd->se_cmd.data_length - cmd->write_data_done, |
|---|
| 1288 | + cmd->first_burst_len); |
|---|
| 1289 | + |
|---|
| 1290 | + pr_debug("Dumping min(%d - %d, %d) = %d bytes of immediate data\n", |
|---|
| 1291 | + cmd->se_cmd.data_length, cmd->write_data_done, |
|---|
| 1292 | + cmd->first_burst_len, length); |
|---|
| 1293 | + rc = iscsit_dump_data_payload(cmd->conn, length, 1); |
|---|
| 1294 | + pr_debug("Finished dumping immediate data\n"); |
|---|
| 1295 | + if (rc < 0) |
|---|
| 1296 | + immed_ret = IMMEDIATE_DATA_CANNOT_RECOVER; |
|---|
| 1297 | + } else { |
|---|
| 1298 | + immed_ret = iscsit_handle_immediate_data(cmd, hdr, |
|---|
| 1299 | + cmd->first_burst_len); |
|---|
| 1287 | 1300 | } |
|---|
| 1288 | 1301 | |
|---|
| 1289 | | - immed_ret = iscsit_handle_immediate_data(cmd, hdr, |
|---|
| 1290 | | - cmd->first_burst_len); |
|---|
| 1291 | | -after_immediate_data: |
|---|
| 1292 | 1302 | if (immed_ret == IMMEDIATE_DATA_NORMAL_OPERATION) { |
|---|
| 1293 | 1303 | /* |
|---|
| 1294 | 1304 | * A PDU/CmdSN carrying Immediate Data passed |
|---|
| .. | .. |
|---|
| 1301 | 1311 | return -1; |
|---|
| 1302 | 1312 | |
|---|
| 1303 | 1313 | if (cmd->sense_reason || cmdsn_ret == CMDSN_LOWER_THAN_EXP) { |
|---|
| 1304 | | - int rc; |
|---|
| 1305 | | - |
|---|
| 1306 | | - rc = iscsit_dump_data_payload(cmd->conn, |
|---|
| 1307 | | - cmd->first_burst_len, 1); |
|---|
| 1308 | 1314 | target_put_sess_cmd(&cmd->se_cmd); |
|---|
| 1309 | | - return rc; |
|---|
| 1315 | + |
|---|
| 1316 | + return 0; |
|---|
| 1310 | 1317 | } else if (cmd->unsolicited_data) |
|---|
| 1311 | | - iscsit_set_unsoliticed_dataout(cmd); |
|---|
| 1318 | + iscsit_set_unsolicited_dataout(cmd); |
|---|
| 1312 | 1319 | |
|---|
| 1313 | 1320 | } else if (immed_ret == IMMEDIATE_DATA_ERL1_CRC_FAILURE) { |
|---|
| 1314 | 1321 | /* |
|---|
| .. | .. |
|---|
| 1505 | 1512 | if (hdr->flags & ISCSI_FLAG_CMD_FINAL) |
|---|
| 1506 | 1513 | iscsit_stop_dataout_timer(cmd); |
|---|
| 1507 | 1514 | |
|---|
| 1508 | | - transport_check_aborted_status(se_cmd, |
|---|
| 1509 | | - (hdr->flags & ISCSI_FLAG_CMD_FINAL)); |
|---|
| 1510 | 1515 | return iscsit_dump_data_payload(conn, payload_length, 1); |
|---|
| 1511 | 1516 | } |
|---|
| 1512 | 1517 | } else { |
|---|
| .. | .. |
|---|
| 1521 | 1526 | * TASK_ABORTED status. |
|---|
| 1522 | 1527 | */ |
|---|
| 1523 | 1528 | if (se_cmd->transport_state & CMD_T_ABORTED) { |
|---|
| 1524 | | - if (hdr->flags & ISCSI_FLAG_CMD_FINAL) |
|---|
| 1525 | | - if (--cmd->outstanding_r2ts < 1) { |
|---|
| 1526 | | - iscsit_stop_dataout_timer(cmd); |
|---|
| 1527 | | - transport_check_aborted_status( |
|---|
| 1528 | | - se_cmd, 1); |
|---|
| 1529 | | - } |
|---|
| 1529 | + if (hdr->flags & ISCSI_FLAG_CMD_FINAL && |
|---|
| 1530 | + --cmd->outstanding_r2ts < 1) |
|---|
| 1531 | + iscsit_stop_dataout_timer(cmd); |
|---|
| 1530 | 1532 | |
|---|
| 1531 | 1533 | return iscsit_dump_data_payload(conn, payload_length, 1); |
|---|
| 1532 | 1534 | } |
|---|
| .. | .. |
|---|
| 1586 | 1588 | { |
|---|
| 1587 | 1589 | struct kvec *iov; |
|---|
| 1588 | 1590 | u32 checksum, iov_count = 0, padding = 0, rx_got = 0, rx_size = 0; |
|---|
| 1589 | | - u32 payload_length = ntoh24(hdr->dlength); |
|---|
| 1591 | + u32 payload_length; |
|---|
| 1590 | 1592 | int iov_ret, data_crc_failed = 0; |
|---|
| 1591 | 1593 | |
|---|
| 1594 | + payload_length = min_t(u32, cmd->se_cmd.data_length, |
|---|
| 1595 | + ntoh24(hdr->dlength)); |
|---|
| 1592 | 1596 | rx_size += payload_length; |
|---|
| 1593 | 1597 | iov = &cmd->iov_data[0]; |
|---|
| 1594 | 1598 | |
|---|
| 1595 | | - iov_ret = iscsit_map_iovec(cmd, iov, be32_to_cpu(hdr->offset), |
|---|
| 1596 | | - payload_length); |
|---|
| 1599 | + iov_ret = iscsit_map_iovec(cmd, iov, cmd->orig_iov_data_count - 2, |
|---|
| 1600 | + be32_to_cpu(hdr->offset), payload_length); |
|---|
| 1597 | 1601 | if (iov_ret < 0) |
|---|
| 1598 | 1602 | return -1; |
|---|
| 1599 | 1603 | |
|---|
| .. | .. |
|---|
| 1613 | 1617 | rx_size += ISCSI_CRC_LEN; |
|---|
| 1614 | 1618 | } |
|---|
| 1615 | 1619 | |
|---|
| 1620 | + WARN_ON_ONCE(iov_count > cmd->orig_iov_data_count); |
|---|
| 1616 | 1621 | rx_got = rx_data(conn, &cmd->iov_data[0], iov_count, rx_size); |
|---|
| 1617 | 1622 | |
|---|
| 1618 | 1623 | iscsit_unmap_iovec(cmd); |
|---|
| .. | .. |
|---|
| 1878 | 1883 | rx_size += ISCSI_CRC_LEN; |
|---|
| 1879 | 1884 | } |
|---|
| 1880 | 1885 | |
|---|
| 1886 | + WARN_ON_ONCE(niov > ARRAY_SIZE(cmd->iov_misc)); |
|---|
| 1881 | 1887 | rx_got = rx_data(conn, &cmd->iov_misc[0], niov, rx_size); |
|---|
| 1882 | 1888 | if (rx_got != rx_size) { |
|---|
| 1883 | 1889 | ret = -1; |
|---|
| .. | .. |
|---|
| 2008 | 2014 | |
|---|
| 2009 | 2015 | transport_init_se_cmd(&cmd->se_cmd, &iscsi_ops, |
|---|
| 2010 | 2016 | conn->sess->se_sess, 0, DMA_NONE, |
|---|
| 2011 | | - TCM_SIMPLE_TAG, cmd->sense_buffer + 2); |
|---|
| 2017 | + TCM_SIMPLE_TAG, cmd->sense_buffer + 2, |
|---|
| 2018 | + scsilun_to_int(&hdr->lun)); |
|---|
| 2012 | 2019 | |
|---|
| 2013 | 2020 | target_get_sess_cmd(&cmd->se_cmd, true); |
|---|
| 2014 | 2021 | |
|---|
| .. | .. |
|---|
| 2046 | 2053 | * Locate the struct se_lun for all TMRs not related to ERL=2 TASK_REASSIGN |
|---|
| 2047 | 2054 | */ |
|---|
| 2048 | 2055 | if (function != ISCSI_TM_FUNC_TASK_REASSIGN) { |
|---|
| 2049 | | - ret = transport_lookup_tmr_lun(&cmd->se_cmd, |
|---|
| 2050 | | - scsilun_to_int(&hdr->lun)); |
|---|
| 2056 | + ret = transport_lookup_tmr_lun(&cmd->se_cmd); |
|---|
| 2051 | 2057 | if (ret < 0) { |
|---|
| 2052 | 2058 | se_tmr->response = ISCSI_TMF_RSP_NO_LUN; |
|---|
| 2053 | 2059 | goto attach; |
|---|
| .. | .. |
|---|
| 2197 | 2203 | } |
|---|
| 2198 | 2204 | goto empty_sendtargets; |
|---|
| 2199 | 2205 | } |
|---|
| 2200 | | - if (strncmp("SendTargets", text_in, 11) != 0) { |
|---|
| 2206 | + if (strncmp("SendTargets=", text_in, 12) != 0) { |
|---|
| 2201 | 2207 | pr_err("Received Text Data that is not" |
|---|
| 2202 | 2208 | " SendTargets, cannot continue.\n"); |
|---|
| 2203 | 2209 | goto reject; |
|---|
| 2204 | 2210 | } |
|---|
| 2211 | + /* '=' confirmed in strncmp */ |
|---|
| 2205 | 2212 | text_ptr = strchr(text_in, '='); |
|---|
| 2206 | | - if (!text_ptr) { |
|---|
| 2207 | | - pr_err("No \"=\" separator found in Text Data," |
|---|
| 2208 | | - " cannot continue.\n"); |
|---|
| 2209 | | - goto reject; |
|---|
| 2210 | | - } |
|---|
| 2211 | | - if (!strncmp("=All", text_ptr, 4)) { |
|---|
| 2213 | + BUG_ON(!text_ptr); |
|---|
| 2214 | + if (!strncmp("=All", text_ptr, 5)) { |
|---|
| 2212 | 2215 | cmd->cmd_flags |= ICF_SENDTARGETS_ALL; |
|---|
| 2213 | 2216 | } else if (!strncmp("=iqn.", text_ptr, 5) || |
|---|
| 2214 | 2217 | !strncmp("=eui.", text_ptr, 5)) { |
|---|
| 2215 | 2218 | cmd->cmd_flags |= ICF_SENDTARGETS_SINGLE; |
|---|
| 2216 | 2219 | } else { |
|---|
| 2217 | | - pr_err("Unable to locate valid SendTargets=%s value\n", text_ptr); |
|---|
| 2220 | + pr_err("Unable to locate valid SendTargets%s value\n", |
|---|
| 2221 | + text_ptr); |
|---|
| 2218 | 2222 | goto reject; |
|---|
| 2219 | 2223 | } |
|---|
| 2220 | 2224 | |
|---|
| .. | .. |
|---|
| 2258 | 2262 | rx_size = payload_length; |
|---|
| 2259 | 2263 | if (payload_length) { |
|---|
| 2260 | 2264 | u32 checksum = 0, data_crc = 0; |
|---|
| 2261 | | - u32 padding = 0, pad_bytes = 0; |
|---|
| 2265 | + u32 padding = 0; |
|---|
| 2262 | 2266 | int niov = 0, rx_got; |
|---|
| 2263 | | - struct kvec iov[3]; |
|---|
| 2267 | + struct kvec iov[2]; |
|---|
| 2264 | 2268 | |
|---|
| 2265 | | - text_in = kzalloc(payload_length, GFP_KERNEL); |
|---|
| 2269 | + rx_size = ALIGN(payload_length, 4); |
|---|
| 2270 | + text_in = kzalloc(rx_size, GFP_KERNEL); |
|---|
| 2266 | 2271 | if (!text_in) |
|---|
| 2267 | 2272 | goto reject; |
|---|
| 2268 | 2273 | |
|---|
| 2269 | 2274 | cmd->text_in_ptr = text_in; |
|---|
| 2270 | 2275 | |
|---|
| 2271 | | - memset(iov, 0, 3 * sizeof(struct kvec)); |
|---|
| 2276 | + memset(iov, 0, sizeof(iov)); |
|---|
| 2272 | 2277 | iov[niov].iov_base = text_in; |
|---|
| 2273 | | - iov[niov++].iov_len = payload_length; |
|---|
| 2278 | + iov[niov++].iov_len = rx_size; |
|---|
| 2274 | 2279 | |
|---|
| 2275 | | - padding = ((-payload_length) & 3); |
|---|
| 2276 | | - if (padding != 0) { |
|---|
| 2277 | | - iov[niov].iov_base = &pad_bytes; |
|---|
| 2278 | | - iov[niov++].iov_len = padding; |
|---|
| 2279 | | - rx_size += padding; |
|---|
| 2280 | + padding = rx_size - payload_length; |
|---|
| 2281 | + if (padding) |
|---|
| 2280 | 2282 | pr_debug("Receiving %u additional bytes" |
|---|
| 2281 | 2283 | " for padding.\n", padding); |
|---|
| 2282 | | - } |
|---|
| 2283 | 2284 | if (conn->conn_ops->DataDigest) { |
|---|
| 2284 | 2285 | iov[niov].iov_base = &checksum; |
|---|
| 2285 | 2286 | iov[niov++].iov_len = ISCSI_CRC_LEN; |
|---|
| 2286 | 2287 | rx_size += ISCSI_CRC_LEN; |
|---|
| 2287 | 2288 | } |
|---|
| 2288 | 2289 | |
|---|
| 2290 | + WARN_ON_ONCE(niov > ARRAY_SIZE(iov)); |
|---|
| 2289 | 2291 | rx_got = rx_data(conn, &iov[0], niov, rx_size); |
|---|
| 2290 | 2292 | if (rx_got != rx_size) |
|---|
| 2291 | 2293 | goto reject; |
|---|
| 2292 | 2294 | |
|---|
| 2293 | 2295 | if (conn->conn_ops->DataDigest) { |
|---|
| 2294 | | - iscsit_do_crypto_hash_buf(conn->conn_rx_hash, text_in, |
|---|
| 2295 | | - payload_length, padding, |
|---|
| 2296 | | - &pad_bytes, &data_crc); |
|---|
| 2296 | + iscsit_do_crypto_hash_buf(conn->conn_rx_hash, |
|---|
| 2297 | + text_in, rx_size, 0, NULL, |
|---|
| 2298 | + &data_crc); |
|---|
| 2297 | 2299 | |
|---|
| 2298 | 2300 | if (checksum != data_crc) { |
|---|
| 2299 | 2301 | pr_err("Text data CRC32C DataDigest" |
|---|
| .. | .. |
|---|
| 2596 | 2598 | u32 checksum, iov_count = 0, padding = 0; |
|---|
| 2597 | 2599 | struct iscsi_conn *conn = cmd->conn; |
|---|
| 2598 | 2600 | struct kvec *iov; |
|---|
| 2601 | + void *overflow_buf = NULL; |
|---|
| 2599 | 2602 | |
|---|
| 2600 | | - iov_ret = iscsit_map_iovec(cmd, cmd->iov_data, cmd->write_data_done, length); |
|---|
| 2603 | + BUG_ON(cmd->write_data_done > cmd->se_cmd.data_length); |
|---|
| 2604 | + rx_size = min(cmd->se_cmd.data_length - cmd->write_data_done, length); |
|---|
| 2605 | + iov_ret = iscsit_map_iovec(cmd, cmd->iov_data, |
|---|
| 2606 | + cmd->orig_iov_data_count - 2, |
|---|
| 2607 | + cmd->write_data_done, rx_size); |
|---|
| 2601 | 2608 | if (iov_ret < 0) |
|---|
| 2602 | 2609 | return IMMEDIATE_DATA_CANNOT_RECOVER; |
|---|
| 2603 | 2610 | |
|---|
| 2604 | | - rx_size = length; |
|---|
| 2605 | 2611 | iov_count = iov_ret; |
|---|
| 2606 | 2612 | iov = &cmd->iov_data[0]; |
|---|
| 2613 | + if (rx_size < length) { |
|---|
| 2614 | + /* |
|---|
| 2615 | + * Special case: length of immediate data exceeds the data |
|---|
| 2616 | + * buffer size derived from the CDB. |
|---|
| 2617 | + */ |
|---|
| 2618 | + overflow_buf = kmalloc(length - rx_size, GFP_KERNEL); |
|---|
| 2619 | + if (!overflow_buf) { |
|---|
| 2620 | + iscsit_unmap_iovec(cmd); |
|---|
| 2621 | + return IMMEDIATE_DATA_CANNOT_RECOVER; |
|---|
| 2622 | + } |
|---|
| 2623 | + cmd->overflow_buf = overflow_buf; |
|---|
| 2624 | + iov[iov_count].iov_base = overflow_buf; |
|---|
| 2625 | + iov[iov_count].iov_len = length - rx_size; |
|---|
| 2626 | + iov_count++; |
|---|
| 2627 | + rx_size = length; |
|---|
| 2628 | + } |
|---|
| 2607 | 2629 | |
|---|
| 2608 | 2630 | padding = ((-length) & 3); |
|---|
| 2609 | 2631 | if (padding != 0) { |
|---|
| .. | .. |
|---|
| 2618 | 2640 | rx_size += ISCSI_CRC_LEN; |
|---|
| 2619 | 2641 | } |
|---|
| 2620 | 2642 | |
|---|
| 2643 | + WARN_ON_ONCE(iov_count > cmd->orig_iov_data_count); |
|---|
| 2621 | 2644 | rx_got = rx_data(conn, &cmd->iov_data[0], iov_count, rx_size); |
|---|
| 2622 | 2645 | |
|---|
| 2623 | 2646 | iscsit_unmap_iovec(cmd); |
|---|
| .. | .. |
|---|
| 2672 | 2695 | return IMMEDIATE_DATA_NORMAL_OPERATION; |
|---|
| 2673 | 2696 | } |
|---|
| 2674 | 2697 | |
|---|
| 2675 | | -/* |
|---|
| 2676 | | - * Called with sess->conn_lock held. |
|---|
| 2677 | | - */ |
|---|
| 2678 | 2698 | /* #warning iscsi_build_conn_drop_async_message() only sends out on connections |
|---|
| 2679 | 2699 | with active network interface */ |
|---|
| 2680 | 2700 | static void iscsit_build_conn_drop_async_message(struct iscsi_conn *conn) |
|---|
| .. | .. |
|---|
| 2682 | 2702 | struct iscsi_cmd *cmd; |
|---|
| 2683 | 2703 | struct iscsi_conn *conn_p; |
|---|
| 2684 | 2704 | bool found = false; |
|---|
| 2705 | + |
|---|
| 2706 | + lockdep_assert_held(&conn->sess->conn_lock); |
|---|
| 2685 | 2707 | |
|---|
| 2686 | 2708 | /* |
|---|
| 2687 | 2709 | * Only send a Asynchronous Message on connections whos network |
|---|
| .. | .. |
|---|
| 3143 | 3165 | else |
|---|
| 3144 | 3166 | xfer_len = conn->sess->sess_ops->MaxBurstLength; |
|---|
| 3145 | 3167 | } |
|---|
| 3168 | + |
|---|
| 3169 | + if ((s32)xfer_len < 0) { |
|---|
| 3170 | + cmd->cmd_flags |= ICF_SENT_LAST_R2T; |
|---|
| 3171 | + break; |
|---|
| 3172 | + } |
|---|
| 3173 | + |
|---|
| 3146 | 3174 | cmd->r2t_offset += xfer_len; |
|---|
| 3147 | 3175 | |
|---|
| 3148 | 3176 | if (cmd->r2t_offset == cmd->se_cmd.data_length) |
|---|
| .. | .. |
|---|
| 3723 | 3751 | case ISTATE_SEND_LOGOUTRSP: |
|---|
| 3724 | 3752 | if (!iscsit_logout_post_handler(cmd, conn)) |
|---|
| 3725 | 3753 | return -ECONNRESET; |
|---|
| 3726 | | - /* fall through */ |
|---|
| 3754 | + fallthrough; |
|---|
| 3727 | 3755 | case ISTATE_SEND_STATUS: |
|---|
| 3728 | 3756 | case ISTATE_SEND_ASYNCMSG: |
|---|
| 3729 | 3757 | case ISTATE_SEND_NOPIN: |
|---|
| .. | .. |
|---|
| 4371 | 4399 | * restart the timer and exit. |
|---|
| 4372 | 4400 | */ |
|---|
| 4373 | 4401 | if (!in_interrupt()) { |
|---|
| 4374 | | - if (iscsit_check_session_usage_count(sess) == 1) |
|---|
| 4375 | | - iscsit_stop_session(sess, 1, 1); |
|---|
| 4402 | + iscsit_check_session_usage_count(sess); |
|---|
| 4376 | 4403 | } else { |
|---|
| 4377 | 4404 | if (iscsit_check_session_usage_count(sess) == 2) { |
|---|
| 4378 | 4405 | atomic_set(&sess->session_logout, 0); |
|---|
| .. | .. |
|---|
| 4384 | 4411 | transport_deregister_session(sess->se_sess); |
|---|
| 4385 | 4412 | |
|---|
| 4386 | 4413 | if (sess->sess_ops->ErrorRecoveryLevel == 2) |
|---|
| 4387 | | - iscsit_free_connection_recovery_entires(sess); |
|---|
| 4414 | + iscsit_free_connection_recovery_entries(sess); |
|---|
| 4388 | 4415 | |
|---|
| 4389 | 4416 | iscsit_free_all_ooo_cmdsns(sess); |
|---|
| 4390 | 4417 | |
|---|
| .. | .. |
|---|
| 4510 | 4537 | iscsit_logout_post_handler_closesession(conn); |
|---|
| 4511 | 4538 | break; |
|---|
| 4512 | 4539 | } |
|---|
| 4513 | | - ret = 0; |
|---|
| 4514 | 4540 | break; |
|---|
| 4515 | 4541 | case ISCSI_LOGOUT_REASON_CLOSE_CONNECTION: |
|---|
| 4516 | 4542 | if (conn->cid == cmd->logout_cid) { |
|---|
| .. | .. |
|---|
| 4521 | 4547 | iscsit_logout_post_handler_samecid(conn); |
|---|
| 4522 | 4548 | break; |
|---|
| 4523 | 4549 | } |
|---|
| 4524 | | - ret = 0; |
|---|
| 4525 | 4550 | } else { |
|---|
| 4526 | 4551 | switch (cmd->logout_response) { |
|---|
| 4527 | 4552 | case ISCSI_LOGOUT_SUCCESS: |
|---|