diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-22 00:21:19 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-22 00:21:19 +0300 |
commit | e20d3ef5406d3a28b76a63905b2a6bd3fb95c377 (patch) | |
tree | 63711e10f8c746eaa154b18bd7f05e111b79151d /drivers/target | |
parent | 1acd2de5facd7fbea499aea64a3a3d0ec7bb9b51 (diff) | |
parent | aa04dae454d087376d97f44710c4422df030a8f2 (diff) | |
download | linux-e20d3ef5406d3a28b76a63905b2a6bd3fb95c377.tar.xz |
Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending
Pull SCSI target updates from Nicholas Bellinger:
"The highlights this round include:
- Update vhost-scsi to support F_ANY_LAYOUT using mm/iov_iter.c
logic, and signal VERSION_1 support (MST + Viro + nab)
- Fix iscsi/iser-target to remove problematic active_ts_set usage
(Gavin Guo)
- Update iscsi/iser-target to support multi-sequence sendtargets
(Sagi)
- Fix original PR_APTPL_BUF_LEN 8k size limitation (Martin Svec)
- Add missing WRITE_SAME end-of-device sanity check (Bart)
- Check for LBA + sectors wrap-around in sbc_parse_cdb() (nab)
- Other various minor SPC/SBC compliance fixes based upon Ronnie
Sahlberg test suite (nab)"
* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending: (32 commits)
target: Set LBPWS10 bit in Logical Block Provisioning EVPD
target: Fail UNMAP when emulate_tpu=0
target: Fail WRITE_SAME w/ UNMAP=1 when emulate_tpws=0
target: Add sanity checks for DPO/FUA bit usage
target: Perform PROTECT sanity checks for WRITE_SAME
target: Fail I/O with PROTECT bit when protection is unsupported
target: Check for LBA + sectors wrap-around in sbc_parse_cdb
target: Add missing WRITE_SAME end-of-device sanity check
iscsi-target: Avoid IN_LOGOUT failure case for iser-target
target: Fix PR_APTPL_BUF_LEN buffer size limitation
iscsi-target: Drop problematic active_ts_list usage
iscsi/iser-target: Support multi-sequence sendtargets text response
iser-target: Remove duplicate function names
vhost/scsi: potential memory corruption
vhost/scsi: Global tcm_vhost -> vhost_scsi rename
vhost/scsi: Drop left-over scsi_tcq.h include
vhost/scsi: Set VIRTIO_F_ANY_LAYOUT + VIRTIO_F_VERSION_1 feature bits
vhost/scsi: Add ANY_LAYOUT support in vhost_scsi_handle_vq
vhost/scsi: Add ANY_LAYOUT iov -> sgl mapping prerequisites
vhost/scsi: Change vhost_scsi_map_to_sgl to accept iov ptr + len
...
Diffstat (limited to 'drivers/target')
26 files changed, 239 insertions, 1086 deletions
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index aebde3289c50..50bad55a0c42 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -30,7 +30,7 @@ #include <target/target_core_fabric.h> #include <target/target_core_configfs.h> -#include "iscsi_target_core.h" +#include <target/iscsi/iscsi_target_core.h> #include "iscsi_target_parameters.h" #include "iscsi_target_seq_pdu_list.h" #include "iscsi_target_tq.h" @@ -45,7 +45,7 @@ #include "iscsi_target_util.h" #include "iscsi_target.h" #include "iscsi_target_device.h" -#include "iscsi_target_stat.h" +#include <target/iscsi/iscsi_target_stat.h> #include <target/iscsi/iscsi_transport.h> @@ -968,11 +968,7 @@ int iscsit_setup_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, conn->sess->init_task_tag = cmd->init_task_tag = hdr->itt; if (hdr->flags & ISCSI_FLAG_CMD_READ) { - spin_lock_bh(&conn->sess->ttt_lock); - cmd->targ_xfer_tag = conn->sess->targ_xfer_tag++; - if (cmd->targ_xfer_tag == 0xFFFFFFFF) - cmd->targ_xfer_tag = conn->sess->targ_xfer_tag++; - spin_unlock_bh(&conn->sess->ttt_lock); + cmd->targ_xfer_tag = session_get_next_ttt(conn->sess); } else if (hdr->flags & ISCSI_FLAG_CMD_WRITE) cmd->targ_xfer_tag = 0xFFFFFFFF; cmd->cmd_sn = be32_to_cpu(hdr->cmdsn); @@ -1998,6 +1994,7 @@ iscsit_setup_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, cmd->cmd_sn = be32_to_cpu(hdr->cmdsn); cmd->exp_stat_sn = be32_to_cpu(hdr->exp_statsn); cmd->data_direction = DMA_NONE; + cmd->text_in_ptr = NULL; return 0; } @@ -2011,9 +2008,13 @@ iscsit_process_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, int cmdsn_ret; if (!text_in) { - pr_err("Unable to locate text_in buffer for sendtargets" - " discovery\n"); - goto reject; + cmd->targ_xfer_tag = be32_to_cpu(hdr->ttt); + if (cmd->targ_xfer_tag == 0xFFFFFFFF) { + pr_err("Unable to locate text_in buffer for sendtargets" + " discovery\n"); + goto reject; + } + goto empty_sendtargets; } if (strncmp("SendTargets", text_in, 11) != 0) { pr_err("Received Text Data that is not" @@ -2040,6 +2041,7 @@ iscsit_process_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list); spin_unlock_bh(&conn->cmd_lock); +empty_sendtargets: iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn)); if (!(hdr->opcode & ISCSI_OP_IMMEDIATE)) { @@ -3047,11 +3049,7 @@ static int iscsit_send_r2t( int_to_scsilun(cmd->se_cmd.orig_fe_lun, (struct scsi_lun *)&hdr->lun); hdr->itt = cmd->init_task_tag; - spin_lock_bh(&conn->sess->ttt_lock); - r2t->targ_xfer_tag = conn->sess->targ_xfer_tag++; - if (r2t->targ_xfer_tag == 0xFFFFFFFF) - r2t->targ_xfer_tag = conn->sess->targ_xfer_tag++; - spin_unlock_bh(&conn->sess->ttt_lock); + r2t->targ_xfer_tag = session_get_next_ttt(conn->sess); hdr->ttt = cpu_to_be32(r2t->targ_xfer_tag); hdr->statsn = cpu_to_be32(conn->stat_sn); hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn); @@ -3393,7 +3391,8 @@ static bool iscsit_check_inaddr_any(struct iscsi_np *np) static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd, - enum iscsit_transport_type network_transport) + enum iscsit_transport_type network_transport, + int skip_bytes, bool *completed) { char *payload = NULL; struct iscsi_conn *conn = cmd->conn; @@ -3405,7 +3404,7 @@ iscsit_build_sendtargets_response(struct iscsi_cmd *cmd, unsigned char buf[ISCSI_IQN_LEN+12]; /* iqn + "TargetName=" + \0 */ unsigned char *text_in = cmd->text_in_ptr, *text_ptr = NULL; - buffer_len = max(conn->conn_ops->MaxRecvDataSegmentLength, + buffer_len = min(conn->conn_ops->MaxRecvDataSegmentLength, SENDTARGETS_BUF_LIMIT); payload = kzalloc(buffer_len, GFP_KERNEL); @@ -3484,9 +3483,16 @@ iscsit_build_sendtargets_response(struct iscsi_cmd *cmd, end_of_buf = 1; goto eob; } - memcpy(payload + payload_len, buf, len); - payload_len += len; - target_name_printed = 1; + + if (skip_bytes && len <= skip_bytes) { + skip_bytes -= len; + } else { + memcpy(payload + payload_len, buf, len); + payload_len += len; + target_name_printed = 1; + if (len > skip_bytes) + skip_bytes = 0; + } } len = sprintf(buf, "TargetAddress=" @@ -3502,15 +3508,24 @@ iscsit_build_sendtargets_response(struct iscsi_cmd *cmd, end_of_buf = 1; goto eob; } - memcpy(payload + payload_len, buf, len); - payload_len += len; + + if (skip_bytes && len <= skip_bytes) { + skip_bytes -= len; + } else { + memcpy(payload + payload_len, buf, len); + payload_len += len; + if (len > skip_bytes) + skip_bytes = 0; + } } spin_unlock(&tpg->tpg_np_lock); } spin_unlock(&tiqn->tiqn_tpg_lock); eob: - if (end_of_buf) + if (end_of_buf) { + *completed = false; break; + } if (cmd->cmd_flags & ICF_SENDTARGETS_SINGLE) break; @@ -3528,13 +3543,23 @@ iscsit_build_text_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn, enum iscsit_transport_type network_transport) { int text_length, padding; + bool completed = true; - text_length = iscsit_build_sendtargets_response(cmd, network_transport); + text_length = iscsit_build_sendtargets_response(cmd, network_transport, + cmd->read_data_done, + &completed); if (text_length < 0) return text_length; + if (completed) { + hdr->flags |= ISCSI_FLAG_CMD_FINAL; + } else { + hdr->flags |= ISCSI_FLAG_TEXT_CONTINUE; + cmd->read_data_done += text_length; + if (cmd->targ_xfer_tag == 0xFFFFFFFF) + cmd->targ_xfer_tag = session_get_next_ttt(conn->sess); + } hdr->opcode = ISCSI_OP_TEXT_RSP; - hdr->flags |= ISCSI_FLAG_CMD_FINAL; padding = ((-text_length) & 3); hton24(hdr->dlength, text_length); hdr->itt = cmd->init_task_tag; @@ -3543,21 +3568,25 @@ iscsit_build_text_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn, hdr->statsn = cpu_to_be32(cmd->stat_sn); iscsit_increment_maxcmdsn(cmd, conn->sess); + /* + * Reset maxcmdsn_inc in multi-part text payload exchanges to + * correctly increment MaxCmdSN for each response answering a + * non immediate text request with a valid CmdSN. + */ + cmd->maxcmdsn_inc = 0; hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn); hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn); - pr_debug("Built Text Response: ITT: 0x%08x, StatSN: 0x%08x," - " Length: %u, CID: %hu\n", cmd->init_task_tag, cmd->stat_sn, - text_length, conn->cid); + pr_debug("Built Text Response: ITT: 0x%08x, TTT: 0x%08x, StatSN: 0x%08x," + " Length: %u, CID: %hu F: %d C: %d\n", cmd->init_task_tag, + cmd->targ_xfer_tag, cmd->stat_sn, text_length, conn->cid, + !!(hdr->flags & ISCSI_FLAG_CMD_FINAL), + !!(hdr->flags & ISCSI_FLAG_TEXT_CONTINUE)); return text_length + padding; } EXPORT_SYMBOL(iscsit_build_text_rsp); -/* - * FIXME: Add support for F_BIT and C_BIT when the length is longer than - * MaxRecvDataSegmentLength. - */ static int iscsit_send_text_rsp( struct iscsi_cmd *cmd, struct iscsi_conn *conn) @@ -4021,9 +4050,15 @@ static int iscsi_target_rx_opcode(struct iscsi_conn *conn, unsigned char *buf) ret = iscsit_handle_task_mgt_cmd(conn, cmd, buf); break; case ISCSI_OP_TEXT: - cmd = iscsit_allocate_cmd(conn, TASK_INTERRUPTIBLE); - if (!cmd) - goto reject; + if (hdr->ttt != cpu_to_be32(0xFFFFFFFF)) { + cmd = iscsit_find_cmd_from_itt(conn, hdr->itt); + if (!cmd) + goto reject; + } else { + cmd = iscsit_allocate_cmd(conn, TASK_INTERRUPTIBLE); + if (!cmd) + goto reject; + } ret = iscsit_handle_text_cmd(conn, cmd, buf); break; diff --git a/drivers/target/iscsi/iscsi_target_auth.c b/drivers/target/iscsi/iscsi_target_auth.c index ab4915c0d933..47e249dccb5f 100644 --- a/drivers/target/iscsi/iscsi_target_auth.c +++ b/drivers/target/iscsi/iscsi_target_auth.c @@ -22,7 +22,7 @@ #include <linux/err.h> #include <linux/scatterlist.h> -#include "iscsi_target_core.h" +#include <target/iscsi/iscsi_target_core.h> #include "iscsi_target_nego.h" #include "iscsi_target_auth.h" diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index 9059c1e0b26e..48384b675e62 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -28,7 +28,7 @@ #include <target/configfs_macros.h> #include <target/iscsi/iscsi_transport.h> -#include "iscsi_target_core.h" +#include <target/iscsi/iscsi_target_core.h> #include "iscsi_target_parameters.h" #include "iscsi_target_device.h" #include "iscsi_target_erl0.h" @@ -36,7 +36,7 @@ #include "iscsi_target_tpg.h" #include "iscsi_target_util.h" #include "iscsi_target.h" -#include "iscsi_target_stat.h" +#include <target/iscsi/iscsi_target_stat.h> #include "iscsi_target_configfs.h" struct target_fabric_configfs *lio_target_fabric_configfs; @@ -674,12 +674,9 @@ static ssize_t lio_target_nacl_show_info( rb += sprintf(page+rb, "InitiatorAlias: %s\n", sess->sess_ops->InitiatorAlias); - rb += sprintf(page+rb, "LIO Session ID: %u " - "ISID: 0x%02x %02x %02x %02x %02x %02x " - "TSIH: %hu ", sess->sid, - sess->isid[0], sess->isid[1], sess->isid[2], - sess->isid[3], sess->isid[4], sess->isid[5], - sess->tsih); + rb += sprintf(page+rb, + "LIO Session ID: %u ISID: 0x%6ph TSIH: %hu ", + sess->sid, sess->isid, sess->tsih); rb += sprintf(page+rb, "SessionType: %s\n", (sess->sess_ops->SessionType) ? "Discovery" : "Normal"); @@ -1758,9 +1755,7 @@ static u32 lio_sess_get_initiator_sid( /* * iSCSI Initiator Session Identifier from RFC-3720. */ - return snprintf(buf, size, "%02x%02x%02x%02x%02x%02x", - sess->isid[0], sess->isid[1], sess->isid[2], - sess->isid[3], sess->isid[4], sess->isid[5]); + return snprintf(buf, size, "%6phN", sess->isid); } static int lio_queue_data_in(struct se_cmd *se_cmd) diff --git a/drivers/target/iscsi/iscsi_target_core.h b/drivers/target/iscsi/iscsi_target_core.h deleted file mode 100644 index cbcff38ac9b7..000000000000 --- a/drivers/target/iscsi/iscsi_target_core.h +++ /dev/null @@ -1,883 +0,0 @@ -#ifndef ISCSI_TARGET_CORE_H -#define ISCSI_TARGET_CORE_H - -#include <linux/in.h> -#include <linux/configfs.h> -#include <net/sock.h> -#include <net/tcp.h> -#include <scsi/scsi_cmnd.h> -#include <scsi/iscsi_proto.h> -#include <target/target_core_base.h> - -#define ISCSIT_VERSION "v4.1.0" -#define ISCSI_MAX_DATASN_MISSING_COUNT 16 -#define ISCSI_TX_THREAD_TCP_TIMEOUT 2 -#define ISCSI_RX_THREAD_TCP_TIMEOUT 2 -#define SECONDS_FOR_ASYNC_LOGOUT 10 -#define SECONDS_FOR_ASYNC_TEXT 10 -#define SECONDS_FOR_LOGOUT_COMP 15 -#define WHITE_SPACE " \t\v\f\n\r" -#define ISCSIT_MIN_TAGS 16 -#define ISCSIT_EXTRA_TAGS 8 -#define ISCSIT_TCP_BACKLOG 256 - -/* struct iscsi_node_attrib sanity values */ -#define NA_DATAOUT_TIMEOUT 3 -#define NA_DATAOUT_TIMEOUT_MAX 60 -#define NA_DATAOUT_TIMEOUT_MIX 2 -#define NA_DATAOUT_TIMEOUT_RETRIES 5 -#define NA_DATAOUT_TIMEOUT_RETRIES_MAX 15 -#define NA_DATAOUT_TIMEOUT_RETRIES_MIN 1 -#define NA_NOPIN_TIMEOUT 15 -#define NA_NOPIN_TIMEOUT_MAX 60 -#define NA_NOPIN_TIMEOUT_MIN 3 -#define NA_NOPIN_RESPONSE_TIMEOUT 30 -#define NA_NOPIN_RESPONSE_TIMEOUT_MAX 60 -#define NA_NOPIN_RESPONSE_TIMEOUT_MIN 3 -#define NA_RANDOM_DATAIN_PDU_OFFSETS 0 -#define NA_RANDOM_DATAIN_SEQ_OFFSETS 0 -#define NA_RANDOM_R2T_OFFSETS 0 - -/* struct iscsi_tpg_attrib sanity values */ -#define TA_AUTHENTICATION 1 -#define TA_LOGIN_TIMEOUT 15 -#define TA_LOGIN_TIMEOUT_MAX 30 -#define TA_LOGIN_TIMEOUT_MIN 5 -#define TA_NETIF_TIMEOUT 2 -#define TA_NETIF_TIMEOUT_MAX 15 -#define TA_NETIF_TIMEOUT_MIN 2 -#define TA_GENERATE_NODE_ACLS 0 -#define TA_DEFAULT_CMDSN_DEPTH 64 -#define TA_DEFAULT_CMDSN_DEPTH_MAX 512 -#define TA_DEFAULT_CMDSN_DEPTH_MIN 1 -#define TA_CACHE_DYNAMIC_ACLS 0 -/* Enabled by default in demo mode (generic_node_acls=1) */ -#define TA_DEMO_MODE_WRITE_PROTECT 1 -/* Disabled by default in production mode w/ explict ACLs */ -#define TA_PROD_MODE_WRITE_PROTECT 0 -#define TA_DEMO_MODE_DISCOVERY 1 -#define TA_DEFAULT_ERL 0 -#define TA_CACHE_CORE_NPS 0 -/* T10 protection information disabled by default */ -#define TA_DEFAULT_T10_PI 0 - -#define ISCSI_IOV_DATA_BUFFER 5 - -enum iscsit_transport_type { - ISCSI_TCP = 0, - ISCSI_SCTP_TCP = 1, - ISCSI_SCTP_UDP = 2, - ISCSI_IWARP_TCP = 3, - ISCSI_IWARP_SCTP = 4, - ISCSI_INFINIBAND = 5, -}; - -/* RFC-3720 7.1.4 Standard Connection State Diagram for a Target */ -enum target_conn_state_table { - TARG_CONN_STATE_FREE = 0x1, - TARG_CONN_STATE_XPT_UP = 0x3, - TARG_CONN_STATE_IN_LOGIN = 0x4, - TARG_CONN_STATE_LOGGED_IN = 0x5, - TARG_CONN_STATE_IN_LOGOUT = 0x6, - TARG_CONN_STATE_LOGOUT_REQUESTED = 0x7, - TARG_CONN_STATE_CLEANUP_WAIT = 0x8, -}; - -/* RFC-3720 7.3.2 Session State Diagram for a Target */ -enum target_sess_state_table { - TARG_SESS_STATE_FREE = 0x1, - TARG_SESS_STATE_ACTIVE = 0x2, - TARG_SESS_STATE_LOGGED_IN = 0x3, - TARG_SESS_STATE_FAILED = 0x4, - TARG_SESS_STATE_IN_CONTINUE = 0x5, -}; - -/* struct iscsi_data_count->type */ -enum data_count_type { - ISCSI_RX_DATA = 1, - ISCSI_TX_DATA = 2, -}; - -/* struct iscsi_datain_req->dr_complete */ -enum datain_req_comp_table { - DATAIN_COMPLETE_NORMAL = 1, - DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY = 2, - DATAIN_COMPLETE_CONNECTION_RECOVERY = 3, -}; - -/* struct iscsi_datain_req->recovery */ -enum datain_req_rec_table { - DATAIN_WITHIN_COMMAND_RECOVERY = 1, - DATAIN_CONNECTION_RECOVERY = 2, -}; - -/* struct iscsi_portal_group->state */ -enum tpg_state_table { - TPG_STATE_FREE = 0, - TPG_STATE_ACTIVE = 1, - TPG_STATE_INACTIVE = 2, - TPG_STATE_COLD_RESET = 3, -}; - -/* struct iscsi_tiqn->tiqn_state */ -enum tiqn_state_table { - TIQN_STATE_ACTIVE = 1, - TIQN_STATE_SHUTDOWN = 2, -}; - -/* struct iscsi_cmd->cmd_flags */ -enum cmd_flags_table { - ICF_GOT_LAST_DATAOUT = 0x00000001, - ICF_GOT_DATACK_SNACK = 0x00000002, - ICF_NON_IMMEDIATE_UNSOLICITED_DATA = 0x00000004, - ICF_SENT_LAST_R2T = 0x00000008, - ICF_WITHIN_COMMAND_RECOVERY = 0x00000010, - ICF_CONTIG_MEMORY = 0x00000020, - ICF_ATTACHED_TO_RQUEUE = 0x00000040, - ICF_OOO_CMDSN = 0x00000080, - ICF_SENDTARGETS_ALL = 0x00000100, - ICF_SENDTARGETS_SINGLE = 0x00000200, -}; - -/* struct iscsi_cmd->i_state */ -enum cmd_i_state_table { - ISTATE_NO_STATE = 0, - ISTATE_NEW_CMD = 1, - ISTATE_DEFERRED_CMD = 2, - ISTATE_UNSOLICITED_DATA = 3, - ISTATE_RECEIVE_DATAOUT = 4, - ISTATE_RECEIVE_DATAOUT_RECOVERY = 5, - ISTATE_RECEIVED_LAST_DATAOUT = 6, - ISTATE_WITHIN_DATAOUT_RECOVERY = 7, - ISTATE_IN_CONNECTION_RECOVERY = 8, - ISTATE_RECEIVED_TASKMGT = 9, - ISTATE_SEND_ASYNCMSG = 10, - ISTATE_SENT_ASYNCMSG = 11, - ISTATE_SEND_DATAIN = 12, - ISTATE_SEND_LAST_DATAIN = 13, - ISTATE_SENT_LAST_DATAIN = 14, - ISTATE_SEND_LOGOUTRSP = 15, - ISTATE_SENT_LOGOUTRSP = 16, - ISTATE_SEND_NOPIN = 17, - ISTATE_SENT_NOPIN = 18, - ISTATE_SEND_REJECT = 19, - ISTATE_SENT_REJECT = 20, - ISTATE_SEND_R2T = 21, - ISTATE_SENT_R2T = 22, - ISTATE_SEND_R2T_RECOVERY = 23, - ISTATE_SENT_R2T_RECOVERY = 24, - ISTATE_SEND_LAST_R2T = 25, - ISTATE_SENT_LAST_R2T = 26, - ISTATE_SEND_LAST_R2T_RECOVERY = 27, - ISTATE_SENT_LAST_R2T_RECOVERY = 28, - ISTATE_SEND_STATUS = 29, - ISTATE_SEND_STATUS_BROKEN_PC = 30, - ISTATE_SENT_STATUS = 31, - ISTATE_SEND_STATUS_RECOVERY = 32, - ISTATE_SENT_STATUS_RECOVERY = 33, - ISTATE_SEND_TASKMGTRSP = 34, - ISTATE_SENT_TASKMGTRSP = 35, - ISTATE_SEND_TEXTRSP = 36, - ISTATE_SENT_TEXTRSP = 37, - ISTATE_SEND_NOPIN_WANT_RESPONSE = 38, - ISTATE_SENT_NOPIN_WANT_RESPONSE = 39, - ISTATE_SEND_NOPIN_NO_RESPONSE = 40, - ISTATE_REMOVE = 41, - ISTATE_FREE = 42, -}; - -/* Used for iscsi_recover_cmdsn() return values */ -enum recover_cmdsn_ret_table { - CMDSN_ERROR_CANNOT_RECOVER = -1, - CMDSN_NORMAL_OPERATION = 0, - CMDSN_LOWER_THAN_EXP = 1, - CMDSN_HIGHER_THAN_EXP = 2, - CMDSN_MAXCMDSN_OVERRUN = 3, -}; - -/* Used for iscsi_handle_immediate_data() return values */ -enum immedate_data_ret_table { - IMMEDIATE_DATA_CANNOT_RECOVER = -1, - IMMEDIATE_DATA_NORMAL_OPERATION = 0, - IMMEDIATE_DATA_ERL1_CRC_FAILURE = 1, -}; - -/* Used for iscsi_decide_dataout_action() return values */ -enum dataout_action_ret_table { - DATAOUT_CANNOT_RECOVER = -1, - DATAOUT_NORMAL = 0, - DATAOUT_SEND_R2T = 1, - DATAOUT_SEND_TO_TRANSPORT = 2, - DATAOUT_WITHIN_COMMAND_RECOVERY = 3, -}; - -/* Used for struct iscsi_node_auth->naf_flags */ -enum naf_flags_table { - NAF_USERID_SET = 0x01, - NAF_PASSWORD_SET = 0x02, - NAF_USERID_IN_SET = 0x04, - NAF_PASSWORD_IN_SET = 0x08, -}; - -/* Used by various struct timer_list to manage iSCSI specific state */ -enum iscsi_timer_flags_table { - ISCSI_TF_RUNNING = 0x01, - ISCSI_TF_STOP = 0x02, - ISCSI_TF_EXPIRED = 0x04, -}; - -/* Used for struct iscsi_np->np_flags */ -enum np_flags_table { - NPF_IP_NETWORK = 0x00, -}; - -/* Used for struct iscsi_np->np_thread_state */ -enum np_thread_state_table { - ISCSI_NP_THREAD_ACTIVE = 1, - ISCSI_NP_THREAD_INACTIVE = 2, - ISCSI_NP_THREAD_RESET = 3, - ISCSI_NP_THREAD_SHUTDOWN = 4, - ISCSI_NP_THREAD_EXIT = 5, -}; - -struct iscsi_conn_ops { - u8 HeaderDigest; /* [0,1] == [None,CRC32C] */ - u8 DataDigest; /* [0,1] == [None,CRC32C] */ - u32 MaxRecvDataSegmentLength; /* [512..2**24-1] */ - u32 MaxXmitDataSegmentLength; /* [512..2**24-1] */ - u8 OFMarker; /* [0,1] == [No,Yes] */ - u8 IFMarker; /* [0,1] == [No,Yes] */ - u32 OFMarkInt; /* [1..65535] */ - u32 IFMarkInt; /* [1..65535] */ - /* - * iSER specific connection parameters - */ - u32 InitiatorRecvDataSegmentLength; /* [512..2**24-1] */ - u32 TargetRecvDataSegmentLength; /* [512..2**24-1] */ -}; - -struct iscsi_sess_ops { - char InitiatorName[224]; - char InitiatorAlias[256]; - char TargetName[224]; - char TargetAlias[256]; - char TargetAddress[256]; - u16 TargetPortalGroupTag; /* [0..65535] */ - u16 MaxConnections; /* [1..65535] */ - u8 InitialR2T; /* [0,1] == [No,Yes] */ - u8 ImmediateData; /* [0,1] == [No,Yes] */ - u32 MaxBurstLength; /* [512..2**24-1] */ - u32 FirstBurstLength; /* [512..2**24-1] */ - u16 DefaultTime2Wait; /* [0..3600] */ - u16 DefaultTime2Retain; /* [0..3600] */ - u16 MaxOutstandingR2T; /* [1..65535] */ - u8 DataPDUInOrder; /* [0,1] == [No,Yes] */ - u8 DataSequenceInOrder; /* [0,1] == [No,Yes] */ - u8 ErrorRecoveryLevel; /* [0..2] */ - u8 SessionType; /* [0,1] == [Normal,Discovery]*/ - /* - * iSER specific session parameters - */ - u8 RDMAExtensions; /* [0,1] == [No,Yes] */ -}; - -struct iscsi_queue_req { - int state; - struct iscsi_cmd *cmd; - struct list_head qr_list; -}; - -struct iscsi_data_count { - int data_length; - int sync_and_steering; - enum data_count_type type; - u32 iov_count; - u32 ss_iov_count; - u32 ss_marker_count; - struct kvec *iov; -}; - -struct iscsi_param_list { - bool iser; - struct list_head param_list; - struct list_head extra_response_list; -}; - -struct iscsi_datain_req { - enum datain_req_comp_table dr_complete; - int generate_recovery_values; - enum datain_req_rec_table recovery; - u32 begrun; - u32 runlength; - u32 data_length; - u32 data_offset; - u32 data_sn; - u32 next_burst_len; - u32 read_data_done; - u32 seq_send_order; - struct list_head cmd_datain_node; -} ____cacheline_aligned; - -struct iscsi_ooo_cmdsn { - u16 cid; - u32 batch_count; - u32 cmdsn; - u32 exp_cmdsn; - struct iscsi_cmd *cmd; - struct list_head ooo_list; -} ____cacheline_aligned; - -struct iscsi_datain { - u8 flags; - u32 data_sn; - u32 length; - u32 offset; -} ____cacheline_aligned; - -struct iscsi_r2t { - int seq_complete; - int recovery_r2t; - int sent_r2t; - u32 r2t_sn; - u32 offset; - u32 targ_xfer_tag; - u32 xfer_len; - struct list_head r2t_list; -} ____cacheline_aligned; - -struct iscsi_cmd { - enum iscsi_timer_flags_table dataout_timer_flags; - /* DataOUT timeout retries */ - u8 dataout_timeout_retries; - /* Within command recovery count */ - u8 error_recovery_count; - /* iSCSI dependent state for out or order CmdSNs */ - enum cmd_i_state_table deferred_i_state; - /* iSCSI dependent state */ - enum cmd_i_state_table i_state; - /* Command is an immediate command (ISCSI_OP_IMMEDIATE set) */ - u8 immediate_cmd; - /* Immediate data present */ - u8 immediate_data; - /* iSCSI Opcode */ - u8 iscsi_opcode; - /* iSCSI Response Code */ - u8 iscsi_response; - /* Logout reason when iscsi_opcode == ISCSI_INIT_LOGOUT_CMND */ - u8 logout_reason; - /* Logout response code when iscsi_opcode == ISCSI_INIT_LOGOUT_CMND */ - u8 logout_response; - /* MaxCmdSN has been incremented */ - u8 maxcmdsn_inc; - /* Immediate Unsolicited Dataout */ - u8 unsolicited_data; - /* Reject reason code */ - u8 reject_reason; - /* CID contained in logout PDU when opcode == ISCSI_INIT_LOGOUT_CMND */ - u16 logout_cid; - /* Command flags */ - enum cmd_flags_table cmd_flags; - /* Initiator Task Tag assigned from Initiator */ - itt_t init_task_tag; - /* Target Transfer Tag assigned from Target */ - u32 targ_xfer_tag; - /* CmdSN assigned from Initiator */ - u32 cmd_sn; - /* ExpStatSN assigned from Initiator */ - u32 exp_stat_sn; - /* StatSN assigned to this ITT */ - u32 stat_sn; - /* DataSN Counter */ - u32 data_sn; - /* R2TSN Counter */ - u32 r2t_sn; - /* Last DataSN acknowledged via DataAck SNACK */ - u32 acked_data_sn; - /* Used for echoing NOPOUT ping data */ - u32 buf_ptr_size; - /* Used to store DataDigest */ - u32 data_crc; - /* Counter for MaxOutstandingR2T */ - u32 outstanding_r2ts; - /* Next R2T Offset when DataSequenceInOrder=Yes */ - u32 r2t_offset; - /* Iovec current and orig count for iscsi_cmd->iov_data */ - u32 iov_data_count; - u32 orig_iov_data_count; - /* Number of miscellaneous iovecs used for IP stack calls */ - u32 iov_misc_count; - /* Number of struct iscsi_pdu in struct iscsi_cmd->pdu_list */ - u32 pdu_count; - /* Next struct iscsi_pdu to send in struct iscsi_cmd->pdu_list */ - u32 pdu_send_order; - /* Current struct iscsi_pdu in struct iscsi_cmd->pdu_list */ - u32 pdu_start; - /* Next struct iscsi_seq to send in struct iscsi_cmd->seq_list */ - u32 seq_send_order; - /* Number of struct iscsi_seq in struct iscsi_cmd->seq_list */ - u32 seq_count; - /* Current struct iscsi_seq in struct iscsi_cmd->seq_list */ - u32 seq_no; - /* Lowest offset in current DataOUT sequence */ - u32 seq_start_offset; - /* Highest offset in current DataOUT sequence */ - u32 seq_end_offset; - /* Total size in bytes received so far of READ data */ - u32 read_data_done; - /* Total size in bytes received so far of WRITE data */ - u32 write_data_done; - /* Counter for FirstBurstLength key */ - u32 first_burst_len; - /* Counter for MaxBurstLength key */ - u32 next_burst_len; - /* Transfer size used for IP stack calls */ - u32 tx_size; - /* Buffer used for various purposes */ - void *buf_ptr; - /* Used by SendTargets=[iqn.,eui.] discovery */ - void *text_in_ptr; - /* See include/linux/dma-mapping.h */ - enum dma_data_direction data_direction; - /* iSCSI PDU Header + CRC */ - unsigned char pdu[ISCSI_HDR_LEN + ISCSI_CRC_LEN]; - /* Number of times struct iscsi_cmd is present in immediate queue */ - atomic_t immed_queue_count; - atomic_t response_queue_count; - spinlock_t datain_lock; - spinlock_t dataout_timeout_lock; - /* spinlock for protecting struct iscsi_cmd->i_state */ - spinlock_t istate_lock; - /* spinlock for adding within command recovery entries */ - spinlock_t error_lock; - /* spinlock for adding R2Ts */ - spinlock_t r2t_lock; - /* DataIN List */ - struct list_head datain_list; - /* R2T List */ - struct list_head cmd_r2t_list; - /* Timer for DataOUT */ - struct timer_list dataout_timer; - /* Iovecs for SCSI data payload RX/TX w/ kernel level sockets */ - struct kvec *iov_data; - /* Iovecs for miscellaneous purposes */ -#define ISCSI_MISC_IOVECS 5 - struct kvec iov_misc[ISCSI_MISC_IOVECS]; - /* Array of struct iscsi_pdu used for DataPDUInOrder=No */ - struct iscsi_pdu *pdu_list; - /* Current struct iscsi_pdu used for DataPDUInOrder=No */ - struct iscsi_pdu *pdu_ptr; - /* Array of struct iscsi_seq used for DataSequenceInOrder=No */ - struct iscsi_seq *seq_list; - /* Current struct iscsi_seq used for DataSequenceInOrder=No */ - struct iscsi_seq *seq_ptr; - /* TMR Request when iscsi_opcode == ISCSI_OP_SCSI_TMFUNC */ - struct iscsi_tmr_req *tmr_req; - /* Connection this command is alligient to */ - struct iscsi_conn *conn; - /* Pointer to connection recovery entry */ - struct iscsi_conn_recovery *cr; - /* Session the command is part of, used for connection recovery */ - struct iscsi_session *sess; - /* list_head for connection list */ - struct list_head i_conn_node; - /* The TCM I/O descriptor that is accessed via container_of() */ - struct se_cmd se_cmd; - /* Sense buffer that will be mapped into outgoing status */ -#define ISCSI_SENSE_BUFFER_LEN (TRANSPORT_SENSE_BUFFER + 2) - unsigned char sense_buffer[ISCSI_SENSE_BUFFER_LEN]; - - u32 padding; - u8 pad_bytes[4]; - - struct scatterlist *first_data_sg; - u32 first_data_sg_off; - u32 kmapped_nents; - sense_reason_t sense_reason; -} ____cacheline_aligned; - -struct iscsi_tmr_req { - bool task_reassign:1; - u32 exp_data_sn; - struct iscsi_cmd *ref_cmd; - struct iscsi_conn_recovery *conn_recovery; - struct se_tmr_req *se_tmr_req; -}; - -struct iscsi_conn { - wait_queue_head_t queues_wq; - /* Authentication Successful for this connection */ - u8 auth_complete; - /* State connection is currently in */ - u8 conn_state; - u8 conn_logout_reason; - u8 network_transport; - enum iscsi_timer_flags_table nopin_timer_flags; - enum iscsi_timer_flags_table nopin_response_timer_flags; - /* Used to know what thread encountered a transport failure */ - u8 which_thread; - /* connection id assigned by the Initiator */ - u16 cid; - /* Remote TCP Port */ - u16 login_port; - u16 local_port; - int net_size; - int login_family; - u32 auth_id; - u32 conn_flags; - /* Used for iscsi_tx_login_rsp() */ - itt_t login_itt; - u32 exp_statsn; - /* Per connection status sequence number */ - u32 stat_sn; - /* IFMarkInt's Current Value */ - u32 if_marker; - /* OFMarkInt's Current Value */ - u32 of_marker; - /* Used for calculating OFMarker offset to next PDU */ - u32 of_marker_offset; -#define IPV6_ADDRESS_SPACE 48 - unsigned char login_ip[IPV6_ADDRESS_SPACE]; - unsigned char local_ip[IPV6_ADDRESS_SPACE]; - int conn_usage_count; - int conn_waiting_on_uc; - atomic_t check_immediate_queue; - atomic_t conn_logout_remove; - atomic_t connection_exit; - atomic_t connection_recovery; - atomic_t connection_reinstatement; - atomic_t connection_wait_rcfr; - atomic_t sleep_on_conn_wait_comp; - atomic_t transport_failed; - struct completion conn_post_wait_comp; - struct completion conn_wait_comp; - struct completion conn_wait_rcfr_comp; - struct completion conn_waiting_on_uc_comp; - struct completion conn_logout_comp; - struct completion tx_half_close_comp; - struct completion rx_half_close_comp; - /* socket used by this connection */ - struct socket *sock; - void (*orig_data_ready)(struct sock *); - void (*orig_state_change)(struct sock *); -#define LOGIN_FLAGS_READ_ACTIVE 1 -#define LOGIN_FLAGS_CLOSED 2 -#define LOGIN_FLAGS_READY 4 - unsigned long login_flags; - struct delayed_work login_work; - struct delayed_work login_cleanup_work; - struct iscsi_login *login; - struct timer_list nopin_timer; - struct timer_list nopin_response_timer; - struct timer_list transport_timer; - struct task_struct *login_kworker; - /* Spinlock used for add/deleting cmd's from conn_cmd_list */ - spinlock_t cmd_lock; - spinlock_t conn_usage_lock; - spinlock_t immed_queue_lock; - spinlock_t nopin_timer_lock; - spinlock_t response_queue_lock; - spinlock_t state_lock; - /* libcrypto RX and TX contexts for crc32c */ - struct hash_desc conn_rx_hash; - struct hash_desc conn_tx_hash; - /* Used for scheduling TX and RX connection kthreads */ - cpumask_var_t conn_cpumask; - unsigned int conn_rx_reset_cpumask:1; - unsigned int conn_tx_reset_cpumask:1; - /* list_head of struct iscsi_cmd for this connection */ - struct list_head conn_cmd_list; - struct list_head immed_queue_list; - struct list_head response_queue_list; - struct iscsi_conn_ops *conn_ops; - struct iscsi_login *conn_login; - struct iscsit_transport *conn_transport; - struct iscsi_param_list *param_list; - /* Used for per connection auth state machine */ - void *auth_protocol; - void *context; - struct iscsi_login_thread_s *login_thread; - struct iscsi_portal_group *tpg; - struct iscsi_tpg_np *tpg_np; - /* Pointer to parent session */ - struct iscsi_session *sess; - /* Pointer to thread_set in use for this conn's threads */ - struct iscsi_thread_set *thread_set; - /* list_head for session connection list */ - struct list_head conn_list; -} ____cacheline_aligned; - -struct iscsi_conn_recovery { - u16 cid; - u32 cmd_count; - u32 maxrecvdatasegmentlength; - u32 maxxmitdatasegmentlength; - int ready_for_reallegiance; - struct list_head conn_recovery_cmd_list; - spinlock_t conn_recovery_cmd_lock; - struct timer_list time2retain_timer; - struct iscsi_session *sess; - struct list_head cr_list; -} ____cacheline_aligned; - -struct iscsi_session { - u8 initiator_vendor; - u8 isid[6]; - enum iscsi_timer_flags_table time2retain_timer_flags; - u8 version_active; - u16 cid_called; - u16 conn_recovery_count; - u16 tsih; - /* state session is currently in */ - u32 session_state; - /* session wide counter: initiator assigned task tag */ - itt_t init_task_tag; - /* session wide counter: target assigned task tag */ - u32 targ_xfer_tag; - u32 cmdsn_window; - - /* protects cmdsn values */ - struct mutex cmdsn_mutex; - /* session wide counter: expected command sequence number */ - u32 exp_cmd_sn; - /* session wide counter: maximum allowed command sequence number */ - u32 max_cmd_sn; - struct list_head sess_ooo_cmdsn_list; - - /* LIO specific session ID */ - u32 sid; - char auth_type[8]; - /* unique within the target */ - int session_index; - /* Used for session reference counting */ - int session_usage_count; - int session_waiting_on_uc; - atomic_long_t cmd_pdus; - atomic_long_t rsp_pdus; - atomic_long_t tx_data_octets; - atomic_long_t rx_data_octets; - atomic_long_t conn_digest_errors; - atomic_long_t conn_timeout_errors; - u64 creation_time; - /* Number of active connections */ - atomic_t nconn; - atomic_t session_continuation; - atomic_t session_fall_back_to_erl0; - atomic_t session_logout; - atomic_t session_reinstatement; - atomic_t session_stop_active; - atomic_t sleep_on_sess_wait_comp; - /* connection list */ - struct list_head sess_conn_list; - struct list_head cr_active_list; - struct list_head cr_inactive_list; - spinlock_t conn_lock; - spinlock_t cr_a_lock; - spinlock_t cr_i_lock; - spinlock_t session_usage_lock; - spinlock_t ttt_lock; - struct completion async_msg_comp; - struct completion reinstatement_comp; - struct completion session_wait_comp; - struct completion session_waiting_on_uc_comp; - struct timer_list time2retain_timer; - struct iscsi_sess_ops *sess_ops; - struct se_session *se_sess; - struct iscsi_portal_group *tpg; -} ____cacheline_aligned; - -struct iscsi_login { - u8 auth_complete; - u8 checked_for_existing; - u8 current_stage; - u8 leading_connection; - u8 first_request; - u8 version_min; - u8 version_max; - u8 login_complete; - u8 login_failed; - bool zero_tsih; - char isid[6]; - u32 cmd_sn; - itt_t init_task_tag; - u32 initial_exp_statsn; - u32 rsp_length; - u16 cid; - u16 tsih; - char req[ISCSI_HDR_LEN]; - char rsp[ISCSI_HDR_LEN]; - char *req_buf; - char *rsp_buf; - struct iscsi_conn *conn; - struct iscsi_np *np; -} ____cacheline_aligned; - -struct iscsi_node_attrib { - u32 dataout_timeout; - u32 dataout_timeout_retries; - u32 default_erl; - u32 nopin_timeout; - u32 nopin_response_timeout; - u32 random_datain_pdu_offsets; - u32 random_datain_seq_offsets; - u32 random_r2t_offsets; - u32 tmr_cold_reset; - u32 tmr_warm_reset; - struct iscsi_node_acl *nacl; -}; - -struct se_dev_entry_s; - -struct iscsi_node_auth { - enum naf_flags_table naf_flags; - int authenticate_target; - /* Used for iscsit_global->discovery_auth, - * set to zero (auth disabled) by default */ - int enforce_discovery_auth; -#define MAX_USER_LEN 256 -#define MAX_PASS_LEN 256 - char userid[MAX_USER_LEN]; - char password[MAX_PASS_LEN]; - char userid_mutual[MAX_USER_LEN]; - char password_mutual[MAX_PASS_LEN]; -}; - -#include "iscsi_target_stat.h" - -struct iscsi_node_stat_grps { - struct config_group iscsi_sess_stats_group; - struct config_group iscsi_conn_stats_group; -}; - -struct iscsi_node_acl { - struct iscsi_node_attrib node_attrib; - struct iscsi_node_auth node_auth; - struct iscsi_node_stat_grps node_stat_grps; - struct se_node_acl se_node_acl; -}; - -struct iscsi_tpg_attrib { - u32 authentication; - u32 login_timeout; - u32 netif_timeout; - u32 generate_node_acls; - u32 cache_dynamic_acls; - u32 default_cmdsn_depth; - u32 demo_mode_write_protect; - u32 prod_mode_write_protect; - u32 demo_mode_discovery; - u32 default_erl; - u8 t10_pi; - struct iscsi_portal_group *tpg; -}; - -struct iscsi_np { - int np_network_transport; - int np_ip_proto; - int np_sock_type; - enum np_thread_state_table np_thread_state; - bool enabled; - enum iscsi_timer_flags_table np_login_timer_flags; - u32 np_exports; - enum np_flags_table np_flags; - unsigned char np_ip[IPV6_ADDRESS_SPACE]; - u16 np_port; - spinlock_t np_thread_lock; - struct completion np_restart_comp; - struct socket *np_socket; - struct __kernel_sockaddr_storage np_sockaddr; - struct task_struct *np_thread; - struct timer_list np_login_timer; - void *np_context; - struct iscsit_transport *np_transport; - struct list_head np_list; -} ____cacheline_aligned; - -struct iscsi_tpg_np { - struct iscsi_np *tpg_np; - struct iscsi_portal_group *tpg; - struct iscsi_tpg_np *tpg_np_parent; - struct list_head tpg_np_list; - struct list_head tpg_np_child_list; - struct list_head tpg_np_parent_list; - struct se_tpg_np se_tpg_np; - spinlock_t tpg_np_parent_lock; - struct completion tpg_np_comp; - struct kref tpg_np_kref; -}; - -struct iscsi_portal_group { - unsigned char tpg_chap_id; - /* TPG State */ - enum tpg_state_table tpg_state; - /* Target Portal Group Tag */ - u16 tpgt; - /* Id assigned to target sessions */ - u16 ntsih; - /* Number of active sessions */ - u32 nsessions; - /* Number of Network Portals available for this TPG */ - u32 num_tpg_nps; - /* Per TPG LIO specific session ID. */ - u32 sid; - /* Spinlock for adding/removing Network Portals */ - spinlock_t tpg_np_lock; - spinlock_t tpg_state_lock; - struct se_portal_group tpg_se_tpg; - struct mutex tpg_access_lock; - struct semaphore np_login_sem; - struct iscsi_tpg_attrib tpg_attrib; - struct iscsi_node_auth tpg_demo_auth; - /* Pointer to default list of iSCSI parameters for TPG */ - struct iscsi_param_list *param_list; - struct iscsi_tiqn *tpg_tiqn; - struct list_head tpg_gnp_list; - struct list_head tpg_list; -} ____cacheline_aligned; - -struct iscsi_wwn_stat_grps { - struct config_group iscsi_stat_group; - struct config_group iscsi_instance_group; - struct config_group iscsi_sess_err_group; - struct config_group iscsi_tgt_attr_group; - struct config_group iscsi_login_stats_group; - struct config_group iscsi_logout_stats_group; -}; - -struct iscsi_tiqn { -#define ISCSI_IQN_LEN 224 - unsigned char tiqn[ISCSI_IQN_LEN]; - enum tiqn_state_table tiqn_state; - int tiqn_access_count; - u32 tiqn_active_tpgs; - u32 tiqn_ntpgs; - u32 tiqn_num_tpg_nps; - u32 tiqn_nsessions; - struct list_head tiqn_list; - struct list_head tiqn_tpg_list; - spinlock_t tiqn_state_lock; - spinlock_t tiqn_tpg_lock; - struct se_wwn tiqn_wwn; - struct iscsi_wwn_stat_grps tiqn_stat_grps; - int tiqn_index; - struct iscsi_sess_err_stats sess_err_stats; - struct iscsi_login_stats login_stats; - struct iscsi_logout_stats logout_stats; -} ____cacheline_aligned; - -struct iscsit_global { - /* In core shutdown */ - u32 in_shutdown; - u32 active_ts; - /* Unique identifier used for the authentication daemon */ - u32 auth_id; - u32 inactive_ts; - /* Thread Set bitmap count */ - int ts_bitmap_count; - /* Thread Set bitmap pointer */ - unsigned long *ts_bitmap; - /* Used for iSCSI discovery session authentication */ - struct iscsi_node_acl discovery_acl; - struct iscsi_portal_group *discovery_tpg; -}; - -#endif /* ISCSI_TARGET_CORE_H */ diff --git a/drivers/target/iscsi/iscsi_target_datain_values.c b/drivers/target/iscsi/iscsi_target_datain_values.c index e93d5a7a3f81..fb3b52b124ac 100644 --- a/drivers/target/iscsi/iscsi_target_datain_values.c +++ b/drivers/target/iscsi/iscsi_target_datain_values.c @@ -18,7 +18,7 @@ #include <scsi/iscsi_proto.h> -#include "iscsi_target_core.h" +#include <target/iscsi/iscsi_target_core.h> #include "iscsi_target_seq_pdu_list.h" #include "iscsi_target_erl1.h" #include "iscsi_target_util.h" diff --git a/drivers/target/iscsi/iscsi_target_device.c b/drivers/target/iscsi/iscsi_target_device.c index 7087c736daa5..34c3cd1b05ce 100644 --- a/drivers/target/iscsi/iscsi_target_device.c +++ b/drivers/target/iscsi/iscsi_target_device.c @@ -21,7 +21,7 @@ #include <target/target_core_base.h> #include <target/target_core_fabric.h> -#include "iscsi_target_core.h" +#include <target/iscsi/iscsi_target_core.h> #include "iscsi_target_device.h" #include "iscsi_target_tpg.h" #include "iscsi_target_util.h" diff --git a/drivers/target/iscsi/iscsi_target_erl0.c b/drivers/target/iscsi/iscsi_target_erl0.c index a0ae5fc0ad75..1c197bad6132 100644 --- a/drivers/target/iscsi/iscsi_target_erl0.c +++ b/drivers/target/iscsi/iscsi_target_erl0.c @@ -21,7 +21,8 @@ #include <target/target_core_base.h> #include <target/target_core_fabric.h> -#include "iscsi_target_core.h" +#include <target/iscsi/iscsi_target_core.h> +#include <target/iscsi/iscsi_transport.h> #include "iscsi_target_seq_pdu_list.h" #include "iscsi_target_tq.h" #include "iscsi_target_erl0.h" @@ -939,7 +940,8 @@ void iscsit_take_action_for_connection_exit(struct iscsi_conn *conn) if (conn->conn_state == TARG_CONN_STATE_IN_LOGOUT) { spin_unlock_bh(&conn->state_lock); - iscsit_close_connection(conn); + if (conn->conn_transport->transport_type == ISCSI_TCP) + iscsit_close_connection(conn); return; } diff --git a/drivers/target/iscsi/iscsi_target_erl1.c b/drivers/target/iscsi/iscsi_target_erl1.c index cda4d80cfaef..2e561deb30a2 100644 --- a/drivers/target/iscsi/iscsi_target_erl1.c +++ b/drivers/target/iscsi/iscsi_target_erl1.c @@ -22,7 +22,7 @@ #include <target/target_core_fabric.h> #include <target/iscsi/iscsi_transport.h> -#include "iscsi_target_core.h" +#include <target/iscsi/iscsi_target_core.h> #include "iscsi_target_seq_pdu_list.h" #include "iscsi_target_datain_values.h" #include "iscsi_target_device.h" diff --git a/drivers/target/iscsi/iscsi_target_erl2.c b/drivers/target/iscsi/iscsi_target_erl2.c index 4ca8fd2a70db..e24f1c7c5862 100644 --- a/drivers/target/iscsi/iscsi_target_erl2.c +++ b/drivers/target/iscsi/iscsi_target_erl2.c @@ -21,7 +21,7 @@ #include <target/target_core_base.h> #include <target/target_core_fabric.h> -#include "iscsi_target_core.h" +#include <target/iscsi/iscsi_target_core.h> #include "iscsi_target_datain_values.h" #include "iscsi_target_util.h" #include "iscsi_target_erl0.h" diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index 713c0c1877ab..153fb66ac1b8 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c @@ -24,14 +24,14 @@ #include <target/target_core_base.h> #include <target/target_core_fabric.h> -#include "iscsi_target_core.h" +#include <target/iscsi/iscsi_target_core.h> +#include <target/iscsi/iscsi_target_stat.h> #include "iscsi_target_tq.h" #include "iscsi_target_device.h" #include "iscsi_target_nego.h" #include "iscsi_target_erl0.h" #include "iscsi_target_erl2.h" #include "iscsi_target_login.h" -#include "iscsi_target_stat.h" #include "iscsi_target_tpg.h" #include "iscsi_target_util.h" #include "iscsi_target.h" diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c index 62a095f36bf2..8c02fa34716f 100644 --- a/drivers/target/iscsi/iscsi_target_nego.c +++ b/drivers/target/iscsi/iscsi_target_nego.c @@ -22,7 +22,7 @@ #include <target/target_core_fabric.h> #include <target/iscsi/iscsi_transport.h> -#include "iscsi_target_core.h" +#include <target/iscsi/iscsi_target_core.h> #include "iscsi_target_parameters.h" #include "iscsi_target_login.h" #include "iscsi_target_nego.h" diff --git a/drivers/target/iscsi/iscsi_target_nodeattrib.c b/drivers/target/iscsi/iscsi_target_nodeattrib.c index 16454a922e2b..208cca8a363c 100644 --- a/drivers/target/iscsi/iscsi_target_nodeattrib.c +++ b/drivers/target/iscsi/iscsi_target_nodeattrib.c @@ -18,7 +18,7 @@ #include <target/target_core_base.h> -#include "iscsi_target_core.h" +#include <target/iscsi/iscsi_target_core.h> #include "iscsi_target_device.h" #include "iscsi_target_tpg.h" #include "iscsi_target_util.h" diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c index 18c29260b4a2..d4f9e9645697 100644 --- a/drivers/target/iscsi/iscsi_target_parameters.c +++ b/drivers/target/iscsi/iscsi_target_parameters.c @@ -18,7 +18,7 @@ #include <linux/slab.h> -#include "iscsi_target_core.h" +#include <target/iscsi/iscsi_target_core.h> #include "iscsi_target_util.h" #include "iscsi_target_parameters.h" diff --git a/drivers/target/iscsi/iscsi_target_seq_pdu_list.c b/drivers/target/iscsi/iscsi_target_seq_pdu_list.c index ca41b583f2f6..e446a09c886b 100644 --- a/drivers/target/iscsi/iscsi_target_seq_pdu_list.c +++ b/drivers/target/iscsi/iscsi_target_seq_pdu_list.c @@ -20,7 +20,7 @@ #include <linux/slab.h> #include <linux/random.h> -#include "iscsi_target_core.h" +#include <target/iscsi/iscsi_target_core.h> #include "iscsi_target_util.h" #include "iscsi_target_tpg.h" #include "iscsi_target_seq_pdu_list.h" diff --git a/drivers/target/iscsi/iscsi_target_stat.c b/drivers/target/iscsi/iscsi_target_stat.c index 103395510307..5e1349a3b143 100644 --- a/drivers/target/iscsi/iscsi_target_stat.c +++ b/drivers/target/iscsi/iscsi_target_stat.c @@ -23,12 +23,12 @@ #include <target/target_core_base.h> #include <target/configfs_macros.h> -#include "iscsi_target_core.h" +#include <target/iscsi/iscsi_target_core.h> #include "iscsi_target_parameters.h" #include "iscsi_target_device.h" #include "iscsi_target_tpg.h" #include "iscsi_target_util.h" -#include "iscsi_target_stat.h" +#include <target/iscsi/iscsi_target_stat.h> #ifndef INITIAL_JIFFIES #define INITIAL_JIFFIES ((unsigned long)(unsigned int) (-300*HZ)) diff --git a/drivers/target/iscsi/iscsi_target_stat.h b/drivers/target/iscsi/iscsi_target_stat.h deleted file mode 100644 index 3ff76b4faad3..000000000000 --- a/drivers/target/iscsi/iscsi_target_stat.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef ISCSI_TARGET_STAT_H -#define ISCSI_TARGET_STAT_H - -/* - * For struct iscsi_tiqn->tiqn_wwn default groups - */ -extern struct config_item_type iscsi_stat_instance_cit; -extern struct config_item_type iscsi_stat_sess_err_cit; -extern struct config_item_type iscsi_stat_tgt_attr_cit; -extern struct config_item_type iscsi_stat_login_cit; -extern struct config_item_type iscsi_stat_logout_cit; - -/* - * For struct iscsi_session->se_sess default groups - */ -extern struct config_item_type iscsi_stat_sess_cit; - -/* iSCSI session error types */ -#define ISCSI_SESS_ERR_UNKNOWN 0 -#define ISCSI_SESS_ERR_DIGEST 1 -#define ISCSI_SESS_ERR_CXN_TIMEOUT 2 -#define ISCSI_SESS_ERR_PDU_FORMAT 3 - -/* iSCSI session error stats */ -struct iscsi_sess_err_stats { - spinlock_t lock; - u32 digest_errors; - u32 cxn_timeout_errors; - u32 pdu_format_errors; - u32 last_sess_failure_type; - char last_sess_fail_rem_name[224]; -} ____cacheline_aligned; - -/* iSCSI login failure types (sub oids) */ -#define ISCSI_LOGIN_FAIL_OTHER 2 -#define ISCSI_LOGIN_FAIL_REDIRECT 3 -#define ISCSI_LOGIN_FAIL_AUTHORIZE 4 -#define ISCSI_LOGIN_FAIL_AUTHENTICATE 5 -#define ISCSI_LOGIN_FAIL_NEGOTIATE 6 - -/* iSCSI login stats */ -struct iscsi_login_stats { - spinlock_t lock; - u32 accepts; - u32 other_fails; - u32 redirects; - u32 authorize_fails; - u32 authenticate_fails; - u32 negotiate_fails; /* used for notifications */ - u64 last_fail_time; /* time stamp (jiffies) */ - u32 last_fail_type; - int last_intr_fail_ip_family; - unsigned char last_intr_fail_ip_addr[IPV6_ADDRESS_SPACE]; - char last_intr_fail_name[224]; -} ____cacheline_aligned; - -/* iSCSI logout stats */ -struct iscsi_logout_stats { - spinlock_t lock; - u32 normal_logouts; - u32 abnormal_logouts; -} ____cacheline_aligned; - -#endif /*** ISCSI_TARGET_STAT_H ***/ diff --git a/drivers/target/iscsi/iscsi_target_tmr.c b/drivers/target/iscsi/iscsi_target_tmr.c index 78404b1cc0bf..b0224a77e26d 100644 --- a/drivers/target/iscsi/iscsi_target_tmr.c +++ b/drivers/target/iscsi/iscsi_target_tmr.c @@ -23,7 +23,7 @@ #include <target/target_core_fabric.h> #include <target/iscsi/iscsi_transport.h> -#include "iscsi_target_core.h" +#include <target/iscsi/iscsi_target_core.h> #include "iscsi_target_seq_pdu_list.h" #include "iscsi_target_datain_values.h" #include "iscsi_target_device.h" diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c index 9053a3c0c6e5..bdd127c0e3ae 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.c +++ b/drivers/target/iscsi/iscsi_target_tpg.c @@ -20,7 +20,7 @@ #include <target/target_core_fabric.h> #include <target/target_core_configfs.h> -#include "iscsi_target_core.h" +#include <target/iscsi/iscsi_target_core.h> #include "iscsi_target_erl0.h" #include "iscsi_target_login.h" #include "iscsi_target_nodeattrib.h" diff --git a/drivers/target/iscsi/iscsi_target_tq.c b/drivers/target/iscsi/iscsi_target_tq.c index 601e9cc61e98..26aa50996473 100644 --- a/drivers/target/iscsi/iscsi_target_tq.c +++ b/drivers/target/iscsi/iscsi_target_tq.c @@ -20,40 +20,26 @@ #include <linux/list.h> #include <linux/bitmap.h> -#include "iscsi_target_core.h" +#include <target/iscsi/iscsi_target_core.h> #include "iscsi_target_tq.h" #include "iscsi_target.h" -static LIST_HEAD(active_ts_list); static LIST_HEAD(inactive_ts_list); -static DEFINE_SPINLOCK(active_ts_lock); static DEFINE_SPINLOCK(inactive_ts_lock); static DEFINE_SPINLOCK(ts_bitmap_lock); -static void iscsi_add_ts_to_active_list(struct iscsi_thread_set *ts) -{ - spin_lock(&active_ts_lock); - list_add_tail(&ts->ts_list, &active_ts_list); - iscsit_global->active_ts++; - spin_unlock(&active_ts_lock); -} - static void iscsi_add_ts_to_inactive_list(struct iscsi_thread_set *ts) { + if (!list_empty(&ts->ts_list)) { + WARN_ON(1); + return; + } spin_lock(&inactive_ts_lock); list_add_tail(&ts->ts_list, &inactive_ts_list); iscsit_global->inactive_ts++; spin_unlock(&inactive_ts_lock); } -static void iscsi_del_ts_from_active_list(struct iscsi_thread_set *ts) -{ - spin_lock(&active_ts_lock); - list_del(&ts->ts_list); - iscsit_global->active_ts--; - spin_unlock(&active_ts_lock); -} - static struct iscsi_thread_set *iscsi_get_ts_from_inactive_list(void) { struct iscsi_thread_set *ts; @@ -66,7 +52,7 @@ static struct iscsi_thread_set *iscsi_get_ts_from_inactive_list(void) ts = list_first_entry(&inactive_ts_list, struct iscsi_thread_set, ts_list); - list_del(&ts->ts_list); + list_del_init(&ts->ts_list); iscsit_global->inactive_ts--; spin_unlock(&inactive_ts_lock); @@ -204,8 +190,6 @@ static void iscsi_deallocate_extra_thread_sets(void) void iscsi_activate_thread_set(struct iscsi_conn *conn, struct iscsi_thread_set *ts) { - iscsi_add_ts_to_active_list(ts); - spin_lock_bh(&ts->ts_state_lock); conn->thread_set = ts; ts->conn = conn; @@ -397,7 +381,6 @@ struct iscsi_conn *iscsi_rx_thread_pre_handler(struct iscsi_thread_set *ts) if (ts->delay_inactive && (--ts->thread_count == 0)) { spin_unlock_bh(&ts->ts_state_lock); - iscsi_del_ts_from_active_list(ts); if (!iscsit_global->in_shutdown) iscsi_deallocate_extra_thread_sets(); @@ -452,7 +435,6 @@ struct iscsi_conn *iscsi_tx_thread_pre_handler(struct iscsi_thread_set *ts) if (ts->delay_inactive && (--ts->thread_count == 0)) { spin_unlock_bh(&ts->ts_state_lock); - iscsi_del_ts_from_active_list(ts); if (!iscsit_global->in_shutdown) iscsi_deallocate_extra_thread_sets(); diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index bcd88ec99793..390df8ed72b2 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c @@ -25,7 +25,7 @@ #include <target/target_core_configfs.h> #include <target/iscsi/iscsi_transport.h> -#include "iscsi_target_core.h" +#include <target/iscsi/iscsi_target_core.h> #include "iscsi_target_parameters.h" #include "iscsi_target_seq_pdu_list.h" #include "iscsi_target_datain_values.h" @@ -390,6 +390,7 @@ struct iscsi_cmd *iscsit_find_cmd_from_itt( init_task_tag, conn->cid); return NULL; } +EXPORT_SYMBOL(iscsit_find_cmd_from_itt); struct iscsi_cmd *iscsit_find_cmd_from_itt_or_dump( struct iscsi_conn *conn, @@ -939,13 +940,8 @@ static int iscsit_add_nopin(struct iscsi_conn *conn, int want_response) state = (want_response) ? ISTATE_SEND_NOPIN_WANT_RESPONSE : ISTATE_SEND_NOPIN_NO_RESPONSE; cmd->init_task_tag = RESERVED_ITT; - spin_lock_bh(&conn->sess->ttt_lock); - cmd->targ_xfer_tag = (want_response) ? conn->sess->targ_xfer_tag++ : - 0xFFFFFFFF; - if (want_response && (cmd->targ_xfer_tag == 0xFFFFFFFF)) - cmd->targ_xfer_tag = conn->sess->targ_xfer_tag++; - spin_unlock_bh(&conn->sess->ttt_lock); - + cmd->targ_xfer_tag = (want_response) ? + session_get_next_ttt(conn->sess) : 0xFFFFFFFF; spin_lock_bh(&conn->cmd_lock); list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list); spin_unlock_bh(&conn->cmd_lock); diff --git a/drivers/target/iscsi/iscsi_target_util.h b/drivers/target/iscsi/iscsi_target_util.h index a68508c4fec8..1ab754a671ff 100644 --- a/drivers/target/iscsi/iscsi_target_util.h +++ b/drivers/target/iscsi/iscsi_target_util.h @@ -16,7 +16,6 @@ extern struct iscsi_r2t *iscsit_get_holder_for_r2tsn(struct iscsi_cmd *, u32); extern int iscsit_sequence_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, unsigned char * ,__be32 cmdsn); extern int iscsit_check_unsolicited_dataout(struct iscsi_cmd *, unsigned char *); -extern struct iscsi_cmd *iscsit_find_cmd_from_itt(struct iscsi_conn *, itt_t); extern struct iscsi_cmd *iscsit_find_cmd_from_itt_or_dump(struct iscsi_conn *, itt_t, u32); extern struct iscsi_cmd *iscsit_find_cmd_from_ttt(struct iscsi_conn *, u32); diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index d836de200a03..44620fb6bd45 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -494,6 +494,11 @@ fd_execute_write_same(struct se_cmd *cmd) target_complete_cmd(cmd, SAM_STAT_GOOD); return 0; } + if (cmd->prot_op) { + pr_err("WRITE_SAME: Protection information with FILEIO" + " backends not supported\n"); + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + } sg = &cmd->t_data_sg[0]; if (cmd->t_data_nents > 1 || diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index 78346b850968..d4a4b0fb444a 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -464,6 +464,11 @@ iblock_execute_write_same(struct se_cmd *cmd) sector_t block_lba = cmd->t_task_lba; sector_t sectors = sbc_get_write_same_sectors(cmd); + if (cmd->prot_op) { + pr_err("WRITE_SAME: Protection information with IBLOCK" + " backends not supported\n"); + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + } sg = &cmd->t_data_sg[0]; if (cmd->t_data_nents > 1 || diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 283cf786ef98..2de6fb8cee8d 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -1874,8 +1874,8 @@ static int core_scsi3_update_aptpl_buf( } if ((len + strlen(tmp) >= pr_aptpl_buf_len)) { - pr_err("Unable to update renaming" - " APTPL metadata\n"); + pr_err("Unable to update renaming APTPL metadata," + " reallocating larger buffer\n"); ret = -EMSGSIZE; goto out; } @@ -1892,8 +1892,8 @@ static int core_scsi3_update_aptpl_buf( lun->lun_sep->sep_rtpi, lun->unpacked_lun, reg_count); if ((len + strlen(tmp) >= pr_aptpl_buf_len)) { - pr_err("Unable to update renaming" - " APTPL metadata\n"); + pr_err("Unable to update renaming APTPL metadata," + " reallocating larger buffer\n"); ret = -EMSGSIZE; goto out; } @@ -1956,7 +1956,7 @@ static int __core_scsi3_write_aptpl_to_file( static sense_reason_t core_scsi3_update_and_write_aptpl(struct se_device *dev, bool aptpl) { unsigned char *buf; - int rc; + int rc, len = PR_APTPL_BUF_LEN; if (!aptpl) { char *null_buf = "No Registrations or Reservations\n"; @@ -1970,25 +1970,26 @@ static sense_reason_t core_scsi3_update_and_write_aptpl(struct se_device *dev, b return 0; } - - buf = kzalloc(PR_APTPL_BUF_LEN, GFP_KERNEL); +retry: + buf = vzalloc(len); if (!buf) return TCM_OUT_OF_RESOURCES; - rc = core_scsi3_update_aptpl_buf(dev, buf, PR_APTPL_BUF_LEN); + rc = core_scsi3_update_aptpl_buf(dev, buf, len); if (rc < 0) { - kfree(buf); - return TCM_OUT_OF_RESOURCES; + vfree(buf); + len *= 2; + goto retry; } rc = __core_scsi3_write_aptpl_to_file(dev, buf); if (rc != 0) { pr_err("SPC-3 PR: Could not update APTPL\n"); - kfree(buf); + vfree(buf); return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } dev->t10_pr.pr_aptpl_active = 1; - kfree(buf); + vfree(buf); pr_debug("SPC-3 PR: Set APTPL Bit Activated\n"); return 0; } diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index cd4bed7b2757..9a2f9d3a6e70 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -37,6 +37,9 @@ #include "target_core_alua.h" static sense_reason_t +sbc_check_prot(struct se_device *, struct se_cmd *, unsigned char *, u32, bool); + +static sense_reason_t sbc_emulate_readcapacity(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; @@ -251,7 +254,10 @@ static inline unsigned long long transport_lba_64_ext(unsigned char *cdb) static sense_reason_t sbc_setup_write_same(struct se_cmd *cmd, unsigned char *flags, struct sbc_ops *ops) { + struct se_device *dev = cmd->se_dev; + sector_t end_lba = dev->transport->get_blocks(dev) + 1; unsigned int sectors = sbc_get_write_same_sectors(cmd); + sense_reason_t ret; if ((flags[0] & 0x04) || (flags[0] & 0x02)) { pr_err("WRITE_SAME PBDATA and LBDATA" @@ -264,6 +270,16 @@ sbc_setup_write_same(struct se_cmd *cmd, unsigned char *flags, struct sbc_ops *o sectors, cmd->se_dev->dev_attrib.max_write_same_len); return TCM_INVALID_CDB_FIELD; } + /* + * Sanity check for LBA wrap and request past end of device. + */ + if (((cmd->t_task_lba + sectors) < cmd->t_task_lba) || + ((cmd->t_task_lba + sectors) > end_lba)) { + pr_err("WRITE_SAME exceeds last lba %llu (lba %llu, sectors %u)\n", + (unsigned long long)end_lba, cmd->t_task_lba, sectors); + return TCM_ADDRESS_OUT_OF_RANGE; + } + /* We always have ANC_SUP == 0 so setting ANCHOR is always an error */ if (flags[0] & 0x10) { pr_warn("WRITE SAME with ANCHOR not supported\n"); @@ -277,12 +293,21 @@ sbc_setup_write_same(struct se_cmd *cmd, unsigned char *flags, struct sbc_ops *o if (!ops->execute_write_same_unmap) return TCM_UNSUPPORTED_SCSI_OPCODE; + if (!dev->dev_attrib.emulate_tpws) { + pr_err("Got WRITE_SAME w/ UNMAP=1, but backend device" + " has emulate_tpws disabled\n"); + return TCM_UNSUPPORTED_SCSI_OPCODE; + } cmd->execute_cmd = ops->execute_write_same_unmap; return 0; } if (!ops->execute_write_same) return TCM_UNSUPPORTED_SCSI_OPCODE; + ret = sbc_check_prot(dev, cmd, &cmd->t_task_cdb[0], sectors, true); + if (ret) + return ret; + cmd->execute_cmd = ops->execute_write_same; return 0; } @@ -614,14 +639,21 @@ sbc_set_prot_op_checks(u8 protect, enum target_prot_type prot_type, return 0; } -static bool +static sense_reason_t sbc_check_prot(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb, u32 sectors, bool is_write) { u8 protect = cdb[1] >> 5; - if ((!cmd->t_prot_sg || !cmd->t_prot_nents) && cmd->prot_pto) - return true; + if (!cmd->t_prot_sg || !cmd->t_prot_nents) { + if (protect && !dev->dev_attrib.pi_prot_type) { + pr_err("CDB contains protect bit, but device does not" + " advertise PROTECT=1 feature bit\n"); + return TCM_INVALID_CDB_FIELD; + } + if (cmd->prot_pto) + return TCM_NO_SENSE; + } switch (dev->dev_attrib.pi_prot_type) { case TARGET_DIF_TYPE3_PROT: @@ -629,7 +661,7 @@ sbc_check_prot(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb, break; case TARGET_DIF_TYPE2_PROT: if (protect) - return false; + return TCM_INVALID_CDB_FIELD; cmd->reftag_seed = cmd->t_task_lba; break; @@ -638,12 +670,12 @@ sbc_check_prot(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb, break; case TARGET_DIF_TYPE0_PROT: default: - return true; + return TCM_NO_SENSE; } if (sbc_set_prot_op_checks(protect, dev->dev_attrib.pi_prot_type, is_write, cmd)) - return false; + return TCM_INVALID_CDB_FIELD; cmd->prot_type = dev->dev_attrib.pi_prot_type; cmd->prot_length = dev->prot_length * sectors; @@ -662,7 +694,30 @@ sbc_check_prot(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb, __func__, cmd->prot_type, cmd->data_length, cmd->prot_length, cmd->prot_op, cmd->prot_checks); - return true; + return TCM_NO_SENSE; +} + +static int +sbc_check_dpofua(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb) +{ + if (cdb[1] & 0x10) { + if (!dev->dev_attrib.emulate_dpo) { + pr_err("Got CDB: 0x%02x with DPO bit set, but device" + " does not advertise support for DPO\n", cdb[0]); + return -EINVAL; + } + } + if (cdb[1] & 0x8) { + if (!dev->dev_attrib.emulate_fua_write || + !dev->dev_attrib.emulate_write_cache) { + pr_err("Got CDB: 0x%02x with FUA bit set, but device" + " does not advertise support for FUA write\n", + cdb[0]); + return -EINVAL; + } + cmd->se_cmd_flags |= SCF_FUA; + } + return 0; } sense_reason_t @@ -686,8 +741,12 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) sectors = transport_get_sectors_10(cdb); cmd->t_task_lba = transport_lba_32(cdb); - if (!sbc_check_prot(dev, cmd, cdb, sectors, false)) - return TCM_UNSUPPORTED_SCSI_OPCODE; + if (sbc_check_dpofua(dev, cmd, cdb)) + return TCM_INVALID_CDB_FIELD; + + ret = sbc_check_prot(dev, cmd, cdb, sectors, false); + if (ret) + return ret; cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; cmd->execute_rw = ops->execute_rw; @@ -697,8 +756,12 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) sectors = transport_get_sectors_12(cdb); cmd->t_task_lba = transport_lba_32(cdb); - if (!sbc_check_prot(dev, cmd, cdb, sectors, false)) - return TCM_UNSUPPORTED_SCSI_OPCODE; + if (sbc_check_dpofua(dev, cmd, cdb)) + return TCM_INVALID_CDB_FIELD; + + ret = sbc_check_prot(dev, cmd, cdb, sectors, false); + if (ret) + return ret; cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; cmd->execute_rw = ops->execute_rw; @@ -708,8 +771,12 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) sectors = transport_get_sectors_16(cdb); cmd->t_task_lba = transport_lba_64(cdb); - if (!sbc_check_prot(dev, cmd, cdb, sectors, false)) - return TCM_UNSUPPORTED_SCSI_OPCODE; + if (sbc_check_dpofua(dev, cmd, cdb)) + return TCM_INVALID_CDB_FIELD; + + ret = sbc_check_prot(dev, cmd, cdb, sectors, false); + if (ret) + return ret; cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; cmd->execute_rw = ops->execute_rw; @@ -727,11 +794,13 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) sectors = transport_get_sectors_10(cdb); cmd->t_task_lba = transport_lba_32(cdb); - if (!sbc_check_prot(dev, cmd, cdb, sectors, true)) - return TCM_UNSUPPORTED_SCSI_OPCODE; + if (sbc_check_dpofua(dev, cmd, cdb)) + return TCM_INVALID_CDB_FIELD; + + ret = sbc_check_prot(dev, cmd, cdb, sectors, true); + if (ret) + return ret; - if (cdb[1] & 0x8) - cmd->se_cmd_flags |= SCF_FUA; cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; cmd->execute_rw = ops->execute_rw; cmd->execute_cmd = sbc_execute_rw; @@ -740,11 +809,13 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) sectors = transport_get_sectors_12(cdb); cmd->t_task_lba = transport_lba_32(cdb); - if (!sbc_check_prot(dev, cmd, cdb, sectors, true)) - return TCM_UNSUPPORTED_SCSI_OPCODE; + if (sbc_check_dpofua(dev, cmd, cdb)) + return TCM_INVALID_CDB_FIELD; + + ret = sbc_check_prot(dev, cmd, cdb, sectors, true); + if (ret) + return ret; - if (cdb[1] & 0x8) - cmd->se_cmd_flags |= SCF_FUA; cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; cmd->execute_rw = ops->execute_rw; cmd->execute_cmd = sbc_execute_rw; @@ -753,11 +824,13 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) sectors = transport_get_sectors_16(cdb); cmd->t_task_lba = transport_lba_64(cdb); - if (!sbc_check_prot(dev, cmd, cdb, sectors, true)) - return TCM_UNSUPPORTED_SCSI_OPCODE; + if (sbc_check_dpofua(dev, cmd, cdb)) + return TCM_INVALID_CDB_FIELD; + + ret = sbc_check_prot(dev, cmd, cdb, sectors, true); + if (ret) + return ret; - if (cdb[1] & 0x8) - cmd->se_cmd_flags |= SCF_FUA; cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; cmd->execute_rw = ops->execute_rw; cmd->execute_cmd = sbc_execute_rw; @@ -768,6 +841,9 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) return TCM_INVALID_CDB_FIELD; sectors = transport_get_sectors_10(cdb); + if (sbc_check_dpofua(dev, cmd, cdb)) + return TCM_INVALID_CDB_FIELD; + cmd->t_task_lba = transport_lba_32(cdb); cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; @@ -777,8 +853,6 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) cmd->execute_rw = ops->execute_rw; cmd->execute_cmd = sbc_execute_rw; cmd->transport_complete_callback = &xdreadwrite_callback; - if (cdb[1] & 0x8) - cmd->se_cmd_flags |= SCF_FUA; break; case VARIABLE_LENGTH_CMD: { @@ -787,6 +861,8 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) case XDWRITEREAD_32: sectors = transport_get_sectors_32(cdb); + if (sbc_check_dpofua(dev, cmd, cdb)) + return TCM_INVALID_CDB_FIELD; /* * Use WRITE_32 and READ_32 opcodes for the emulated * XDWRITE_READ_32 logic. @@ -801,8 +877,6 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) cmd->execute_rw = ops->execute_rw; cmd->execute_cmd = sbc_execute_rw; cmd->transport_complete_callback = &xdreadwrite_callback; - if (cdb[1] & 0x8) - cmd->se_cmd_flags |= SCF_FUA; break; case WRITE_SAME_32: sectors = transport_get_sectors_32(cdb); @@ -888,6 +962,11 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) if (!ops->execute_unmap) return TCM_UNSUPPORTED_SCSI_OPCODE; + if (!dev->dev_attrib.emulate_tpu) { + pr_err("Got UNMAP, but backend device has" + " emulate_tpu disabled\n"); + return TCM_UNSUPPORTED_SCSI_OPCODE; + } size = get_unaligned_be16(&cdb[7]); cmd->execute_cmd = ops->execute_unmap; break; @@ -955,7 +1034,8 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) unsigned long long end_lba; check_lba: end_lba = dev->transport->get_blocks(dev) + 1; - if (cmd->t_task_lba + sectors > end_lba) { + if (((cmd->t_task_lba + sectors) < cmd->t_task_lba) || + ((cmd->t_task_lba + sectors) > end_lba)) { pr_err("cmd exceeds last lba %llu " "(lba %llu, sectors %u)\n", end_lba, cmd->t_task_lba, sectors); diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index 4c71657da56a..460e93109473 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -647,7 +647,7 @@ spc_emulate_evpd_b2(struct se_cmd *cmd, unsigned char *buf) * support the use of the WRITE SAME (16) command to unmap LBAs. */ if (dev->dev_attrib.emulate_tpws != 0) - buf[5] |= 0x40; + buf[5] |= 0x40 | 0x20; return 0; } |