diff options
Diffstat (limited to 'drivers/target')
43 files changed, 1474 insertions, 2373 deletions
diff --git a/drivers/target/Makefile b/drivers/target/Makefile index 1060c7b7f803..62e54053bcd8 100644 --- a/drivers/target/Makefile +++ b/drivers/target/Makefile @@ -6,7 +6,6 @@ target_core_mod-y := target_core_configfs.o \ target_core_hba.o \ target_core_pr.o \ target_core_alua.o \ - target_core_scdb.o \ target_core_tmr.o \ target_core_tpg.o \ target_core_transport.o \ diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 6a4ea29c2f36..0fd96c10271d 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -22,6 +22,7 @@ #include <linux/kthread.h> #include <linux/crypto.h> #include <linux/completion.h> +#include <linux/module.h> #include <asm/unaligned.h> #include <scsi/scsi_device.h> #include <scsi/iscsi_proto.h> @@ -765,7 +766,7 @@ static int iscsit_allocate_iovecs(struct iscsi_cmd *cmd) u32 iov_count = (cmd->se_cmd.t_data_nents == 0) ? 1 : cmd->se_cmd.t_data_nents; - iov_count += TRANSPORT_IOV_DATA_BUFFER; + iov_count += ISCSI_IOV_DATA_BUFFER; cmd->iov_data = kzalloc(iov_count * sizeof(struct kvec), GFP_KERNEL); if (!cmd->iov_data) { @@ -1079,7 +1080,9 @@ attach_cmd: */ if (!cmd->immediate_data) { cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn); - if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) + if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) + return 0; + else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) return iscsit_add_reject_from_cmd( ISCSI_REASON_PROTOCOL_ERROR, 1, 0, buf, cmd); @@ -1819,17 +1822,16 @@ attach: int cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn); if (cmdsn_ret == CMDSN_HIGHER_THAN_EXP) out_of_order_cmdsn = 1; - else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) { + else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) return 0; - } else { /* (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) */ + else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) return iscsit_add_reject_from_cmd( ISCSI_REASON_PROTOCOL_ERROR, 1, 0, buf, cmd); - } } iscsit_ack_from_expstatsn(conn, hdr->exp_statsn); - if (out_of_order_cmdsn) + if (out_of_order_cmdsn || !(hdr->opcode & ISCSI_OP_IMMEDIATE)) return 0; /* * Found the referenced task, send to transport for processing. @@ -3538,16 +3540,8 @@ get_immediate: spin_lock_bh(&conn->cmd_lock); list_del(&cmd->i_list); spin_unlock_bh(&conn->cmd_lock); - /* - * Determine if a struct se_cmd is assoicated with - * this struct iscsi_cmd. - */ - if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) && - !(cmd->tmr_req)) - iscsit_release_cmd(cmd); - else - transport_generic_free_cmd(&cmd->se_cmd, - 1, 0); + + iscsit_free_cmd(cmd); goto get_immediate; case ISTATE_SEND_NOPIN_WANT_RESPONSE: spin_unlock_bh(&cmd->istate_lock); @@ -3940,7 +3934,6 @@ static void iscsit_release_commands_from_conn(struct iscsi_conn *conn) { struct iscsi_cmd *cmd = NULL, *cmd_tmp = NULL; struct iscsi_session *sess = conn->sess; - struct se_cmd *se_cmd; /* * We expect this function to only ever be called from either RX or TX * thread context via iscsit_close_connection() once the other context @@ -3948,35 +3941,13 @@ static void iscsit_release_commands_from_conn(struct iscsi_conn *conn) */ spin_lock_bh(&conn->cmd_lock); list_for_each_entry_safe(cmd, cmd_tmp, &conn->conn_cmd_list, i_list) { - if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD)) { - list_del(&cmd->i_list); - spin_unlock_bh(&conn->cmd_lock); - iscsit_increment_maxcmdsn(cmd, sess); - se_cmd = &cmd->se_cmd; - /* - * Special cases for active iSCSI TMR, and - * transport_lookup_cmd_lun() failing from - * iscsit_get_lun_for_cmd() in iscsit_handle_scsi_cmd(). - */ - if (cmd->tmr_req && se_cmd->transport_wait_for_tasks) - se_cmd->transport_wait_for_tasks(se_cmd, 1, 1); - else if (cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) - transport_release_cmd(se_cmd); - else - iscsit_release_cmd(cmd); - - spin_lock_bh(&conn->cmd_lock); - continue; - } list_del(&cmd->i_list); spin_unlock_bh(&conn->cmd_lock); iscsit_increment_maxcmdsn(cmd, sess); - se_cmd = &cmd->se_cmd; - if (se_cmd->transport_wait_for_tasks) - se_cmd->transport_wait_for_tasks(se_cmd, 1, 1); + iscsit_free_cmd(cmd); spin_lock_bh(&conn->cmd_lock); } diff --git a/drivers/target/iscsi/iscsi_target_auth.c b/drivers/target/iscsi/iscsi_target_auth.c index 11fd74307811..beb39469e7f1 100644 --- a/drivers/target/iscsi/iscsi_target_auth.c +++ b/drivers/target/iscsi/iscsi_target_auth.c @@ -18,6 +18,7 @@ * GNU General Public License for more details. ******************************************************************************/ +#include <linux/kernel.h> #include <linux/string.h> #include <linux/crypto.h> #include <linux/err.h> @@ -27,40 +28,11 @@ #include "iscsi_target_nego.h" #include "iscsi_target_auth.h" -static unsigned char chap_asciihex_to_binaryhex(unsigned char val[2]) -{ - unsigned char result = 0; - /* - * MSB - */ - if ((val[0] >= 'a') && (val[0] <= 'f')) - result = ((val[0] - 'a' + 10) & 0xf) << 4; - else - if ((val[0] >= 'A') && (val[0] <= 'F')) - result = ((val[0] - 'A' + 10) & 0xf) << 4; - else /* digit */ - result = ((val[0] - '0') & 0xf) << 4; - /* - * LSB - */ - if ((val[1] >= 'a') && (val[1] <= 'f')) - result |= ((val[1] - 'a' + 10) & 0xf); - else - if ((val[1] >= 'A') && (val[1] <= 'F')) - result |= ((val[1] - 'A' + 10) & 0xf); - else /* digit */ - result |= ((val[1] - '0') & 0xf); - - return result; -} - static int chap_string_to_hex(unsigned char *dst, unsigned char *src, int len) { - int i, j = 0; + int j = DIV_ROUND_UP(len, 2); - for (i = 0; i < len; i += 2) { - dst[j++] = (unsigned char) chap_asciihex_to_binaryhex(&src[i]); - } + hex2bin(dst, src, j); dst[j] = '\0'; return j; diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index f1643dbf6a92..db327845e46b 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -20,6 +20,7 @@ ****************************************************************************/ #include <linux/configfs.h> +#include <linux/export.h> #include <target/target_core_base.h> #include <target/target_core_transport.h> #include <target/target_core_fabric_ops.h> diff --git a/drivers/target/iscsi/iscsi_target_core.h b/drivers/target/iscsi/iscsi_target_core.h index 470ed551eeb5..3723d90d5ae5 100644 --- a/drivers/target/iscsi/iscsi_target_core.h +++ b/drivers/target/iscsi/iscsi_target_core.h @@ -57,6 +57,9 @@ #define TA_PROD_MODE_WRITE_PROTECT 0 #define TA_CACHE_CORE_NPS 0 + +#define ISCSI_IOV_DATA_BUFFER 5 + enum tpg_np_network_transport_table { ISCSI_TCP = 0, ISCSI_SCTP_TCP = 1, @@ -425,7 +428,6 @@ struct iscsi_cmd { /* Number of times struct iscsi_cmd is present in immediate queue */ atomic_t immed_queue_count; atomic_t response_queue_count; - atomic_t transport_sent; spinlock_t datain_lock; spinlock_t dataout_timeout_lock; /* spinlock for protecting struct iscsi_cmd->i_state */ diff --git a/drivers/target/iscsi/iscsi_target_erl2.c b/drivers/target/iscsi/iscsi_target_erl2.c index 91a4d170bda4..0b8404c30125 100644 --- a/drivers/target/iscsi/iscsi_target_erl2.c +++ b/drivers/target/iscsi/iscsi_target_erl2.c @@ -143,12 +143,7 @@ void iscsit_free_connection_recovery_entires(struct iscsi_session *sess) list_del(&cmd->i_list); cmd->conn = NULL; spin_unlock(&cr->conn_recovery_cmd_lock); - if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) || - !(cmd->se_cmd.transport_wait_for_tasks)) - iscsit_release_cmd(cmd); - else - cmd->se_cmd.transport_wait_for_tasks( - &cmd->se_cmd, 1, 1); + iscsit_free_cmd(cmd); spin_lock(&cr->conn_recovery_cmd_lock); } spin_unlock(&cr->conn_recovery_cmd_lock); @@ -170,12 +165,7 @@ void iscsit_free_connection_recovery_entires(struct iscsi_session *sess) list_del(&cmd->i_list); cmd->conn = NULL; spin_unlock(&cr->conn_recovery_cmd_lock); - if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) || - !(cmd->se_cmd.transport_wait_for_tasks)) - iscsit_release_cmd(cmd); - else - cmd->se_cmd.transport_wait_for_tasks( - &cmd->se_cmd, 1, 1); + iscsit_free_cmd(cmd); spin_lock(&cr->conn_recovery_cmd_lock); } spin_unlock(&cr->conn_recovery_cmd_lock); @@ -260,12 +250,7 @@ void iscsit_discard_cr_cmds_by_expstatsn( iscsit_remove_cmd_from_connection_recovery(cmd, sess); spin_unlock(&cr->conn_recovery_cmd_lock); - if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) || - !(cmd->se_cmd.transport_wait_for_tasks)) - iscsit_release_cmd(cmd); - else - cmd->se_cmd.transport_wait_for_tasks( - &cmd->se_cmd, 1, 0); + iscsit_free_cmd(cmd); spin_lock(&cr->conn_recovery_cmd_lock); } spin_unlock(&cr->conn_recovery_cmd_lock); @@ -319,12 +304,7 @@ int iscsit_discard_unacknowledged_ooo_cmdsns_for_conn(struct iscsi_conn *conn) list_del(&cmd->i_list); spin_unlock_bh(&conn->cmd_lock); - if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) || - !(cmd->se_cmd.transport_wait_for_tasks)) - iscsit_release_cmd(cmd); - else - cmd->se_cmd.transport_wait_for_tasks( - &cmd->se_cmd, 1, 1); + iscsit_free_cmd(cmd); spin_lock_bh(&conn->cmd_lock); } spin_unlock_bh(&conn->cmd_lock); @@ -377,13 +357,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn) list_del(&cmd->i_list); spin_unlock_bh(&conn->cmd_lock); - - if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) || - !(cmd->se_cmd.transport_wait_for_tasks)) - iscsit_release_cmd(cmd); - else - cmd->se_cmd.transport_wait_for_tasks( - &cmd->se_cmd, 1, 0); + iscsit_free_cmd(cmd); spin_lock_bh(&conn->cmd_lock); continue; } @@ -403,13 +377,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn) (cmd->cmd_sn >= conn->sess->exp_cmd_sn)) { list_del(&cmd->i_list); spin_unlock_bh(&conn->cmd_lock); - - if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) || - !(cmd->se_cmd.transport_wait_for_tasks)) - iscsit_release_cmd(cmd); - else - cmd->se_cmd.transport_wait_for_tasks( - &cmd->se_cmd, 1, 1); + iscsit_free_cmd(cmd); spin_lock_bh(&conn->cmd_lock); continue; } @@ -434,10 +402,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn) iscsit_free_all_datain_reqs(cmd); - if ((cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) && - cmd->se_cmd.transport_wait_for_tasks) - cmd->se_cmd.transport_wait_for_tasks(&cmd->se_cmd, - 0, 0); + transport_wait_for_tasks(&cmd->se_cmd); /* * Add the struct iscsi_cmd to the connection recovery cmd list */ diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c index 4d087ac11067..426cd4bf6a9a 100644 --- a/drivers/target/iscsi/iscsi_target_nego.c +++ b/drivers/target/iscsi/iscsi_target_nego.c @@ -504,7 +504,7 @@ static int iscsi_target_do_authentication( break; case 1: pr_debug("iSCSI security negotiation" - " completed sucessfully.\n"); + " completed successfully.\n"); login->auth_complete = 1; if ((login_req->flags & ISCSI_FLAG_LOGIN_NEXT_STAGE1) && (login_req->flags & ISCSI_FLAG_LOGIN_TRANSIT)) { diff --git a/drivers/target/iscsi/iscsi_target_stat.c b/drivers/target/iscsi/iscsi_target_stat.c index bbdbe9301b27..f1db83077e0a 100644 --- a/drivers/target/iscsi/iscsi_target_stat.c +++ b/drivers/target/iscsi/iscsi_target_stat.c @@ -20,6 +20,7 @@ ******************************************************************************/ #include <linux/configfs.h> +#include <linux/export.h> #include <scsi/iscsi_proto.h> #include <target/target_core_base.h> #include <target/target_core_transport.h> diff --git a/drivers/target/iscsi/iscsi_target_tmr.c b/drivers/target/iscsi/iscsi_target_tmr.c index db1fe1ec84df..490207eacde9 100644 --- a/drivers/target/iscsi/iscsi_target_tmr.c +++ b/drivers/target/iscsi/iscsi_target_tmr.c @@ -250,7 +250,7 @@ static int iscsit_task_reassign_complete_write( * so if we have received all DataOUT we can safety ignore Initiator. */ if (cmd->cmd_flags & ICF_GOT_LAST_DATAOUT) { - if (!atomic_read(&cmd->transport_sent)) { + if (!atomic_read(&cmd->se_cmd.t_transport_sent)) { pr_debug("WRITE ITT: 0x%08x: t_state: %d" " never sent to transport\n", cmd->init_task_tag, cmd->se_cmd.t_state); @@ -314,11 +314,11 @@ static int iscsit_task_reassign_complete_read( cmd->acked_data_sn = (tmr_req->exp_data_sn - 1); } - if (!atomic_read(&cmd->transport_sent)) { + if (!atomic_read(&cmd->se_cmd.t_transport_sent)) { pr_debug("READ ITT: 0x%08x: t_state: %d never sent to" " transport\n", cmd->init_task_tag, cmd->se_cmd.t_state); - transport_generic_handle_cdb(se_cmd); + transport_handle_cdb_direct(se_cmd); return 0; } diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index f00137f377b2..02348f727bd4 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c @@ -289,7 +289,8 @@ struct iscsi_cmd *iscsit_allocate_se_cmd_for_tmr( } se_cmd->se_tmr_req = core_tmr_alloc_req(se_cmd, - (void *)cmd->tmr_req, tcm_function); + (void *)cmd->tmr_req, tcm_function, + GFP_KERNEL); if (!se_cmd->se_tmr_req) goto out; @@ -839,6 +840,23 @@ void iscsit_release_cmd(struct iscsi_cmd *cmd) kmem_cache_free(lio_cmd_cache, cmd); } +void iscsit_free_cmd(struct iscsi_cmd *cmd) +{ + /* + * Determine if a struct se_cmd is assoicated with + * this struct iscsi_cmd. + */ + switch (cmd->iscsi_opcode) { + case ISCSI_OP_SCSI_CMD: + case ISCSI_OP_SCSI_TMFUNC: + transport_generic_free_cmd(&cmd->se_cmd, 1); + break; + default: + iscsit_release_cmd(cmd); + break; + } +} + int iscsit_check_session_usage_count(struct iscsi_session *sess) { spin_lock_bh(&sess->session_usage_lock); diff --git a/drivers/target/iscsi/iscsi_target_util.h b/drivers/target/iscsi/iscsi_target_util.h index 2cd49d607bda..835bf7de0281 100644 --- a/drivers/target/iscsi/iscsi_target_util.h +++ b/drivers/target/iscsi/iscsi_target_util.h @@ -30,6 +30,7 @@ extern struct iscsi_queue_req *iscsit_get_cmd_from_response_queue(struct iscsi_c extern void iscsit_remove_cmd_from_tx_queues(struct iscsi_cmd *, struct iscsi_conn *); extern void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *); extern void iscsit_release_cmd(struct iscsi_cmd *); +extern void iscsit_free_cmd(struct iscsi_cmd *); extern int iscsit_check_session_usage_count(struct iscsi_session *); extern void iscsit_dec_session_usage_count(struct iscsi_session *); extern void iscsit_inc_session_usage_count(struct iscsi_session *); diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index aa2d67997235..3df1c9b8ae6b 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -174,6 +174,24 @@ static int tcm_loop_new_cmd_map(struct se_cmd *se_cmd) sgl_bidi = sdb->table.sgl; sgl_bidi_count = sdb->table.nents; } + /* + * Because some userspace code via scsi-generic do not memset their + * associated read buffers, go ahead and do that here for type + * SCF_SCSI_CONTROL_SG_IO_CDB. Also note that this is currently + * guaranteed to be a single SGL for SCF_SCSI_CONTROL_SG_IO_CDB + * by target core in transport_generic_allocate_tasks() -> + * transport_generic_cmd_sequencer(). + */ + if (se_cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB && + se_cmd->data_direction == DMA_FROM_DEVICE) { + struct scatterlist *sg = scsi_sglist(sc); + unsigned char *buf = kmap(sg_page(sg)) + sg->offset; + + if (buf != NULL) { + memset(buf, 0, sg->length); + kunmap(sg_page(sg)); + } + } /* Tell the core about our preallocated memory */ ret = transport_generic_map_mem_to_cmd(se_cmd, scsi_sglist(sc), @@ -187,7 +205,7 @@ static int tcm_loop_new_cmd_map(struct se_cmd *se_cmd) /* * Called from struct target_core_fabric_ops->check_stop_free() */ -static void tcm_loop_check_stop_free(struct se_cmd *se_cmd) +static int tcm_loop_check_stop_free(struct se_cmd *se_cmd) { /* * Do not release struct se_cmd's containing a valid TMR @@ -195,12 +213,13 @@ static void tcm_loop_check_stop_free(struct se_cmd *se_cmd) * with transport_generic_free_cmd(). */ if (se_cmd->se_tmr_req) - return; + return 0; /* * Release the struct se_cmd, which will make a callback to release * struct tcm_loop_cmd * in tcm_loop_deallocate_core_cmd() */ - transport_generic_free_cmd(se_cmd, 0, 0); + transport_generic_free_cmd(se_cmd, 0); + return 1; } static void tcm_loop_release_cmd(struct se_cmd *se_cmd) @@ -290,6 +309,15 @@ static int tcm_loop_queuecommand( */ tl_hba = *(struct tcm_loop_hba **)shost_priv(sc->device->host); tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id]; + /* + * Ensure that this tl_tpg reference from the incoming sc->device->id + * has already been configured via tcm_loop_make_naa_tpg(). + */ + if (!tl_tpg->tl_hba) { + set_host_byte(sc, DID_NO_CONNECT); + sc->scsi_done(sc); + return 0; + } se_tpg = &tl_tpg->tl_se_tpg; /* * Determine the SAM Task Attribute and allocate tl_cmd and @@ -366,7 +394,7 @@ static int tcm_loop_device_reset(struct scsi_cmnd *sc) * Allocate the LUN_RESET TMR */ se_cmd->se_tmr_req = core_tmr_alloc_req(se_cmd, tl_tmr, - TMR_LUN_RESET); + TMR_LUN_RESET, GFP_KERNEL); if (IS_ERR(se_cmd->se_tmr_req)) goto release; /* @@ -388,7 +416,7 @@ static int tcm_loop_device_reset(struct scsi_cmnd *sc) SUCCESS : FAILED; release: if (se_cmd) - transport_generic_free_cmd(se_cmd, 1, 0); + transport_generic_free_cmd(se_cmd, 1); else kmem_cache_free(tcm_loop_cmd_cache, tl_cmd); kfree(tl_tmr); @@ -1245,6 +1273,9 @@ void tcm_loop_drop_naa_tpg( */ core_tpg_deregister(se_tpg); + tl_tpg->tl_hba = NULL; + tl_tpg->tl_tpgt = 0; + pr_debug("TCM_Loop_ConfigFS: Deallocated Emulated %s" " Target Port %s,t,0x%04x\n", tcm_loop_dump_proto_id(tl_hba), config_item_name(&wwn->wwn_group.cg_item), tpgt); diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index 98c98a3a0250..88f2ad43ec8b 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -24,10 +24,10 @@ * ******************************************************************************/ -#include <linux/version.h> #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/configfs.h> +#include <linux/export.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> @@ -59,8 +59,9 @@ struct t10_alua_lu_gp *default_lu_gp; * * See spc4r17 section 6.27 */ -int core_emulate_report_target_port_groups(struct se_cmd *cmd) +int target_emulate_report_target_port_groups(struct se_task *task) { + struct se_cmd *cmd = task->task_se_cmd; struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev; struct se_port *port; struct t10_alua_tg_pt_gp *tg_pt_gp; @@ -68,6 +69,15 @@ int core_emulate_report_target_port_groups(struct se_cmd *cmd) unsigned char *buf; u32 rd_len = 0, off = 4; /* Skip over RESERVED area to first Target port group descriptor */ + /* + * Need at least 4 bytes of response data or else we can't + * even fit the return data length. + */ + if (cmd->data_length < 4) { + pr_warn("REPORT TARGET PORT GROUPS allocation length %u" + " too small\n", cmd->data_length); + return -EINVAL; + } buf = transport_kmap_first_data_page(cmd); @@ -75,6 +85,17 @@ int core_emulate_report_target_port_groups(struct se_cmd *cmd) list_for_each_entry(tg_pt_gp, &su_dev->t10_alua.tg_pt_gps_list, tg_pt_gp_list) { /* + * Check if the Target port group and Target port descriptor list + * based on tg_pt_gp_members count will fit into the response payload. + * Otherwise, bump rd_len to let the initiator know we have exceeded + * the allocation length and the response is truncated. + */ + if ((off + 8 + (tg_pt_gp->tg_pt_gp_members * 4)) > + cmd->data_length) { + rd_len += 8 + (tg_pt_gp->tg_pt_gp_members * 4); + continue; + } + /* * PREF: Preferred target port bit, determine if this * bit should be set for port group. */ @@ -145,6 +166,8 @@ int core_emulate_report_target_port_groups(struct se_cmd *cmd) transport_kunmap_first_data_page(cmd); + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); return 0; } @@ -153,8 +176,9 @@ int core_emulate_report_target_port_groups(struct se_cmd *cmd) * * See spc4r17 section 6.35 */ -int core_emulate_set_target_port_groups(struct se_cmd *cmd) +int target_emulate_set_target_port_groups(struct se_task *task) { + struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; struct se_subsystem_dev *su_dev = dev->se_sub_dev; struct se_port *port, *l_port = cmd->se_lun->lun_sep; @@ -322,7 +346,8 @@ int core_emulate_set_target_port_groups(struct se_cmd *cmd) out: transport_kunmap_first_data_page(cmd); - + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); return 0; } diff --git a/drivers/target/target_core_alua.h b/drivers/target/target_core_alua.h index c86f97a081ed..c5b4ecd3e745 100644 --- a/drivers/target/target_core_alua.h +++ b/drivers/target/target_core_alua.h @@ -66,8 +66,8 @@ extern struct kmem_cache *t10_alua_lu_gp_mem_cache; extern struct kmem_cache *t10_alua_tg_pt_gp_cache; extern struct kmem_cache *t10_alua_tg_pt_gp_mem_cache; -extern int core_emulate_report_target_port_groups(struct se_cmd *); -extern int core_emulate_set_target_port_groups(struct se_cmd *); +extern int target_emulate_report_target_port_groups(struct se_task *); +extern int target_emulate_set_target_port_groups(struct se_task *); extern int core_alua_check_nonop_delay(struct se_cmd *); extern int core_alua_do_port_transition(struct t10_alua_tg_pt_gp *, struct se_device *, struct se_port *, diff --git a/drivers/target/target_core_cdb.c b/drivers/target/target_core_cdb.c index f04d4ef99dca..683ba02b8247 100644 --- a/drivers/target/target_core_cdb.c +++ b/drivers/target/target_core_cdb.c @@ -24,7 +24,7 @@ */ #include <linux/kernel.h> -#include <linux/ctype.h> +#include <linux/module.h> #include <asm/unaligned.h> #include <scsi/scsi.h> @@ -32,6 +32,7 @@ #include <target/target_core_transport.h> #include <target/target_core_fabric_ops.h> #include "target_core_ua.h" +#include "target_core_cdb.h" static void target_fill_alua_data(struct se_port *port, unsigned char *buf) @@ -156,11 +157,12 @@ target_emulate_evpd_80(struct se_cmd *cmd, unsigned char *buf) } static void -target_parse_naa_6h_vendor_specific(struct se_device *dev, unsigned char *buf_off) +target_parse_naa_6h_vendor_specific(struct se_device *dev, unsigned char *buf) { unsigned char *p = &dev->se_sub_dev->t10_wwn.unit_serial[0]; - unsigned char *buf = buf_off; - int cnt = 0, next = 1; + int cnt; + bool next = true; + /* * Generate up to 36 bits of VENDOR SPECIFIC IDENTIFIER starting on * byte 3 bit 3-0 for NAA IEEE Registered Extended DESIGNATOR field @@ -169,19 +171,18 @@ target_parse_naa_6h_vendor_specific(struct se_device *dev, unsigned char *buf_of * NUMBER set via vpd_unit_serial in target_core_configfs.c to ensure * per device uniqeness. */ - while (*p != '\0') { - if (cnt >= 13) - break; - if (!isxdigit(*p)) { - p++; + for (cnt = 0; *p && cnt < 13; p++) { + int val = hex_to_bin(*p); + + if (val < 0) continue; - } - if (next != 0) { - buf[cnt++] |= hex_to_bin(*p++); - next = 0; + + if (next) { + next = false; + buf[cnt++] |= val; } else { - buf[cnt] = hex_to_bin(*p++) << 4; - next = 1; + next = true; + buf[cnt] = val << 4; } } } @@ -679,16 +680,18 @@ target_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf) return 0; } -static int -target_emulate_inquiry(struct se_cmd *cmd) +int target_emulate_inquiry(struct se_task *task) { + struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; unsigned char *buf; unsigned char *cdb = cmd->t_task_cdb; int p, ret; - if (!(cdb[1] & 0x1)) - return target_emulate_inquiry_std(cmd); + if (!(cdb[1] & 0x1)) { + ret = target_emulate_inquiry_std(cmd); + goto out; + } /* * Make sure we at least have 4 bytes of INQUIRY response @@ -707,22 +710,30 @@ target_emulate_inquiry(struct se_cmd *cmd) buf[0] = dev->transport->get_device_type(dev); - for (p = 0; p < ARRAY_SIZE(evpd_handlers); ++p) + for (p = 0; p < ARRAY_SIZE(evpd_handlers); ++p) { if (cdb[2] == evpd_handlers[p].page) { buf[1] = cdb[2]; ret = evpd_handlers[p].emulate(cmd, buf); - transport_kunmap_first_data_page(cmd); - return ret; + goto out_unmap; } + } - transport_kunmap_first_data_page(cmd); pr_err("Unknown VPD Code: 0x%02x\n", cdb[2]); - return -EINVAL; + ret = -EINVAL; + +out_unmap: + transport_kunmap_first_data_page(cmd); +out: + if (!ret) { + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); + } + return ret; } -static int -target_emulate_readcapacity(struct se_cmd *cmd) +int target_emulate_readcapacity(struct se_task *task) { + struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; unsigned char *buf; unsigned long long blocks_long = dev->transport->get_blocks(dev); @@ -751,12 +762,14 @@ target_emulate_readcapacity(struct se_cmd *cmd) transport_kunmap_first_data_page(cmd); + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); return 0; } -static int -target_emulate_readcapacity_16(struct se_cmd *cmd) +int target_emulate_readcapacity_16(struct se_task *task) { + struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; unsigned char *buf; unsigned long long blocks = dev->transport->get_blocks(dev); @@ -784,6 +797,8 @@ target_emulate_readcapacity_16(struct se_cmd *cmd) transport_kunmap_first_data_page(cmd); + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); return 0; } @@ -922,14 +937,15 @@ target_modesense_dpofua(unsigned char *buf, int type) } } -static int -target_emulate_modesense(struct se_cmd *cmd, int ten) +int target_emulate_modesense(struct se_task *task) { + struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; char *cdb = cmd->t_task_cdb; unsigned char *rbuf; int type = dev->transport->get_device_type(dev); - int offset = (ten) ? 8 : 4; + int ten = (cmd->t_task_cdb[0] == MODE_SENSE_10); + int offset = ten ? 8 : 4; int length = 0; unsigned char buf[SE_MODE_PAGE_BUF]; @@ -995,12 +1011,14 @@ target_emulate_modesense(struct se_cmd *cmd, int ten) memcpy(rbuf, buf, offset); transport_kunmap_first_data_page(cmd); + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); return 0; } -static int -target_emulate_request_sense(struct se_cmd *cmd) +int target_emulate_request_sense(struct se_task *task) { + struct se_cmd *cmd = task->task_se_cmd; unsigned char *cdb = cmd->t_task_cdb; unsigned char *buf; u8 ua_asc = 0, ua_ascq = 0; @@ -1059,7 +1077,8 @@ target_emulate_request_sense(struct se_cmd *cmd) end: transport_kunmap_first_data_page(cmd); - + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); return 0; } @@ -1067,8 +1086,7 @@ end: * Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support. * Note this is not used for TCM/pSCSI passthrough */ -static int -target_emulate_unmap(struct se_task *task) +int target_emulate_unmap(struct se_task *task) { struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; @@ -1079,6 +1097,12 @@ target_emulate_unmap(struct se_task *task) int ret = 0, offset; unsigned short dl, bd_dl; + if (!dev->transport->do_discard) { + pr_err("UNMAP emulation not supported for: %s\n", + dev->transport->name); + return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; + } + /* First UNMAP block descriptor starts at 8 byte offset */ offset = 8; size -= 8; @@ -1110,7 +1134,10 @@ target_emulate_unmap(struct se_task *task) err: transport_kunmap_first_data_page(cmd); - + if (!ret) { + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); + } return ret; } @@ -1118,14 +1145,28 @@ err: * Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support. * Note this is not used for TCM/pSCSI passthrough */ -static int -target_emulate_write_same(struct se_task *task, u32 num_blocks) +int target_emulate_write_same(struct se_task *task) { struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; sector_t range; sector_t lba = cmd->t_task_lba; + u32 num_blocks; int ret; + + if (!dev->transport->do_discard) { + pr_err("WRITE_SAME emulation not supported" + " for: %s\n", dev->transport->name); + return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; + } + + if (cmd->t_task_cdb[0] == WRITE_SAME) + num_blocks = get_unaligned_be16(&cmd->t_task_cdb[7]); + else if (cmd->t_task_cdb[0] == WRITE_SAME_16) + num_blocks = get_unaligned_be32(&cmd->t_task_cdb[10]); + else /* WRITE_SAME_32 via VARIABLE_LENGTH_CMD */ + num_blocks = get_unaligned_be32(&cmd->t_task_cdb[28]); + /* * Use the explicit range when non zero is supplied, otherwise calculate * the remaining range based on ->get_blocks() - starting LBA. @@ -1144,125 +1185,77 @@ target_emulate_write_same(struct se_task *task, u32 num_blocks) return ret; } + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); return 0; } -int -transport_emulate_control_cdb(struct se_task *task) +int target_emulate_synchronize_cache(struct se_task *task) { - struct se_cmd *cmd = task->task_se_cmd; - struct se_device *dev = cmd->se_dev; - unsigned short service_action; - int ret = 0; + struct se_device *dev = task->task_se_cmd->se_dev; - switch (cmd->t_task_cdb[0]) { - case INQUIRY: - ret = target_emulate_inquiry(cmd); - break; - case READ_CAPACITY: - ret = target_emulate_readcapacity(cmd); - break; - case MODE_SENSE: - ret = target_emulate_modesense(cmd, 0); - break; - case MODE_SENSE_10: - ret = target_emulate_modesense(cmd, 1); - break; - case SERVICE_ACTION_IN: - switch (cmd->t_task_cdb[1] & 0x1f) { - case SAI_READ_CAPACITY_16: - ret = target_emulate_readcapacity_16(cmd); + if (!dev->transport->do_sync_cache) { + pr_err("SYNCHRONIZE_CACHE emulation not supported" + " for: %s\n", dev->transport->name); + return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; + } + + dev->transport->do_sync_cache(task); + return 0; +} + +int target_emulate_noop(struct se_task *task) +{ + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); + return 0; +} + +/* + * Write a CDB into @cdb that is based on the one the intiator sent us, + * but updated to only cover the sectors that the current task handles. + */ +void target_get_task_cdb(struct se_task *task, unsigned char *cdb) +{ + struct se_cmd *cmd = task->task_se_cmd; + unsigned int cdb_len = scsi_command_size(cmd->t_task_cdb); + + memcpy(cdb, cmd->t_task_cdb, cdb_len); + if (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) { + unsigned long long lba = task->task_lba; + u32 sectors = task->task_sectors; + + switch (cdb_len) { + case 6: + /* 21-bit LBA and 8-bit sectors */ + cdb[1] = (lba >> 16) & 0x1f; + cdb[2] = (lba >> 8) & 0xff; + cdb[3] = lba & 0xff; + cdb[4] = sectors & 0xff; break; - default: - pr_err("Unsupported SA: 0x%02x\n", - cmd->t_task_cdb[1] & 0x1f); - return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; - } - break; - case REQUEST_SENSE: - ret = target_emulate_request_sense(cmd); - break; - case UNMAP: - if (!dev->transport->do_discard) { - pr_err("UNMAP emulation not supported for: %s\n", - dev->transport->name); - return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; - } - ret = target_emulate_unmap(task); - break; - case WRITE_SAME: - if (!dev->transport->do_discard) { - pr_err("WRITE_SAME emulation not supported" - " for: %s\n", dev->transport->name); - return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; - } - ret = target_emulate_write_same(task, - get_unaligned_be16(&cmd->t_task_cdb[7])); - break; - case WRITE_SAME_16: - if (!dev->transport->do_discard) { - pr_err("WRITE_SAME_16 emulation not supported" - " for: %s\n", dev->transport->name); - return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; - } - ret = target_emulate_write_same(task, - get_unaligned_be32(&cmd->t_task_cdb[10])); - break; - case VARIABLE_LENGTH_CMD: - service_action = - get_unaligned_be16(&cmd->t_task_cdb[8]); - switch (service_action) { - case WRITE_SAME_32: - if (!dev->transport->do_discard) { - pr_err("WRITE_SAME_32 SA emulation not" - " supported for: %s\n", - dev->transport->name); - return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; - } - ret = target_emulate_write_same(task, - get_unaligned_be32(&cmd->t_task_cdb[28])); + case 10: + /* 32-bit LBA and 16-bit sectors */ + put_unaligned_be32(lba, &cdb[2]); + put_unaligned_be16(sectors, &cdb[7]); break; - default: - pr_err("Unsupported VARIABLE_LENGTH_CMD SA:" - " 0x%02x\n", service_action); + case 12: + /* 32-bit LBA and 32-bit sectors */ + put_unaligned_be32(lba, &cdb[2]); + put_unaligned_be32(sectors, &cdb[6]); break; + case 16: + /* 64-bit LBA and 32-bit sectors */ + put_unaligned_be64(lba, &cdb[2]); + put_unaligned_be32(sectors, &cdb[10]); + break; + case 32: + /* 64-bit LBA and 32-bit sectors, extended CDB */ + put_unaligned_be64(lba, &cdb[12]); + put_unaligned_be32(sectors, &cdb[28]); + break; + default: + BUG(); } - break; - case SYNCHRONIZE_CACHE: - case 0x91: /* SYNCHRONIZE_CACHE_16: */ - if (!dev->transport->do_sync_cache) { - pr_err("SYNCHRONIZE_CACHE emulation not supported" - " for: %s\n", dev->transport->name); - return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; - } - dev->transport->do_sync_cache(task); - break; - case ALLOW_MEDIUM_REMOVAL: - case ERASE: - case REZERO_UNIT: - case SEEK_10: - case SPACE: - case START_STOP: - case TEST_UNIT_READY: - case VERIFY: - case WRITE_FILEMARKS: - break; - default: - pr_err("Unsupported SCSI Opcode: 0x%02x for %s\n", - cmd->t_task_cdb[0], dev->transport->name); - return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; } - - if (ret < 0) - return ret; - /* - * Handle the successful completion here unless a caller - * has explictly requested an asychronous completion. - */ - if (!(cmd->se_cmd_flags & SCF_EMULATE_CDB_ASYNC)) { - task->task_scsi_status = GOOD; - transport_complete_task(task, 1); - } - - return PYX_TRANSPORT_SENT_TO_TRANSPORT; } +EXPORT_SYMBOL(target_get_task_cdb); diff --git a/drivers/target/target_core_cdb.h b/drivers/target/target_core_cdb.h new file mode 100644 index 000000000000..ad6b1e393001 --- /dev/null +++ b/drivers/target/target_core_cdb.h @@ -0,0 +1,14 @@ +#ifndef TARGET_CORE_CDB_H +#define TARGET_CORE_CDB_H + +int target_emulate_inquiry(struct se_task *task); +int target_emulate_readcapacity(struct se_task *task); +int target_emulate_readcapacity_16(struct se_task *task); +int target_emulate_modesense(struct se_task *task); +int target_emulate_request_sense(struct se_task *task); +int target_emulate_unmap(struct se_task *task); +int target_emulate_write_same(struct se_task *task); +int target_emulate_synchronize_cache(struct se_task *task); +int target_emulate_noop(struct se_task *task); + +#endif /* TARGET_CORE_CDB_H */ diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index b2575d8568cc..e0c1e8a8dd4e 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -23,7 +23,6 @@ #include <linux/module.h> #include <linux/moduleparam.h> -#include <linux/version.h> #include <generated/utsrelease.h> #include <linux/utsname.h> #include <linux/init.h> @@ -133,14 +132,6 @@ static struct config_group *target_core_register_fabric( pr_debug("Target_Core_ConfigFS: REGISTER -> group: %p name:" " %s\n", group, name); /* - * Ensure that TCM subsystem plugins are loaded at this point for - * using the RAMDISK_DR virtual LUN 0 and all other struct se_port - * LUN symlinks. - */ - if (transport_subsystem_check_init() < 0) - return ERR_PTR(-EINVAL); - - /* * Below are some hardcoded request_module() calls to automatically * local fabric modules when the following is called: * @@ -725,9 +716,6 @@ SE_DEV_ATTR_RO(hw_queue_depth); DEF_DEV_ATTRIB(queue_depth); SE_DEV_ATTR(queue_depth, S_IRUGO | S_IWUSR); -DEF_DEV_ATTRIB(task_timeout); -SE_DEV_ATTR(task_timeout, S_IRUGO | S_IWUSR); - DEF_DEV_ATTRIB(max_unmap_lba_count); SE_DEV_ATTR(max_unmap_lba_count, S_IRUGO | S_IWUSR); @@ -761,7 +749,6 @@ static struct configfs_attribute *target_core_dev_attrib_attrs[] = { &target_core_dev_attrib_optimal_sectors.attr, &target_core_dev_attrib_hw_queue_depth.attr, &target_core_dev_attrib_queue_depth.attr, - &target_core_dev_attrib_task_timeout.attr, &target_core_dev_attrib_max_unmap_lba_count.attr, &target_core_dev_attrib_max_unmap_block_desc_count.attr, &target_core_dev_attrib_unmap_granularity.attr, @@ -3080,8 +3067,7 @@ static struct config_group *target_core_call_addhbatotarget( /* * Load up TCM subsystem plugins if they have not already been loaded. */ - if (transport_subsystem_check_init() < 0) - return ERR_PTR(-EINVAL); + transport_subsystem_check_init(); hba = core_alloc_hba(se_plugin_str, plugin_dep_id, 0); if (IS_ERR(hba)) diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index ca6e4a4df134..ba5edec2c5f8 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -35,6 +35,7 @@ #include <linux/spinlock.h> #include <linux/kthread.h> #include <linux/in.h> +#include <linux/export.h> #include <net/sock.h> #include <net/tcp.h> #include <scsi/scsi.h> @@ -651,23 +652,15 @@ void core_dev_unexport( lun->lun_se_dev = NULL; } -int transport_core_report_lun_response(struct se_cmd *se_cmd) +int target_report_luns(struct se_task *se_task) { + struct se_cmd *se_cmd = se_task->task_se_cmd; struct se_dev_entry *deve; struct se_lun *se_lun; struct se_session *se_sess = se_cmd->se_sess; - struct se_task *se_task; unsigned char *buf; u32 cdb_offset = 0, lun_count = 0, offset = 8, i; - list_for_each_entry(se_task, &se_cmd->t_task_list, t_list) - break; - - if (!se_task) { - pr_err("Unable to locate struct se_task for struct se_cmd\n"); - return PYX_TRANSPORT_LU_COMM_FAILURE; - } - buf = transport_kmap_first_data_page(se_cmd); /* @@ -713,6 +706,8 @@ done: buf[2] = ((lun_count >> 8) & 0xff); buf[3] = (lun_count & 0xff); + se_task->task_scsi_status = GOOD; + transport_complete_task(se_task, 1); return PYX_TRANSPORT_SENT_TO_TRANSPORT; } @@ -914,21 +909,6 @@ void se_dev_set_default_attribs( dev->se_sub_dev->se_dev_attrib.queue_depth = dev_limits->queue_depth; } -int se_dev_set_task_timeout(struct se_device *dev, u32 task_timeout) -{ - if (task_timeout > DA_TASK_TIMEOUT_MAX) { - pr_err("dev[%p]: Passed task_timeout: %u larger then" - " DA_TASK_TIMEOUT_MAX\n", dev, task_timeout); - return -EINVAL; - } else { - dev->se_sub_dev->se_dev_attrib.task_timeout = task_timeout; - pr_debug("dev[%p]: Set SE Device task_timeout: %u\n", - dev, task_timeout); - } - - return 0; -} - int se_dev_set_max_unmap_lba_count( struct se_device *dev, u32 max_unmap_lba_count) @@ -972,36 +952,24 @@ int se_dev_set_unmap_granularity_alignment( int se_dev_set_emulate_dpo(struct se_device *dev, int flag) { - if ((flag != 0) && (flag != 1)) { + if (flag != 0 && flag != 1) { pr_err("Illegal value %d\n", flag); return -EINVAL; } - if (dev->transport->dpo_emulated == NULL) { - pr_err("dev->transport->dpo_emulated is NULL\n"); - return -EINVAL; - } - if (dev->transport->dpo_emulated(dev) == 0) { - pr_err("dev->transport->dpo_emulated not supported\n"); - return -EINVAL; - } - dev->se_sub_dev->se_dev_attrib.emulate_dpo = flag; - pr_debug("dev[%p]: SE Device Page Out (DPO) Emulation" - " bit: %d\n", dev, dev->se_sub_dev->se_dev_attrib.emulate_dpo); - return 0; + + pr_err("dpo_emulated not supported\n"); + return -EINVAL; } int se_dev_set_emulate_fua_write(struct se_device *dev, int flag) { - if ((flag != 0) && (flag != 1)) { + if (flag != 0 && flag != 1) { pr_err("Illegal value %d\n", flag); return -EINVAL; } - if (dev->transport->fua_write_emulated == NULL) { - pr_err("dev->transport->fua_write_emulated is NULL\n"); - return -EINVAL; - } - if (dev->transport->fua_write_emulated(dev) == 0) { - pr_err("dev->transport->fua_write_emulated not supported\n"); + + if (dev->transport->fua_write_emulated == 0) { + pr_err("fua_write_emulated not supported\n"); return -EINVAL; } dev->se_sub_dev->se_dev_attrib.emulate_fua_write = flag; @@ -1012,36 +980,23 @@ int se_dev_set_emulate_fua_write(struct se_device *dev, int flag) int se_dev_set_emulate_fua_read(struct se_device *dev, int flag) { - if ((flag != 0) && (flag != 1)) { + if (flag != 0 && flag != 1) { pr_err("Illegal value %d\n", flag); return -EINVAL; } - if (dev->transport->fua_read_emulated == NULL) { - pr_err("dev->transport->fua_read_emulated is NULL\n"); - return -EINVAL; - } - if (dev->transport->fua_read_emulated(dev) == 0) { - pr_err("dev->transport->fua_read_emulated not supported\n"); - return -EINVAL; - } - dev->se_sub_dev->se_dev_attrib.emulate_fua_read = flag; - pr_debug("dev[%p]: SE Device Forced Unit Access READs: %d\n", - dev, dev->se_sub_dev->se_dev_attrib.emulate_fua_read); - return 0; + + pr_err("ua read emulated not supported\n"); + return -EINVAL; } int se_dev_set_emulate_write_cache(struct se_device *dev, int flag) { - if ((flag != 0) && (flag != 1)) { + if (flag != 0 && flag != 1) { pr_err("Illegal value %d\n", flag); return -EINVAL; } - if (dev->transport->write_cache_emulated == NULL) { - pr_err("dev->transport->write_cache_emulated is NULL\n"); - return -EINVAL; - } - if (dev->transport->write_cache_emulated(dev) == 0) { - pr_err("dev->transport->write_cache_emulated not supported\n"); + if (dev->transport->write_cache_emulated == 0) { + pr_err("write_cache_emulated not supported\n"); return -EINVAL; } dev->se_sub_dev->se_dev_attrib.emulate_write_cache = flag; diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index 55bbe0847a6d..09b6f8729f91 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -22,7 +22,6 @@ #include <linux/module.h> #include <linux/moduleparam.h> -#include <linux/version.h> #include <generated/utsrelease.h> #include <linux/utsname.h> #include <linux/init.h> diff --git a/drivers/target/target_core_fabric_lib.c b/drivers/target/target_core_fabric_lib.c index c4ea3a9a555b..ec4249be617e 100644 --- a/drivers/target/target_core_fabric_lib.c +++ b/drivers/target/target_core_fabric_lib.c @@ -29,6 +29,7 @@ #include <linux/string.h> #include <linux/ctype.h> #include <linux/spinlock.h> +#include <linux/export.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> @@ -63,6 +64,7 @@ u32 sas_get_pr_transport_id( unsigned char *buf) { unsigned char *ptr; + int ret; /* * Set PROTOCOL IDENTIFIER to 6h for SAS @@ -74,7 +76,9 @@ u32 sas_get_pr_transport_id( */ ptr = &se_nacl->initiatorname[4]; /* Skip over 'naa. prefix */ - hex2bin(&buf[4], ptr, 8); + ret = hex2bin(&buf[4], ptr, 8); + if (ret < 0) + pr_debug("sas transport_id: invalid hex string\n"); /* * The SAS Transport ID is a hardcoded 24-byte length @@ -156,8 +160,9 @@ u32 fc_get_pr_transport_id( unsigned char *buf) { unsigned char *ptr; - int i; + int i, ret; u32 off = 8; + /* * PROTOCOL IDENTIFIER is 0h for FCP-2 * @@ -174,7 +179,9 @@ u32 fc_get_pr_transport_id( i++; continue; } - hex2bin(&buf[off++], &ptr[i], 1); + ret = hex2bin(&buf[off++], &ptr[i], 1); + if (ret < 0) + pr_debug("fc transport_id: invalid hex string\n"); i += 2; } /* diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index bc1b33639b8d..67cd6fe05bfa 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -26,13 +26,13 @@ * ******************************************************************************/ -#include <linux/version.h> #include <linux/string.h> #include <linux/parser.h> #include <linux/timer.h> #include <linux/blkdev.h> #include <linux/slab.h> #include <linux/spinlock.h> +#include <linux/module.h> #include <scsi/scsi.h> #include <scsi/scsi_host.h> @@ -273,13 +273,14 @@ fd_alloc_task(unsigned char *cdb) static int fd_do_readv(struct se_task *task) { struct fd_request *req = FILE_REQ(task); - struct fd_dev *dev = req->fd_task.se_dev->dev_ptr; + struct se_device *se_dev = req->fd_task.task_se_cmd->se_dev; + struct fd_dev *dev = se_dev->dev_ptr; struct file *fd = dev->fd_file; struct scatterlist *sg = task->task_sg; struct iovec *iov; mm_segment_t old_fs; loff_t pos = (task->task_lba * - task->se_dev->se_sub_dev->se_dev_attrib.block_size); + se_dev->se_sub_dev->se_dev_attrib.block_size); int ret = 0, i; iov = kzalloc(sizeof(struct iovec) * task->task_sg_nents, GFP_KERNEL); @@ -325,13 +326,14 @@ static int fd_do_readv(struct se_task *task) static int fd_do_writev(struct se_task *task) { struct fd_request *req = FILE_REQ(task); - struct fd_dev *dev = req->fd_task.se_dev->dev_ptr; + struct se_device *se_dev = req->fd_task.task_se_cmd->se_dev; + struct fd_dev *dev = se_dev->dev_ptr; struct file *fd = dev->fd_file; struct scatterlist *sg = task->task_sg; struct iovec *iov; mm_segment_t old_fs; loff_t pos = (task->task_lba * - task->se_dev->se_sub_dev->se_dev_attrib.block_size); + se_dev->se_sub_dev->se_dev_attrib.block_size); int ret, i = 0; iov = kzalloc(sizeof(struct iovec) * task->task_sg_nents, GFP_KERNEL); @@ -399,33 +401,6 @@ static void fd_emulate_sync_cache(struct se_task *task) } /* - * Tell TCM Core that we are capable of WriteCache emulation for - * an underlying struct se_device. - */ -static int fd_emulated_write_cache(struct se_device *dev) -{ - return 1; -} - -static int fd_emulated_dpo(struct se_device *dev) -{ - return 0; -} -/* - * Tell TCM Core that we will be emulating Forced Unit Access (FUA) for WRITEs - * for TYPE_DISK. - */ -static int fd_emulated_fua_write(struct se_device *dev) -{ - return 1; -} - -static int fd_emulated_fua_read(struct se_device *dev) -{ - return 0; -} - -/* * WRITE Force Unit Access (FUA) emulation on a per struct se_task * LBA range basis.. */ @@ -608,17 +583,6 @@ static ssize_t fd_show_configfs_dev_params( return bl; } -/* fd_get_cdb(): (Part of se_subsystem_api_t template) - * - * - */ -static unsigned char *fd_get_cdb(struct se_task *task) -{ - struct fd_request *req = FILE_REQ(task); - - return req->fd_scsi_cdb; -} - /* fd_get_device_rev(): (Part of se_subsystem_api_t template) * * @@ -650,15 +614,13 @@ static struct se_subsystem_api fileio_template = { .name = "fileio", .owner = THIS_MODULE, .transport_type = TRANSPORT_PLUGIN_VHBA_PDEV, + .write_cache_emulated = 1, + .fua_write_emulated = 1, .attach_hba = fd_attach_hba, .detach_hba = fd_detach_hba, .allocate_virtdevice = fd_allocate_virtdevice, .create_virtdevice = fd_create_virtdevice, .free_device = fd_free_device, - .dpo_emulated = fd_emulated_dpo, - .fua_write_emulated = fd_emulated_fua_write, - .fua_read_emulated = fd_emulated_fua_read, - .write_cache_emulated = fd_emulated_write_cache, .alloc_task = fd_alloc_task, .do_task = fd_do_task, .do_sync_cache = fd_emulate_sync_cache, @@ -666,7 +628,6 @@ static struct se_subsystem_api fileio_template = { .check_configfs_dev_params = fd_check_configfs_dev_params, .set_configfs_dev_params = fd_set_configfs_dev_params, .show_configfs_dev_params = fd_show_configfs_dev_params, - .get_cdb = fd_get_cdb, .get_device_rev = fd_get_device_rev, .get_device_type = fd_get_device_type, .get_blocks = fd_get_blocks, diff --git a/drivers/target/target_core_file.h b/drivers/target/target_core_file.h index daebd710b893..59e6e73106c2 100644 --- a/drivers/target/target_core_file.h +++ b/drivers/target/target_core_file.h @@ -14,9 +14,7 @@ struct fd_request { struct se_task fd_task; - /* SCSI CDB from iSCSI Command PDU */ - unsigned char fd_scsi_cdb[TCM_MAX_COMMAND_SIZE]; -} ____cacheline_aligned; +}; #define FBDF_HAS_PATH 0x01 #define FBDF_HAS_SIZE 0x02 diff --git a/drivers/target/target_core_hba.c b/drivers/target/target_core_hba.c index 0639b975d6f5..c68019d6c406 100644 --- a/drivers/target/target_core_hba.c +++ b/drivers/target/target_core_hba.c @@ -32,6 +32,7 @@ #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/in.h> +#include <linux/module.h> #include <net/sock.h> #include <net/tcp.h> diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index 7e1234105442..7698efe29262 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -27,7 +27,6 @@ * ******************************************************************************/ -#include <linux/version.h> #include <linux/string.h> #include <linux/parser.h> #include <linux/timer.h> @@ -38,6 +37,7 @@ #include <linux/bio.h> #include <linux/genhd.h> #include <linux/file.h> +#include <linux/module.h> #include <scsi/scsi.h> #include <scsi/scsi_host.h> @@ -314,104 +314,42 @@ static unsigned long long iblock_emulate_read_cap_with_block_size( return blocks_long; } +static void iblock_end_io_flush(struct bio *bio, int err) +{ + struct se_cmd *cmd = bio->bi_private; + + if (err) + pr_err("IBLOCK: cache flush failed: %d\n", err); + + if (cmd) + transport_complete_sync_cache(cmd, err == 0); + bio_put(bio); +} + /* - * Emulate SYCHRONIZE_CACHE_* + * Implement SYCHRONIZE CACHE. Note that we can't handle lba ranges and must + * always flush the whole cache. */ static void iblock_emulate_sync_cache(struct se_task *task) { struct se_cmd *cmd = task->task_se_cmd; struct iblock_dev *ib_dev = cmd->se_dev->dev_ptr; int immed = (cmd->t_task_cdb[1] & 0x2); - sector_t error_sector; - int ret; + struct bio *bio; /* * If the Immediate bit is set, queue up the GOOD response - * for this SYNCHRONIZE_CACHE op + * for this SYNCHRONIZE_CACHE op. */ if (immed) transport_complete_sync_cache(cmd, 1); - /* - * blkdev_issue_flush() does not support a specifying a range, so - * we have to flush the entire cache. - */ - ret = blkdev_issue_flush(ib_dev->ibd_bd, GFP_KERNEL, &error_sector); - if (ret != 0) { - pr_err("IBLOCK: block_issue_flush() failed: %d " - " error_sector: %llu\n", ret, - (unsigned long long)error_sector); - } - + bio = bio_alloc(GFP_KERNEL, 0); + bio->bi_end_io = iblock_end_io_flush; + bio->bi_bdev = ib_dev->ibd_bd; if (!immed) - transport_complete_sync_cache(cmd, ret == 0); -} - -/* - * Tell TCM Core that we are capable of WriteCache emulation for - * an underlying struct se_device. - */ -static int iblock_emulated_write_cache(struct se_device *dev) -{ - return 1; -} - -static int iblock_emulated_dpo(struct se_device *dev) -{ - return 0; -} - -/* - * Tell TCM Core that we will be emulating Forced Unit Access (FUA) for WRITEs - * for TYPE_DISK. - */ -static int iblock_emulated_fua_write(struct se_device *dev) -{ - return 1; -} - -static int iblock_emulated_fua_read(struct se_device *dev) -{ - return 0; -} - -static int iblock_do_task(struct se_task *task) -{ - struct se_device *dev = task->task_se_cmd->se_dev; - struct iblock_req *req = IBLOCK_REQ(task); - struct bio *bio = req->ib_bio, *nbio = NULL; - struct blk_plug plug; - int rw; - - if (task->task_data_direction == DMA_TO_DEVICE) { - /* - * Force data to disk if we pretend to not have a volatile - * write cache, or the initiator set the Force Unit Access bit. - */ - if (dev->se_sub_dev->se_dev_attrib.emulate_write_cache == 0 || - (dev->se_sub_dev->se_dev_attrib.emulate_fua_write > 0 && - task->task_se_cmd->t_tasks_fua)) - rw = WRITE_FUA; - else - rw = WRITE; - } else { - rw = READ; - } - - blk_start_plug(&plug); - while (bio) { - nbio = bio->bi_next; - bio->bi_next = NULL; - pr_debug("Calling submit_bio() task: %p bio: %p" - " bio->bi_sector: %llu\n", task, bio, - (unsigned long long)bio->bi_sector); - - submit_bio(rw, bio); - bio = nbio; - } - blk_finish_plug(&plug); - - return PYX_TRANSPORT_SENT_TO_TRANSPORT; + bio->bi_private = cmd; + submit_bio(WRITE_FLUSH, bio); } static int iblock_do_discard(struct se_device *dev, sector_t lba, u32 range) @@ -425,20 +363,7 @@ static int iblock_do_discard(struct se_device *dev, sector_t lba, u32 range) static void iblock_free_task(struct se_task *task) { - struct iblock_req *req = IBLOCK_REQ(task); - struct bio *bio, *hbio = req->ib_bio; - /* - * We only release the bio(s) here if iblock_bio_done() has not called - * bio_put() -> iblock_bio_destructor(). - */ - while (hbio != NULL) { - bio = hbio; - hbio = hbio->bi_next; - bio->bi_next = NULL; - bio_put(bio); - } - - kfree(req); + kfree(IBLOCK_REQ(task)); } enum { @@ -552,25 +477,21 @@ static ssize_t iblock_show_configfs_dev_params( static void iblock_bio_destructor(struct bio *bio) { struct se_task *task = bio->bi_private; - struct iblock_dev *ib_dev = task->se_dev->dev_ptr; + struct iblock_dev *ib_dev = task->task_se_cmd->se_dev->dev_ptr; bio_free(bio, ib_dev->ibd_bio_set); } -static struct bio *iblock_get_bio( - struct se_task *task, - struct iblock_req *ib_req, - struct iblock_dev *ib_dev, - int *ret, - sector_t lba, - u32 sg_num) +static struct bio * +iblock_get_bio(struct se_task *task, sector_t lba, u32 sg_num) { + struct iblock_dev *ib_dev = task->task_se_cmd->se_dev->dev_ptr; + struct iblock_req *ib_req = IBLOCK_REQ(task); struct bio *bio; bio = bio_alloc_bioset(GFP_NOIO, sg_num, ib_dev->ibd_bio_set); if (!bio) { pr_err("Unable to allocate memory for bio\n"); - *ret = PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES; return NULL; } @@ -591,17 +512,33 @@ static struct bio *iblock_get_bio( return bio; } -static int iblock_map_data_SG(struct se_task *task) +static int iblock_do_task(struct se_task *task) { struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; - struct iblock_dev *ib_dev = task->se_dev->dev_ptr; - struct iblock_req *ib_req = IBLOCK_REQ(task); - struct bio *bio = NULL, *hbio = NULL, *tbio = NULL; + struct bio *bio; + struct bio_list list; struct scatterlist *sg; - int ret = 0; u32 i, sg_num = task->task_sg_nents; sector_t block_lba; + struct blk_plug plug; + int rw; + + if (task->task_data_direction == DMA_TO_DEVICE) { + /* + * Force data to disk if we pretend to not have a volatile + * write cache, or the initiator set the Force Unit Access bit. + */ + if (dev->se_sub_dev->se_dev_attrib.emulate_write_cache == 0 || + (dev->se_sub_dev->se_dev_attrib.emulate_fua_write > 0 && + task->task_se_cmd->t_tasks_fua)) + rw = WRITE_FUA; + else + rw = WRITE; + } else { + rw = READ; + } + /* * Do starting conversion up from non 512-byte blocksize with * struct se_task SCSI blocksize into Linux/Block 512 units for BIO. @@ -620,68 +557,43 @@ static int iblock_map_data_SG(struct se_task *task) return PYX_TRANSPORT_LU_COMM_FAILURE; } - bio = iblock_get_bio(task, ib_req, ib_dev, &ret, block_lba, sg_num); + bio = iblock_get_bio(task, block_lba, sg_num); if (!bio) - return ret; + return PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES; + + bio_list_init(&list); + bio_list_add(&list, bio); - ib_req->ib_bio = bio; - hbio = tbio = bio; - /* - * Use fs/bio.c:bio_add_pages() to setup the bio_vec maplist - * from task->task_sg -> struct scatterlist memory. - */ for_each_sg(task->task_sg, sg, task->task_sg_nents, i) { - pr_debug("task: %p bio: %p Calling bio_add_page(): page:" - " %p len: %u offset: %u\n", task, bio, sg_page(sg), - sg->length, sg->offset); -again: - ret = bio_add_page(bio, sg_page(sg), sg->length, sg->offset); - if (ret != sg->length) { - - pr_debug("*** Set bio->bi_sector: %llu\n", - (unsigned long long)bio->bi_sector); - pr_debug("** task->task_size: %u\n", - task->task_size); - pr_debug("*** bio->bi_max_vecs: %u\n", - bio->bi_max_vecs); - pr_debug("*** bio->bi_vcnt: %u\n", - bio->bi_vcnt); - - bio = iblock_get_bio(task, ib_req, ib_dev, &ret, - block_lba, sg_num); + /* + * XXX: if the length the device accepts is shorter than the + * length of the S/G list entry this will cause and + * endless loop. Better hope no driver uses huge pages. + */ + while (bio_add_page(bio, sg_page(sg), sg->length, sg->offset) + != sg->length) { + bio = iblock_get_bio(task, block_lba, sg_num); if (!bio) goto fail; - - tbio = tbio->bi_next = bio; - pr_debug("-----------------> Added +1 bio: %p to" - " list, Going to again\n", bio); - goto again; + bio_list_add(&list, bio); } + /* Always in 512 byte units for Linux/Block */ block_lba += sg->length >> IBLOCK_LBA_SHIFT; sg_num--; - pr_debug("task: %p bio-add_page() passed!, decremented" - " sg_num to %u\n", task, sg_num); - pr_debug("task: %p bio_add_page() passed!, increased lba" - " to %llu\n", task, (unsigned long long)block_lba); - pr_debug("task: %p bio_add_page() passed!, bio->bi_vcnt:" - " %u\n", task, bio->bi_vcnt); } - return 0; + blk_start_plug(&plug); + while ((bio = bio_list_pop(&list))) + submit_bio(rw, bio); + blk_finish_plug(&plug); + + return PYX_TRANSPORT_SENT_TO_TRANSPORT; + fail: - while (hbio) { - bio = hbio; - hbio = hbio->bi_next; - bio->bi_next = NULL; + while ((bio = bio_list_pop(&list))) bio_put(bio); - } - return ret; -} - -static unsigned char *iblock_get_cdb(struct se_task *task) -{ - return IBLOCK_REQ(task)->ib_scsi_cdb; + return PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES; } static u32 iblock_get_device_rev(struct se_device *dev) @@ -707,6 +619,7 @@ static void iblock_bio_done(struct bio *bio, int err) { struct se_task *task = bio->bi_private; struct iblock_req *ibr = IBLOCK_REQ(task); + /* * Set -EIO if !BIO_UPTODATE and the passed is still err=0 */ @@ -721,50 +634,31 @@ static void iblock_bio_done(struct bio *bio, int err) */ atomic_inc(&ibr->ib_bio_err_cnt); smp_mb__after_atomic_inc(); - bio_put(bio); - /* - * Wait to complete the task until the last bio as completed. - */ - if (!atomic_dec_and_test(&ibr->ib_bio_cnt)) - return; - - ibr->ib_bio = NULL; - transport_complete_task(task, 0); - return; } - pr_debug("done[%p] bio: %p task_lba: %llu bio_lba: %llu err=%d\n", - task, bio, task->task_lba, (unsigned long long)bio->bi_sector, err); - /* - * bio_put() will call iblock_bio_destructor() to release the bio back - * to ibr->ib_bio_set. - */ + bio_put(bio); - /* - * Wait to complete the task until the last bio as completed. - */ + if (!atomic_dec_and_test(&ibr->ib_bio_cnt)) return; - /* - * Return GOOD status for task if zero ib_bio_err_cnt exists. - */ - ibr->ib_bio = NULL; - transport_complete_task(task, (!atomic_read(&ibr->ib_bio_err_cnt))); + + pr_debug("done[%p] bio: %p task_lba: %llu bio_lba: %llu err=%d\n", + task, bio, task->task_lba, + (unsigned long long)bio->bi_sector, err); + + transport_complete_task(task, !atomic_read(&ibr->ib_bio_err_cnt)); } static struct se_subsystem_api iblock_template = { .name = "iblock", .owner = THIS_MODULE, .transport_type = TRANSPORT_PLUGIN_VHBA_PDEV, - .map_data_SG = iblock_map_data_SG, + .write_cache_emulated = 1, + .fua_write_emulated = 1, .attach_hba = iblock_attach_hba, .detach_hba = iblock_detach_hba, .allocate_virtdevice = iblock_allocate_virtdevice, .create_virtdevice = iblock_create_virtdevice, .free_device = iblock_free_device, - .dpo_emulated = iblock_emulated_dpo, - .fua_write_emulated = iblock_emulated_fua_write, - .fua_read_emulated = iblock_emulated_fua_read, - .write_cache_emulated = iblock_emulated_write_cache, .alloc_task = iblock_alloc_task, .do_task = iblock_do_task, .do_discard = iblock_do_discard, @@ -773,7 +667,6 @@ static struct se_subsystem_api iblock_template = { .check_configfs_dev_params = iblock_check_configfs_dev_params, .set_configfs_dev_params = iblock_set_configfs_dev_params, .show_configfs_dev_params = iblock_show_configfs_dev_params, - .get_cdb = iblock_get_cdb, .get_device_rev = iblock_get_device_rev, .get_device_type = iblock_get_device_type, .get_blocks = iblock_get_blocks, diff --git a/drivers/target/target_core_iblock.h b/drivers/target/target_core_iblock.h index a121cd1b6575..5cf1860c10d0 100644 --- a/drivers/target/target_core_iblock.h +++ b/drivers/target/target_core_iblock.h @@ -8,10 +8,8 @@ struct iblock_req { struct se_task ib_task; - unsigned char ib_scsi_cdb[TCM_MAX_COMMAND_SIZE]; atomic_t ib_bio_cnt; atomic_t ib_bio_err_cnt; - struct bio *ib_bio; } ____cacheline_aligned; #define IBDF_HAS_UDEV_PATH 0x01 diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 7fd3a161f7cc..5a4ebfc3a54f 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -25,7 +25,6 @@ * ******************************************************************************/ -#include <linux/version.h> #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/list.h> @@ -117,114 +116,21 @@ static int core_scsi2_reservation_check(struct se_cmd *cmd, u32 *pr_reg_type) return ret; } -static int core_scsi2_reservation_release(struct se_cmd *cmd) -{ - struct se_device *dev = cmd->se_dev; - struct se_session *sess = cmd->se_sess; - struct se_portal_group *tpg = sess->se_tpg; - - if (!sess || !tpg) - return 0; - - spin_lock(&dev->dev_reservation_lock); - if (!dev->dev_reserved_node_acl || !sess) { - spin_unlock(&dev->dev_reservation_lock); - return 0; - } - - if (dev->dev_reserved_node_acl != sess->se_node_acl) { - spin_unlock(&dev->dev_reservation_lock); - return 0; - } - dev->dev_reserved_node_acl = NULL; - dev->dev_flags &= ~DF_SPC2_RESERVATIONS; - if (dev->dev_flags & DF_SPC2_RESERVATIONS_WITH_ISID) { - dev->dev_res_bin_isid = 0; - dev->dev_flags &= ~DF_SPC2_RESERVATIONS_WITH_ISID; - } - pr_debug("SCSI-2 Released reservation for %s LUN: %u ->" - " MAPPED LUN: %u for %s\n", tpg->se_tpg_tfo->get_fabric_name(), - cmd->se_lun->unpacked_lun, cmd->se_deve->mapped_lun, - sess->se_node_acl->initiatorname); - spin_unlock(&dev->dev_reservation_lock); - - return 0; -} - -static int core_scsi2_reservation_reserve(struct se_cmd *cmd) -{ - struct se_device *dev = cmd->se_dev; - struct se_session *sess = cmd->se_sess; - struct se_portal_group *tpg = sess->se_tpg; - - if ((cmd->t_task_cdb[1] & 0x01) && - (cmd->t_task_cdb[1] & 0x02)) { - pr_err("LongIO and Obselete Bits set, returning" - " ILLEGAL_REQUEST\n"); - return PYX_TRANSPORT_ILLEGAL_REQUEST; - } - /* - * This is currently the case for target_core_mod passthrough struct se_cmd - * ops - */ - if (!sess || !tpg) - return 0; - - spin_lock(&dev->dev_reservation_lock); - if (dev->dev_reserved_node_acl && - (dev->dev_reserved_node_acl != sess->se_node_acl)) { - pr_err("SCSI-2 RESERVATION CONFLIFT for %s fabric\n", - tpg->se_tpg_tfo->get_fabric_name()); - pr_err("Original reserver LUN: %u %s\n", - cmd->se_lun->unpacked_lun, - dev->dev_reserved_node_acl->initiatorname); - pr_err("Current attempt - LUN: %u -> MAPPED LUN: %u" - " from %s \n", cmd->se_lun->unpacked_lun, - cmd->se_deve->mapped_lun, - sess->se_node_acl->initiatorname); - spin_unlock(&dev->dev_reservation_lock); - return PYX_TRANSPORT_RESERVATION_CONFLICT; - } - - dev->dev_reserved_node_acl = sess->se_node_acl; - dev->dev_flags |= DF_SPC2_RESERVATIONS; - if (sess->sess_bin_isid != 0) { - dev->dev_res_bin_isid = sess->sess_bin_isid; - dev->dev_flags |= DF_SPC2_RESERVATIONS_WITH_ISID; - } - pr_debug("SCSI-2 Reserved %s LUN: %u -> MAPPED LUN: %u" - " for %s\n", tpg->se_tpg_tfo->get_fabric_name(), - cmd->se_lun->unpacked_lun, cmd->se_deve->mapped_lun, - sess->se_node_acl->initiatorname); - spin_unlock(&dev->dev_reservation_lock); - - return 0; -} - static struct t10_pr_registration *core_scsi3_locate_pr_reg(struct se_device *, struct se_node_acl *, struct se_session *); static void core_scsi3_put_pr_reg(struct t10_pr_registration *); -/* - * Setup in target_core_transport.c:transport_generic_cmd_sequencer() - * and called via struct se_cmd->transport_emulate_cdb() in TCM processing - * thread context. - */ -int core_scsi2_emulate_crh(struct se_cmd *cmd) +static int target_check_scsi2_reservation_conflict(struct se_cmd *cmd, int *ret) { struct se_session *se_sess = cmd->se_sess; struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev; struct t10_pr_registration *pr_reg; struct t10_reservation *pr_tmpl = &su_dev->t10_pr; - unsigned char *cdb = &cmd->t_task_cdb[0]; int crh = (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS); int conflict = 0; - if (!se_sess) - return 0; - if (!crh) - goto after_crh; + return false; pr_reg = core_scsi3_locate_pr_reg(cmd->se_dev, se_sess->se_node_acl, se_sess); @@ -252,14 +158,16 @@ int core_scsi2_emulate_crh(struct se_cmd *cmd) */ if (pr_reg->pr_res_holder) { core_scsi3_put_pr_reg(pr_reg); - return 0; + *ret = 0; + return false; } if ((pr_reg->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_REGONLY) || (pr_reg->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_REGONLY) || (pr_reg->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) || (pr_reg->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)) { core_scsi3_put_pr_reg(pr_reg); - return 0; + *ret = 0; + return true; } core_scsi3_put_pr_reg(pr_reg); conflict = 1; @@ -283,18 +191,118 @@ int core_scsi2_emulate_crh(struct se_cmd *cmd) pr_err("Received legacy SPC-2 RESERVE/RELEASE" " while active SPC-3 registrations exist," " returning RESERVATION_CONFLICT\n"); - return PYX_TRANSPORT_RESERVATION_CONFLICT; + *ret = PYX_TRANSPORT_RESERVATION_CONFLICT; + return true; } -after_crh: - if ((cdb[0] == RESERVE) || (cdb[0] == RESERVE_10)) - return core_scsi2_reservation_reserve(cmd); - else if ((cdb[0] == RELEASE) || (cdb[0] == RELEASE_10)) - return core_scsi2_reservation_release(cmd); - else - return PYX_TRANSPORT_INVALID_CDB_FIELD; + return false; +} + +int target_scsi2_reservation_release(struct se_task *task) +{ + struct se_cmd *cmd = task->task_se_cmd; + struct se_device *dev = cmd->se_dev; + struct se_session *sess = cmd->se_sess; + struct se_portal_group *tpg = sess->se_tpg; + int ret = 0; + + if (!sess || !tpg) + goto out; + if (target_check_scsi2_reservation_conflict(cmd, &ret)) + goto out; + + ret = 0; + spin_lock(&dev->dev_reservation_lock); + if (!dev->dev_reserved_node_acl || !sess) + goto out_unlock; + + if (dev->dev_reserved_node_acl != sess->se_node_acl) + goto out_unlock; + + dev->dev_reserved_node_acl = NULL; + dev->dev_flags &= ~DF_SPC2_RESERVATIONS; + if (dev->dev_flags & DF_SPC2_RESERVATIONS_WITH_ISID) { + dev->dev_res_bin_isid = 0; + dev->dev_flags &= ~DF_SPC2_RESERVATIONS_WITH_ISID; + } + pr_debug("SCSI-2 Released reservation for %s LUN: %u ->" + " MAPPED LUN: %u for %s\n", tpg->se_tpg_tfo->get_fabric_name(), + cmd->se_lun->unpacked_lun, cmd->se_deve->mapped_lun, + sess->se_node_acl->initiatorname); + +out_unlock: + spin_unlock(&dev->dev_reservation_lock); +out: + if (!ret) { + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); + } + return ret; +} + +int target_scsi2_reservation_reserve(struct se_task *task) +{ + struct se_cmd *cmd = task->task_se_cmd; + struct se_device *dev = cmd->se_dev; + struct se_session *sess = cmd->se_sess; + struct se_portal_group *tpg = sess->se_tpg; + int ret = 0; + + if ((cmd->t_task_cdb[1] & 0x01) && + (cmd->t_task_cdb[1] & 0x02)) { + pr_err("LongIO and Obselete Bits set, returning" + " ILLEGAL_REQUEST\n"); + ret = PYX_TRANSPORT_ILLEGAL_REQUEST; + goto out; + } + /* + * This is currently the case for target_core_mod passthrough struct se_cmd + * ops + */ + if (!sess || !tpg) + goto out; + if (target_check_scsi2_reservation_conflict(cmd, &ret)) + goto out; + + ret = 0; + spin_lock(&dev->dev_reservation_lock); + if (dev->dev_reserved_node_acl && + (dev->dev_reserved_node_acl != sess->se_node_acl)) { + pr_err("SCSI-2 RESERVATION CONFLIFT for %s fabric\n", + tpg->se_tpg_tfo->get_fabric_name()); + pr_err("Original reserver LUN: %u %s\n", + cmd->se_lun->unpacked_lun, + dev->dev_reserved_node_acl->initiatorname); + pr_err("Current attempt - LUN: %u -> MAPPED LUN: %u" + " from %s \n", cmd->se_lun->unpacked_lun, + cmd->se_deve->mapped_lun, + sess->se_node_acl->initiatorname); + ret = PYX_TRANSPORT_RESERVATION_CONFLICT; + goto out_unlock; + } + + dev->dev_reserved_node_acl = sess->se_node_acl; + dev->dev_flags |= DF_SPC2_RESERVATIONS; + if (sess->sess_bin_isid != 0) { + dev->dev_res_bin_isid = sess->sess_bin_isid; + dev->dev_flags |= DF_SPC2_RESERVATIONS_WITH_ISID; + } + pr_debug("SCSI-2 Reserved %s LUN: %u -> MAPPED LUN: %u" + " for %s\n", tpg->se_tpg_tfo->get_fabric_name(), + cmd->se_lun->unpacked_lun, cmd->se_deve->mapped_lun, + sess->se_node_acl->initiatorname); + +out_unlock: + spin_unlock(&dev->dev_reservation_lock); +out: + if (!ret) { + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); + } + return ret; } + /* * Begin SPC-3/SPC-4 Persistent Reservations emulation support * @@ -419,12 +427,12 @@ static int core_scsi3_pr_seq_non_holder( break; case RELEASE: case RELEASE_10: - /* Handled by CRH=1 in core_scsi2_emulate_crh() */ + /* Handled by CRH=1 in target_scsi2_reservation_release() */ ret = 0; break; case RESERVE: case RESERVE_10: - /* Handled by CRH=1 in core_scsi2_emulate_crh() */ + /* Handled by CRH=1 in target_scsi2_reservation_reserve() */ ret = 0; break; case TEST_UNIT_READY: @@ -3740,12 +3748,33 @@ static unsigned long long core_scsi3_extract_reservation_key(unsigned char *cdb) /* * See spc4r17 section 6.14 Table 170 */ -static int core_scsi3_emulate_pr_out(struct se_cmd *cmd, unsigned char *cdb) +int target_scsi3_emulate_pr_out(struct se_task *task) { + struct se_cmd *cmd = task->task_se_cmd; + unsigned char *cdb = &cmd->t_task_cdb[0]; unsigned char *buf; u64 res_key, sa_res_key; int sa, scope, type, aptpl; int spec_i_pt = 0, all_tg_pt = 0, unreg = 0; + int ret; + + /* + * Following spc2r20 5.5.1 Reservations overview: + * + * If a logical unit has been reserved by any RESERVE command and is + * still reserved by any initiator, all PERSISTENT RESERVE IN and all + * PERSISTENT RESERVE OUT commands shall conflict regardless of + * initiator or service action and shall terminate with a RESERVATION + * CONFLICT status. + */ + if (cmd->se_dev->dev_flags & DF_SPC2_RESERVATIONS) { + pr_err("Received PERSISTENT_RESERVE CDB while legacy" + " SPC-2 reservation is held, returning" + " RESERVATION_CONFLICT\n"); + ret = PYX_TRANSPORT_RESERVATION_CONFLICT; + goto out; + } + /* * FIXME: A NULL struct se_session pointer means an this is not coming from * a $FABRIC_MOD's nexus, but from internal passthrough ops. @@ -3756,7 +3785,8 @@ static int core_scsi3_emulate_pr_out(struct se_cmd *cmd, unsigned char *cdb) if (cmd->data_length < 24) { pr_warn("SPC-PR: Received PR OUT parameter list" " length too small: %u\n", cmd->data_length); - return PYX_TRANSPORT_INVALID_PARAMETER_LIST; + ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST; + goto out; } /* * From the PERSISTENT_RESERVE_OUT command descriptor block (CDB) @@ -3789,8 +3819,11 @@ static int core_scsi3_emulate_pr_out(struct se_cmd *cmd, unsigned char *cdb) /* * SPEC_I_PT=1 is only valid for Service action: REGISTER */ - if (spec_i_pt && ((cdb[1] & 0x1f) != PRO_REGISTER)) - return PYX_TRANSPORT_INVALID_PARAMETER_LIST; + if (spec_i_pt && ((cdb[1] & 0x1f) != PRO_REGISTER)) { + ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST; + goto out; + } + /* * From spc4r17 section 6.14: * @@ -3804,7 +3837,8 @@ static int core_scsi3_emulate_pr_out(struct se_cmd *cmd, unsigned char *cdb) (cmd->data_length != 24)) { pr_warn("SPC-PR: Received PR OUT illegal parameter" " list length: %u\n", cmd->data_length); - return PYX_TRANSPORT_INVALID_PARAMETER_LIST; + ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST; + goto out; } /* * (core_scsi3_emulate_pro_* function parameters @@ -3813,35 +3847,47 @@ static int core_scsi3_emulate_pr_out(struct se_cmd *cmd, unsigned char *cdb) */ switch (sa) { case PRO_REGISTER: - return core_scsi3_emulate_pro_register(cmd, + ret = core_scsi3_emulate_pro_register(cmd, res_key, sa_res_key, aptpl, all_tg_pt, spec_i_pt, 0); + break; case PRO_RESERVE: - return core_scsi3_emulate_pro_reserve(cmd, - type, scope, res_key); + ret = core_scsi3_emulate_pro_reserve(cmd, type, scope, res_key); + break; case PRO_RELEASE: - return core_scsi3_emulate_pro_release(cmd, - type, scope, res_key); + ret = core_scsi3_emulate_pro_release(cmd, type, scope, res_key); + break; case PRO_CLEAR: - return core_scsi3_emulate_pro_clear(cmd, res_key); + ret = core_scsi3_emulate_pro_clear(cmd, res_key); + break; case PRO_PREEMPT: - return core_scsi3_emulate_pro_preempt(cmd, type, scope, + ret = core_scsi3_emulate_pro_preempt(cmd, type, scope, res_key, sa_res_key, 0); + break; case PRO_PREEMPT_AND_ABORT: - return core_scsi3_emulate_pro_preempt(cmd, type, scope, + ret = core_scsi3_emulate_pro_preempt(cmd, type, scope, res_key, sa_res_key, 1); + break; case PRO_REGISTER_AND_IGNORE_EXISTING_KEY: - return core_scsi3_emulate_pro_register(cmd, + ret = core_scsi3_emulate_pro_register(cmd, 0, sa_res_key, aptpl, all_tg_pt, spec_i_pt, 1); + break; case PRO_REGISTER_AND_MOVE: - return core_scsi3_emulate_pro_register_and_move(cmd, res_key, + ret = core_scsi3_emulate_pro_register_and_move(cmd, res_key, sa_res_key, aptpl, unreg); + break; default: pr_err("Unknown PERSISTENT_RESERVE_OUT service" " action: 0x%02x\n", cdb[1] & 0x1f); - return PYX_TRANSPORT_INVALID_CDB_FIELD; + ret = PYX_TRANSPORT_INVALID_CDB_FIELD; + break; } - return PYX_TRANSPORT_INVALID_CDB_FIELD; +out: + if (!ret) { + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); + } + return ret; } /* @@ -4191,29 +4237,11 @@ static int core_scsi3_pri_read_full_status(struct se_cmd *cmd) return 0; } -static int core_scsi3_emulate_pr_in(struct se_cmd *cmd, unsigned char *cdb) +int target_scsi3_emulate_pr_in(struct se_task *task) { - switch (cdb[1] & 0x1f) { - case PRI_READ_KEYS: - return core_scsi3_pri_read_keys(cmd); - case PRI_READ_RESERVATION: - return core_scsi3_pri_read_reservation(cmd); - case PRI_REPORT_CAPABILITIES: - return core_scsi3_pri_report_capabilities(cmd); - case PRI_READ_FULL_STATUS: - return core_scsi3_pri_read_full_status(cmd); - default: - pr_err("Unknown PERSISTENT_RESERVE_IN service" - " action: 0x%02x\n", cdb[1] & 0x1f); - return PYX_TRANSPORT_INVALID_CDB_FIELD; - } - -} + struct se_cmd *cmd = task->task_se_cmd; + int ret; -int core_scsi3_emulate_pr(struct se_cmd *cmd) -{ - unsigned char *cdb = &cmd->t_task_cdb[0]; - struct se_device *dev = cmd->se_dev; /* * Following spc2r20 5.5.1 Reservations overview: * @@ -4223,16 +4251,38 @@ int core_scsi3_emulate_pr(struct se_cmd *cmd) * initiator or service action and shall terminate with a RESERVATION * CONFLICT status. */ - if (dev->dev_flags & DF_SPC2_RESERVATIONS) { + if (cmd->se_dev->dev_flags & DF_SPC2_RESERVATIONS) { pr_err("Received PERSISTENT_RESERVE CDB while legacy" " SPC-2 reservation is held, returning" " RESERVATION_CONFLICT\n"); return PYX_TRANSPORT_RESERVATION_CONFLICT; } - return (cdb[0] == PERSISTENT_RESERVE_OUT) ? - core_scsi3_emulate_pr_out(cmd, cdb) : - core_scsi3_emulate_pr_in(cmd, cdb); + switch (cmd->t_task_cdb[1] & 0x1f) { + case PRI_READ_KEYS: + ret = core_scsi3_pri_read_keys(cmd); + break; + case PRI_READ_RESERVATION: + ret = core_scsi3_pri_read_reservation(cmd); + break; + case PRI_REPORT_CAPABILITIES: + ret = core_scsi3_pri_report_capabilities(cmd); + break; + case PRI_READ_FULL_STATUS: + ret = core_scsi3_pri_read_full_status(cmd); + break; + default: + pr_err("Unknown PERSISTENT_RESERVE_IN service" + " action: 0x%02x\n", cmd->t_task_cdb[1] & 0x1f); + ret = PYX_TRANSPORT_INVALID_CDB_FIELD; + break; + } + + if (!ret) { + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); + } + return ret; } static int core_pt_reservation_check(struct se_cmd *cmd, u32 *pr_res_type) diff --git a/drivers/target/target_core_pr.h b/drivers/target/target_core_pr.h index c8f47d064584..b97f6940dd05 100644 --- a/drivers/target/target_core_pr.h +++ b/drivers/target/target_core_pr.h @@ -47,7 +47,8 @@ extern struct kmem_cache *t10_pr_reg_cache; extern int core_pr_dump_initiator_port(struct t10_pr_registration *, char *, u32); -extern int core_scsi2_emulate_crh(struct se_cmd *); +extern int target_scsi2_reservation_release(struct se_task *task); +extern int target_scsi2_reservation_reserve(struct se_task *task); extern int core_scsi3_alloc_aptpl_registration( struct t10_reservation *, u64, unsigned char *, unsigned char *, u32, @@ -61,7 +62,9 @@ extern void core_scsi3_free_all_registrations(struct se_device *); extern unsigned char *core_scsi3_pr_dump_type(int); extern int core_scsi3_check_cdb_abort_and_preempt(struct list_head *, struct se_cmd *); -extern int core_scsi3_emulate_pr(struct se_cmd *); + +extern int target_scsi3_emulate_pr_in(struct se_task *task); +extern int target_scsi3_emulate_pr_out(struct se_task *task); extern int core_setup_reservations(struct se_device *, int); #endif /* TARGET_CORE_PR_H */ diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index 2b7b0da9146d..ed32e1efe429 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -26,7 +26,6 @@ * ******************************************************************************/ -#include <linux/version.h> #include <linux/string.h> #include <linux/parser.h> #include <linux/timer.h> @@ -37,6 +36,7 @@ #include <linux/genhd.h> #include <linux/cdrom.h> #include <linux/file.h> +#include <linux/module.h> #include <scsi/scsi.h> #include <scsi/scsi_device.h> #include <scsi/scsi_cmnd.h> @@ -567,7 +567,7 @@ static struct se_device *pscsi_create_virtdevice( if (IS_ERR(sh)) { pr_err("pSCSI: Unable to locate" " pdv_host_id: %d\n", pdv->pdv_host_id); - return (struct se_device *) sh; + return ERR_CAST(sh); } } } else { @@ -677,7 +677,7 @@ static inline struct pscsi_plugin_task *PSCSI_TASK(struct se_task *task) */ static int pscsi_transport_complete(struct se_task *task) { - struct pscsi_dev_virt *pdv = task->se_dev->dev_ptr; + struct pscsi_dev_virt *pdv = task->task_se_cmd->se_dev->dev_ptr; struct scsi_device *sd = pdv->pdv_sd; int result; struct pscsi_plugin_task *pt = PSCSI_TASK(task); @@ -777,95 +777,6 @@ pscsi_alloc_task(unsigned char *cdb) return &pt->pscsi_task; } -static inline void pscsi_blk_init_request( - struct se_task *task, - struct pscsi_plugin_task *pt, - struct request *req, - int bidi_read) -{ - /* - * Defined as "scsi command" in include/linux/blkdev.h. - */ - req->cmd_type = REQ_TYPE_BLOCK_PC; - /* - * For the extra BIDI-COMMAND READ struct request we do not - * need to setup the remaining structure members - */ - if (bidi_read) - return; - /* - * Setup the done function pointer for struct request, - * also set the end_io_data pointer.to struct se_task. - */ - req->end_io = pscsi_req_done; - req->end_io_data = task; - /* - * Load the referenced struct se_task's SCSI CDB into - * include/linux/blkdev.h:struct request->cmd - */ - req->cmd_len = scsi_command_size(pt->pscsi_cdb); - req->cmd = &pt->pscsi_cdb[0]; - /* - * Setup pointer for outgoing sense data. - */ - req->sense = &pt->pscsi_sense[0]; - req->sense_len = 0; -} - -/* - * Used for pSCSI data payloads for all *NON* SCF_SCSI_DATA_SG_IO_CDB -*/ -static int pscsi_blk_get_request(struct se_task *task) -{ - struct pscsi_plugin_task *pt = PSCSI_TASK(task); - struct pscsi_dev_virt *pdv = task->se_dev->dev_ptr; - - pt->pscsi_req = blk_get_request(pdv->pdv_sd->request_queue, - (task->task_data_direction == DMA_TO_DEVICE), - GFP_KERNEL); - if (!pt->pscsi_req || IS_ERR(pt->pscsi_req)) { - pr_err("PSCSI: blk_get_request() failed: %ld\n", - IS_ERR(pt->pscsi_req)); - return PYX_TRANSPORT_LU_COMM_FAILURE; - } - /* - * Setup the newly allocated struct request for REQ_TYPE_BLOCK_PC, - * and setup rq callback, CDB and sense. - */ - pscsi_blk_init_request(task, pt, pt->pscsi_req, 0); - return 0; -} - -/* pscsi_do_task(): (Part of se_subsystem_api_t template) - * - * - */ -static int pscsi_do_task(struct se_task *task) -{ - struct pscsi_plugin_task *pt = PSCSI_TASK(task); - struct pscsi_dev_virt *pdv = task->se_dev->dev_ptr; - /* - * Set the struct request->timeout value based on peripheral - * device type from SCSI. - */ - if (pdv->pdv_sd->type == TYPE_DISK) - pt->pscsi_req->timeout = PS_TIMEOUT_DISK; - else - pt->pscsi_req->timeout = PS_TIMEOUT_OTHER; - - pt->pscsi_req->retries = PS_RETRY; - /* - * Queue the struct request into the struct scsi_device->request_queue. - * Also check for HEAD_OF_QUEUE SAM TASK attr from received se_cmd - * descriptor - */ - blk_execute_rq_nowait(pdv->pdv_sd->request_queue, NULL, pt->pscsi_req, - (task->task_se_cmd->sam_task_attr == MSG_HEAD_TAG), - pscsi_req_done); - - return PYX_TRANSPORT_SENT_TO_TRANSPORT; -} - static void pscsi_free_task(struct se_task *task) { struct pscsi_plugin_task *pt = PSCSI_TASK(task); @@ -1049,15 +960,12 @@ static inline struct bio *pscsi_get_bio(int sg_num) return bio; } -static int __pscsi_map_SG( - struct se_task *task, - struct scatterlist *task_sg, - u32 task_sg_num, - int bidi_read) +static int pscsi_map_sg(struct se_task *task, struct scatterlist *task_sg, + struct bio **hbio) { - struct pscsi_plugin_task *pt = PSCSI_TASK(task); - struct pscsi_dev_virt *pdv = task->se_dev->dev_ptr; - struct bio *bio = NULL, *hbio = NULL, *tbio = NULL; + struct pscsi_dev_virt *pdv = task->task_se_cmd->se_dev->dev_ptr; + u32 task_sg_num = task->task_sg_nents; + struct bio *bio = NULL, *tbio = NULL; struct page *page; struct scatterlist *sg; u32 data_len = task->task_size, i, len, bytes, off; @@ -1066,19 +974,8 @@ static int __pscsi_map_SG( int nr_vecs = 0, rc, ret = PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES; int rw = (task->task_data_direction == DMA_TO_DEVICE); - if (!task->task_size) - return 0; - /* - * For SCF_SCSI_DATA_SG_IO_CDB, Use fs/bio.c:bio_add_page() to setup - * the bio_vec maplist from task->task_sg -> - * struct scatterlist memory. The struct se_task->task_sg[] currently needs - * to be attached to struct bios for submission to Linux/SCSI using - * struct request to struct scsi_device->request_queue. - * - * Note that this will be changing post v2.6.28 as Target_Core_Mod/pSCSI - * is ported to upstream SCSI passthrough functionality that accepts - * struct scatterlist->page_link or struct page as a paraemeter. - */ + *hbio = NULL; + pr_debug("PSCSI: nr_pages: %d\n", nr_pages); for_each_sg(task_sg, sg, task_sg_num, i) { @@ -1115,8 +1012,8 @@ static int __pscsi_map_SG( * bios need to be added to complete a given * struct se_task */ - if (!hbio) - hbio = tbio = bio; + if (!*hbio) + *hbio = tbio = bio; else tbio = tbio->bi_next = bio; } @@ -1152,92 +1049,82 @@ static int __pscsi_map_SG( off = 0; } } - /* - * Setup the primary pt->pscsi_req used for non BIDI and BIDI-COMMAND - * primary SCSI WRITE poayload mapped for struct se_task->task_sg[] - */ - if (!bidi_read) { - /* - * Starting with v2.6.31, call blk_make_request() passing in *hbio to - * allocate the pSCSI task a struct request. - */ - pt->pscsi_req = blk_make_request(pdv->pdv_sd->request_queue, - hbio, GFP_KERNEL); - if (!pt->pscsi_req) { - pr_err("pSCSI: blk_make_request() failed\n"); - goto fail; - } - /* - * Setup the newly allocated struct request for REQ_TYPE_BLOCK_PC, - * and setup rq callback, CDB and sense. - */ - pscsi_blk_init_request(task, pt, pt->pscsi_req, 0); - - return task->task_sg_nents; - } - /* - * Setup the secondary pt->pscsi_req->next_rq used for the extra BIDI-COMMAND - * SCSI READ paylaod mapped for struct se_task->task_sg_bidi[] - */ - pt->pscsi_req->next_rq = blk_make_request(pdv->pdv_sd->request_queue, - hbio, GFP_KERNEL); - if (!pt->pscsi_req->next_rq) { - pr_err("pSCSI: blk_make_request() failed for BIDI\n"); - goto fail; - } - pscsi_blk_init_request(task, pt, pt->pscsi_req->next_rq, 1); return task->task_sg_nents; fail: - while (hbio) { - bio = hbio; - hbio = hbio->bi_next; + while (*hbio) { + bio = *hbio; + *hbio = (*hbio)->bi_next; bio->bi_next = NULL; - bio_endio(bio, 0); + bio_endio(bio, 0); /* XXX: should be error */ } return ret; } -/* - * pSCSI maps both ->map_control_SG() and ->map_data_SG() to a single call. - */ -static int pscsi_map_SG(struct se_task *task) +static int pscsi_do_task(struct se_task *task) { + struct pscsi_dev_virt *pdv = task->task_se_cmd->se_dev->dev_ptr; + struct pscsi_plugin_task *pt = PSCSI_TASK(task); + struct request *req; + struct bio *hbio; int ret; - /* - * Setup the main struct request for the task->task_sg[] payload - */ + target_get_task_cdb(task, pt->pscsi_cdb); + + if (task->task_se_cmd->se_cmd_flags & SCF_SCSI_NON_DATA_CDB) { + req = blk_get_request(pdv->pdv_sd->request_queue, + (task->task_data_direction == DMA_TO_DEVICE), + GFP_KERNEL); + if (!req || IS_ERR(req)) { + pr_err("PSCSI: blk_get_request() failed: %ld\n", + req ? IS_ERR(req) : -ENOMEM); + return PYX_TRANSPORT_LU_COMM_FAILURE; + } + } else { + BUG_ON(!task->task_size); - ret = __pscsi_map_SG(task, task->task_sg, task->task_sg_nents, 0); - if (ret >= 0 && task->task_sg_bidi) { /* - * If present, set up the extra BIDI-COMMAND SCSI READ - * struct request and payload. + * Setup the main struct request for the task->task_sg[] payload */ - ret = __pscsi_map_SG(task, task->task_sg_bidi, - task->task_sg_nents, 1); + ret = pscsi_map_sg(task, task->task_sg, &hbio); + if (ret < 0) + return PYX_TRANSPORT_LU_COMM_FAILURE; + + req = blk_make_request(pdv->pdv_sd->request_queue, hbio, + GFP_KERNEL); + if (IS_ERR(req)) { + pr_err("pSCSI: blk_make_request() failed\n"); + goto fail; + } } - if (ret < 0) - return PYX_TRANSPORT_LU_COMM_FAILURE; - return 0; -} + req->cmd_type = REQ_TYPE_BLOCK_PC; + req->end_io = pscsi_req_done; + req->end_io_data = task; + req->cmd_len = scsi_command_size(pt->pscsi_cdb); + req->cmd = &pt->pscsi_cdb[0]; + req->sense = &pt->pscsi_sense[0]; + req->sense_len = 0; + if (pdv->pdv_sd->type == TYPE_DISK) + req->timeout = PS_TIMEOUT_DISK; + else + req->timeout = PS_TIMEOUT_OTHER; + req->retries = PS_RETRY; -static int pscsi_CDB_none(struct se_task *task) -{ - return pscsi_blk_get_request(task); -} + blk_execute_rq_nowait(pdv->pdv_sd->request_queue, NULL, req, + (task->task_se_cmd->sam_task_attr == MSG_HEAD_TAG), + pscsi_req_done); -/* pscsi_get_cdb(): - * - * - */ -static unsigned char *pscsi_get_cdb(struct se_task *task) -{ - struct pscsi_plugin_task *pt = PSCSI_TASK(task); + return PYX_TRANSPORT_SENT_TO_TRANSPORT; - return pt->pscsi_cdb; +fail: + while (hbio) { + struct bio *bio = hbio; + hbio = hbio->bi_next; + bio->bi_next = NULL; + bio_endio(bio, 0); /* XXX: should be error */ + } + return PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES; } /* pscsi_get_sense_buffer(): @@ -1328,23 +1215,13 @@ static void pscsi_req_done(struct request *req, int uptodate) pt->pscsi_resid = req->resid_len; pscsi_process_SAM_status(task, pt); - /* - * Release BIDI-READ if present - */ - if (req->next_rq != NULL) - __blk_put_request(req->q, req->next_rq); - __blk_put_request(req->q, req); - pt->pscsi_req = NULL; } static struct se_subsystem_api pscsi_template = { .name = "pscsi", .owner = THIS_MODULE, .transport_type = TRANSPORT_PLUGIN_PHBA_PDEV, - .cdb_none = pscsi_CDB_none, - .map_control_SG = pscsi_map_SG, - .map_data_SG = pscsi_map_SG, .attach_hba = pscsi_attach_hba, .detach_hba = pscsi_detach_hba, .pmode_enable_hba = pscsi_pmode_enable_hba, @@ -1358,7 +1235,6 @@ static struct se_subsystem_api pscsi_template = { .check_configfs_dev_params = pscsi_check_configfs_dev_params, .set_configfs_dev_params = pscsi_set_configfs_dev_params, .show_configfs_dev_params = pscsi_show_configfs_dev_params, - .get_cdb = pscsi_get_cdb, .get_sense_buffer = pscsi_get_sense_buffer, .get_device_rev = pscsi_get_device_rev, .get_device_type = pscsi_get_device_type, diff --git a/drivers/target/target_core_pscsi.h b/drivers/target/target_core_pscsi.h index ebf4f1ae2c83..fdc17b6aefb3 100644 --- a/drivers/target/target_core_pscsi.h +++ b/drivers/target/target_core_pscsi.h @@ -27,7 +27,6 @@ struct pscsi_plugin_task { int pscsi_direction; int pscsi_result; u32 pscsi_resid; - struct request *pscsi_req; unsigned char pscsi_cdb[0]; } ____cacheline_aligned; diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c index e567e129c697..5158d3846f19 100644 --- a/drivers/target/target_core_rd.c +++ b/drivers/target/target_core_rd.c @@ -27,7 +27,6 @@ * ******************************************************************************/ -#include <linux/version.h> #include <linux/string.h> #include <linux/parser.h> #include <linux/timer.h> @@ -351,7 +350,7 @@ static struct rd_dev_sg_table *rd_get_sg_table(struct rd_dev *rd_dev, u32 page) static int rd_MEMCPY_read(struct rd_request *req) { struct se_task *task = &req->rd_task; - struct rd_dev *dev = req->rd_task.se_dev->dev_ptr; + struct rd_dev *dev = req->rd_task.task_se_cmd->se_dev->dev_ptr; struct rd_dev_sg_table *table; struct scatterlist *sg_d, *sg_s; void *dst, *src; @@ -467,7 +466,7 @@ static int rd_MEMCPY_read(struct rd_request *req) static int rd_MEMCPY_write(struct rd_request *req) { struct se_task *task = &req->rd_task; - struct rd_dev *dev = req->rd_task.se_dev->dev_ptr; + struct rd_dev *dev = req->rd_task.task_se_cmd->se_dev->dev_ptr; struct rd_dev_sg_table *table; struct scatterlist *sg_d, *sg_s; void *dst, *src; @@ -582,7 +581,7 @@ static int rd_MEMCPY_write(struct rd_request *req) */ static int rd_MEMCPY_do_task(struct se_task *task) { - struct se_device *dev = task->se_dev; + struct se_device *dev = task->task_se_cmd->se_dev; struct rd_request *req = RD_REQ(task); unsigned long long lba; int ret; @@ -692,17 +691,6 @@ static ssize_t rd_show_configfs_dev_params( return bl; } -/* rd_get_cdb(): (Part of se_subsystem_api_t template) - * - * - */ -static unsigned char *rd_get_cdb(struct se_task *task) -{ - struct rd_request *req = RD_REQ(task); - - return req->rd_scsi_cdb; -} - static u32 rd_get_device_rev(struct se_device *dev) { return SCSI_SPC_2; /* Returns SPC-3 in Initiator Data */ @@ -736,7 +724,6 @@ static struct se_subsystem_api rd_mcp_template = { .check_configfs_dev_params = rd_check_configfs_dev_params, .set_configfs_dev_params = rd_set_configfs_dev_params, .show_configfs_dev_params = rd_show_configfs_dev_params, - .get_cdb = rd_get_cdb, .get_device_rev = rd_get_device_rev, .get_device_type = rd_get_device_type, .get_blocks = rd_get_blocks, diff --git a/drivers/target/target_core_rd.h b/drivers/target/target_core_rd.h index 0d027732cd00..784e56a04100 100644 --- a/drivers/target/target_core_rd.h +++ b/drivers/target/target_core_rd.h @@ -22,8 +22,6 @@ void rd_module_exit(void); struct rd_request { struct se_task rd_task; - /* SCSI CDB from iSCSI Command PDU */ - unsigned char rd_scsi_cdb[TCM_MAX_COMMAND_SIZE]; /* Offset from start of page */ u32 rd_offset; /* Starting page in Ramdisk for request */ diff --git a/drivers/target/target_core_scdb.c b/drivers/target/target_core_scdb.c deleted file mode 100644 index 72843441d4fa..000000000000 --- a/drivers/target/target_core_scdb.c +++ /dev/null @@ -1,105 +0,0 @@ -/******************************************************************************* - * Filename: target_core_scdb.c - * - * This file contains the generic target engine Split CDB related functions. - * - * Copyright (c) 2004-2005 PyX Technologies, Inc. - * Copyright (c) 2005, 2006, 2007 SBE, Inc. - * Copyright (c) 2007-2010 Rising Tide Systems - * Copyright (c) 2008-2010 Linux-iSCSI.org - * - * Nicholas A. Bellinger <nab@kernel.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - ******************************************************************************/ - -#include <linux/net.h> -#include <linux/string.h> -#include <scsi/scsi.h> -#include <asm/unaligned.h> - -#include <target/target_core_base.h> -#include <target/target_core_transport.h> - -#include "target_core_scdb.h" - -/* split_cdb_XX_6(): - * - * 21-bit LBA w/ 8-bit SECTORS - */ -void split_cdb_XX_6( - unsigned long long lba, - u32 sectors, - unsigned char *cdb) -{ - cdb[1] = (lba >> 16) & 0x1f; - cdb[2] = (lba >> 8) & 0xff; - cdb[3] = lba & 0xff; - cdb[4] = sectors & 0xff; -} - -/* split_cdb_XX_10(): - * - * 32-bit LBA w/ 16-bit SECTORS - */ -void split_cdb_XX_10( - unsigned long long lba, - u32 sectors, - unsigned char *cdb) -{ - put_unaligned_be32(lba, &cdb[2]); - put_unaligned_be16(sectors, &cdb[7]); -} - -/* split_cdb_XX_12(): - * - * 32-bit LBA w/ 32-bit SECTORS - */ -void split_cdb_XX_12( - unsigned long long lba, - u32 sectors, - unsigned char *cdb) -{ - put_unaligned_be32(lba, &cdb[2]); - put_unaligned_be32(sectors, &cdb[6]); -} - -/* split_cdb_XX_16(): - * - * 64-bit LBA w/ 32-bit SECTORS - */ -void split_cdb_XX_16( - unsigned long long lba, - u32 sectors, - unsigned char *cdb) -{ - put_unaligned_be64(lba, &cdb[2]); - put_unaligned_be32(sectors, &cdb[10]); -} - -/* - * split_cdb_XX_32(): - * - * 64-bit LBA w/ 32-bit SECTORS such as READ_32, WRITE_32 and emulated XDWRITEREAD_32 - */ -void split_cdb_XX_32( - unsigned long long lba, - u32 sectors, - unsigned char *cdb) -{ - put_unaligned_be64(lba, &cdb[12]); - put_unaligned_be32(sectors, &cdb[28]); -} diff --git a/drivers/target/target_core_scdb.h b/drivers/target/target_core_scdb.h deleted file mode 100644 index 48e9ccc9585e..000000000000 --- a/drivers/target/target_core_scdb.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef TARGET_CORE_SCDB_H -#define TARGET_CORE_SCDB_H - -extern void split_cdb_XX_6(unsigned long long, u32, unsigned char *); -extern void split_cdb_XX_10(unsigned long long, u32, unsigned char *); -extern void split_cdb_XX_12(unsigned long long, u32, unsigned char *); -extern void split_cdb_XX_16(unsigned long long, u32, unsigned char *); -extern void split_cdb_XX_32(unsigned long long, u32, unsigned char *); - -#endif /* TARGET_CORE_SCDB_H */ diff --git a/drivers/target/target_core_stat.c b/drivers/target/target_core_stat.c index a8d6e1dee938..874152aed94a 100644 --- a/drivers/target/target_core_stat.c +++ b/drivers/target/target_core_stat.c @@ -32,7 +32,6 @@ #include <linux/delay.h> #include <linux/timer.h> #include <linux/string.h> -#include <linux/version.h> #include <generated/utsrelease.h> #include <linux/utsname.h> #include <linux/proc_fs.h> diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c index 27d4925e51c3..217e29df6297 100644 --- a/drivers/target/target_core_tmr.c +++ b/drivers/target/target_core_tmr.c @@ -24,10 +24,10 @@ * ******************************************************************************/ -#include <linux/version.h> #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/list.h> +#include <linux/export.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> @@ -44,12 +44,12 @@ struct se_tmr_req *core_tmr_alloc_req( struct se_cmd *se_cmd, void *fabric_tmr_ptr, - u8 function) + u8 function, + gfp_t gfp_flags) { struct se_tmr_req *tmr; - tmr = kmem_cache_zalloc(se_tmr_req_cache, (in_interrupt()) ? - GFP_ATOMIC : GFP_KERNEL); + tmr = kmem_cache_zalloc(se_tmr_req_cache, gfp_flags); if (!tmr) { pr_err("Unable to allocate struct se_tmr_req\n"); return ERR_PTR(-ENOMEM); @@ -67,15 +67,16 @@ void core_tmr_release_req( struct se_tmr_req *tmr) { struct se_device *dev = tmr->tmr_dev; + unsigned long flags; if (!dev) { kmem_cache_free(se_tmr_req_cache, tmr); return; } - spin_lock_irq(&dev->se_tmr_lock); + spin_lock_irqsave(&dev->se_tmr_lock, flags); list_del(&tmr->tmr_list); - spin_unlock_irq(&dev->se_tmr_lock); + spin_unlock_irqrestore(&dev->se_tmr_lock, flags); kmem_cache_free(se_tmr_req_cache, tmr); } @@ -100,59 +101,25 @@ static void core_tmr_handle_tas_abort( transport_cmd_finish_abort(cmd, 0); } -int core_tmr_lun_reset( +static void core_tmr_drain_tmr_list( struct se_device *dev, struct se_tmr_req *tmr, - struct list_head *preempt_and_abort_list, - struct se_cmd *prout_cmd) + struct list_head *preempt_and_abort_list) { - struct se_cmd *cmd, *tcmd; - struct se_node_acl *tmr_nacl = NULL; - struct se_portal_group *tmr_tpg = NULL; - struct se_queue_obj *qobj = &dev->dev_queue_obj; + LIST_HEAD(drain_tmr_list); struct se_tmr_req *tmr_p, *tmr_pp; - struct se_task *task, *task_tmp; + struct se_cmd *cmd; unsigned long flags; - int fe_count, tas; - /* - * TASK_ABORTED status bit, this is configurable via ConfigFS - * struct se_device attributes. spc4r17 section 7.4.6 Control mode page - * - * A task aborted status (TAS) bit set to zero specifies that aborted - * tasks shall be terminated by the device server without any response - * to the application client. A TAS bit set to one specifies that tasks - * aborted by the actions of an I_T nexus other than the I_T nexus on - * which the command was received shall be completed with TASK ABORTED - * status (see SAM-4). - */ - tas = dev->se_sub_dev->se_dev_attrib.emulate_tas; - /* - * Determine if this se_tmr is coming from a $FABRIC_MOD - * or struct se_device passthrough.. - */ - if (tmr && tmr->task_cmd && tmr->task_cmd->se_sess) { - tmr_nacl = tmr->task_cmd->se_sess->se_node_acl; - tmr_tpg = tmr->task_cmd->se_sess->se_tpg; - if (tmr_nacl && tmr_tpg) { - pr_debug("LUN_RESET: TMR caller fabric: %s" - " initiator port %s\n", - tmr_tpg->se_tpg_tfo->get_fabric_name(), - tmr_nacl->initiatorname); - } - } - pr_debug("LUN_RESET: %s starting for [%s], tas: %d\n", - (preempt_and_abort_list) ? "Preempt" : "TMR", - dev->transport->name, tas); /* * Release all pending and outgoing TMRs aside from the received * LUN_RESET tmr.. */ - spin_lock_irq(&dev->se_tmr_lock); + spin_lock_irqsave(&dev->se_tmr_lock, flags); list_for_each_entry_safe(tmr_p, tmr_pp, &dev->dev_tmr_list, tmr_list) { /* * Allow the received TMR to return with FUNCTION_COMPLETE. */ - if (tmr && (tmr_p == tmr)) + if (tmr_p == tmr) continue; cmd = tmr_p->task_cmd; @@ -169,29 +136,47 @@ int core_tmr_lun_reset( (core_scsi3_check_cdb_abort_and_preempt( preempt_and_abort_list, cmd) != 0)) continue; - spin_unlock_irq(&dev->se_tmr_lock); - spin_lock_irqsave(&cmd->t_state_lock, flags); + spin_lock(&cmd->t_state_lock); if (!atomic_read(&cmd->t_transport_active)) { - spin_unlock_irqrestore(&cmd->t_state_lock, flags); - spin_lock_irq(&dev->se_tmr_lock); + spin_unlock(&cmd->t_state_lock); continue; } if (cmd->t_state == TRANSPORT_ISTATE_PROCESSING) { - spin_unlock_irqrestore(&cmd->t_state_lock, flags); - spin_lock_irq(&dev->se_tmr_lock); + spin_unlock(&cmd->t_state_lock); continue; } + spin_unlock(&cmd->t_state_lock); + + list_move_tail(&tmr_p->tmr_list, &drain_tmr_list); + } + spin_unlock_irqrestore(&dev->se_tmr_lock, flags); + + list_for_each_entry_safe(tmr_p, tmr_pp, &drain_tmr_list, tmr_list) { + list_del_init(&tmr_p->tmr_list); + cmd = tmr_p->task_cmd; + pr_debug("LUN_RESET: %s releasing TMR %p Function: 0x%02x," " Response: 0x%02x, t_state: %d\n", (preempt_and_abort_list) ? "Preempt" : "", tmr_p, tmr_p->function, tmr_p->response, cmd->t_state); - spin_unlock_irqrestore(&cmd->t_state_lock, flags); - transport_cmd_finish_abort_tmr(cmd); - spin_lock_irq(&dev->se_tmr_lock); + transport_cmd_finish_abort(cmd, 1); } - spin_unlock_irq(&dev->se_tmr_lock); +} + +static void core_tmr_drain_task_list( + struct se_device *dev, + struct se_cmd *prout_cmd, + struct se_node_acl *tmr_nacl, + int tas, + struct list_head *preempt_and_abort_list) +{ + LIST_HEAD(drain_task_list); + struct se_cmd *cmd; + struct se_task *task, *task_tmp; + unsigned long flags; + int fe_count; /* * Complete outstanding struct se_task CDBs with TASK_ABORTED SAM status. * This is following sam4r17, section 5.6 Aborting commands, Table 38 @@ -236,18 +221,28 @@ int core_tmr_lun_reset( if (prout_cmd == cmd) continue; - list_del(&task->t_state_list); + list_move_tail(&task->t_state_list, &drain_task_list); atomic_set(&task->task_state_active, 0); - spin_unlock_irqrestore(&dev->execute_task_lock, flags); + /* + * Remove from task execute list before processing drain_task_list + */ + if (!list_empty(&task->t_execute_list)) + __transport_remove_task_from_execute_queue(task, dev); + } + spin_unlock_irqrestore(&dev->execute_task_lock, flags); + + while (!list_empty(&drain_task_list)) { + task = list_entry(drain_task_list.next, struct se_task, t_state_list); + list_del(&task->t_state_list); + cmd = task->task_se_cmd; - spin_lock_irqsave(&cmd->t_state_lock, flags); pr_debug("LUN_RESET: %s cmd: %p task: %p" - " ITT/CmdSN: 0x%08x/0x%08x, i_state: %d, t_state/" - "def_t_state: %d/%d cdb: 0x%02x\n", + " ITT/CmdSN: 0x%08x/0x%08x, i_state: %d, t_state: %d" + "cdb: 0x%02x\n", (preempt_and_abort_list) ? "Preempt" : "", cmd, task, cmd->se_tfo->get_task_tag(cmd), 0, cmd->se_tfo->get_cmd_state(cmd), cmd->t_state, - cmd->deferred_t_state, cmd->t_task_cdb[0]); + cmd->t_task_cdb[0]); pr_debug("LUN_RESET: ITT[0x%08x] - pr_res_key: 0x%016Lx" " t_task_cdbs: %d t_task_cdbs_left: %d" " t_task_cdbs_sent: %d -- t_transport_active: %d" @@ -260,35 +255,24 @@ int core_tmr_lun_reset( atomic_read(&cmd->t_transport_stop), atomic_read(&cmd->t_transport_sent)); - if (atomic_read(&task->task_active)) { - atomic_set(&task->task_stop, 1); - spin_unlock_irqrestore( - &cmd->t_state_lock, flags); - - pr_debug("LUN_RESET: Waiting for task: %p to shutdown" - " for dev: %p\n", task, dev); - wait_for_completion(&task->task_stop_comp); - pr_debug("LUN_RESET Completed task: %p shutdown for" - " dev: %p\n", task, dev); - spin_lock_irqsave(&cmd->t_state_lock, flags); - atomic_dec(&cmd->t_task_cdbs_left); - - atomic_set(&task->task_active, 0); - atomic_set(&task->task_stop, 0); - } else { - if (atomic_read(&task->task_execute_queue) != 0) - transport_remove_task_from_execute_queue(task, dev); - } - __transport_stop_task_timer(task, &flags); + /* + * If the command may be queued onto a workqueue cancel it now. + * + * This is equivalent to removal from the execute queue in the + * loop above, but we do it down here given that + * cancel_work_sync may block. + */ + if (cmd->t_state == TRANSPORT_COMPLETE) + cancel_work_sync(&cmd->work); + + spin_lock_irqsave(&cmd->t_state_lock, flags); + target_stop_task(task, &flags); if (!atomic_dec_and_test(&cmd->t_task_cdbs_ex_left)) { - spin_unlock_irqrestore( - &cmd->t_state_lock, flags); + spin_unlock_irqrestore(&cmd->t_state_lock, flags); pr_debug("LUN_RESET: Skipping task: %p, dev: %p for" " t_task_cdbs_ex_left: %d\n", task, dev, atomic_read(&cmd->t_task_cdbs_ex_left)); - - spin_lock_irqsave(&dev->execute_task_lock, flags); continue; } fe_count = atomic_read(&cmd->t_fe_count); @@ -298,22 +282,31 @@ int core_tmr_lun_reset( " task: %p, t_fe_count: %d dev: %p\n", task, fe_count, dev); atomic_set(&cmd->t_transport_aborted, 1); - spin_unlock_irqrestore(&cmd->t_state_lock, - flags); - core_tmr_handle_tas_abort(tmr_nacl, cmd, tas, fe_count); + spin_unlock_irqrestore(&cmd->t_state_lock, flags); - spin_lock_irqsave(&dev->execute_task_lock, flags); + core_tmr_handle_tas_abort(tmr_nacl, cmd, tas, fe_count); continue; } pr_debug("LUN_RESET: Got t_transport_active = 0 for task: %p," " t_fe_count: %d dev: %p\n", task, fe_count, dev); atomic_set(&cmd->t_transport_aborted, 1); spin_unlock_irqrestore(&cmd->t_state_lock, flags); - core_tmr_handle_tas_abort(tmr_nacl, cmd, tas, fe_count); - spin_lock_irqsave(&dev->execute_task_lock, flags); + core_tmr_handle_tas_abort(tmr_nacl, cmd, tas, fe_count); } - spin_unlock_irqrestore(&dev->execute_task_lock, flags); +} + +static void core_tmr_drain_cmd_list( + struct se_device *dev, + struct se_cmd *prout_cmd, + struct se_node_acl *tmr_nacl, + int tas, + struct list_head *preempt_and_abort_list) +{ + LIST_HEAD(drain_cmd_list); + struct se_queue_obj *qobj = &dev->dev_queue_obj; + struct se_cmd *cmd, *tcmd; + unsigned long flags; /* * Release all commands remaining in the struct se_device cmd queue. * @@ -338,10 +331,15 @@ int core_tmr_lun_reset( if (prout_cmd == cmd) continue; - atomic_dec(&cmd->t_transport_queue_active); + atomic_set(&cmd->t_transport_queue_active, 0); atomic_dec(&qobj->queue_cnt); - list_del(&cmd->se_queue_node); - spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); + list_move_tail(&cmd->se_queue_node, &drain_cmd_list); + } + spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); + + while (!list_empty(&drain_cmd_list)) { + cmd = list_entry(drain_cmd_list.next, struct se_cmd, se_queue_node); + list_del_init(&cmd->se_queue_node); pr_debug("LUN_RESET: %s from Device Queue: cmd: %p t_state:" " %d t_fe_count: %d\n", (preempt_and_abort_list) ? @@ -354,9 +352,53 @@ int core_tmr_lun_reset( core_tmr_handle_tas_abort(tmr_nacl, cmd, tas, atomic_read(&cmd->t_fe_count)); - spin_lock_irqsave(&qobj->cmd_queue_lock, flags); } - spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); +} + +int core_tmr_lun_reset( + struct se_device *dev, + struct se_tmr_req *tmr, + struct list_head *preempt_and_abort_list, + struct se_cmd *prout_cmd) +{ + struct se_node_acl *tmr_nacl = NULL; + struct se_portal_group *tmr_tpg = NULL; + int tas; + /* + * TASK_ABORTED status bit, this is configurable via ConfigFS + * struct se_device attributes. spc4r17 section 7.4.6 Control mode page + * + * A task aborted status (TAS) bit set to zero specifies that aborted + * tasks shall be terminated by the device server without any response + * to the application client. A TAS bit set to one specifies that tasks + * aborted by the actions of an I_T nexus other than the I_T nexus on + * which the command was received shall be completed with TASK ABORTED + * status (see SAM-4). + */ + tas = dev->se_sub_dev->se_dev_attrib.emulate_tas; + /* + * Determine if this se_tmr is coming from a $FABRIC_MOD + * or struct se_device passthrough.. + */ + if (tmr && tmr->task_cmd && tmr->task_cmd->se_sess) { + tmr_nacl = tmr->task_cmd->se_sess->se_node_acl; + tmr_tpg = tmr->task_cmd->se_sess->se_tpg; + if (tmr_nacl && tmr_tpg) { + pr_debug("LUN_RESET: TMR caller fabric: %s" + " initiator port %s\n", + tmr_tpg->se_tpg_tfo->get_fabric_name(), + tmr_nacl->initiatorname); + } + } + pr_debug("LUN_RESET: %s starting for [%s], tas: %d\n", + (preempt_and_abort_list) ? "Preempt" : "TMR", + dev->transport->name, tas); + + core_tmr_drain_tmr_list(dev, tmr, preempt_and_abort_list); + core_tmr_drain_task_list(dev, prout_cmd, tmr_nacl, tas, + preempt_and_abort_list); + core_tmr_drain_cmd_list(dev, prout_cmd, tmr_nacl, tas, + preempt_and_abort_list); /* * Clear any legacy SPC-2 reservation when called during * LOGICAL UNIT RESET @@ -379,3 +421,4 @@ int core_tmr_lun_reset( dev->transport->name); return 0; } + diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index 162b736c7342..8ddd133025b9 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -32,6 +32,7 @@ #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/in.h> +#include <linux/export.h> #include <net/sock.h> #include <net/tcp.h> #include <scsi/scsi.h> @@ -593,7 +594,7 @@ int core_tpg_set_initiator_node_queue_depth( if (init_sess) tpg->se_tpg_tfo->close_session(init_sess); - pr_debug("Successfuly changed queue depth to: %d for Initiator" + pr_debug("Successfully changed queue depth to: %d for Initiator" " Node: %s on %s Target Portal Group: %u\n", queue_depth, initiatorname, tpg->se_tpg_tfo->get_fabric_name(), tpg->se_tpg_tfo->tpg_get_tag(tpg)); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index a4b0a8d27f25..3400ae6e93f8 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -26,7 +26,6 @@ * ******************************************************************************/ -#include <linux/version.h> #include <linux/net.h> #include <linux/delay.h> #include <linux/string.h> @@ -37,6 +36,7 @@ #include <linux/kthread.h> #include <linux/in.h> #include <linux/cdrom.h> +#include <linux/module.h> #include <asm/unaligned.h> #include <net/sock.h> #include <net/tcp.h> @@ -53,13 +53,14 @@ #include <target/target_core_configfs.h> #include "target_core_alua.h" +#include "target_core_cdb.h" #include "target_core_hba.h" #include "target_core_pr.h" -#include "target_core_scdb.h" #include "target_core_ua.h" static int sub_api_initialized; +static struct workqueue_struct *target_completion_wq; static struct kmem_cache *se_cmd_cache; static struct kmem_cache *se_sess_cache; struct kmem_cache *se_tmr_req_cache; @@ -70,30 +71,19 @@ struct kmem_cache *t10_alua_lu_gp_mem_cache; struct kmem_cache *t10_alua_tg_pt_gp_cache; struct kmem_cache *t10_alua_tg_pt_gp_mem_cache; -/* Used for transport_dev_get_map_*() */ -typedef int (*map_func_t)(struct se_task *, u32); - static int transport_generic_write_pending(struct se_cmd *); static int transport_processing_thread(void *param); static int __transport_execute_tasks(struct se_device *dev); static void transport_complete_task_attr(struct se_cmd *cmd); -static int transport_complete_qf(struct se_cmd *cmd); static void transport_handle_queue_full(struct se_cmd *cmd, - struct se_device *dev, int (*qf_callback)(struct se_cmd *)); -static void transport_direct_request_timeout(struct se_cmd *cmd); + struct se_device *dev); static void transport_free_dev_tasks(struct se_cmd *cmd); -static u32 transport_allocate_tasks(struct se_cmd *cmd, - unsigned long long starting_lba, - enum dma_data_direction data_direction, - struct scatterlist *sgl, unsigned int nents); static int transport_generic_get_mem(struct se_cmd *cmd); -static int transport_generic_remove(struct se_cmd *cmd, - int session_reinstatement); -static void transport_release_fe_cmd(struct se_cmd *cmd); -static void transport_remove_cmd_from_queue(struct se_cmd *cmd, - struct se_queue_obj *qobj); +static void transport_put_cmd(struct se_cmd *cmd); +static void transport_remove_cmd_from_queue(struct se_cmd *cmd); static int transport_set_sense_codes(struct se_cmd *cmd, u8 asc, u8 ascq); -static void transport_stop_all_task_timers(struct se_cmd *cmd); +static void transport_generic_request_failure(struct se_cmd *, int, int); +static void target_complete_ok_work(struct work_struct *work); int init_se_kmem_caches(void) { @@ -109,7 +99,7 @@ int init_se_kmem_caches(void) if (!se_tmr_req_cache) { pr_err("kmem_cache_create() for struct se_tmr_req" " failed\n"); - goto out; + goto out_free_cmd_cache; } se_sess_cache = kmem_cache_create("se_sess_cache", sizeof(struct se_session), __alignof__(struct se_session), @@ -117,14 +107,14 @@ int init_se_kmem_caches(void) if (!se_sess_cache) { pr_err("kmem_cache_create() for struct se_session" " failed\n"); - goto out; + goto out_free_tmr_req_cache; } se_ua_cache = kmem_cache_create("se_ua_cache", sizeof(struct se_ua), __alignof__(struct se_ua), 0, NULL); if (!se_ua_cache) { pr_err("kmem_cache_create() for struct se_ua failed\n"); - goto out; + goto out_free_sess_cache; } t10_pr_reg_cache = kmem_cache_create("t10_pr_reg_cache", sizeof(struct t10_pr_registration), @@ -132,7 +122,7 @@ int init_se_kmem_caches(void) if (!t10_pr_reg_cache) { pr_err("kmem_cache_create() for struct t10_pr_registration" " failed\n"); - goto out; + goto out_free_ua_cache; } t10_alua_lu_gp_cache = kmem_cache_create("t10_alua_lu_gp_cache", sizeof(struct t10_alua_lu_gp), __alignof__(struct t10_alua_lu_gp), @@ -140,7 +130,7 @@ int init_se_kmem_caches(void) if (!t10_alua_lu_gp_cache) { pr_err("kmem_cache_create() for t10_alua_lu_gp_cache" " failed\n"); - goto out; + goto out_free_pr_reg_cache; } t10_alua_lu_gp_mem_cache = kmem_cache_create("t10_alua_lu_gp_mem_cache", sizeof(struct t10_alua_lu_gp_member), @@ -148,7 +138,7 @@ int init_se_kmem_caches(void) if (!t10_alua_lu_gp_mem_cache) { pr_err("kmem_cache_create() for t10_alua_lu_gp_mem_" "cache failed\n"); - goto out; + goto out_free_lu_gp_cache; } t10_alua_tg_pt_gp_cache = kmem_cache_create("t10_alua_tg_pt_gp_cache", sizeof(struct t10_alua_tg_pt_gp), @@ -156,7 +146,7 @@ int init_se_kmem_caches(void) if (!t10_alua_tg_pt_gp_cache) { pr_err("kmem_cache_create() for t10_alua_tg_pt_gp_" "cache failed\n"); - goto out; + goto out_free_lu_gp_mem_cache; } t10_alua_tg_pt_gp_mem_cache = kmem_cache_create( "t10_alua_tg_pt_gp_mem_cache", @@ -166,34 +156,41 @@ int init_se_kmem_caches(void) if (!t10_alua_tg_pt_gp_mem_cache) { pr_err("kmem_cache_create() for t10_alua_tg_pt_gp_" "mem_t failed\n"); - goto out; + goto out_free_tg_pt_gp_cache; } + target_completion_wq = alloc_workqueue("target_completion", + WQ_MEM_RECLAIM, 0); + if (!target_completion_wq) + goto out_free_tg_pt_gp_mem_cache; + return 0; + +out_free_tg_pt_gp_mem_cache: + kmem_cache_destroy(t10_alua_tg_pt_gp_mem_cache); +out_free_tg_pt_gp_cache: + kmem_cache_destroy(t10_alua_tg_pt_gp_cache); +out_free_lu_gp_mem_cache: + kmem_cache_destroy(t10_alua_lu_gp_mem_cache); +out_free_lu_gp_cache: + kmem_cache_destroy(t10_alua_lu_gp_cache); +out_free_pr_reg_cache: + kmem_cache_destroy(t10_pr_reg_cache); +out_free_ua_cache: + kmem_cache_destroy(se_ua_cache); +out_free_sess_cache: + kmem_cache_destroy(se_sess_cache); +out_free_tmr_req_cache: + kmem_cache_destroy(se_tmr_req_cache); +out_free_cmd_cache: + kmem_cache_destroy(se_cmd_cache); out: - if (se_cmd_cache) - kmem_cache_destroy(se_cmd_cache); - if (se_tmr_req_cache) - kmem_cache_destroy(se_tmr_req_cache); - if (se_sess_cache) - kmem_cache_destroy(se_sess_cache); - if (se_ua_cache) - kmem_cache_destroy(se_ua_cache); - if (t10_pr_reg_cache) - kmem_cache_destroy(t10_pr_reg_cache); - if (t10_alua_lu_gp_cache) - kmem_cache_destroy(t10_alua_lu_gp_cache); - if (t10_alua_lu_gp_mem_cache) - kmem_cache_destroy(t10_alua_lu_gp_mem_cache); - if (t10_alua_tg_pt_gp_cache) - kmem_cache_destroy(t10_alua_tg_pt_gp_cache); - if (t10_alua_tg_pt_gp_mem_cache) - kmem_cache_destroy(t10_alua_tg_pt_gp_mem_cache); return -ENOMEM; } void release_se_kmem_caches(void) { + destroy_workqueue(target_completion_wq); kmem_cache_destroy(se_cmd_cache); kmem_cache_destroy(se_tmr_req_cache); kmem_cache_destroy(se_sess_cache); @@ -234,10 +231,13 @@ void transport_init_queue_obj(struct se_queue_obj *qobj) } EXPORT_SYMBOL(transport_init_queue_obj); -static int transport_subsystem_reqmods(void) +void transport_subsystem_check_init(void) { int ret; + if (sub_api_initialized) + return; + ret = request_module("target_core_iblock"); if (ret != 0) pr_err("Unable to load target_core_iblock\n"); @@ -254,24 +254,8 @@ static int transport_subsystem_reqmods(void) if (ret != 0) pr_err("Unable to load target_core_stgt\n"); - return 0; -} - -int transport_subsystem_check_init(void) -{ - int ret; - - if (sub_api_initialized) - return 0; - /* - * Request the loading of known TCM subsystem plugins.. - */ - ret = transport_subsystem_reqmods(); - if (ret < 0) - return ret; - sub_api_initialized = 1; - return 0; + return; } struct se_session *transport_init_session(void) @@ -286,6 +270,9 @@ struct se_session *transport_init_session(void) } INIT_LIST_HEAD(&se_sess->sess_list); INIT_LIST_HEAD(&se_sess->sess_acl_list); + INIT_LIST_HEAD(&se_sess->sess_cmd_list); + INIT_LIST_HEAD(&se_sess->sess_wait_list); + spin_lock_init(&se_sess->sess_cmd_lock); return se_sess; } @@ -438,16 +425,15 @@ EXPORT_SYMBOL(transport_deregister_session); */ static void transport_all_task_dev_remove_state(struct se_cmd *cmd) { - struct se_device *dev; + struct se_device *dev = cmd->se_dev; struct se_task *task; unsigned long flags; - list_for_each_entry(task, &cmd->t_task_list, t_list) { - dev = task->se_dev; - if (!dev) - continue; + if (!dev) + return; - if (atomic_read(&task->task_active)) + list_for_each_entry(task, &cmd->t_task_list, t_list) { + if (task->task_flags & TF_ACTIVE) continue; if (!atomic_read(&task->task_state_active)) @@ -489,8 +475,6 @@ static int transport_cmd_check_stop( " == TRUE for ITT: 0x%08x\n", __func__, __LINE__, cmd->se_tfo->get_task_tag(cmd)); - cmd->deferred_t_state = cmd->t_state; - cmd->t_state = TRANSPORT_DEFERRED_CMD; atomic_set(&cmd->t_transport_active, 0); if (transport_off == 2) transport_all_task_dev_remove_state(cmd); @@ -508,8 +492,6 @@ static int transport_cmd_check_stop( " TRUE for ITT: 0x%08x\n", __func__, __LINE__, cmd->se_tfo->get_task_tag(cmd)); - cmd->deferred_t_state = cmd->t_state; - cmd->t_state = TRANSPORT_DEFERRED_CMD; if (transport_off == 2) transport_all_task_dev_remove_state(cmd); @@ -537,13 +519,16 @@ static int transport_cmd_check_stop( * Some fabric modules like tcm_loop can release * their internally allocated I/O reference now and * struct se_cmd now. + * + * Fabric modules are expected to return '1' here if the + * se_cmd being passed is released at this point, + * or zero if not being released. */ if (cmd->se_tfo->check_stop_free != NULL) { spin_unlock_irqrestore( &cmd->t_state_lock, flags); - cmd->se_tfo->check_stop_free(cmd); - return 1; + return cmd->se_tfo->check_stop_free(cmd); } } spin_unlock_irqrestore(&cmd->t_state_lock, flags); @@ -594,35 +579,24 @@ check_lun: void transport_cmd_finish_abort(struct se_cmd *cmd, int remove) { - transport_remove_cmd_from_queue(cmd, &cmd->se_dev->dev_queue_obj); - transport_lun_remove_cmd(cmd); + if (!cmd->se_tmr_req) + transport_lun_remove_cmd(cmd); if (transport_cmd_check_stop_to_fabric(cmd)) return; - if (remove) - transport_generic_remove(cmd, 0); -} - -void transport_cmd_finish_abort_tmr(struct se_cmd *cmd) -{ - transport_remove_cmd_from_queue(cmd, &cmd->se_dev->dev_queue_obj); - - if (transport_cmd_check_stop_to_fabric(cmd)) - return; - - transport_generic_remove(cmd, 0); + if (remove) { + transport_remove_cmd_from_queue(cmd); + transport_put_cmd(cmd); + } } -static void transport_add_cmd_to_queue( - struct se_cmd *cmd, - int t_state) +static void transport_add_cmd_to_queue(struct se_cmd *cmd, int t_state, + bool at_head) { struct se_device *dev = cmd->se_dev; struct se_queue_obj *qobj = &dev->dev_queue_obj; unsigned long flags; - INIT_LIST_HEAD(&cmd->se_queue_node); - if (t_state) { spin_lock_irqsave(&cmd->t_state_lock, flags); cmd->t_state = t_state; @@ -631,15 +605,20 @@ static void transport_add_cmd_to_queue( } spin_lock_irqsave(&qobj->cmd_queue_lock, flags); - if (cmd->se_cmd_flags & SCF_EMULATE_QUEUE_FULL) { - cmd->se_cmd_flags &= ~SCF_EMULATE_QUEUE_FULL; + + /* If the cmd is already on the list, remove it before we add it */ + if (!list_empty(&cmd->se_queue_node)) + list_del(&cmd->se_queue_node); + else + atomic_inc(&qobj->queue_cnt); + + if (at_head) list_add(&cmd->se_queue_node, &qobj->qobj_list); - } else + else list_add_tail(&cmd->se_queue_node, &qobj->qobj_list); - atomic_inc(&cmd->t_transport_queue_active); + atomic_set(&cmd->t_transport_queue_active, 1); spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); - atomic_inc(&qobj->queue_cnt); wake_up_interruptible(&qobj->thread_wq); } @@ -656,19 +635,18 @@ transport_get_cmd_from_queue(struct se_queue_obj *qobj) } cmd = list_first_entry(&qobj->qobj_list, struct se_cmd, se_queue_node); - atomic_dec(&cmd->t_transport_queue_active); + atomic_set(&cmd->t_transport_queue_active, 0); - list_del(&cmd->se_queue_node); + list_del_init(&cmd->se_queue_node); atomic_dec(&qobj->queue_cnt); spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); return cmd; } -static void transport_remove_cmd_from_queue(struct se_cmd *cmd, - struct se_queue_obj *qobj) +static void transport_remove_cmd_from_queue(struct se_cmd *cmd) { - struct se_cmd *t; + struct se_queue_obj *qobj = &cmd->se_dev->dev_queue_obj; unsigned long flags; spin_lock_irqsave(&qobj->cmd_queue_lock, flags); @@ -676,14 +654,9 @@ static void transport_remove_cmd_from_queue(struct se_cmd *cmd, spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); return; } - - list_for_each_entry(t, &qobj->qobj_list, se_queue_node) - if (t == cmd) { - atomic_dec(&cmd->t_transport_queue_active); - atomic_dec(&qobj->queue_cnt); - list_del(&cmd->se_queue_node); - break; - } + atomic_set(&cmd->t_transport_queue_active, 0); + atomic_dec(&qobj->queue_cnt); + list_del_init(&cmd->se_queue_node); spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); if (atomic_read(&cmd->t_transport_queue_active)) { @@ -716,6 +689,13 @@ void transport_complete_sync_cache(struct se_cmd *cmd, int good) } EXPORT_SYMBOL(transport_complete_sync_cache); +static void target_complete_failure_work(struct work_struct *work) +{ + struct se_cmd *cmd = container_of(work, struct se_cmd, work); + + transport_generic_request_failure(cmd, 1, 1); +} + /* transport_complete_task(): * * Called from interrupt and non interrupt context depending @@ -724,8 +704,7 @@ EXPORT_SYMBOL(transport_complete_sync_cache); void transport_complete_task(struct se_task *task, int success) { struct se_cmd *cmd = task->task_se_cmd; - struct se_device *dev = task->se_dev; - int t_state; + struct se_device *dev = cmd->se_dev; unsigned long flags; #if 0 pr_debug("task: %p CDB: 0x%02x obj_ptr: %p\n", task, @@ -735,7 +714,7 @@ void transport_complete_task(struct se_task *task, int success) atomic_inc(&dev->depth_left); spin_lock_irqsave(&cmd->t_state_lock, flags); - atomic_set(&task->task_active, 0); + task->task_flags &= ~TF_ACTIVE; /* * See if any sense data exists, if so set the TASK_SENSE flag. @@ -754,39 +733,14 @@ void transport_complete_task(struct se_task *task, int success) * See if we are waiting for outstanding struct se_task * to complete for an exception condition */ - if (atomic_read(&task->task_stop)) { - /* - * Decrement cmd->t_se_count if this task had - * previously thrown its timeout exception handler. - */ - if (atomic_read(&task->task_timeout)) { - atomic_dec(&cmd->t_se_count); - atomic_set(&task->task_timeout, 0); - } + if (task->task_flags & TF_REQUEST_STOP) { spin_unlock_irqrestore(&cmd->t_state_lock, flags); - complete(&task->task_stop_comp); return; } - /* - * If the task's timeout handler has fired, use the t_task_cdbs_timeout - * left counter to determine when the struct se_cmd is ready to be queued to - * the processing thread. - */ - if (atomic_read(&task->task_timeout)) { - if (!atomic_dec_and_test( - &cmd->t_task_cdbs_timeout_left)) { - spin_unlock_irqrestore(&cmd->t_state_lock, - flags); - return; - } - t_state = TRANSPORT_COMPLETE_TIMEOUT; - spin_unlock_irqrestore(&cmd->t_state_lock, flags); - transport_add_cmd_to_queue(cmd, t_state); - return; - } - atomic_dec(&cmd->t_task_cdbs_timeout_left); + if (!success) + cmd->t_tasks_failed = 1; /* * Decrement the outstanding t_task_cdbs_left count. The last @@ -794,28 +748,28 @@ void transport_complete_task(struct se_task *task, int success) * device queue depending upon int success. */ if (!atomic_dec_and_test(&cmd->t_task_cdbs_left)) { - if (!success) - cmd->t_tasks_failed = 1; - spin_unlock_irqrestore(&cmd->t_state_lock, flags); return; } - if (!success || cmd->t_tasks_failed) { - t_state = TRANSPORT_COMPLETE_FAILURE; + if (cmd->t_tasks_failed) { if (!task->task_error_status) { task->task_error_status = PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; cmd->transport_error_status = PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; } + INIT_WORK(&cmd->work, target_complete_failure_work); } else { atomic_set(&cmd->t_transport_complete, 1); - t_state = TRANSPORT_COMPLETE_OK; + INIT_WORK(&cmd->work, target_complete_ok_work); } + + cmd->t_state = TRANSPORT_COMPLETE; + atomic_set(&cmd->t_transport_active, 1); spin_unlock_irqrestore(&cmd->t_state_lock, flags); - transport_add_cmd_to_queue(cmd, t_state); + queue_work(target_completion_wq, &cmd->work); } EXPORT_SYMBOL(transport_complete_task); @@ -902,14 +856,12 @@ static void __transport_add_task_to_execute_queue( static void transport_add_tasks_to_state_queue(struct se_cmd *cmd) { - struct se_device *dev; + struct se_device *dev = cmd->se_dev; struct se_task *task; unsigned long flags; spin_lock_irqsave(&cmd->t_state_lock, flags); list_for_each_entry(task, &cmd->t_task_list, t_list) { - dev = task->se_dev; - if (atomic_read(&task->task_state_active)) continue; @@ -934,43 +886,41 @@ static void transport_add_tasks_from_cmd(struct se_cmd *cmd) spin_lock_irqsave(&dev->execute_task_lock, flags); list_for_each_entry(task, &cmd->t_task_list, t_list) { - if (atomic_read(&task->task_execute_queue)) + if (!list_empty(&task->t_execute_list)) continue; /* * __transport_add_task_to_execute_queue() handles the * SAM Task Attribute emulation if enabled */ __transport_add_task_to_execute_queue(task, task_prev, dev); - atomic_set(&task->task_execute_queue, 1); task_prev = task; } spin_unlock_irqrestore(&dev->execute_task_lock, flags); } -/* transport_remove_task_from_execute_queue(): - * - * - */ +void __transport_remove_task_from_execute_queue(struct se_task *task, + struct se_device *dev) +{ + list_del_init(&task->t_execute_list); + atomic_dec(&dev->execute_tasks); +} + void transport_remove_task_from_execute_queue( struct se_task *task, struct se_device *dev) { unsigned long flags; - if (atomic_read(&task->task_execute_queue) == 0) { - dump_stack(); + if (WARN_ON(list_empty(&task->t_execute_list))) return; - } spin_lock_irqsave(&dev->execute_task_lock, flags); - list_del(&task->t_execute_list); - atomic_set(&task->task_execute_queue, 0); - atomic_dec(&dev->execute_tasks); + __transport_remove_task_from_execute_queue(task, dev); spin_unlock_irqrestore(&dev->execute_task_lock, flags); } /* - * Handle QUEUE_FULL / -EAGAIN status + * Handle QUEUE_FULL / -EAGAIN and -ENOMEM status */ static void target_qf_do_work(struct work_struct *work) @@ -991,14 +941,11 @@ static void target_qf_do_work(struct work_struct *work) pr_debug("Processing %s cmd: %p QUEUE_FULL in work queue" " context: %s\n", cmd->se_tfo->get_fabric_name(), cmd, - (cmd->t_state == TRANSPORT_COMPLETE_OK) ? "COMPLETE_OK" : + (cmd->t_state == TRANSPORT_COMPLETE_QF_OK) ? "COMPLETE_OK" : (cmd->t_state == TRANSPORT_COMPLETE_QF_WP) ? "WRITE_PENDING" : "UNKNOWN"); - /* - * The SCF_EMULATE_QUEUE_FULL flag will be cleared once se_cmd - * has been added to head of queue - */ - transport_add_cmd_to_queue(cmd, cmd->t_state); + + transport_add_cmd_to_queue(cmd, cmd->t_state, true); } } @@ -1053,41 +1000,6 @@ void transport_dump_dev_state( *bl += sprintf(b + *bl, " "); } -/* transport_release_all_cmds(): - * - * - */ -static void transport_release_all_cmds(struct se_device *dev) -{ - struct se_cmd *cmd, *tcmd; - int bug_out = 0, t_state; - unsigned long flags; - - spin_lock_irqsave(&dev->dev_queue_obj.cmd_queue_lock, flags); - list_for_each_entry_safe(cmd, tcmd, &dev->dev_queue_obj.qobj_list, - se_queue_node) { - t_state = cmd->t_state; - list_del(&cmd->se_queue_node); - spin_unlock_irqrestore(&dev->dev_queue_obj.cmd_queue_lock, - flags); - - pr_err("Releasing ITT: 0x%08x, i_state: %u," - " t_state: %u directly\n", - cmd->se_tfo->get_task_tag(cmd), - cmd->se_tfo->get_cmd_state(cmd), t_state); - - transport_release_fe_cmd(cmd); - bug_out = 1; - - spin_lock_irqsave(&dev->dev_queue_obj.cmd_queue_lock, flags); - } - spin_unlock_irqrestore(&dev->dev_queue_obj.cmd_queue_lock, flags); -#if 0 - if (bug_out) - BUG(); -#endif -} - void transport_dump_vpd_proto_id( struct t10_vpd *vpd, unsigned char *p_buf, @@ -1573,7 +1485,6 @@ transport_generic_get_task(struct se_cmd *cmd, INIT_LIST_HEAD(&task->t_state_list); init_completion(&task->task_stop_comp); task->task_se_cmd = cmd; - task->se_dev = dev; task->task_data_direction = data_direction; return task; @@ -1598,11 +1509,13 @@ void transport_init_se_cmd( INIT_LIST_HEAD(&cmd->se_delayed_node); INIT_LIST_HEAD(&cmd->se_ordered_node); INIT_LIST_HEAD(&cmd->se_qf_node); - + INIT_LIST_HEAD(&cmd->se_queue_node); + INIT_LIST_HEAD(&cmd->se_cmd_list); INIT_LIST_HEAD(&cmd->t_task_list); init_completion(&cmd->transport_lun_fe_stop_comp); init_completion(&cmd->transport_lun_stop_comp); init_completion(&cmd->t_transport_stop_comp); + init_completion(&cmd->cmd_wait_comp); spin_lock_init(&cmd->t_state_lock); atomic_set(&cmd->transport_dev_active, 1); @@ -1641,21 +1554,6 @@ static int transport_check_alloc_task_attr(struct se_cmd *cmd) return 0; } -void transport_free_se_cmd( - struct se_cmd *se_cmd) -{ - if (se_cmd->se_tmr_req) - core_tmr_release_req(se_cmd->se_tmr_req); - /* - * Check and free any extended CDB buffer that was allocated - */ - if (se_cmd->t_task_cdb != se_cmd->__t_task_cdb) - kfree(se_cmd->t_task_cdb); -} -EXPORT_SYMBOL(transport_free_se_cmd); - -static void transport_generic_wait_for_tasks(struct se_cmd *, int, int); - /* transport_generic_allocate_tasks(): * * Called from fabric RX Thread. @@ -1667,12 +1565,6 @@ int transport_generic_allocate_tasks( int ret; transport_generic_prepare_cdb(cdb); - - /* - * This is needed for early exceptions. - */ - cmd->transport_wait_for_tasks = &transport_generic_wait_for_tasks; - /* * Ensure that the received CDB is less than the max (252 + 8) bytes * for VARIABLE_LENGTH_CMD @@ -1730,26 +1622,6 @@ int transport_generic_allocate_tasks( EXPORT_SYMBOL(transport_generic_allocate_tasks); /* - * Used by fabric module frontends not defining a TFO->new_cmd_map() - * to queue up a newly setup se_cmd w/ TRANSPORT_NEW_CMD statis - */ -int transport_generic_handle_cdb( - struct se_cmd *cmd) -{ - if (!cmd->se_lun) { - dump_stack(); - pr_err("cmd->se_lun is NULL\n"); - return -EINVAL; - } - - transport_add_cmd_to_queue(cmd, TRANSPORT_NEW_CMD); - return 0; -} -EXPORT_SYMBOL(transport_generic_handle_cdb); - -static void transport_generic_request_failure(struct se_cmd *, - struct se_device *, int, int); -/* * Used by fabric module frontends to queue tasks directly. * Many only be used from process context only */ @@ -1773,7 +1645,7 @@ int transport_handle_cdb_direct( * Set TRANSPORT_NEW_CMD state and cmd->t_transport_active=1 following * transport_generic_handle_cdb*() -> transport_add_cmd_to_queue() * in existing usage to ensure that outstanding descriptors are handled - * correctly during shutdown via transport_generic_wait_for_tasks() + * correctly during shutdown via transport_wait_for_tasks() * * Also, we don't take cmd->t_state_lock here as we only expect * this to be called for initial descriptor submission. @@ -1786,11 +1658,9 @@ int transport_handle_cdb_direct( * and call transport_generic_request_failure() if necessary.. */ ret = transport_generic_new_cmd(cmd); - if (ret == -EAGAIN) - return 0; - else if (ret < 0) { + if (ret < 0) { cmd->transport_error_status = ret; - transport_generic_request_failure(cmd, NULL, 0, + transport_generic_request_failure(cmd, 0, (cmd->data_direction != DMA_TO_DEVICE)); } return 0; @@ -1811,7 +1681,7 @@ int transport_generic_handle_cdb_map( return -EINVAL; } - transport_add_cmd_to_queue(cmd, TRANSPORT_NEW_CMD_MAP); + transport_add_cmd_to_queue(cmd, TRANSPORT_NEW_CMD_MAP, false); return 0; } EXPORT_SYMBOL(transport_generic_handle_cdb_map); @@ -1841,7 +1711,7 @@ int transport_generic_handle_data( if (transport_check_aborted_status(cmd, 1) != 0) return 0; - transport_add_cmd_to_queue(cmd, TRANSPORT_PROCESS_WRITE); + transport_add_cmd_to_queue(cmd, TRANSPORT_PROCESS_WRITE, false); return 0; } EXPORT_SYMBOL(transport_generic_handle_data); @@ -1853,22 +1723,36 @@ EXPORT_SYMBOL(transport_generic_handle_data); int transport_generic_handle_tmr( struct se_cmd *cmd) { - /* - * This is needed for early exceptions. - */ - cmd->transport_wait_for_tasks = &transport_generic_wait_for_tasks; - - transport_add_cmd_to_queue(cmd, TRANSPORT_PROCESS_TMR); + transport_add_cmd_to_queue(cmd, TRANSPORT_PROCESS_TMR, false); return 0; } EXPORT_SYMBOL(transport_generic_handle_tmr); -void transport_generic_free_cmd_intr( - struct se_cmd *cmd) +/* + * If the task is active, request it to be stopped and sleep until it + * has completed. + */ +bool target_stop_task(struct se_task *task, unsigned long *flags) { - transport_add_cmd_to_queue(cmd, TRANSPORT_FREE_CMD_INTR); + struct se_cmd *cmd = task->task_se_cmd; + bool was_active = false; + + if (task->task_flags & TF_ACTIVE) { + task->task_flags |= TF_REQUEST_STOP; + spin_unlock_irqrestore(&cmd->t_state_lock, *flags); + + pr_debug("Task %p waiting to complete\n", task); + wait_for_completion(&task->task_stop_comp); + pr_debug("Task %p stopped successfully\n", task); + + spin_lock_irqsave(&cmd->t_state_lock, *flags); + atomic_dec(&cmd->t_task_cdbs_left); + task->task_flags &= ~(TF_ACTIVE | TF_REQUEST_STOP); + was_active = true; + } + + return was_active; } -EXPORT_SYMBOL(transport_generic_free_cmd_intr); static int transport_stop_tasks_for_cmd(struct se_cmd *cmd) { @@ -1885,51 +1769,26 @@ static int transport_stop_tasks_for_cmd(struct se_cmd *cmd) spin_lock_irqsave(&cmd->t_state_lock, flags); list_for_each_entry_safe(task, task_tmp, &cmd->t_task_list, t_list) { - pr_debug("task_no[%d] - Processing task %p\n", - task->task_no, task); + pr_debug("Processing task %p\n", task); /* * If the struct se_task has not been sent and is not active, * remove the struct se_task from the execution queue. */ - if (!atomic_read(&task->task_sent) && - !atomic_read(&task->task_active)) { + if (!(task->task_flags & (TF_ACTIVE | TF_SENT))) { spin_unlock_irqrestore(&cmd->t_state_lock, flags); transport_remove_task_from_execute_queue(task, - task->se_dev); + cmd->se_dev); - pr_debug("task_no[%d] - Removed from execute queue\n", - task->task_no); + pr_debug("Task %p removed from execute queue\n", task); spin_lock_irqsave(&cmd->t_state_lock, flags); continue; } - /* - * If the struct se_task is active, sleep until it is returned - * from the plugin. - */ - if (atomic_read(&task->task_active)) { - atomic_set(&task->task_stop, 1); - spin_unlock_irqrestore(&cmd->t_state_lock, - flags); - - pr_debug("task_no[%d] - Waiting to complete\n", - task->task_no); - wait_for_completion(&task->task_stop_comp); - pr_debug("task_no[%d] - Stopped successfully\n", - task->task_no); - - spin_lock_irqsave(&cmd->t_state_lock, flags); - atomic_dec(&cmd->t_task_cdbs_left); - - atomic_set(&task->task_active, 0); - atomic_set(&task->task_stop, 0); - } else { - pr_debug("task_no[%d] - Did nothing\n", task->task_no); + if (!target_stop_task(task, &flags)) { + pr_debug("Task %p - did nothing\n", task); ret++; } - - __transport_stop_task_timer(task, &flags); } spin_unlock_irqrestore(&cmd->t_state_lock, flags); @@ -1941,7 +1800,6 @@ static int transport_stop_tasks_for_cmd(struct se_cmd *cmd) */ static void transport_generic_request_failure( struct se_cmd *cmd, - struct se_device *dev, int complete, int sc) { @@ -1950,10 +1808,9 @@ static void transport_generic_request_failure( pr_debug("-----[ Storage Engine Exception for cmd: %p ITT: 0x%08x" " CDB: 0x%02x\n", cmd, cmd->se_tfo->get_task_tag(cmd), cmd->t_task_cdb[0]); - pr_debug("-----[ i_state: %d t_state/def_t_state:" - " %d/%d transport_error_status: %d\n", + pr_debug("-----[ i_state: %d t_state: %d transport_error_status: %d\n", cmd->se_tfo->get_cmd_state(cmd), - cmd->t_state, cmd->deferred_t_state, + cmd->t_state, cmd->transport_error_status); pr_debug("-----[ t_tasks: %d t_task_cdbs_left: %d" " t_task_cdbs_sent: %d t_task_cdbs_ex_left: %d --" @@ -1966,10 +1823,6 @@ static void transport_generic_request_failure( atomic_read(&cmd->t_transport_stop), atomic_read(&cmd->t_transport_sent)); - transport_stop_all_task_timers(cmd); - - if (dev) - atomic_inc(&dev->depth_left); /* * For SAM Task Attribute emulation for failed struct se_cmd */ @@ -1977,7 +1830,6 @@ static void transport_generic_request_failure( transport_complete_task_attr(cmd); if (complete) { - transport_direct_request_timeout(cmd); cmd->transport_error_status = PYX_TRANSPORT_LU_COMM_FAILURE; } @@ -2038,7 +1890,7 @@ static void transport_generic_request_failure( ASCQ_2CH_PREVIOUS_RESERVATION_CONFLICT_STATUS); ret = cmd->se_tfo->queue_status(cmd); - if (ret == -EAGAIN) + if (ret == -EAGAIN || ret == -ENOMEM) goto queue_full; goto check_stop; case PYX_TRANSPORT_USE_SENSE_REASON: @@ -2065,7 +1917,7 @@ static void transport_generic_request_failure( else { ret = transport_send_check_condition_and_sense(cmd, cmd->scsi_sense_reason, 0); - if (ret == -EAGAIN) + if (ret == -EAGAIN || ret == -ENOMEM) goto queue_full; } @@ -2076,46 +1928,8 @@ check_stop: return; queue_full: - cmd->t_state = TRANSPORT_COMPLETE_OK; - transport_handle_queue_full(cmd, cmd->se_dev, transport_complete_qf); -} - -static void transport_direct_request_timeout(struct se_cmd *cmd) -{ - unsigned long flags; - - spin_lock_irqsave(&cmd->t_state_lock, flags); - if (!atomic_read(&cmd->t_transport_timeout)) { - spin_unlock_irqrestore(&cmd->t_state_lock, flags); - return; - } - if (atomic_read(&cmd->t_task_cdbs_timeout_left)) { - spin_unlock_irqrestore(&cmd->t_state_lock, flags); - return; - } - - atomic_sub(atomic_read(&cmd->t_transport_timeout), - &cmd->t_se_count); - spin_unlock_irqrestore(&cmd->t_state_lock, flags); -} - -static void transport_generic_request_timeout(struct se_cmd *cmd) -{ - unsigned long flags; - - /* - * Reset cmd->t_se_count to allow transport_generic_remove() - * to allow last call to free memory resources. - */ - spin_lock_irqsave(&cmd->t_state_lock, flags); - if (atomic_read(&cmd->t_transport_timeout) > 1) { - int tmp = (atomic_read(&cmd->t_transport_timeout) - 1); - - atomic_sub(tmp, &cmd->t_se_count); - } - spin_unlock_irqrestore(&cmd->t_state_lock, flags); - - transport_generic_remove(cmd, 0); + cmd->t_state = TRANSPORT_COMPLETE_QF_OK; + transport_handle_queue_full(cmd, cmd->se_dev); } static inline u32 transport_lba_21(unsigned char *cdb) @@ -2160,127 +1974,6 @@ static void transport_set_supported_SAM_opcode(struct se_cmd *se_cmd) spin_unlock_irqrestore(&se_cmd->t_state_lock, flags); } -/* - * Called from interrupt context. - */ -static void transport_task_timeout_handler(unsigned long data) -{ - struct se_task *task = (struct se_task *)data; - struct se_cmd *cmd = task->task_se_cmd; - unsigned long flags; - - pr_debug("transport task timeout fired! task: %p cmd: %p\n", task, cmd); - - spin_lock_irqsave(&cmd->t_state_lock, flags); - if (task->task_flags & TF_STOP) { - spin_unlock_irqrestore(&cmd->t_state_lock, flags); - return; - } - task->task_flags &= ~TF_RUNNING; - - /* - * Determine if transport_complete_task() has already been called. - */ - if (!atomic_read(&task->task_active)) { - pr_debug("transport task: %p cmd: %p timeout task_active" - " == 0\n", task, cmd); - spin_unlock_irqrestore(&cmd->t_state_lock, flags); - return; - } - - atomic_inc(&cmd->t_se_count); - atomic_inc(&cmd->t_transport_timeout); - cmd->t_tasks_failed = 1; - - atomic_set(&task->task_timeout, 1); - task->task_error_status = PYX_TRANSPORT_TASK_TIMEOUT; - task->task_scsi_status = 1; - - if (atomic_read(&task->task_stop)) { - pr_debug("transport task: %p cmd: %p timeout task_stop" - " == 1\n", task, cmd); - spin_unlock_irqrestore(&cmd->t_state_lock, flags); - complete(&task->task_stop_comp); - return; - } - - if (!atomic_dec_and_test(&cmd->t_task_cdbs_left)) { - pr_debug("transport task: %p cmd: %p timeout non zero" - " t_task_cdbs_left\n", task, cmd); - spin_unlock_irqrestore(&cmd->t_state_lock, flags); - return; - } - pr_debug("transport task: %p cmd: %p timeout ZERO t_task_cdbs_left\n", - task, cmd); - - cmd->t_state = TRANSPORT_COMPLETE_FAILURE; - spin_unlock_irqrestore(&cmd->t_state_lock, flags); - - transport_add_cmd_to_queue(cmd, TRANSPORT_COMPLETE_FAILURE); -} - -/* - * Called with cmd->t_state_lock held. - */ -static void transport_start_task_timer(struct se_task *task) -{ - struct se_device *dev = task->se_dev; - int timeout; - - if (task->task_flags & TF_RUNNING) - return; - /* - * If the task_timeout is disabled, exit now. - */ - timeout = dev->se_sub_dev->se_dev_attrib.task_timeout; - if (!timeout) - return; - - init_timer(&task->task_timer); - task->task_timer.expires = (get_jiffies_64() + timeout * HZ); - task->task_timer.data = (unsigned long) task; - task->task_timer.function = transport_task_timeout_handler; - - task->task_flags |= TF_RUNNING; - add_timer(&task->task_timer); -#if 0 - pr_debug("Starting task timer for cmd: %p task: %p seconds:" - " %d\n", task->task_se_cmd, task, timeout); -#endif -} - -/* - * Called with spin_lock_irq(&cmd->t_state_lock) held. - */ -void __transport_stop_task_timer(struct se_task *task, unsigned long *flags) -{ - struct se_cmd *cmd = task->task_se_cmd; - - if (!task->task_flags & TF_RUNNING) - return; - - task->task_flags |= TF_STOP; - spin_unlock_irqrestore(&cmd->t_state_lock, *flags); - - del_timer_sync(&task->task_timer); - - spin_lock_irqsave(&cmd->t_state_lock, *flags); - task->task_flags &= ~TF_RUNNING; - task->task_flags &= ~TF_STOP; -} - -static void transport_stop_all_task_timers(struct se_cmd *cmd) -{ - struct se_task *task = NULL, *task_tmp; - unsigned long flags; - - spin_lock_irqsave(&cmd->t_state_lock, flags); - list_for_each_entry_safe(task, task_tmp, - &cmd->t_task_list, t_list) - __transport_stop_task_timer(task, &flags); - spin_unlock_irqrestore(&cmd->t_state_lock, flags); -} - static inline int transport_tcq_window_closed(struct se_device *dev) { if (dev->dev_tcq_window_closed++ < @@ -2385,7 +2078,7 @@ static int transport_execute_tasks(struct se_cmd *cmd) if (se_dev_check_online(cmd->se_orig_obj_ptr) != 0) { cmd->transport_error_status = PYX_TRANSPORT_LU_COMM_FAILURE; - transport_generic_request_failure(cmd, NULL, 0, 1); + transport_generic_request_failure(cmd, 0, 1); return 0; } @@ -2448,9 +2141,7 @@ check_depth: } task = list_first_entry(&dev->execute_task_list, struct se_task, t_execute_list); - list_del(&task->t_execute_list); - atomic_set(&task->task_execute_queue, 0); - atomic_dec(&dev->execute_tasks); + __transport_remove_task_from_execute_queue(task, dev); spin_unlock_irq(&dev->execute_task_lock); atomic_dec(&dev->depth_left); @@ -2458,66 +2149,28 @@ check_depth: cmd = task->task_se_cmd; spin_lock_irqsave(&cmd->t_state_lock, flags); - atomic_set(&task->task_active, 1); - atomic_set(&task->task_sent, 1); + task->task_flags |= (TF_ACTIVE | TF_SENT); atomic_inc(&cmd->t_task_cdbs_sent); if (atomic_read(&cmd->t_task_cdbs_sent) == cmd->t_task_list_num) - atomic_set(&cmd->transport_sent, 1); + atomic_set(&cmd->t_transport_sent, 1); - transport_start_task_timer(task); spin_unlock_irqrestore(&cmd->t_state_lock, flags); - /* - * The struct se_cmd->transport_emulate_cdb() function pointer is used - * to grab REPORT_LUNS and other CDBs we want to handle before they hit the - * struct se_subsystem_api->do_task() caller below. - */ - if (cmd->transport_emulate_cdb) { - error = cmd->transport_emulate_cdb(cmd); - if (error != 0) { - cmd->transport_error_status = error; - atomic_set(&task->task_active, 0); - atomic_set(&cmd->transport_sent, 0); - transport_stop_tasks_for_cmd(cmd); - transport_generic_request_failure(cmd, dev, 0, 1); - goto check_depth; - } - /* - * Handle the successful completion for transport_emulate_cdb() - * for synchronous operation, following SCF_EMULATE_CDB_ASYNC - * Otherwise the caller is expected to complete the task with - * proper status. - */ - if (!(cmd->se_cmd_flags & SCF_EMULATE_CDB_ASYNC)) { - cmd->scsi_status = SAM_STAT_GOOD; - task->task_scsi_status = GOOD; - transport_complete_task(task, 1); - } - } else { - /* - * Currently for all virtual TCM plugins including IBLOCK, FILEIO and - * RAMDISK we use the internal transport_emulate_control_cdb() logic - * with struct se_subsystem_api callers for the primary SPC-3 TYPE_DISK - * LUN emulation code. - * - * For TCM/pSCSI and all other SCF_SCSI_DATA_SG_IO_CDB I/O tasks we - * call ->do_task() directly and let the underlying TCM subsystem plugin - * code handle the CDB emulation. - */ - if ((dev->transport->transport_type != TRANSPORT_PLUGIN_PHBA_PDEV) && - (!(task->task_se_cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB))) - error = transport_emulate_control_cdb(task); - else - error = dev->transport->do_task(task); - - if (error != 0) { - cmd->transport_error_status = error; - atomic_set(&task->task_active, 0); - atomic_set(&cmd->transport_sent, 0); - transport_stop_tasks_for_cmd(cmd); - transport_generic_request_failure(cmd, dev, 0, 1); - } + + if (cmd->execute_task) + error = cmd->execute_task(task); + else + error = dev->transport->do_task(task); + if (error != 0) { + cmd->transport_error_status = error; + spin_lock_irqsave(&cmd->t_state_lock, flags); + task->task_flags &= ~TF_ACTIVE; + spin_unlock_irqrestore(&cmd->t_state_lock, flags); + atomic_set(&cmd->t_transport_sent, 0); + transport_stop_tasks_for_cmd(cmd); + atomic_inc(&dev->depth_left); + transport_generic_request_failure(cmd, 0, 1); } goto check_depth; @@ -2538,8 +2191,6 @@ void transport_new_cmd_failure(struct se_cmd *se_cmd) spin_unlock_irqrestore(&se_cmd->t_state_lock, flags); } -static void transport_nop_wait_for_tasks(struct se_cmd *, int, int); - static inline u32 transport_get_sectors_6( unsigned char *cdb, struct se_cmd *cmd, @@ -2752,13 +2403,16 @@ out: static int transport_get_sense_data(struct se_cmd *cmd) { unsigned char *buffer = cmd->sense_buffer, *sense_buffer = NULL; - struct se_device *dev; + struct se_device *dev = cmd->se_dev; struct se_task *task = NULL, *task_tmp; unsigned long flags; u32 offset = 0; WARN_ON(!cmd->se_lun); + if (!dev) + return 0; + spin_lock_irqsave(&cmd->t_state_lock, flags); if (cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION) { spin_unlock_irqrestore(&cmd->t_state_lock, flags); @@ -2767,14 +2421,9 @@ static int transport_get_sense_data(struct se_cmd *cmd) list_for_each_entry_safe(task, task_tmp, &cmd->t_task_list, t_list) { - if (!task->task_sense) continue; - dev = task->se_dev; - if (!dev) - continue; - if (!dev->transport->get_sense_buffer) { pr_err("dev->transport->get_sense_buffer" " is NULL\n"); @@ -2783,9 +2432,9 @@ static int transport_get_sense_data(struct se_cmd *cmd) sense_buffer = dev->transport->get_sense_buffer(task); if (!sense_buffer) { - pr_err("ITT[0x%08x]_TASK[%d]: Unable to locate" + pr_err("ITT[0x%08x]_TASK[%p]: Unable to locate" " sense buffer for task with sense\n", - cmd->se_tfo->get_task_tag(cmd), task->task_no); + cmd->se_tfo->get_task_tag(cmd), task); continue; } spin_unlock_irqrestore(&cmd->t_state_lock, flags); @@ -2814,7 +2463,6 @@ static int transport_get_sense_data(struct se_cmd *cmd) static int transport_handle_reservation_conflict(struct se_cmd *cmd) { - cmd->transport_wait_for_tasks = &transport_nop_wait_for_tasks; cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; cmd->se_cmd_flags |= SCF_SCSI_RESERVATION_CONFLICT; cmd->scsi_status = SAM_STAT_RESERVATION_CONFLICT; @@ -2915,8 +2563,6 @@ static int transport_generic_cmd_sequencer( * Check for an existing UNIT ATTENTION condition */ if (core_scsi3_ua_check(cmd, cdb) < 0) { - cmd->transport_wait_for_tasks = - &transport_nop_wait_for_tasks; cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; cmd->scsi_sense_reason = TCM_CHECK_CONDITION_UNIT_ATTENTION; return -EINVAL; @@ -2926,7 +2572,6 @@ static int transport_generic_cmd_sequencer( */ ret = su_dev->t10_alua.alua_state_check(cmd, cdb, &alua_ascq); if (ret != 0) { - cmd->transport_wait_for_tasks = &transport_nop_wait_for_tasks; /* * Set SCSI additional sense code (ASC) to 'LUN Not Accessible'; * The ALUA additional sense code qualifier (ASCQ) is determined @@ -2959,13 +2604,19 @@ static int transport_generic_cmd_sequencer( */ } + /* + * If we operate in passthrough mode we skip most CDB emulation and + * instead hand the commands down to the physical SCSI device. + */ + passthrough = + (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV); + switch (cdb[0]) { case READ_6: sectors = transport_get_sectors_6(cdb, cmd, §or_ret); if (sector_ret) goto out_unsupported_cdb; size = transport_get_size(sectors, cdb, cmd); - cmd->transport_split_cdb = &split_cdb_XX_6; cmd->t_task_lba = transport_lba_21(cdb); cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; break; @@ -2974,7 +2625,6 @@ static int transport_generic_cmd_sequencer( if (sector_ret) goto out_unsupported_cdb; size = transport_get_size(sectors, cdb, cmd); - cmd->transport_split_cdb = &split_cdb_XX_10; cmd->t_task_lba = transport_lba_32(cdb); cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; break; @@ -2983,7 +2633,6 @@ static int transport_generic_cmd_sequencer( if (sector_ret) goto out_unsupported_cdb; size = transport_get_size(sectors, cdb, cmd); - cmd->transport_split_cdb = &split_cdb_XX_12; cmd->t_task_lba = transport_lba_32(cdb); cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; break; @@ -2992,7 +2641,6 @@ static int transport_generic_cmd_sequencer( if (sector_ret) goto out_unsupported_cdb; size = transport_get_size(sectors, cdb, cmd); - cmd->transport_split_cdb = &split_cdb_XX_16; cmd->t_task_lba = transport_lba_64(cdb); cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; break; @@ -3001,7 +2649,6 @@ static int transport_generic_cmd_sequencer( if (sector_ret) goto out_unsupported_cdb; size = transport_get_size(sectors, cdb, cmd); - cmd->transport_split_cdb = &split_cdb_XX_6; cmd->t_task_lba = transport_lba_21(cdb); cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; break; @@ -3010,7 +2657,6 @@ static int transport_generic_cmd_sequencer( if (sector_ret) goto out_unsupported_cdb; size = transport_get_size(sectors, cdb, cmd); - cmd->transport_split_cdb = &split_cdb_XX_10; cmd->t_task_lba = transport_lba_32(cdb); cmd->t_tasks_fua = (cdb[1] & 0x8); cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; @@ -3020,7 +2666,6 @@ static int transport_generic_cmd_sequencer( if (sector_ret) goto out_unsupported_cdb; size = transport_get_size(sectors, cdb, cmd); - cmd->transport_split_cdb = &split_cdb_XX_12; cmd->t_task_lba = transport_lba_32(cdb); cmd->t_tasks_fua = (cdb[1] & 0x8); cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; @@ -3030,7 +2675,6 @@ static int transport_generic_cmd_sequencer( if (sector_ret) goto out_unsupported_cdb; size = transport_get_size(sectors, cdb, cmd); - cmd->transport_split_cdb = &split_cdb_XX_16; cmd->t_task_lba = transport_lba_64(cdb); cmd->t_tasks_fua = (cdb[1] & 0x8); cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; @@ -3043,31 +2687,23 @@ static int transport_generic_cmd_sequencer( if (sector_ret) goto out_unsupported_cdb; size = transport_get_size(sectors, cdb, cmd); - cmd->transport_split_cdb = &split_cdb_XX_10; cmd->t_task_lba = transport_lba_32(cdb); cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; - passthrough = (dev->transport->transport_type == - TRANSPORT_PLUGIN_PHBA_PDEV); + /* - * Skip the remaining assignments for TCM/PSCSI passthrough + * Do now allow BIDI commands for passthrough mode. */ if (passthrough) - break; + goto out_unsupported_cdb; + /* - * Setup BIDI XOR callback to be run during transport_generic_complete_ok() + * Setup BIDI XOR callback to be run after I/O completion. */ cmd->transport_complete_callback = &transport_xor_callback; cmd->t_tasks_fua = (cdb[1] & 0x8); break; case VARIABLE_LENGTH_CMD: service_action = get_unaligned_be16(&cdb[8]); - /* - * Determine if this is TCM/PSCSI device and we should disable - * internal emulation for this CDB. - */ - passthrough = (dev->transport->transport_type == - TRANSPORT_PLUGIN_PHBA_PDEV); - switch (service_action) { case XDWRITEREAD_32: sectors = transport_get_sectors_32(cdb, cmd, §or_ret); @@ -3078,19 +2714,18 @@ static int transport_generic_cmd_sequencer( * Use WRITE_32 and READ_32 opcodes for the emulated * XDWRITE_READ_32 logic. */ - cmd->transport_split_cdb = &split_cdb_XX_32; cmd->t_task_lba = transport_lba_64_ext(cdb); cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; /* - * Skip the remaining assignments for TCM/PSCSI passthrough + * Do now allow BIDI commands for passthrough mode. */ if (passthrough) - break; + goto out_unsupported_cdb; /* - * Setup BIDI XOR callback to be run during - * transport_generic_complete_ok() + * Setup BIDI XOR callback to be run during after I/O + * completion. */ cmd->transport_complete_callback = &transport_xor_callback; cmd->t_tasks_fua = (cdb[10] & 0x8); @@ -3113,7 +2748,8 @@ static int transport_generic_cmd_sequencer( if (target_check_write_same_discard(&cdb[10], dev) < 0) goto out_invalid_cdb_field; - + if (!passthrough) + cmd->execute_task = target_emulate_write_same; break; default: pr_err("VARIABLE_LENGTH_CMD service action" @@ -3127,12 +2763,10 @@ static int transport_generic_cmd_sequencer( /* * Check for emulated MI_REPORT_TARGET_PGS. */ - if (cdb[1] == MI_REPORT_TARGET_PGS) { - cmd->transport_emulate_cdb = - (su_dev->t10_alua.alua_type == - SPC3_ALUA_EMULATED) ? - core_emulate_report_target_port_groups : - NULL; + if (cdb[1] == MI_REPORT_TARGET_PGS && + su_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED) { + cmd->execute_task = + target_emulate_report_target_port_groups; } size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; @@ -3153,8 +2787,15 @@ static int transport_generic_cmd_sequencer( case MODE_SENSE: size = cdb[4]; cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; + if (!passthrough) + cmd->execute_task = target_emulate_modesense; break; case MODE_SENSE_10: + size = (cdb[7] << 8) + cdb[8]; + cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; + if (!passthrough) + cmd->execute_task = target_emulate_modesense; + break; case GPCMD_READ_BUFFER_CAPACITY: case GPCMD_SEND_OPC: case LOG_SELECT: @@ -3174,11 +2815,14 @@ static int transport_generic_cmd_sequencer( cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; break; case PERSISTENT_RESERVE_IN: + if (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS) + cmd->execute_task = target_scsi3_emulate_pr_in; + size = (cdb[7] << 8) + cdb[8]; + cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; + break; case PERSISTENT_RESERVE_OUT: - cmd->transport_emulate_cdb = - (su_dev->t10_pr.res_type == - SPC3_PERSISTENT_RESERVATIONS) ? - core_scsi3_emulate_pr : NULL; + if (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS) + cmd->execute_task = target_scsi3_emulate_pr_out; size = (cdb[7] << 8) + cdb[8]; cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; break; @@ -3197,12 +2841,10 @@ static int transport_generic_cmd_sequencer( * * Check for emulated MO_SET_TARGET_PGS. */ - if (cdb[1] == MO_SET_TARGET_PGS) { - cmd->transport_emulate_cdb = - (su_dev->t10_alua.alua_type == - SPC3_ALUA_EMULATED) ? - core_emulate_set_target_port_groups : - NULL; + if (cdb[1] == MO_SET_TARGET_PGS && + su_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED) { + cmd->execute_task = + target_emulate_set_target_port_groups; } size = (cdb[6] << 24) | (cdb[7] << 16) | @@ -3222,6 +2864,8 @@ static int transport_generic_cmd_sequencer( if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED) cmd->sam_task_attr = MSG_HEAD_TAG; cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; + if (!passthrough) + cmd->execute_task = target_emulate_inquiry; break; case READ_BUFFER: size = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8]; @@ -3230,6 +2874,8 @@ static int transport_generic_cmd_sequencer( case READ_CAPACITY: size = READ_CAP_LEN; cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; + if (!passthrough) + cmd->execute_task = target_emulate_readcapacity; break; case READ_MEDIA_SERIAL_NUMBER: case SECURITY_PROTOCOL_IN: @@ -3238,6 +2884,21 @@ static int transport_generic_cmd_sequencer( cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; break; case SERVICE_ACTION_IN: + switch (cmd->t_task_cdb[1] & 0x1f) { + case SAI_READ_CAPACITY_16: + if (!passthrough) + cmd->execute_task = + target_emulate_readcapacity_16; + break; + default: + if (passthrough) + break; + + pr_err("Unsupported SA: 0x%02x\n", + cmd->t_task_cdb[1] & 0x1f); + goto out_unsupported_cdb; + } + /*FALLTHROUGH*/ case ACCESS_CONTROL_IN: case ACCESS_CONTROL_OUT: case EXTENDED_COPY: @@ -3268,6 +2929,8 @@ static int transport_generic_cmd_sequencer( case REQUEST_SENSE: size = cdb[4]; cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; + if (!passthrough) + cmd->execute_task = target_emulate_request_sense; break; case READ_ELEMENT_STATUS: size = 65536 * cdb[7] + 256 * cdb[8] + cdb[9]; @@ -3295,10 +2958,8 @@ static int transport_generic_cmd_sequencer( * is running in SPC_PASSTHROUGH, and wants reservations * emulation disabled. */ - cmd->transport_emulate_cdb = - (su_dev->t10_pr.res_type != - SPC_PASSTHROUGH) ? - core_scsi2_emulate_crh : NULL; + if (su_dev->t10_pr.res_type != SPC_PASSTHROUGH) + cmd->execute_task = target_scsi2_reservation_reserve; cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB; break; case RELEASE: @@ -3312,10 +2973,8 @@ static int transport_generic_cmd_sequencer( else size = cmd->data_length; - cmd->transport_emulate_cdb = - (su_dev->t10_pr.res_type != - SPC_PASSTHROUGH) ? - core_scsi2_emulate_crh : NULL; + if (su_dev->t10_pr.res_type != SPC_PASSTHROUGH) + cmd->execute_task = target_scsi2_reservation_release; cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB; break; case SYNCHRONIZE_CACHE: @@ -3336,16 +2995,9 @@ static int transport_generic_cmd_sequencer( size = transport_get_size(sectors, cdb, cmd); cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB; - /* - * For TCM/pSCSI passthrough, skip cmd->transport_emulate_cdb() - */ - if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) + if (passthrough) break; - /* - * Set SCF_EMULATE_CDB_ASYNC to ensure asynchronous operation - * for SYNCHRONIZE_CACHE* Immed=1 case in __transport_execute_tasks() - */ - cmd->se_cmd_flags |= SCF_EMULATE_CDB_ASYNC; + /* * Check to ensure that LBA + Range does not exceed past end of * device for IBLOCK and FILEIO ->do_sync_cache() backend calls @@ -3354,10 +3006,13 @@ static int transport_generic_cmd_sequencer( if (transport_cmd_get_valid_sectors(cmd) < 0) goto out_invalid_cdb_field; } + cmd->execute_task = target_emulate_synchronize_cache; break; case UNMAP: size = get_unaligned_be16(&cdb[7]); cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; + if (!passthrough) + cmd->execute_task = target_emulate_unmap; break; case WRITE_SAME_16: sectors = transport_get_sectors_16(cdb, cmd, §or_ret); @@ -3376,6 +3031,8 @@ static int transport_generic_cmd_sequencer( if (target_check_write_same_discard(&cdb[1], dev) < 0) goto out_invalid_cdb_field; + if (!passthrough) + cmd->execute_task = target_emulate_write_same; break; case WRITE_SAME: sectors = transport_get_sectors_10(cdb, cmd, §or_ret); @@ -3397,26 +3054,31 @@ static int transport_generic_cmd_sequencer( */ if (target_check_write_same_discard(&cdb[1], dev) < 0) goto out_invalid_cdb_field; + if (!passthrough) + cmd->execute_task = target_emulate_write_same; break; case ALLOW_MEDIUM_REMOVAL: - case GPCMD_CLOSE_TRACK: case ERASE: - case INITIALIZE_ELEMENT_STATUS: - case GPCMD_LOAD_UNLOAD: case REZERO_UNIT: case SEEK_10: - case GPCMD_SET_SPEED: case SPACE: case START_STOP: case TEST_UNIT_READY: case VERIFY: case WRITE_FILEMARKS: + cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB; + if (!passthrough) + cmd->execute_task = target_emulate_noop; + break; + case GPCMD_CLOSE_TRACK: + case INITIALIZE_ELEMENT_STATUS: + case GPCMD_LOAD_UNLOAD: + case GPCMD_SET_SPEED: case MOVE_MEDIUM: cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB; break; case REPORT_LUNS: - cmd->transport_emulate_cdb = - transport_core_report_lun_response; + cmd->execute_task = target_report_luns; size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; /* * Do implict HEAD_OF_QUEUE processing for REPORT_LUNS @@ -3430,7 +3092,6 @@ static int transport_generic_cmd_sequencer( pr_warn("TARGET_CORE[%s]: Unsupported SCSI Opcode" " 0x%02x, sending CHECK_CONDITION.\n", cmd->se_tfo->get_fabric_name(), cdb[0]); - cmd->transport_wait_for_tasks = &transport_nop_wait_for_tasks; goto out_unsupported_cdb; } @@ -3469,6 +3130,11 @@ static int transport_generic_cmd_sequencer( cmd->data_length = size; } + /* reject any command that we don't have a handler for */ + if (!(passthrough || cmd->execute_task || + (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB))) + goto out_unsupported_cdb; + /* Let's limit control cdbs to a page, for simplicity's sake. */ if ((cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB) && size > PAGE_SIZE) @@ -3488,8 +3154,7 @@ out_invalid_cdb_field: } /* - * Called from transport_generic_complete_ok() and - * transport_generic_request_failure() to determine which dormant/delayed + * Called from I/O completion to determine which dormant/delayed * and ordered cmds need to have their tasks added to the execution queue. */ static void transport_complete_task_attr(struct se_cmd *cmd) @@ -3557,12 +3222,18 @@ static void transport_complete_task_attr(struct se_cmd *cmd) wake_up_interruptible(&dev->dev_queue_obj.thread_wq); } -static int transport_complete_qf(struct se_cmd *cmd) +static void transport_complete_qf(struct se_cmd *cmd) { int ret = 0; - if (cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) - return cmd->se_tfo->queue_status(cmd); + if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED) + transport_complete_task_attr(cmd); + + if (cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) { + ret = cmd->se_tfo->queue_status(cmd); + if (ret) + goto out; + } switch (cmd->data_direction) { case DMA_FROM_DEVICE: @@ -3572,7 +3243,7 @@ static int transport_complete_qf(struct se_cmd *cmd) if (cmd->t_bidi_data_sg) { ret = cmd->se_tfo->queue_data_in(cmd); if (ret < 0) - return ret; + break; } /* Fall through for DMA_TO_DEVICE */ case DMA_NONE: @@ -3582,17 +3253,20 @@ static int transport_complete_qf(struct se_cmd *cmd) break; } - return ret; +out: + if (ret < 0) { + transport_handle_queue_full(cmd, cmd->se_dev); + return; + } + transport_lun_remove_cmd(cmd); + transport_cmd_check_stop_to_fabric(cmd); } static void transport_handle_queue_full( struct se_cmd *cmd, - struct se_device *dev, - int (*qf_callback)(struct se_cmd *)) + struct se_device *dev) { spin_lock_irq(&dev->qf_cmd_lock); - cmd->se_cmd_flags |= SCF_EMULATE_QUEUE_FULL; - cmd->transport_qf_callback = qf_callback; list_add_tail(&cmd->se_qf_node, &cmd->se_dev->qf_cmd_list); atomic_inc(&dev->dev_qf_count); smp_mb__after_atomic_inc(); @@ -3601,9 +3275,11 @@ static void transport_handle_queue_full( schedule_work(&cmd->se_dev->qf_work_queue); } -static void transport_generic_complete_ok(struct se_cmd *cmd) +static void target_complete_ok_work(struct work_struct *work) { + struct se_cmd *cmd = container_of(work, struct se_cmd, work); int reason = 0, ret; + /* * Check if we need to move delayed/dormant tasks from cmds on the * delayed execution list after a HEAD_OF_QUEUE or ORDERED Task @@ -3618,14 +3294,6 @@ static void transport_generic_complete_ok(struct se_cmd *cmd) if (atomic_read(&cmd->se_dev->dev_qf_count) != 0) schedule_work(&cmd->se_dev->qf_work_queue); - if (cmd->transport_qf_callback) { - ret = cmd->transport_qf_callback(cmd); - if (ret < 0) - goto queue_full; - - cmd->transport_qf_callback = NULL; - goto done; - } /* * Check if we need to retrieve a sense buffer from * the struct se_cmd in question. @@ -3641,7 +3309,7 @@ static void transport_generic_complete_ok(struct se_cmd *cmd) if (cmd->scsi_status) { ret = transport_send_check_condition_and_sense( cmd, reason, 1); - if (ret == -EAGAIN) + if (ret == -EAGAIN || ret == -ENOMEM) goto queue_full; transport_lun_remove_cmd(cmd); @@ -3666,7 +3334,7 @@ static void transport_generic_complete_ok(struct se_cmd *cmd) spin_unlock(&cmd->se_lun->lun_sep_lock); ret = cmd->se_tfo->queue_data_in(cmd); - if (ret == -EAGAIN) + if (ret == -EAGAIN || ret == -ENOMEM) goto queue_full; break; case DMA_TO_DEVICE: @@ -3687,21 +3355,20 @@ static void transport_generic_complete_ok(struct se_cmd *cmd) } spin_unlock(&cmd->se_lun->lun_sep_lock); ret = cmd->se_tfo->queue_data_in(cmd); - if (ret == -EAGAIN) + if (ret == -EAGAIN || ret == -ENOMEM) goto queue_full; break; } /* Fall through for DMA_TO_DEVICE */ case DMA_NONE: ret = cmd->se_tfo->queue_status(cmd); - if (ret == -EAGAIN) + if (ret == -EAGAIN || ret == -ENOMEM) goto queue_full; break; default: break; } -done: transport_lun_remove_cmd(cmd); transport_cmd_check_stop_to_fabric(cmd); return; @@ -3709,34 +3376,35 @@ done: queue_full: pr_debug("Handling complete_ok QUEUE_FULL: se_cmd: %p," " data_direction: %d\n", cmd, cmd->data_direction); - transport_handle_queue_full(cmd, cmd->se_dev, transport_complete_qf); + cmd->t_state = TRANSPORT_COMPLETE_QF_OK; + transport_handle_queue_full(cmd, cmd->se_dev); } static void transport_free_dev_tasks(struct se_cmd *cmd) { struct se_task *task, *task_tmp; unsigned long flags; + LIST_HEAD(dispose_list); spin_lock_irqsave(&cmd->t_state_lock, flags); list_for_each_entry_safe(task, task_tmp, &cmd->t_task_list, t_list) { - if (atomic_read(&task->task_active)) - continue; + if (!(task->task_flags & TF_ACTIVE)) + list_move_tail(&task->t_list, &dispose_list); + } + spin_unlock_irqrestore(&cmd->t_state_lock, flags); + + while (!list_empty(&dispose_list)) { + task = list_first_entry(&dispose_list, struct se_task, t_list); - kfree(task->task_sg_bidi); - kfree(task->task_sg); + if (task->task_sg != cmd->t_data_sg && + task->task_sg != cmd->t_bidi_data_sg) + kfree(task->task_sg); list_del(&task->t_list); - spin_unlock_irqrestore(&cmd->t_state_lock, flags); - if (task->se_dev) - task->se_dev->transport->free_task(task); - else - pr_err("task[%u] - task->se_dev is NULL\n", - task->task_no); - spin_lock_irqsave(&cmd->t_state_lock, flags); + cmd->se_dev->transport->free_task(task); } - spin_unlock_irqrestore(&cmd->t_state_lock, flags); } static inline void transport_free_sgl(struct scatterlist *sgl, int nents) @@ -3764,89 +3432,43 @@ static inline void transport_free_pages(struct se_cmd *cmd) cmd->t_bidi_data_nents = 0; } -static inline void transport_release_tasks(struct se_cmd *cmd) -{ - transport_free_dev_tasks(cmd); -} - -static inline int transport_dec_and_check(struct se_cmd *cmd) +/** + * transport_put_cmd - release a reference to a command + * @cmd: command to release + * + * This routine releases our reference to the command and frees it if possible. + */ +static void transport_put_cmd(struct se_cmd *cmd) { unsigned long flags; + int free_tasks = 0; spin_lock_irqsave(&cmd->t_state_lock, flags); if (atomic_read(&cmd->t_fe_count)) { - if (!atomic_dec_and_test(&cmd->t_fe_count)) { - spin_unlock_irqrestore(&cmd->t_state_lock, - flags); - return 1; - } + if (!atomic_dec_and_test(&cmd->t_fe_count)) + goto out_busy; } if (atomic_read(&cmd->t_se_count)) { - if (!atomic_dec_and_test(&cmd->t_se_count)) { - spin_unlock_irqrestore(&cmd->t_state_lock, - flags); - return 1; - } - } - spin_unlock_irqrestore(&cmd->t_state_lock, flags); - - return 0; -} - -static void transport_release_fe_cmd(struct se_cmd *cmd) -{ - unsigned long flags; - - if (transport_dec_and_check(cmd)) - return; - - spin_lock_irqsave(&cmd->t_state_lock, flags); - if (!atomic_read(&cmd->transport_dev_active)) { - spin_unlock_irqrestore(&cmd->t_state_lock, flags); - goto free_pages; + if (!atomic_dec_and_test(&cmd->t_se_count)) + goto out_busy; } - atomic_set(&cmd->transport_dev_active, 0); - transport_all_task_dev_remove_state(cmd); - spin_unlock_irqrestore(&cmd->t_state_lock, flags); - transport_release_tasks(cmd); -free_pages: - transport_free_pages(cmd); - transport_free_se_cmd(cmd); - cmd->se_tfo->release_cmd(cmd); -} - -static int -transport_generic_remove(struct se_cmd *cmd, int session_reinstatement) -{ - unsigned long flags; - - if (transport_dec_and_check(cmd)) { - if (session_reinstatement) { - spin_lock_irqsave(&cmd->t_state_lock, flags); - transport_all_task_dev_remove_state(cmd); - spin_unlock_irqrestore(&cmd->t_state_lock, - flags); - } - return 1; - } - - spin_lock_irqsave(&cmd->t_state_lock, flags); - if (!atomic_read(&cmd->transport_dev_active)) { - spin_unlock_irqrestore(&cmd->t_state_lock, flags); - goto free_pages; + if (atomic_read(&cmd->transport_dev_active)) { + atomic_set(&cmd->transport_dev_active, 0); + transport_all_task_dev_remove_state(cmd); + free_tasks = 1; } - atomic_set(&cmd->transport_dev_active, 0); - transport_all_task_dev_remove_state(cmd); spin_unlock_irqrestore(&cmd->t_state_lock, flags); - transport_release_tasks(cmd); + if (free_tasks != 0) + transport_free_dev_tasks(cmd); -free_pages: transport_free_pages(cmd); transport_release_cmd(cmd); - return 0; + return; +out_busy: + spin_unlock_irqrestore(&cmd->t_state_lock, flags); } /* @@ -3888,62 +3510,6 @@ int transport_generic_map_mem_to_cmd( } EXPORT_SYMBOL(transport_generic_map_mem_to_cmd); -static int transport_new_cmd_obj(struct se_cmd *cmd) -{ - struct se_device *dev = cmd->se_dev; - int set_counts = 1, rc, task_cdbs; - - /* - * Setup any BIDI READ tasks and memory from - * cmd->t_mem_bidi_list so the READ struct se_tasks - * are queued first for the non pSCSI passthrough case. - */ - if (cmd->t_bidi_data_sg && - (dev->transport->transport_type != TRANSPORT_PLUGIN_PHBA_PDEV)) { - rc = transport_allocate_tasks(cmd, - cmd->t_task_lba, - DMA_FROM_DEVICE, - cmd->t_bidi_data_sg, - cmd->t_bidi_data_nents); - if (rc <= 0) { - cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; - cmd->scsi_sense_reason = - TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - return -EINVAL; - } - atomic_inc(&cmd->t_fe_count); - atomic_inc(&cmd->t_se_count); - set_counts = 0; - } - /* - * Setup the tasks and memory from cmd->t_mem_list - * Note for BIDI transfers this will contain the WRITE payload - */ - task_cdbs = transport_allocate_tasks(cmd, - cmd->t_task_lba, - cmd->data_direction, - cmd->t_data_sg, - cmd->t_data_nents); - if (task_cdbs <= 0) { - cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; - cmd->scsi_sense_reason = - TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - return -EINVAL; - } - - if (set_counts) { - atomic_inc(&cmd->t_fe_count); - atomic_inc(&cmd->t_se_count); - } - - cmd->t_task_list_num = task_cdbs; - - atomic_set(&cmd->t_task_cdbs_left, task_cdbs); - atomic_set(&cmd->t_task_cdbs_ex_left, task_cdbs); - atomic_set(&cmd->t_task_cdbs_timeout_left, task_cdbs); - return 0; -} - void *transport_kmap_first_data_page(struct se_cmd *cmd) { struct scatterlist *sg = cmd->t_data_sg; @@ -4054,15 +3620,13 @@ void transport_do_task_sg_chain(struct se_cmd *cmd) /* * For the padded tasks, use the extra SGL vector allocated * in transport_allocate_data_tasks() for the sg_prev_nents - * offset into sg_chain() above.. The last task of a - * multi-task list, or a single task will not have - * task->task_sg_padded set.. + * offset into sg_chain() above. + * + * We do not need the padding for the last task (or a single + * task), but in that case we will never use the sg_prev_nents + * value below which would be incorrect. */ - if (task->task_padded_sg) - sg_prev_nents = (task->task_sg_nents + 1); - else - sg_prev_nents = task->task_sg_nents; - + sg_prev_nents = (task->task_sg_nents + 1); sg_prev = task->task_sg; } /* @@ -4092,30 +3656,60 @@ EXPORT_SYMBOL(transport_do_task_sg_chain); /* * Break up cmd into chunks transport can handle */ -static int transport_allocate_data_tasks( - struct se_cmd *cmd, - unsigned long long lba, +static int +transport_allocate_data_tasks(struct se_cmd *cmd, enum dma_data_direction data_direction, - struct scatterlist *sgl, - unsigned int sgl_nents) + struct scatterlist *cmd_sg, unsigned int sgl_nents) { - unsigned char *cdb = NULL; - struct se_task *task; struct se_device *dev = cmd->se_dev; - unsigned long flags; - int task_count, i, ret; - sector_t sectors, dev_max_sectors = dev->se_sub_dev->se_dev_attrib.max_sectors; - u32 sector_size = dev->se_sub_dev->se_dev_attrib.block_size; - struct scatterlist *sg; - struct scatterlist *cmd_sg; + int task_count, i; + unsigned long long lba; + sector_t sectors, dev_max_sectors; + u32 sector_size; + + if (transport_cmd_get_valid_sectors(cmd) < 0) + return -EINVAL; + + dev_max_sectors = dev->se_sub_dev->se_dev_attrib.max_sectors; + sector_size = dev->se_sub_dev->se_dev_attrib.block_size; WARN_ON(cmd->data_length % sector_size); + + lba = cmd->t_task_lba; sectors = DIV_ROUND_UP(cmd->data_length, sector_size); task_count = DIV_ROUND_UP_SECTOR_T(sectors, dev_max_sectors); - - cmd_sg = sgl; + + /* + * If we need just a single task reuse the SG list in the command + * and avoid a lot of work. + */ + if (task_count == 1) { + struct se_task *task; + unsigned long flags; + + task = transport_generic_get_task(cmd, data_direction); + if (!task) + return -ENOMEM; + + task->task_sg = cmd_sg; + task->task_sg_nents = sgl_nents; + + task->task_lba = lba; + task->task_sectors = sectors; + task->task_size = task->task_sectors * sector_size; + + spin_lock_irqsave(&cmd->t_state_lock, flags); + list_add_tail(&task->t_list, &cmd->t_task_list); + spin_unlock_irqrestore(&cmd->t_state_lock, flags); + + return task_count; + } + for (i = 0; i < task_count; i++) { + struct se_task *task; unsigned int task_size, task_sg_nents_padded; + struct scatterlist *sg; + unsigned long flags; int count; task = transport_generic_get_task(cmd, data_direction); @@ -4126,14 +3720,6 @@ static int transport_allocate_data_tasks( task->task_sectors = min(sectors, dev_max_sectors); task->task_size = task->task_sectors * sector_size; - cdb = dev->transport->get_cdb(task); - BUG_ON(!cdb); - - memcpy(cdb, cmd->t_task_cdb, - scsi_command_size(cmd->t_task_cdb)); - - /* Update new cdb with updated lba/sectors */ - cmd->transport_split_cdb(task->task_lba, task->task_sectors, cdb); /* * This now assumes that passed sg_ents are in PAGE_SIZE chunks * in order to calculate the number per task SGL entries @@ -4149,7 +3735,6 @@ static int transport_allocate_data_tasks( */ if (cmd->se_tfo->task_sg_chaining && (i < (task_count - 1))) { task_sg_nents_padded = (task->task_sg_nents + 1); - task->task_padded_sg = 1; } else task_sg_nents_padded = task->task_sg_nents; @@ -4181,20 +3766,6 @@ static int transport_allocate_data_tasks( list_add_tail(&task->t_list, &cmd->t_task_list); spin_unlock_irqrestore(&cmd->t_state_lock, flags); } - /* - * Now perform the memory map of task->task_sg[] into backend - * subsystem memory.. - */ - list_for_each_entry(task, &cmd->t_task_list, t_list) { - if (atomic_read(&task->task_sent)) - continue; - if (!dev->transport->map_data_SG) - continue; - - ret = dev->transport->map_data_SG(task); - if (ret < 0) - return 0; - } return task_count; } @@ -4202,30 +3773,14 @@ static int transport_allocate_data_tasks( static int transport_allocate_control_task(struct se_cmd *cmd) { - struct se_device *dev = cmd->se_dev; - unsigned char *cdb; struct se_task *task; unsigned long flags; - int ret = 0; task = transport_generic_get_task(cmd, cmd->data_direction); if (!task) return -ENOMEM; - cdb = dev->transport->get_cdb(task); - BUG_ON(!cdb); - memcpy(cdb, cmd->t_task_cdb, - scsi_command_size(cmd->t_task_cdb)); - - task->task_sg = kmalloc(sizeof(struct scatterlist) * cmd->t_data_nents, - GFP_KERNEL); - if (!task->task_sg) { - cmd->se_dev->transport->free_task(task); - return -ENOMEM; - } - - memcpy(task->task_sg, cmd->t_data_sg, - sizeof(struct scatterlist) * cmd->t_data_nents); + task->task_sg = cmd->t_data_sg; task->task_size = cmd->data_length; task->task_sg_nents = cmd->t_data_nents; @@ -4233,53 +3788,20 @@ transport_allocate_control_task(struct se_cmd *cmd) list_add_tail(&task->t_list, &cmd->t_task_list); spin_unlock_irqrestore(&cmd->t_state_lock, flags); - if (cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB) { - if (dev->transport->map_control_SG) - ret = dev->transport->map_control_SG(task); - } else if (cmd->se_cmd_flags & SCF_SCSI_NON_DATA_CDB) { - if (dev->transport->cdb_none) - ret = dev->transport->cdb_none(task); - } else { - pr_err("target: Unknown control cmd type!\n"); - BUG(); - } - /* Success! Return number of tasks allocated */ - if (ret == 0) - return 1; - return ret; -} - -static u32 transport_allocate_tasks( - struct se_cmd *cmd, - unsigned long long lba, - enum dma_data_direction data_direction, - struct scatterlist *sgl, - unsigned int sgl_nents) -{ - if (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) { - if (transport_cmd_get_valid_sectors(cmd) < 0) - return -EINVAL; - - return transport_allocate_data_tasks(cmd, lba, data_direction, - sgl, sgl_nents); - } else - return transport_allocate_control_task(cmd); - + return 1; } - -/* transport_generic_new_cmd(): Called from transport_processing_thread() - * - * Allocate storage transport resources from a set of values predefined - * by transport_generic_cmd_sequencer() from the iSCSI Target RX process. - * Any non zero return here is treated as an "out of resource' op here. +/* + * Allocate any required ressources to execute the command, and either place + * it on the execution queue if possible. For writes we might not have the + * payload yet, thus notify the fabric via a call to ->write_pending instead. */ - /* - * Generate struct se_task(s) and/or their payloads for this CDB. - */ int transport_generic_new_cmd(struct se_cmd *cmd) { + struct se_device *dev = cmd->se_dev; + int task_cdbs, task_cdbs_bidi = 0; + int set_counts = 1; int ret = 0; /* @@ -4293,16 +3815,45 @@ int transport_generic_new_cmd(struct se_cmd *cmd) if (ret < 0) return ret; } + /* - * Call transport_new_cmd_obj() to invoke transport_allocate_tasks() for - * control or data CDB types, and perform the map to backend subsystem - * code from SGL memory allocated here by transport_generic_get_mem(), or - * via pre-existing SGL memory setup explictly by fabric module code with - * transport_generic_map_mem_to_cmd(). + * For BIDI command set up the read tasks first. */ - ret = transport_new_cmd_obj(cmd); - if (ret < 0) - return ret; + if (cmd->t_bidi_data_sg && + dev->transport->transport_type != TRANSPORT_PLUGIN_PHBA_PDEV) { + BUG_ON(!(cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB)); + + task_cdbs_bidi = transport_allocate_data_tasks(cmd, + DMA_FROM_DEVICE, cmd->t_bidi_data_sg, + cmd->t_bidi_data_nents); + if (task_cdbs_bidi <= 0) + goto out_fail; + + atomic_inc(&cmd->t_fe_count); + atomic_inc(&cmd->t_se_count); + set_counts = 0; + } + + if (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) { + task_cdbs = transport_allocate_data_tasks(cmd, + cmd->data_direction, cmd->t_data_sg, + cmd->t_data_nents); + } else { + task_cdbs = transport_allocate_control_task(cmd); + } + + if (task_cdbs <= 0) + goto out_fail; + + if (set_counts) { + atomic_inc(&cmd->t_fe_count); + atomic_inc(&cmd->t_se_count); + } + + cmd->t_task_list_num = (task_cdbs + task_cdbs_bidi); + atomic_set(&cmd->t_task_cdbs_left, cmd->t_task_list_num); + atomic_set(&cmd->t_task_cdbs_ex_left, cmd->t_task_list_num); + /* * For WRITEs, let the fabric know its buffer is ready.. * This WRITE struct se_cmd (and all of its associated struct se_task's) @@ -4320,6 +3871,11 @@ int transport_generic_new_cmd(struct se_cmd *cmd) */ transport_execute_tasks(cmd); return 0; + +out_fail: + cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + return -EINVAL; } EXPORT_SYMBOL(transport_generic_new_cmd); @@ -4333,15 +3889,18 @@ void transport_generic_process_write(struct se_cmd *cmd) } EXPORT_SYMBOL(transport_generic_process_write); -static int transport_write_pending_qf(struct se_cmd *cmd) +static void transport_write_pending_qf(struct se_cmd *cmd) { - return cmd->se_tfo->write_pending(cmd); + int ret; + + ret = cmd->se_tfo->write_pending(cmd); + if (ret == -EAGAIN || ret == -ENOMEM) { + pr_debug("Handling write_pending QUEUE__FULL: se_cmd: %p\n", + cmd); + transport_handle_queue_full(cmd, cmd->se_dev); + } } -/* transport_generic_write_pending(): - * - * - */ static int transport_generic_write_pending(struct se_cmd *cmd) { unsigned long flags; @@ -4351,17 +3910,6 @@ static int transport_generic_write_pending(struct se_cmd *cmd) cmd->t_state = TRANSPORT_WRITE_PENDING; spin_unlock_irqrestore(&cmd->t_state_lock, flags); - if (cmd->transport_qf_callback) { - ret = cmd->transport_qf_callback(cmd); - if (ret == -EAGAIN) - goto queue_full; - else if (ret < 0) - return ret; - - cmd->transport_qf_callback = NULL; - return 0; - } - /* * Clear the se_cmd for WRITE_PENDING status in order to set * cmd->t_transport_active=0 so that transport_generic_handle_data @@ -4376,7 +3924,7 @@ static int transport_generic_write_pending(struct se_cmd *cmd) * frontend know that WRITE buffers are ready. */ ret = cmd->se_tfo->write_pending(cmd); - if (ret == -EAGAIN) + if (ret == -EAGAIN || ret == -ENOMEM) goto queue_full; else if (ret < 0) return ret; @@ -4386,60 +3934,167 @@ static int transport_generic_write_pending(struct se_cmd *cmd) queue_full: pr_debug("Handling write_pending QUEUE__FULL: se_cmd: %p\n", cmd); cmd->t_state = TRANSPORT_COMPLETE_QF_WP; - transport_handle_queue_full(cmd, cmd->se_dev, - transport_write_pending_qf); - return ret; + transport_handle_queue_full(cmd, cmd->se_dev); + return 0; } +/** + * transport_release_cmd - free a command + * @cmd: command to free + * + * This routine unconditionally frees a command, and reference counting + * or list removal must be done in the caller. + */ void transport_release_cmd(struct se_cmd *cmd) { BUG_ON(!cmd->se_tfo); - transport_free_se_cmd(cmd); + if (cmd->se_tmr_req) + core_tmr_release_req(cmd->se_tmr_req); + if (cmd->t_task_cdb != cmd->__t_task_cdb) + kfree(cmd->t_task_cdb); + /* + * Check if target_wait_for_sess_cmds() is expecting to + * release se_cmd directly here.. + */ + if (cmd->check_release != 0 && cmd->se_tfo->check_release_cmd) + if (cmd->se_tfo->check_release_cmd(cmd) != 0) + return; + cmd->se_tfo->release_cmd(cmd); } EXPORT_SYMBOL(transport_release_cmd); -/* transport_generic_free_cmd(): - * - * Called from processing frontend to release storage engine resources - */ -void transport_generic_free_cmd( - struct se_cmd *cmd, - int wait_for_tasks, - int session_reinstatement) +void transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks) { - if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD)) + if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD)) { + if (wait_for_tasks && cmd->se_tmr_req) + transport_wait_for_tasks(cmd); + transport_release_cmd(cmd); - else { + } else { + if (wait_for_tasks) + transport_wait_for_tasks(cmd); + core_dec_lacl_count(cmd->se_sess->se_node_acl, cmd); - if (cmd->se_lun) { -#if 0 - pr_debug("cmd: %p ITT: 0x%08x contains" - " cmd->se_lun\n", cmd, - cmd->se_tfo->get_task_tag(cmd)); -#endif + if (cmd->se_lun) transport_lun_remove_cmd(cmd); - } - - if (wait_for_tasks && cmd->transport_wait_for_tasks) - cmd->transport_wait_for_tasks(cmd, 0, 0); transport_free_dev_tasks(cmd); - transport_generic_remove(cmd, session_reinstatement); + transport_put_cmd(cmd); } } EXPORT_SYMBOL(transport_generic_free_cmd); -static void transport_nop_wait_for_tasks( - struct se_cmd *cmd, - int remove_cmd, - int session_reinstatement) +/* target_get_sess_cmd - Add command to active ->sess_cmd_list + * @se_sess: session to reference + * @se_cmd: command descriptor to add + */ +void target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd) { - return; + unsigned long flags; + + spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); + list_add_tail(&se_cmd->se_cmd_list, &se_sess->sess_cmd_list); + se_cmd->check_release = 1; + spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); } +EXPORT_SYMBOL(target_get_sess_cmd); + +/* target_put_sess_cmd - Check for active I/O shutdown or list delete + * @se_sess: session to reference + * @se_cmd: command descriptor to drop + */ +int target_put_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd) +{ + unsigned long flags; + + spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); + if (list_empty(&se_cmd->se_cmd_list)) { + spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); + WARN_ON(1); + return 0; + } + + if (se_sess->sess_tearing_down && se_cmd->cmd_wait_set) { + spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); + complete(&se_cmd->cmd_wait_comp); + return 1; + } + list_del(&se_cmd->se_cmd_list); + spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); + + return 0; +} +EXPORT_SYMBOL(target_put_sess_cmd); + +/* target_splice_sess_cmd_list - Split active cmds into sess_wait_list + * @se_sess: session to split + */ +void target_splice_sess_cmd_list(struct se_session *se_sess) +{ + struct se_cmd *se_cmd; + unsigned long flags; + + WARN_ON(!list_empty(&se_sess->sess_wait_list)); + INIT_LIST_HEAD(&se_sess->sess_wait_list); + + spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); + se_sess->sess_tearing_down = 1; + + list_splice_init(&se_sess->sess_cmd_list, &se_sess->sess_wait_list); + + list_for_each_entry(se_cmd, &se_sess->sess_wait_list, se_cmd_list) + se_cmd->cmd_wait_set = 1; + + spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); +} +EXPORT_SYMBOL(target_splice_sess_cmd_list); + +/* target_wait_for_sess_cmds - Wait for outstanding descriptors + * @se_sess: session to wait for active I/O + * @wait_for_tasks: Make extra transport_wait_for_tasks call + */ +void target_wait_for_sess_cmds( + struct se_session *se_sess, + int wait_for_tasks) +{ + struct se_cmd *se_cmd, *tmp_cmd; + bool rc = false; + + list_for_each_entry_safe(se_cmd, tmp_cmd, + &se_sess->sess_wait_list, se_cmd_list) { + list_del(&se_cmd->se_cmd_list); + + pr_debug("Waiting for se_cmd: %p t_state: %d, fabric state:" + " %d\n", se_cmd, se_cmd->t_state, + se_cmd->se_tfo->get_cmd_state(se_cmd)); + + if (wait_for_tasks) { + pr_debug("Calling transport_wait_for_tasks se_cmd: %p t_state: %d," + " fabric state: %d\n", se_cmd, se_cmd->t_state, + se_cmd->se_tfo->get_cmd_state(se_cmd)); + + rc = transport_wait_for_tasks(se_cmd); + + pr_debug("After transport_wait_for_tasks se_cmd: %p t_state: %d," + " fabric state: %d\n", se_cmd, se_cmd->t_state, + se_cmd->se_tfo->get_cmd_state(se_cmd)); + } + + if (!rc) { + wait_for_completion(&se_cmd->cmd_wait_comp); + pr_debug("After cmd_wait_comp: se_cmd: %p t_state: %d" + " fabric state: %d\n", se_cmd, se_cmd->t_state, + se_cmd->se_tfo->get_cmd_state(se_cmd)); + } + + se_cmd->se_tfo->release_cmd(se_cmd); + } +} +EXPORT_SYMBOL(target_wait_for_sess_cmds); /* transport_lun_wait_for_tasks(): * @@ -4479,7 +4134,7 @@ static int transport_lun_wait_for_tasks(struct se_cmd *cmd, struct se_lun *lun) pr_debug("ConfigFS: ITT[0x%08x] - stopped cmd....\n", cmd->se_tfo->get_task_tag(cmd)); } - transport_remove_cmd_from_queue(cmd, &cmd->se_dev->dev_queue_obj); + transport_remove_cmd_from_queue(cmd); return 0; } @@ -4610,22 +4265,30 @@ int transport_clear_lun_from_sessions(struct se_lun *lun) return 0; } -/* transport_generic_wait_for_tasks(): +/** + * transport_wait_for_tasks - wait for completion to occur + * @cmd: command to wait * - * Called from frontend or passthrough context to wait for storage engine - * to pause and/or release frontend generated struct se_cmd. + * Called from frontend fabric context to wait for storage engine + * to pause and/or release frontend generated struct se_cmd. */ -static void transport_generic_wait_for_tasks( - struct se_cmd *cmd, - int remove_cmd, - int session_reinstatement) +bool transport_wait_for_tasks(struct se_cmd *cmd) { unsigned long flags; - if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD) && !(cmd->se_tmr_req)) - return; - spin_lock_irqsave(&cmd->t_state_lock, flags); + if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD) && !(cmd->se_tmr_req)) { + spin_unlock_irqrestore(&cmd->t_state_lock, flags); + return false; + } + /* + * Only perform a possible wait_for_tasks if SCF_SUPPORTED_SAM_OPCODE + * has been set in transport_set_supported_SAM_opcode(). + */ + if (!(cmd->se_cmd_flags & SCF_SUPPORTED_SAM_OPCODE) && !cmd->se_tmr_req) { + spin_unlock_irqrestore(&cmd->t_state_lock, flags); + return false; + } /* * If we are already stopped due to an external event (ie: LUN shutdown) * sleep until the connection can have the passed struct se_cmd back. @@ -4665,16 +4328,17 @@ static void transport_generic_wait_for_tasks( atomic_set(&cmd->transport_lun_stop, 0); } if (!atomic_read(&cmd->t_transport_active) || - atomic_read(&cmd->t_transport_aborted)) - goto remove; + atomic_read(&cmd->t_transport_aborted)) { + spin_unlock_irqrestore(&cmd->t_state_lock, flags); + return false; + } atomic_set(&cmd->t_transport_stop, 1); pr_debug("wait_for_tasks: Stopping %p ITT: 0x%08x" - " i_state: %d, t_state/def_t_state: %d/%d, t_transport_stop" - " = TRUE\n", cmd, cmd->se_tfo->get_task_tag(cmd), - cmd->se_tfo->get_cmd_state(cmd), cmd->t_state, - cmd->deferred_t_state); + " i_state: %d, t_state: %d, t_transport_stop = TRUE\n", + cmd, cmd->se_tfo->get_task_tag(cmd), + cmd->se_tfo->get_cmd_state(cmd), cmd->t_state); spin_unlock_irqrestore(&cmd->t_state_lock, flags); @@ -4689,13 +4353,12 @@ static void transport_generic_wait_for_tasks( pr_debug("wait_for_tasks: Stopped wait_for_compltion(" "&cmd->t_transport_stop_comp) for ITT: 0x%08x\n", cmd->se_tfo->get_task_tag(cmd)); -remove: + spin_unlock_irqrestore(&cmd->t_state_lock, flags); - if (!remove_cmd) - return; - transport_generic_free_cmd(cmd, 0, session_reinstatement); + return true; } +EXPORT_SYMBOL(transport_wait_for_tasks); static int transport_get_sense_codes( struct se_cmd *cmd, @@ -4920,6 +4583,15 @@ EXPORT_SYMBOL(transport_check_aborted_status); void transport_send_task_abort(struct se_cmd *cmd) { + unsigned long flags; + + spin_lock_irqsave(&cmd->t_state_lock, flags); + if (cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION) { + spin_unlock_irqrestore(&cmd->t_state_lock, flags); + return; + } + spin_unlock_irqrestore(&cmd->t_state_lock, flags); + /* * If there are still expected incoming fabric WRITEs, we wait * until until they have completed before sending a TASK_ABORTED @@ -4984,184 +4656,10 @@ int transport_generic_do_tmr(struct se_cmd *cmd) cmd->t_state = TRANSPORT_ISTATE_PROCESSING; cmd->se_tfo->queue_tm_rsp(cmd); - transport_cmd_check_stop(cmd, 2, 0); + transport_cmd_check_stop_to_fabric(cmd); return 0; } -/* - * Called with spin_lock_irq(&dev->execute_task_lock); held - * - */ -static struct se_task * -transport_get_task_from_state_list(struct se_device *dev) -{ - struct se_task *task; - - if (list_empty(&dev->state_task_list)) - return NULL; - - list_for_each_entry(task, &dev->state_task_list, t_state_list) - break; - - list_del(&task->t_state_list); - atomic_set(&task->task_state_active, 0); - - return task; -} - -static void transport_processing_shutdown(struct se_device *dev) -{ - struct se_cmd *cmd; - struct se_task *task; - unsigned long flags; - /* - * Empty the struct se_device's struct se_task state list. - */ - spin_lock_irqsave(&dev->execute_task_lock, flags); - while ((task = transport_get_task_from_state_list(dev))) { - if (!task->task_se_cmd) { - pr_err("task->task_se_cmd is NULL!\n"); - continue; - } - cmd = task->task_se_cmd; - - spin_unlock_irqrestore(&dev->execute_task_lock, flags); - - spin_lock_irqsave(&cmd->t_state_lock, flags); - - pr_debug("PT: cmd: %p task: %p ITT: 0x%08x," - " i_state: %d, t_state/def_t_state:" - " %d/%d cdb: 0x%02x\n", cmd, task, - cmd->se_tfo->get_task_tag(cmd), - cmd->se_tfo->get_cmd_state(cmd), - cmd->t_state, cmd->deferred_t_state, - cmd->t_task_cdb[0]); - pr_debug("PT: ITT[0x%08x] - t_tasks: %d t_task_cdbs_left:" - " %d t_task_cdbs_sent: %d -- t_transport_active: %d" - " t_transport_stop: %d t_transport_sent: %d\n", - cmd->se_tfo->get_task_tag(cmd), - cmd->t_task_list_num, - atomic_read(&cmd->t_task_cdbs_left), - atomic_read(&cmd->t_task_cdbs_sent), - atomic_read(&cmd->t_transport_active), - atomic_read(&cmd->t_transport_stop), - atomic_read(&cmd->t_transport_sent)); - - if (atomic_read(&task->task_active)) { - atomic_set(&task->task_stop, 1); - spin_unlock_irqrestore( - &cmd->t_state_lock, flags); - - pr_debug("Waiting for task: %p to shutdown for dev:" - " %p\n", task, dev); - wait_for_completion(&task->task_stop_comp); - pr_debug("Completed task: %p shutdown for dev: %p\n", - task, dev); - - spin_lock_irqsave(&cmd->t_state_lock, flags); - atomic_dec(&cmd->t_task_cdbs_left); - - atomic_set(&task->task_active, 0); - atomic_set(&task->task_stop, 0); - } else { - if (atomic_read(&task->task_execute_queue) != 0) - transport_remove_task_from_execute_queue(task, dev); - } - __transport_stop_task_timer(task, &flags); - - if (!atomic_dec_and_test(&cmd->t_task_cdbs_ex_left)) { - spin_unlock_irqrestore( - &cmd->t_state_lock, flags); - - pr_debug("Skipping task: %p, dev: %p for" - " t_task_cdbs_ex_left: %d\n", task, dev, - atomic_read(&cmd->t_task_cdbs_ex_left)); - - spin_lock_irqsave(&dev->execute_task_lock, flags); - continue; - } - - if (atomic_read(&cmd->t_transport_active)) { - pr_debug("got t_transport_active = 1 for task: %p, dev:" - " %p\n", task, dev); - - if (atomic_read(&cmd->t_fe_count)) { - spin_unlock_irqrestore( - &cmd->t_state_lock, flags); - transport_send_check_condition_and_sense( - cmd, TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, - 0); - transport_remove_cmd_from_queue(cmd, - &cmd->se_dev->dev_queue_obj); - - transport_lun_remove_cmd(cmd); - transport_cmd_check_stop(cmd, 1, 0); - } else { - spin_unlock_irqrestore( - &cmd->t_state_lock, flags); - - transport_remove_cmd_from_queue(cmd, - &cmd->se_dev->dev_queue_obj); - - transport_lun_remove_cmd(cmd); - - if (transport_cmd_check_stop(cmd, 1, 0)) - transport_generic_remove(cmd, 0); - } - - spin_lock_irqsave(&dev->execute_task_lock, flags); - continue; - } - pr_debug("Got t_transport_active = 0 for task: %p, dev: %p\n", - task, dev); - - if (atomic_read(&cmd->t_fe_count)) { - spin_unlock_irqrestore( - &cmd->t_state_lock, flags); - transport_send_check_condition_and_sense(cmd, - TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0); - transport_remove_cmd_from_queue(cmd, - &cmd->se_dev->dev_queue_obj); - - transport_lun_remove_cmd(cmd); - transport_cmd_check_stop(cmd, 1, 0); - } else { - spin_unlock_irqrestore( - &cmd->t_state_lock, flags); - - transport_remove_cmd_from_queue(cmd, - &cmd->se_dev->dev_queue_obj); - transport_lun_remove_cmd(cmd); - - if (transport_cmd_check_stop(cmd, 1, 0)) - transport_generic_remove(cmd, 0); - } - - spin_lock_irqsave(&dev->execute_task_lock, flags); - } - spin_unlock_irqrestore(&dev->execute_task_lock, flags); - /* - * Empty the struct se_device's struct se_cmd list. - */ - while ((cmd = transport_get_cmd_from_queue(&dev->dev_queue_obj))) { - - pr_debug("From Device Queue: cmd: %p t_state: %d\n", - cmd, cmd->t_state); - - if (atomic_read(&cmd->t_fe_count)) { - transport_send_check_condition_and_sense(cmd, - TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0); - - transport_lun_remove_cmd(cmd); - transport_cmd_check_stop(cmd, 1, 0); - } else { - transport_lun_remove_cmd(cmd); - if (transport_cmd_check_stop(cmd, 1, 0)) - transport_generic_remove(cmd, 0); - } - } -} - /* transport_processing_thread(): * * @@ -5181,14 +4679,6 @@ static int transport_processing_thread(void *param) if (ret < 0) goto out; - spin_lock_irq(&dev->dev_status_lock); - if (dev->dev_status & TRANSPORT_DEVICE_SHUTDOWN) { - spin_unlock_irq(&dev->dev_status_lock); - transport_processing_shutdown(dev); - continue; - } - spin_unlock_irq(&dev->dev_status_lock); - get_cmd: __transport_execute_tasks(dev); @@ -5197,6 +4687,9 @@ get_cmd: continue; switch (cmd->t_state) { + case TRANSPORT_NEW_CMD: + BUG(); + break; case TRANSPORT_NEW_CMD_MAP: if (!cmd->se_tfo->new_cmd_map) { pr_err("cmd->se_tfo->new_cmd_map is" @@ -5206,19 +4699,15 @@ get_cmd: ret = cmd->se_tfo->new_cmd_map(cmd); if (ret < 0) { cmd->transport_error_status = ret; - transport_generic_request_failure(cmd, NULL, + transport_generic_request_failure(cmd, 0, (cmd->data_direction != DMA_TO_DEVICE)); break; } - /* Fall through */ - case TRANSPORT_NEW_CMD: ret = transport_generic_new_cmd(cmd); - if (ret == -EAGAIN) - break; - else if (ret < 0) { + if (ret < 0) { cmd->transport_error_status = ret; - transport_generic_request_failure(cmd, NULL, + transport_generic_request_failure(cmd, 0, (cmd->data_direction != DMA_TO_DEVICE)); } @@ -5226,33 +4715,19 @@ get_cmd: case TRANSPORT_PROCESS_WRITE: transport_generic_process_write(cmd); break; - case TRANSPORT_COMPLETE_OK: - transport_stop_all_task_timers(cmd); - transport_generic_complete_ok(cmd); - break; - case TRANSPORT_REMOVE: - transport_generic_remove(cmd, 0); - break; - case TRANSPORT_FREE_CMD_INTR: - transport_generic_free_cmd(cmd, 0, 0); - break; case TRANSPORT_PROCESS_TMR: transport_generic_do_tmr(cmd); break; - case TRANSPORT_COMPLETE_FAILURE: - transport_generic_request_failure(cmd, NULL, 1, 1); - break; - case TRANSPORT_COMPLETE_TIMEOUT: - transport_stop_all_task_timers(cmd); - transport_generic_request_timeout(cmd); - break; case TRANSPORT_COMPLETE_QF_WP: - transport_generic_write_pending(cmd); + transport_write_pending_qf(cmd); + break; + case TRANSPORT_COMPLETE_QF_OK: + transport_complete_qf(cmd); break; default: - pr_err("Unknown t_state: %d deferred_t_state:" - " %d for ITT: 0x%08x i_state: %d on SE LUN:" - " %u\n", cmd->t_state, cmd->deferred_t_state, + pr_err("Unknown t_state: %d for ITT: 0x%08x " + "i_state: %d on SE LUN: %u\n", + cmd->t_state, cmd->se_tfo->get_task_tag(cmd), cmd->se_tfo->get_cmd_state(cmd), cmd->se_lun->unpacked_lun); @@ -5263,7 +4738,8 @@ get_cmd: } out: - transport_release_all_cmds(dev); + WARN_ON(!list_empty(&dev->state_task_list)); + WARN_ON(!list_empty(&dev->dev_queue_obj.qobj_list)); dev->process_thread = NULL; return 0; } diff --git a/drivers/target/target_core_ua.c b/drivers/target/target_core_ua.c index 31e3c652527e..50a480db7a66 100644 --- a/drivers/target/target_core_ua.c +++ b/drivers/target/target_core_ua.c @@ -24,7 +24,6 @@ * ******************************************************************************/ -#include <linux/version.h> #include <linux/slab.h> #include <linux/spinlock.h> #include <scsi/scsi.h> diff --git a/drivers/target/tcm_fc/tcm_fc.h b/drivers/target/tcm_fc/tcm_fc.h index 3749d8b4b423..e05c55100ec6 100644 --- a/drivers/target/tcm_fc/tcm_fc.h +++ b/drivers/target/tcm_fc/tcm_fc.h @@ -156,7 +156,7 @@ int ft_lport_notify(struct notifier_block *, unsigned long, void *); /* * IO methods. */ -void ft_check_stop_free(struct se_cmd *); +int ft_check_stop_free(struct se_cmd *); void ft_release_cmd(struct se_cmd *); int ft_queue_status(struct se_cmd *); int ft_queue_data_in(struct se_cmd *); diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c index 80fbcde00cb6..4fac37c4c615 100644 --- a/drivers/target/tcm_fc/tfc_cmd.c +++ b/drivers/target/tcm_fc/tfc_cmd.c @@ -19,7 +19,6 @@ #include <linux/module.h> #include <linux/moduleparam.h> -#include <linux/version.h> #include <generated/utsrelease.h> #include <linux/utsname.h> #include <linux/init.h> @@ -113,9 +112,10 @@ void ft_release_cmd(struct se_cmd *se_cmd) ft_free_cmd(cmd); } -void ft_check_stop_free(struct se_cmd *se_cmd) +int ft_check_stop_free(struct se_cmd *se_cmd) { - transport_generic_free_cmd(se_cmd, 0, 0); + transport_generic_free_cmd(se_cmd, 0); + return 1; } /* @@ -268,9 +268,8 @@ static void ft_recv_seq(struct fc_seq *sp, struct fc_frame *fp, void *arg) if (IS_ERR(fp)) { /* XXX need to find cmd if queued */ - cmd->se_cmd.t_state = TRANSPORT_REMOVE; cmd->seq = NULL; - transport_generic_free_cmd(&cmd->se_cmd, 0, 0); + transport_generic_free_cmd(&cmd->se_cmd, 0); return; } @@ -288,7 +287,7 @@ static void ft_recv_seq(struct fc_seq *sp, struct fc_frame *fp, void *arg) __func__, fh->fh_r_ctl); ft_invl_hw_context(cmd); fc_frame_free(fp); - transport_generic_free_cmd(&cmd->se_cmd, 0, 0); + transport_generic_free_cmd(&cmd->se_cmd, 0); break; } } @@ -397,7 +396,7 @@ static void ft_send_tm(struct ft_cmd *cmd) } pr_debug("alloc tm cmd fn %d\n", tm_func); - tmr = core_tmr_alloc_req(&cmd->se_cmd, cmd, tm_func); + tmr = core_tmr_alloc_req(&cmd->se_cmd, cmd, tm_func, GFP_KERNEL); if (!tmr) { pr_debug("alloc failed\n"); ft_send_resp_code_and_free(cmd, FCP_TMF_FAILED); @@ -421,7 +420,7 @@ static void ft_send_tm(struct ft_cmd *cmd) sess = cmd->sess; transport_send_check_condition_and_sense(&cmd->se_cmd, cmd->se_cmd.scsi_sense_reason, 0); - transport_generic_free_cmd(&cmd->se_cmd, 0, 0); + transport_generic_free_cmd(&cmd->se_cmd, 0); ft_sess_put(sess); return; } @@ -628,7 +627,7 @@ static void ft_send_work(struct work_struct *work) if (ret == -ENOMEM) { transport_send_check_condition_and_sense(se_cmd, TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0); - transport_generic_free_cmd(se_cmd, 0, 0); + transport_generic_free_cmd(se_cmd, 0); return; } if (ret == -EINVAL) { @@ -637,10 +636,10 @@ static void ft_send_work(struct work_struct *work) else transport_send_check_condition_and_sense(se_cmd, se_cmd->scsi_sense_reason, 0); - transport_generic_free_cmd(se_cmd, 0, 0); + transport_generic_free_cmd(se_cmd, 0); return; } - transport_generic_handle_cdb(se_cmd); + transport_handle_cdb_direct(se_cmd); return; err: diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c index 8fa39b74f22c..5f770412ca40 100644 --- a/drivers/target/tcm_fc/tfc_conf.c +++ b/drivers/target/tcm_fc/tfc_conf.c @@ -23,7 +23,6 @@ #include <linux/module.h> #include <linux/moduleparam.h> -#include <linux/version.h> #include <generated/utsrelease.h> #include <linux/utsname.h> #include <linux/init.h> @@ -32,6 +31,7 @@ #include <linux/types.h> #include <linux/string.h> #include <linux/configfs.h> +#include <linux/kernel.h> #include <linux/ctype.h> #include <asm/unaligned.h> #include <scsi/scsi.h> @@ -71,10 +71,10 @@ static ssize_t ft_parse_wwn(const char *name, u64 *wwn, int strict) { const char *cp; char c; - u32 nibble; u32 byte = 0; u32 pos = 0; u32 err; + int val; *wwn = 0; for (cp = name; cp < &name[FT_NAMELEN - 1]; cp++) { @@ -95,13 +95,10 @@ static ssize_t ft_parse_wwn(const char *name, u64 *wwn, int strict) return cp - name; } err = 3; - if (isdigit(c)) - nibble = c - '0'; - else if (isxdigit(c) && (islower(c) || !strict)) - nibble = tolower(c) - 'a' + 10; - else + val = hex_to_bin(c); + if (val < 0 || (strict && isupper(c))) goto fail; - *wwn = (*wwn << 4) | nibble; + *wwn = (*wwn << 4) | val; } err = 4; fail: diff --git a/drivers/target/tcm_fc/tfc_io.c b/drivers/target/tcm_fc/tfc_io.c index d35ea5a3d56c..1369b1cb103d 100644 --- a/drivers/target/tcm_fc/tfc_io.c +++ b/drivers/target/tcm_fc/tfc_io.c @@ -28,7 +28,6 @@ #include <linux/module.h> #include <linux/moduleparam.h> -#include <linux/version.h> #include <generated/utsrelease.h> #include <linux/utsname.h> #include <linux/init.h> diff --git a/drivers/target/tcm_fc/tfc_sess.c b/drivers/target/tcm_fc/tfc_sess.c index dbb5eaeee399..326921385aff 100644 --- a/drivers/target/tcm_fc/tfc_sess.c +++ b/drivers/target/tcm_fc/tfc_sess.c @@ -19,7 +19,6 @@ #include <linux/module.h> #include <linux/moduleparam.h> -#include <linux/version.h> #include <generated/utsrelease.h> #include <linux/utsname.h> #include <linux/init.h> |