Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending
Pull SCSI target updates from Nicholas Bellinger: "Here are the target pending updates for v3.15-rc1. Apologies in advance for waiting until the second to last day of the merge window to send these out. The highlights this round include: - iser-target support for T10 PI (DIF) offloads (Sagi + Or) - Fix Task Aborted Status (TAS) handling in target-core (Alex Leung) - Pass in transport supported PI at session initialization (Sagi + MKP + nab) - Add WRITE_INSERT + READ_STRIP T10 PI support in target-core (nab + Sagi) - Fix iscsi-target ERL=2 ASYNC_EVENT connection pointer bug (nab) - Fix tcm_fc use-after-free of ft_tpg (Andy Grover) - Use correct ib_sg_dma primitives in ib_isert (Mike Marciniszyn) Also, note the virtio-scsi + vhost-scsi changes to expose T10 PI metadata into KVM guest have been left-out for now, as there where a few comments from MST + Paolo that where not able to be addressed in time for v3.15. Please expect this feature for v3.16-rc1" * 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending: (43 commits) ib_srpt: Use correct ib_sg_dma primitives target/tcm_fc: Rename ft_tport_create to ft_tport_get target/tcm_fc: Rename ft_{add,del}_lport to {add,del}_wwn target/tcm_fc: Rename structs and list members for clarity target/tcm_fc: Limit to 1 TPG per wwn target/tcm_fc: Don't export ft_lport_list target/tcm_fc: Fix use-after-free of ft_tpg target: Add check to prevent Abort Task from aborting itself target: Enable READ_STRIP emulation in target_complete_ok_work target/sbc: Add sbc_dif_read_strip software emulation target: Enable WRITE_INSERT emulation in target_execute_cmd target/sbc: Add sbc_dif_generate software emulation target/sbc: Only expose PI read_cap16 bits when supported by fabric target/spc: Only expose PI mode page bits when supported by fabric target/spc: Only expose PI inquiry bits when supported by fabric target: Pass in transport supported PI at session initialization target/iblock: Fix double bioset_integrity_free bug Target/sbc: Initialize COMPARE_AND_WRITE write_sg scatterlist target/rd: T10-Dif: RAM disk is allocating more space than required. iscsi-target: Fix ERL=2 ASYNC_EVENT connection pointer bug ...
This commit is contained in:
commit
141eaccd01
File diff suppressed because it is too large
Load Diff
@ -50,11 +50,35 @@ struct iser_tx_desc {
|
||||
struct ib_send_wr send_wr;
|
||||
} __packed;
|
||||
|
||||
enum isert_indicator {
|
||||
ISERT_PROTECTED = 1 << 0,
|
||||
ISERT_DATA_KEY_VALID = 1 << 1,
|
||||
ISERT_PROT_KEY_VALID = 1 << 2,
|
||||
ISERT_SIG_KEY_VALID = 1 << 3,
|
||||
};
|
||||
|
||||
struct pi_context {
|
||||
struct ib_mr *prot_mr;
|
||||
struct ib_fast_reg_page_list *prot_frpl;
|
||||
struct ib_mr *sig_mr;
|
||||
};
|
||||
|
||||
struct fast_reg_descriptor {
|
||||
struct list_head list;
|
||||
struct ib_mr *data_mr;
|
||||
struct ib_fast_reg_page_list *data_frpl;
|
||||
bool valid;
|
||||
struct list_head list;
|
||||
struct ib_mr *data_mr;
|
||||
struct ib_fast_reg_page_list *data_frpl;
|
||||
u8 ind;
|
||||
struct pi_context *pi_ctx;
|
||||
};
|
||||
|
||||
struct isert_data_buf {
|
||||
struct scatterlist *sg;
|
||||
int nents;
|
||||
u32 sg_off;
|
||||
u32 len; /* cur_rdma_length */
|
||||
u32 offset;
|
||||
unsigned int dma_nents;
|
||||
enum dma_data_direction dma_dir;
|
||||
};
|
||||
|
||||
struct isert_rdma_wr {
|
||||
@ -63,12 +87,11 @@ struct isert_rdma_wr {
|
||||
enum iser_ib_op_code iser_ib_op;
|
||||
struct ib_sge *ib_sge;
|
||||
struct ib_sge s_ib_sge;
|
||||
int num_sge;
|
||||
struct scatterlist *sge;
|
||||
int send_wr_num;
|
||||
struct ib_send_wr *send_wr;
|
||||
struct ib_send_wr s_send_wr;
|
||||
u32 cur_rdma_length;
|
||||
struct isert_data_buf data;
|
||||
struct isert_data_buf prot;
|
||||
struct fast_reg_descriptor *fr_desc;
|
||||
};
|
||||
|
||||
@ -141,6 +164,7 @@ struct isert_cq_desc {
|
||||
|
||||
struct isert_device {
|
||||
int use_fastreg;
|
||||
bool pi_capable;
|
||||
int cqs_used;
|
||||
int refcount;
|
||||
int cq_active_qps[ISERT_MAX_CQ];
|
||||
|
@ -1078,6 +1078,7 @@ static void srpt_unmap_sg_to_ib_sge(struct srpt_rdma_ch *ch,
|
||||
static int srpt_map_sg_to_ib_sge(struct srpt_rdma_ch *ch,
|
||||
struct srpt_send_ioctx *ioctx)
|
||||
{
|
||||
struct ib_device *dev = ch->sport->sdev->device;
|
||||
struct se_cmd *cmd;
|
||||
struct scatterlist *sg, *sg_orig;
|
||||
int sg_cnt;
|
||||
@ -1124,7 +1125,7 @@ static int srpt_map_sg_to_ib_sge(struct srpt_rdma_ch *ch,
|
||||
|
||||
db = ioctx->rbufs;
|
||||
tsize = cmd->data_length;
|
||||
dma_len = sg_dma_len(&sg[0]);
|
||||
dma_len = ib_sg_dma_len(dev, &sg[0]);
|
||||
riu = ioctx->rdma_ius;
|
||||
|
||||
/*
|
||||
@ -1155,7 +1156,8 @@ static int srpt_map_sg_to_ib_sge(struct srpt_rdma_ch *ch,
|
||||
++j;
|
||||
if (j < count) {
|
||||
sg = sg_next(sg);
|
||||
dma_len = sg_dma_len(sg);
|
||||
dma_len = ib_sg_dma_len(
|
||||
dev, sg);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -1192,8 +1194,8 @@ static int srpt_map_sg_to_ib_sge(struct srpt_rdma_ch *ch,
|
||||
tsize = cmd->data_length;
|
||||
riu = ioctx->rdma_ius;
|
||||
sg = sg_orig;
|
||||
dma_len = sg_dma_len(&sg[0]);
|
||||
dma_addr = sg_dma_address(&sg[0]);
|
||||
dma_len = ib_sg_dma_len(dev, &sg[0]);
|
||||
dma_addr = ib_sg_dma_address(dev, &sg[0]);
|
||||
|
||||
/* this second loop is really mapped sg_addres to rdma_iu->ib_sge */
|
||||
for (i = 0, j = 0;
|
||||
@ -1216,8 +1218,10 @@ static int srpt_map_sg_to_ib_sge(struct srpt_rdma_ch *ch,
|
||||
++j;
|
||||
if (j < count) {
|
||||
sg = sg_next(sg);
|
||||
dma_len = sg_dma_len(sg);
|
||||
dma_addr = sg_dma_address(sg);
|
||||
dma_len = ib_sg_dma_len(
|
||||
dev, sg);
|
||||
dma_addr = ib_sg_dma_address(
|
||||
dev, sg);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -2580,7 +2584,7 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id,
|
||||
goto destroy_ib;
|
||||
}
|
||||
|
||||
ch->sess = transport_init_session();
|
||||
ch->sess = transport_init_session(TARGET_PROT_NORMAL);
|
||||
if (IS_ERR(ch->sess)) {
|
||||
rej->reason = __constant_cpu_to_be32(
|
||||
SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES);
|
||||
@ -3081,6 +3085,14 @@ static void srpt_queue_tm_rsp(struct se_cmd *cmd)
|
||||
srpt_queue_response(cmd);
|
||||
}
|
||||
|
||||
static void srpt_aborted_task(struct se_cmd *cmd)
|
||||
{
|
||||
struct srpt_send_ioctx *ioctx = container_of(cmd,
|
||||
struct srpt_send_ioctx, cmd);
|
||||
|
||||
srpt_unmap_sg_to_ib_sge(ioctx->ch, ioctx);
|
||||
}
|
||||
|
||||
static int srpt_queue_status(struct se_cmd *cmd)
|
||||
{
|
||||
struct srpt_send_ioctx *ioctx;
|
||||
@ -3928,6 +3940,7 @@ static struct target_core_fabric_ops srpt_template = {
|
||||
.queue_data_in = srpt_queue_data_in,
|
||||
.queue_status = srpt_queue_status,
|
||||
.queue_tm_rsp = srpt_queue_tm_rsp,
|
||||
.aborted_task = srpt_aborted_task,
|
||||
/*
|
||||
* Setup function pointers for generic logic in
|
||||
* target_core_fabric_configfs.c
|
||||
|
@ -684,6 +684,20 @@ static void tcm_qla2xxx_queue_tm_rsp(struct se_cmd *se_cmd)
|
||||
qlt_xmit_tm_rsp(mcmd);
|
||||
}
|
||||
|
||||
static void tcm_qla2xxx_aborted_task(struct se_cmd *se_cmd)
|
||||
{
|
||||
struct qla_tgt_cmd *cmd = container_of(se_cmd,
|
||||
struct qla_tgt_cmd, se_cmd);
|
||||
struct scsi_qla_host *vha = cmd->vha;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
if (!cmd->sg_mapped)
|
||||
return;
|
||||
|
||||
pci_unmap_sg(ha->pdev, cmd->sg, cmd->sg_cnt, cmd->dma_data_direction);
|
||||
cmd->sg_mapped = 0;
|
||||
}
|
||||
|
||||
/* Local pointer to allocated TCM configfs fabric module */
|
||||
struct target_fabric_configfs *tcm_qla2xxx_fabric_configfs;
|
||||
struct target_fabric_configfs *tcm_qla2xxx_npiv_fabric_configfs;
|
||||
@ -1468,7 +1482,7 @@ static int tcm_qla2xxx_check_initiator_node_acl(
|
||||
}
|
||||
se_tpg = &tpg->se_tpg;
|
||||
|
||||
se_sess = transport_init_session();
|
||||
se_sess = transport_init_session(TARGET_PROT_NORMAL);
|
||||
if (IS_ERR(se_sess)) {
|
||||
pr_err("Unable to initialize struct se_session\n");
|
||||
return PTR_ERR(se_sess);
|
||||
@ -1877,6 +1891,7 @@ static struct target_core_fabric_ops tcm_qla2xxx_ops = {
|
||||
.queue_data_in = tcm_qla2xxx_queue_data_in,
|
||||
.queue_status = tcm_qla2xxx_queue_status,
|
||||
.queue_tm_rsp = tcm_qla2xxx_queue_tm_rsp,
|
||||
.aborted_task = tcm_qla2xxx_aborted_task,
|
||||
/*
|
||||
* Setup function pointers for generic logic in
|
||||
* target_core_fabric_configfs.c
|
||||
@ -1926,6 +1941,7 @@ static struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = {
|
||||
.queue_data_in = tcm_qla2xxx_queue_data_in,
|
||||
.queue_status = tcm_qla2xxx_queue_status,
|
||||
.queue_tm_rsp = tcm_qla2xxx_queue_tm_rsp,
|
||||
.aborted_task = tcm_qla2xxx_aborted_task,
|
||||
/*
|
||||
* Setup function pointers for generic logic in
|
||||
* target_core_fabric_configfs.c
|
||||
|
@ -499,6 +499,23 @@ static int iscsit_queue_rsp(struct iscsi_conn *conn, struct iscsi_cmd *cmd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void iscsit_aborted_task(struct iscsi_conn *conn, struct iscsi_cmd *cmd)
|
||||
{
|
||||
bool scsi_cmd = (cmd->iscsi_opcode == ISCSI_OP_SCSI_CMD);
|
||||
|
||||
spin_lock_bh(&conn->cmd_lock);
|
||||
if (!list_empty(&cmd->i_conn_node))
|
||||
list_del_init(&cmd->i_conn_node);
|
||||
spin_unlock_bh(&conn->cmd_lock);
|
||||
|
||||
__iscsit_free_cmd(cmd, scsi_cmd, true);
|
||||
}
|
||||
|
||||
static enum target_prot_op iscsit_get_sup_prot_ops(struct iscsi_conn *conn)
|
||||
{
|
||||
return TARGET_PROT_NORMAL;
|
||||
}
|
||||
|
||||
static struct iscsit_transport iscsi_target_transport = {
|
||||
.name = "iSCSI/TCP",
|
||||
.transport_type = ISCSI_TCP,
|
||||
@ -513,6 +530,8 @@ static struct iscsit_transport iscsi_target_transport = {
|
||||
.iscsit_response_queue = iscsit_response_queue,
|
||||
.iscsit_queue_data_in = iscsit_queue_rsp,
|
||||
.iscsit_queue_status = iscsit_queue_rsp,
|
||||
.iscsit_aborted_task = iscsit_aborted_task,
|
||||
.iscsit_get_sup_prot_ops = iscsit_get_sup_prot_ops,
|
||||
};
|
||||
|
||||
static int __init iscsi_target_init_module(void)
|
||||
@ -1503,6 +1522,16 @@ int iscsit_setup_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
|
||||
{
|
||||
u32 payload_length = ntoh24(hdr->dlength);
|
||||
|
||||
if (!(hdr->flags & ISCSI_FLAG_CMD_FINAL)) {
|
||||
pr_err("NopOUT Flag's, Left Most Bit not set, protocol error.\n");
|
||||
if (!cmd)
|
||||
return iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR,
|
||||
(unsigned char *)hdr);
|
||||
|
||||
return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR,
|
||||
(unsigned char *)hdr);
|
||||
}
|
||||
|
||||
if (hdr->itt == RESERVED_ITT && !(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
|
||||
pr_err("NOPOUT ITT is reserved, but Immediate Bit is"
|
||||
" not set, protocol error.\n");
|
||||
@ -2468,6 +2497,7 @@ static void iscsit_build_conn_drop_async_message(struct iscsi_conn *conn)
|
||||
{
|
||||
struct iscsi_cmd *cmd;
|
||||
struct iscsi_conn *conn_p;
|
||||
bool found = false;
|
||||
|
||||
/*
|
||||
* Only send a Asynchronous Message on connections whos network
|
||||
@ -2476,11 +2506,12 @@ static void iscsit_build_conn_drop_async_message(struct iscsi_conn *conn)
|
||||
list_for_each_entry(conn_p, &conn->sess->sess_conn_list, conn_list) {
|
||||
if (conn_p->conn_state == TARG_CONN_STATE_LOGGED_IN) {
|
||||
iscsit_inc_conn_usage_count(conn_p);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!conn_p)
|
||||
if (!found)
|
||||
return;
|
||||
|
||||
cmd = iscsit_allocate_cmd(conn_p, TASK_RUNNING);
|
||||
|
@ -1052,6 +1052,11 @@ TPG_ATTR(demo_mode_discovery, S_IRUGO | S_IWUSR);
|
||||
*/
|
||||
DEF_TPG_ATTRIB(default_erl);
|
||||
TPG_ATTR(default_erl, S_IRUGO | S_IWUSR);
|
||||
/*
|
||||
* Define iscsi_tpg_attrib_s_t10_pi
|
||||
*/
|
||||
DEF_TPG_ATTRIB(t10_pi);
|
||||
TPG_ATTR(t10_pi, S_IRUGO | S_IWUSR);
|
||||
|
||||
static struct configfs_attribute *lio_target_tpg_attrib_attrs[] = {
|
||||
&iscsi_tpg_attrib_authentication.attr,
|
||||
@ -1064,6 +1069,7 @@ static struct configfs_attribute *lio_target_tpg_attrib_attrs[] = {
|
||||
&iscsi_tpg_attrib_prod_mode_write_protect.attr,
|
||||
&iscsi_tpg_attrib_demo_mode_discovery.attr,
|
||||
&iscsi_tpg_attrib_default_erl.attr,
|
||||
&iscsi_tpg_attrib_t10_pi.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
@ -1815,6 +1821,13 @@ static void lio_queue_tm_rsp(struct se_cmd *se_cmd)
|
||||
iscsit_add_cmd_to_response_queue(cmd, cmd->conn, cmd->i_state);
|
||||
}
|
||||
|
||||
static void lio_aborted_task(struct se_cmd *se_cmd)
|
||||
{
|
||||
struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd);
|
||||
|
||||
cmd->conn->conn_transport->iscsit_aborted_task(cmd->conn, cmd);
|
||||
}
|
||||
|
||||
static char *lio_tpg_get_endpoint_wwn(struct se_portal_group *se_tpg)
|
||||
{
|
||||
struct iscsi_portal_group *tpg = se_tpg->se_tpg_fabric_ptr;
|
||||
@ -1999,6 +2012,7 @@ int iscsi_target_register_configfs(void)
|
||||
fabric->tf_ops.queue_data_in = &lio_queue_data_in;
|
||||
fabric->tf_ops.queue_status = &lio_queue_status;
|
||||
fabric->tf_ops.queue_tm_rsp = &lio_queue_tm_rsp;
|
||||
fabric->tf_ops.aborted_task = &lio_aborted_task;
|
||||
/*
|
||||
* Setup function pointers for generic logic in target_core_fabric_configfs.c
|
||||
*/
|
||||
|
@ -58,7 +58,8 @@
|
||||
#define TA_DEMO_MODE_DISCOVERY 1
|
||||
#define TA_DEFAULT_ERL 0
|
||||
#define TA_CACHE_CORE_NPS 0
|
||||
|
||||
/* T10 protection information disabled by default */
|
||||
#define TA_DEFAULT_T10_PI 0
|
||||
|
||||
#define ISCSI_IOV_DATA_BUFFER 5
|
||||
|
||||
@ -765,6 +766,7 @@ struct iscsi_tpg_attrib {
|
||||
u32 prod_mode_write_protect;
|
||||
u32 demo_mode_discovery;
|
||||
u32 default_erl;
|
||||
u8 t10_pi;
|
||||
struct iscsi_portal_group *tpg;
|
||||
};
|
||||
|
||||
@ -787,6 +789,7 @@ struct iscsi_np {
|
||||
void *np_context;
|
||||
struct iscsit_transport *np_transport;
|
||||
struct list_head np_list;
|
||||
struct iscsi_tpg_np *tpg_np;
|
||||
} ____cacheline_aligned;
|
||||
|
||||
struct iscsi_tpg_np {
|
||||
|
@ -259,6 +259,7 @@ static int iscsi_login_zero_tsih_s1(
|
||||
{
|
||||
struct iscsi_session *sess = NULL;
|
||||
struct iscsi_login_req *pdu = (struct iscsi_login_req *)buf;
|
||||
enum target_prot_op sup_pro_ops;
|
||||
int ret;
|
||||
|
||||
sess = kzalloc(sizeof(struct iscsi_session), GFP_KERNEL);
|
||||
@ -320,8 +321,9 @@ static int iscsi_login_zero_tsih_s1(
|
||||
kfree(sess);
|
||||
return -ENOMEM;
|
||||
}
|
||||
sup_pro_ops = conn->conn_transport->iscsit_get_sup_prot_ops(conn);
|
||||
|
||||
sess->se_sess = transport_init_session();
|
||||
sess->se_sess = transport_init_session(sup_pro_ops);
|
||||
if (IS_ERR(sess->se_sess)) {
|
||||
iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
|
||||
ISCSI_LOGIN_STATUS_NO_RESOURCES);
|
||||
|
@ -225,6 +225,7 @@ static void iscsit_set_default_tpg_attribs(struct iscsi_portal_group *tpg)
|
||||
a->prod_mode_write_protect = TA_PROD_MODE_WRITE_PROTECT;
|
||||
a->demo_mode_discovery = TA_DEMO_MODE_DISCOVERY;
|
||||
a->default_erl = TA_DEFAULT_ERL;
|
||||
a->t10_pi = TA_DEFAULT_T10_PI;
|
||||
}
|
||||
|
||||
int iscsit_tpg_add_portal_group(struct iscsi_tiqn *tiqn, struct iscsi_portal_group *tpg)
|
||||
@ -500,6 +501,7 @@ struct iscsi_tpg_np *iscsit_tpg_add_network_portal(
|
||||
init_completion(&tpg_np->tpg_np_comp);
|
||||
kref_init(&tpg_np->tpg_np_kref);
|
||||
tpg_np->tpg_np = np;
|
||||
np->tpg_np = tpg_np;
|
||||
tpg_np->tpg = tpg;
|
||||
|
||||
spin_lock(&tpg->tpg_np_lock);
|
||||
@ -858,3 +860,22 @@ int iscsit_ta_default_erl(
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iscsit_ta_t10_pi(
|
||||
struct iscsi_portal_group *tpg,
|
||||
u32 flag)
|
||||
{
|
||||
struct iscsi_tpg_attrib *a = &tpg->tpg_attrib;
|
||||
|
||||
if ((flag != 0) && (flag != 1)) {
|
||||
pr_err("Illegal value %d\n", flag);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
a->t10_pi = flag;
|
||||
pr_debug("iSCSI_TPG[%hu] - T10 Protection information bit:"
|
||||
" %s\n", tpg->tpgt, (a->t10_pi) ?
|
||||
"ON" : "OFF");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -39,5 +39,6 @@ extern int iscsit_ta_demo_mode_write_protect(struct iscsi_portal_group *, u32);
|
||||
extern int iscsit_ta_prod_mode_write_protect(struct iscsi_portal_group *, u32);
|
||||
extern int iscsit_ta_demo_mode_discovery(struct iscsi_portal_group *, u32);
|
||||
extern int iscsit_ta_default_erl(struct iscsi_portal_group *, u32);
|
||||
extern int iscsit_ta_t10_pi(struct iscsi_portal_group *, u32);
|
||||
|
||||
#endif /* ISCSI_TARGET_TPG_H */
|
||||
|
@ -705,8 +705,8 @@ void iscsit_release_cmd(struct iscsi_cmd *cmd)
|
||||
}
|
||||
EXPORT_SYMBOL(iscsit_release_cmd);
|
||||
|
||||
static void __iscsit_free_cmd(struct iscsi_cmd *cmd, bool scsi_cmd,
|
||||
bool check_queues)
|
||||
void __iscsit_free_cmd(struct iscsi_cmd *cmd, bool scsi_cmd,
|
||||
bool check_queues)
|
||||
{
|
||||
struct iscsi_conn *conn = cmd->conn;
|
||||
|
||||
|
@ -30,6 +30,7 @@ extern void iscsit_remove_cmd_from_tx_queues(struct iscsi_cmd *, struct iscsi_co
|
||||
extern bool iscsit_conn_all_queues_empty(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 *, bool, bool);
|
||||
extern void iscsit_free_cmd(struct iscsi_cmd *, bool);
|
||||
extern int iscsit_check_session_usage_count(struct iscsi_session *);
|
||||
extern void iscsit_dec_session_usage_count(struct iscsi_session *);
|
||||
|
@ -212,6 +212,10 @@ static void tcm_loop_submission_work(struct work_struct *work)
|
||||
se_cmd->se_cmd_flags |= SCF_BIDI;
|
||||
|
||||
}
|
||||
|
||||
if (!scsi_prot_sg_count(sc) && scsi_get_prot_op(sc) != SCSI_PROT_NORMAL)
|
||||
se_cmd->prot_pto = true;
|
||||
|
||||
rc = target_submit_cmd_map_sgls(se_cmd, tl_nexus->se_sess, sc->cmnd,
|
||||
&tl_cmd->tl_sense_buf[0], tl_cmd->sc->device->lun,
|
||||
scsi_bufflen(sc), tcm_loop_sam_attr(sc),
|
||||
@ -915,6 +919,11 @@ static void tcm_loop_queue_tm_rsp(struct se_cmd *se_cmd)
|
||||
wake_up(&tl_tmr->tl_tmr_wait);
|
||||
}
|
||||
|
||||
static void tcm_loop_aborted_task(struct se_cmd *se_cmd)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static char *tcm_loop_dump_proto_id(struct tcm_loop_hba *tl_hba)
|
||||
{
|
||||
switch (tl_hba->tl_proto_id) {
|
||||
@ -1009,7 +1018,7 @@ static int tcm_loop_make_nexus(
|
||||
/*
|
||||
* Initialize the struct se_session pointer
|
||||
*/
|
||||
tl_nexus->se_sess = transport_init_session();
|
||||
tl_nexus->se_sess = transport_init_session(TARGET_PROT_ALL);
|
||||
if (IS_ERR(tl_nexus->se_sess)) {
|
||||
ret = PTR_ERR(tl_nexus->se_sess);
|
||||
goto out;
|
||||
@ -1483,6 +1492,7 @@ static int tcm_loop_register_configfs(void)
|
||||
fabric->tf_ops.queue_data_in = &tcm_loop_queue_data_in;
|
||||
fabric->tf_ops.queue_status = &tcm_loop_queue_status;
|
||||
fabric->tf_ops.queue_tm_rsp = &tcm_loop_queue_tm_rsp;
|
||||
fabric->tf_ops.aborted_task = &tcm_loop_aborted_task;
|
||||
|
||||
/*
|
||||
* Setup function pointers for generic logic in target_core_fabric_configfs.c
|
||||
|
@ -210,7 +210,7 @@ static struct sbp_session *sbp_session_create(
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
sess->se_sess = transport_init_session();
|
||||
sess->se_sess = transport_init_session(TARGET_PROT_NORMAL);
|
||||
if (IS_ERR(sess->se_sess)) {
|
||||
pr_err("failed to init se_session\n");
|
||||
|
||||
@ -1846,6 +1846,11 @@ static void sbp_queue_tm_rsp(struct se_cmd *se_cmd)
|
||||
{
|
||||
}
|
||||
|
||||
static void sbp_aborted_task(struct se_cmd *se_cmd)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static int sbp_check_stop_free(struct se_cmd *se_cmd)
|
||||
{
|
||||
struct sbp_target_request *req = container_of(se_cmd,
|
||||
@ -2526,6 +2531,7 @@ static struct target_core_fabric_ops sbp_ops = {
|
||||
.queue_data_in = sbp_queue_data_in,
|
||||
.queue_status = sbp_queue_status,
|
||||
.queue_tm_rsp = sbp_queue_tm_rsp,
|
||||
.aborted_task = sbp_aborted_task,
|
||||
.check_stop_free = sbp_check_stop_free,
|
||||
|
||||
.fabric_make_wwn = sbp_make_tport,
|
||||
|
@ -455,11 +455,26 @@ out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static inline int core_alua_state_nonoptimized(
|
||||
static inline void set_ascq(struct se_cmd *cmd, u8 alua_ascq)
|
||||
{
|
||||
/*
|
||||
* Set SCSI additional sense code (ASC) to 'LUN Not Accessible';
|
||||
* The ALUA additional sense code qualifier (ASCQ) is determined
|
||||
* by the ALUA primary or secondary access state..
|
||||
*/
|
||||
pr_debug("[%s]: ALUA TG Port not available, "
|
||||
"SenseKey: NOT_READY, ASC/ASCQ: "
|
||||
"0x04/0x%02x\n",
|
||||
cmd->se_tfo->get_fabric_name(), alua_ascq);
|
||||
|
||||
cmd->scsi_asc = 0x04;
|
||||
cmd->scsi_ascq = alua_ascq;
|
||||
}
|
||||
|
||||
static inline void core_alua_state_nonoptimized(
|
||||
struct se_cmd *cmd,
|
||||
unsigned char *cdb,
|
||||
int nonop_delay_msecs,
|
||||
u8 *alua_ascq)
|
||||
int nonop_delay_msecs)
|
||||
{
|
||||
/*
|
||||
* Set SCF_ALUA_NON_OPTIMIZED here, this value will be checked
|
||||
@ -468,13 +483,11 @@ static inline int core_alua_state_nonoptimized(
|
||||
*/
|
||||
cmd->se_cmd_flags |= SCF_ALUA_NON_OPTIMIZED;
|
||||
cmd->alua_nonop_delay = nonop_delay_msecs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int core_alua_state_lba_dependent(
|
||||
struct se_cmd *cmd,
|
||||
struct t10_alua_tg_pt_gp *tg_pt_gp,
|
||||
u8 *alua_ascq)
|
||||
struct t10_alua_tg_pt_gp *tg_pt_gp)
|
||||
{
|
||||
struct se_device *dev = cmd->se_dev;
|
||||
u64 segment_size, segment_mult, sectors, lba;
|
||||
@ -520,7 +533,7 @@ static inline int core_alua_state_lba_dependent(
|
||||
}
|
||||
if (!cur_map) {
|
||||
spin_unlock(&dev->t10_alua.lba_map_lock);
|
||||
*alua_ascq = ASCQ_04H_ALUA_TG_PT_UNAVAILABLE;
|
||||
set_ascq(cmd, ASCQ_04H_ALUA_TG_PT_UNAVAILABLE);
|
||||
return 1;
|
||||
}
|
||||
list_for_each_entry(map_mem, &cur_map->lba_map_mem_list,
|
||||
@ -531,11 +544,11 @@ static inline int core_alua_state_lba_dependent(
|
||||
switch(map_mem->lba_map_mem_alua_state) {
|
||||
case ALUA_ACCESS_STATE_STANDBY:
|
||||
spin_unlock(&dev->t10_alua.lba_map_lock);
|
||||
*alua_ascq = ASCQ_04H_ALUA_TG_PT_STANDBY;
|
||||
set_ascq(cmd, ASCQ_04H_ALUA_TG_PT_STANDBY);
|
||||
return 1;
|
||||
case ALUA_ACCESS_STATE_UNAVAILABLE:
|
||||
spin_unlock(&dev->t10_alua.lba_map_lock);
|
||||
*alua_ascq = ASCQ_04H_ALUA_TG_PT_UNAVAILABLE;
|
||||
set_ascq(cmd, ASCQ_04H_ALUA_TG_PT_UNAVAILABLE);
|
||||
return 1;
|
||||
default:
|
||||
break;
|
||||
@ -548,8 +561,7 @@ static inline int core_alua_state_lba_dependent(
|
||||
|
||||
static inline int core_alua_state_standby(
|
||||
struct se_cmd *cmd,
|
||||
unsigned char *cdb,
|
||||
u8 *alua_ascq)
|
||||
unsigned char *cdb)
|
||||
{
|
||||
/*
|
||||
* Allowed CDBs for ALUA_ACCESS_STATE_STANDBY as defined by
|
||||
@ -570,7 +582,7 @@ static inline int core_alua_state_standby(
|
||||
case MI_REPORT_TARGET_PGS:
|
||||
return 0;
|
||||
default:
|
||||
*alua_ascq = ASCQ_04H_ALUA_TG_PT_STANDBY;
|
||||
set_ascq(cmd, ASCQ_04H_ALUA_TG_PT_STANDBY);
|
||||
return 1;
|
||||
}
|
||||
case MAINTENANCE_OUT:
|
||||
@ -578,7 +590,7 @@ static inline int core_alua_state_standby(
|
||||
case MO_SET_TARGET_PGS:
|
||||
return 0;
|
||||
default:
|
||||
*alua_ascq = ASCQ_04H_ALUA_TG_PT_STANDBY;
|
||||
set_ascq(cmd, ASCQ_04H_ALUA_TG_PT_STANDBY);
|
||||
return 1;
|
||||
}
|
||||
case REQUEST_SENSE:
|
||||
@ -588,7 +600,7 @@ static inline int core_alua_state_standby(
|
||||
case WRITE_BUFFER:
|
||||
return 0;
|
||||
default:
|
||||
*alua_ascq = ASCQ_04H_ALUA_TG_PT_STANDBY;
|
||||
set_ascq(cmd, ASCQ_04H_ALUA_TG_PT_STANDBY);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -597,8 +609,7 @@ static inline int core_alua_state_standby(
|
||||
|
||||
static inline int core_alua_state_unavailable(
|
||||
struct se_cmd *cmd,
|
||||
unsigned char *cdb,
|
||||
u8 *alua_ascq)
|
||||
unsigned char *cdb)
|
||||
{
|
||||
/*
|
||||
* Allowed CDBs for ALUA_ACCESS_STATE_UNAVAILABLE as defined by
|
||||
@ -613,7 +624,7 @@ static inline int core_alua_state_unavailable(
|
||||
case MI_REPORT_TARGET_PGS:
|
||||
return 0;
|
||||
default:
|
||||
*alua_ascq = ASCQ_04H_ALUA_TG_PT_UNAVAILABLE;
|
||||
set_ascq(cmd, ASCQ_04H_ALUA_TG_PT_UNAVAILABLE);
|
||||
return 1;
|
||||
}
|
||||
case MAINTENANCE_OUT:
|
||||
@ -621,7 +632,7 @@ static inline int core_alua_state_unavailable(
|
||||
case MO_SET_TARGET_PGS:
|
||||
return 0;
|
||||
default:
|
||||
*alua_ascq = ASCQ_04H_ALUA_TG_PT_UNAVAILABLE;
|
||||
set_ascq(cmd, ASCQ_04H_ALUA_TG_PT_UNAVAILABLE);
|
||||
return 1;
|
||||
}
|
||||
case REQUEST_SENSE:
|
||||
@ -629,7 +640,7 @@ static inline int core_alua_state_unavailable(
|
||||
case WRITE_BUFFER:
|
||||
return 0;
|
||||
default:
|
||||
*alua_ascq = ASCQ_04H_ALUA_TG_PT_UNAVAILABLE;
|
||||
set_ascq(cmd, ASCQ_04H_ALUA_TG_PT_UNAVAILABLE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -638,8 +649,7 @@ static inline int core_alua_state_unavailable(
|
||||
|
||||
static inline int core_alua_state_transition(
|
||||
struct se_cmd *cmd,
|
||||
unsigned char *cdb,
|
||||
u8 *alua_ascq)
|
||||
unsigned char *cdb)
|
||||
{
|
||||
/*
|
||||
* Allowed CDBs for ALUA_ACCESS_STATE_TRANSITION as defined by
|
||||
@ -654,7 +664,7 @@ static inline int core_alua_state_transition(
|
||||
case MI_REPORT_TARGET_PGS:
|
||||
return 0;
|
||||
default:
|
||||
*alua_ascq = ASCQ_04H_ALUA_STATE_TRANSITION;
|
||||
set_ascq(cmd, ASCQ_04H_ALUA_STATE_TRANSITION);
|
||||
return 1;
|
||||
}
|
||||
case REQUEST_SENSE:
|
||||
@ -662,7 +672,7 @@ static inline int core_alua_state_transition(
|
||||
case WRITE_BUFFER:
|
||||
return 0;
|
||||
default:
|
||||
*alua_ascq = ASCQ_04H_ALUA_STATE_TRANSITION;
|
||||
set_ascq(cmd, ASCQ_04H_ALUA_STATE_TRANSITION);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -684,8 +694,6 @@ target_alua_state_check(struct se_cmd *cmd)
|
||||
struct t10_alua_tg_pt_gp *tg_pt_gp;
|
||||
struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem;
|
||||
int out_alua_state, nonop_delay_msecs;
|
||||
u8 alua_ascq;
|
||||
int ret;
|
||||
|
||||
if (dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)
|
||||
return 0;
|
||||
@ -701,9 +709,8 @@ target_alua_state_check(struct se_cmd *cmd)
|
||||
if (atomic_read(&port->sep_tg_pt_secondary_offline)) {
|
||||
pr_debug("ALUA: Got secondary offline status for local"
|
||||
" target port\n");
|
||||
alua_ascq = ASCQ_04H_ALUA_OFFLINE;
|
||||
ret = 1;
|
||||
goto out;
|
||||
set_ascq(cmd, ASCQ_04H_ALUA_OFFLINE);
|
||||
return TCM_CHECK_CONDITION_NOT_READY;
|
||||
}
|
||||
/*
|
||||
* Second, obtain the struct t10_alua_tg_pt_gp_member pointer to the
|
||||
@ -731,20 +738,23 @@ target_alua_state_check(struct se_cmd *cmd)
|
||||
|
||||
switch (out_alua_state) {
|
||||
case ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED:
|
||||
ret = core_alua_state_nonoptimized(cmd, cdb,
|
||||
nonop_delay_msecs, &alua_ascq);
|
||||
core_alua_state_nonoptimized(cmd, cdb, nonop_delay_msecs);
|
||||
break;
|
||||
case ALUA_ACCESS_STATE_STANDBY:
|
||||
ret = core_alua_state_standby(cmd, cdb, &alua_ascq);
|
||||
if (core_alua_state_standby(cmd, cdb))
|
||||
return TCM_CHECK_CONDITION_NOT_READY;
|
||||
break;
|
||||
case ALUA_ACCESS_STATE_UNAVAILABLE:
|
||||
ret = core_alua_state_unavailable(cmd, cdb, &alua_ascq);
|
||||
if (core_alua_state_unavailable(cmd, cdb))
|
||||
return TCM_CHECK_CONDITION_NOT_READY;
|
||||
break;
|
||||
case ALUA_ACCESS_STATE_TRANSITION:
|
||||
ret = core_alua_state_transition(cmd, cdb, &alua_ascq);
|
||||
if (core_alua_state_transition(cmd, cdb))
|
||||
return TCM_CHECK_CONDITION_NOT_READY;
|
||||
break;
|
||||
case ALUA_ACCESS_STATE_LBA_DEPENDENT:
|
||||
ret = core_alua_state_lba_dependent(cmd, tg_pt_gp, &alua_ascq);
|
||||
if (core_alua_state_lba_dependent(cmd, tg_pt_gp))
|
||||
return TCM_CHECK_CONDITION_NOT_READY;
|
||||
break;
|
||||
/*
|
||||
* OFFLINE is a secondary ALUA target port group access state, that is
|
||||
@ -757,23 +767,6 @@ target_alua_state_check(struct se_cmd *cmd)
|
||||
return TCM_INVALID_CDB_FIELD;
|
||||
}
|
||||
|
||||
out:
|
||||
if (ret > 0) {
|
||||
/*
|
||||
* Set SCSI additional sense code (ASC) to 'LUN Not Accessible';
|
||||
* The ALUA additional sense code qualifier (ASCQ) is determined
|
||||
* by the ALUA primary or secondary access state..
|
||||
*/
|
||||
pr_debug("[%s]: ALUA TG Port not available, "
|
||||
"SenseKey: NOT_READY, ASC/ASCQ: "
|
||||
"0x04/0x%02x\n",
|
||||
cmd->se_tfo->get_fabric_name(), alua_ascq);
|
||||
|
||||
cmd->scsi_asc = 0x04;
|
||||
cmd->scsi_ascq = alua_ascq;
|
||||
return TCM_CHECK_CONDITION_NOT_READY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -457,6 +457,10 @@ static int target_fabric_tf_ops_check(
|
||||
pr_err("Missing tfo->queue_tm_rsp()\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!tfo->aborted_task) {
|
||||
pr_err("Missing tfo->aborted_task()\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
/*
|
||||
* We at least require tfo->fabric_make_wwn(), tfo->fabric_drop_wwn()
|
||||
* tfo->fabric_make_tpg() and tfo->fabric_drop_tpg() in
|
||||
|
@ -854,25 +854,6 @@ static int fd_init_prot(struct se_device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void fd_init_format_buf(struct se_device *dev, unsigned char *buf,
|
||||
u32 unit_size, u32 *ref_tag, u16 app_tag,
|
||||
bool inc_reftag)
|
||||
{
|
||||
unsigned char *p = buf;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < unit_size; i += dev->prot_length) {
|
||||
*((u16 *)&p[0]) = 0xffff;
|
||||
*((__be16 *)&p[2]) = cpu_to_be16(app_tag);
|
||||
*((__be32 *)&p[4]) = cpu_to_be32(*ref_tag);
|
||||
|
||||
if (inc_reftag)
|
||||
(*ref_tag)++;
|
||||
|
||||
p += dev->prot_length;
|
||||
}
|
||||
}
|
||||
|
||||
static int fd_format_prot(struct se_device *dev)
|
||||
{
|
||||
struct fd_dev *fd_dev = FD_DEV(dev);
|
||||
@ -880,10 +861,8 @@ static int fd_format_prot(struct se_device *dev)
|
||||
sector_t prot_length, prot;
|
||||
unsigned char *buf;
|
||||
loff_t pos = 0;
|
||||
u32 ref_tag = 0;
|
||||
int unit_size = FDBD_FORMAT_UNIT_SIZE * dev->dev_attrib.block_size;
|
||||
int rc, ret = 0, size, len;
|
||||
bool inc_reftag = false;
|
||||
|
||||
if (!dev->dev_attrib.pi_prot_type) {
|
||||
pr_err("Unable to format_prot while pi_prot_type == 0\n");
|
||||
@ -894,37 +873,20 @@ static int fd_format_prot(struct se_device *dev)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
switch (dev->dev_attrib.pi_prot_type) {
|
||||
case TARGET_DIF_TYPE3_PROT:
|
||||
ref_tag = 0xffffffff;
|
||||
break;
|
||||
case TARGET_DIF_TYPE2_PROT:
|
||||
case TARGET_DIF_TYPE1_PROT:
|
||||
inc_reftag = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
buf = vzalloc(unit_size);
|
||||
if (!buf) {
|
||||
pr_err("Unable to allocate FILEIO prot buf\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
prot_length = (dev->transport->get_blocks(dev) + 1) * dev->prot_length;
|
||||
size = prot_length;
|
||||
|
||||
pr_debug("Using FILEIO prot_length: %llu\n",
|
||||
(unsigned long long)prot_length);
|
||||
|
||||
memset(buf, 0xff, unit_size);
|
||||
for (prot = 0; prot < prot_length; prot += unit_size) {
|
||||
|
||||
fd_init_format_buf(dev, buf, unit_size, &ref_tag, 0xffff,
|
||||
inc_reftag);
|
||||
|
||||
len = min(unit_size, size);
|
||||
|
||||
rc = kernel_write(prot_fd, buf, len, pos);
|
||||
if (rc != len) {
|
||||
pr_err("vfs_write to prot file failed: %d\n", rc);
|
||||
|
@ -203,10 +203,9 @@ static void iblock_free_device(struct se_device *dev)
|
||||
|
||||
if (ib_dev->ibd_bd != NULL)
|
||||
blkdev_put(ib_dev->ibd_bd, FMODE_WRITE|FMODE_READ|FMODE_EXCL);
|
||||
if (ib_dev->ibd_bio_set != NULL) {
|
||||
bioset_integrity_free(ib_dev->ibd_bio_set);
|
||||
if (ib_dev->ibd_bio_set != NULL)
|
||||
bioset_free(ib_dev->ibd_bio_set);
|
||||
}
|
||||
|
||||
kfree(ib_dev);
|
||||
}
|
||||
|
||||
|
@ -242,7 +242,7 @@ static void rd_release_prot_space(struct rd_dev *rd_dev)
|
||||
rd_dev->sg_prot_count = 0;
|
||||
}
|
||||
|
||||
static int rd_build_prot_space(struct rd_dev *rd_dev, int prot_length)
|
||||
static int rd_build_prot_space(struct rd_dev *rd_dev, int prot_length, int block_size)
|
||||
{
|
||||
struct rd_dev_sg_table *sg_table;
|
||||
u32 total_sg_needed, sg_tables;
|
||||
@ -252,8 +252,13 @@ static int rd_build_prot_space(struct rd_dev *rd_dev, int prot_length)
|
||||
|
||||
if (rd_dev->rd_flags & RDF_NULLIO)
|
||||
return 0;
|
||||
|
||||
total_sg_needed = rd_dev->rd_page_count / prot_length;
|
||||
/*
|
||||
* prot_length=8byte dif data
|
||||
* tot sg needed = rd_page_count * (PGSZ/block_size) *
|
||||
* (prot_length/block_size) + pad
|
||||
* PGSZ canceled each other.
|
||||
*/
|
||||
total_sg_needed = (rd_dev->rd_page_count * prot_length / block_size) + 1;
|
||||
|
||||
sg_tables = (total_sg_needed / max_sg_per_table) + 1;
|
||||
|
||||
@ -606,7 +611,8 @@ static int rd_init_prot(struct se_device *dev)
|
||||
if (!dev->dev_attrib.pi_prot_type)
|
||||
return 0;
|
||||
|
||||
return rd_build_prot_space(rd_dev, dev->prot_length);
|
||||
return rd_build_prot_space(rd_dev, dev->prot_length,
|
||||
dev->dev_attrib.block_size);
|
||||
}
|
||||
|
||||
static void rd_free_prot(struct se_device *dev)
|
||||
|
@ -89,6 +89,7 @@ static sense_reason_t
|
||||
sbc_emulate_readcapacity_16(struct se_cmd *cmd)
|
||||
{
|
||||
struct se_device *dev = cmd->se_dev;
|
||||
struct se_session *sess = cmd->se_sess;
|
||||
unsigned char *rbuf;
|
||||
unsigned char buf[32];
|
||||
unsigned long long blocks = dev->transport->get_blocks(dev);
|
||||
@ -109,8 +110,10 @@ sbc_emulate_readcapacity_16(struct se_cmd *cmd)
|
||||
/*
|
||||
* Set P_TYPE and PROT_EN bits for DIF support
|
||||
*/
|
||||
if (dev->dev_attrib.pi_prot_type)
|
||||
buf[12] = (dev->dev_attrib.pi_prot_type - 1) << 1 | 0x1;
|
||||
if (sess->sup_prot_ops & (TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS)) {
|
||||
if (dev->dev_attrib.pi_prot_type)
|
||||
buf[12] = (dev->dev_attrib.pi_prot_type - 1) << 1 | 0x1;
|
||||
}
|
||||
|
||||
if (dev->transport->get_lbppbe)
|
||||
buf[13] = dev->transport->get_lbppbe(dev) & 0x0f;
|
||||
@ -425,13 +428,14 @@ static sense_reason_t compare_and_write_callback(struct se_cmd *cmd)
|
||||
goto out;
|
||||
}
|
||||
|
||||
write_sg = kzalloc(sizeof(struct scatterlist) * cmd->t_data_nents,
|
||||
write_sg = kmalloc(sizeof(struct scatterlist) * cmd->t_data_nents,
|
||||
GFP_KERNEL);
|
||||
if (!write_sg) {
|
||||
pr_err("Unable to allocate compare_and_write sg\n");
|
||||
ret = TCM_OUT_OF_RESOURCES;
|
||||
goto out;
|
||||
}
|
||||
sg_init_table(write_sg, cmd->t_data_nents);
|
||||
/*
|
||||
* Setup verify and write data payloads from total NumberLBAs.
|
||||
*/
|
||||
@ -569,30 +573,85 @@ sbc_compare_and_write(struct se_cmd *cmd)
|
||||
return TCM_NO_SENSE;
|
||||
}
|
||||
|
||||
static int
|
||||
sbc_set_prot_op_checks(u8 protect, enum target_prot_type prot_type,
|
||||
bool is_write, struct se_cmd *cmd)
|
||||
{
|
||||
if (is_write) {
|
||||
cmd->prot_op = protect ? TARGET_PROT_DOUT_PASS :
|
||||
TARGET_PROT_DOUT_INSERT;
|
||||
switch (protect) {
|
||||
case 0x0:
|
||||
case 0x3:
|
||||
cmd->prot_checks = 0;
|
||||
break;
|
||||
case 0x1:
|
||||
case 0x5:
|
||||
cmd->prot_checks = TARGET_DIF_CHECK_GUARD;
|
||||
if (prot_type == TARGET_DIF_TYPE1_PROT)
|
||||
cmd->prot_checks |= TARGET_DIF_CHECK_REFTAG;
|
||||
break;
|
||||
case 0x2:
|
||||
if (prot_type == TARGET_DIF_TYPE1_PROT)
|
||||
cmd->prot_checks = TARGET_DIF_CHECK_REFTAG;
|
||||
break;
|
||||
case 0x4:
|
||||
cmd->prot_checks = TARGET_DIF_CHECK_GUARD;
|
||||
break;
|
||||
default:
|
||||
pr_err("Unsupported protect field %d\n", protect);
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
cmd->prot_op = protect ? TARGET_PROT_DIN_PASS :
|
||||
TARGET_PROT_DIN_STRIP;
|
||||
switch (protect) {
|
||||
case 0x0:
|
||||
case 0x1:
|
||||
case 0x5:
|
||||
cmd->prot_checks = TARGET_DIF_CHECK_GUARD;
|
||||
if (prot_type == TARGET_DIF_TYPE1_PROT)
|
||||
cmd->prot_checks |= TARGET_DIF_CHECK_REFTAG;
|
||||
break;
|
||||
case 0x2:
|
||||
if (prot_type == TARGET_DIF_TYPE1_PROT)
|
||||
cmd->prot_checks = TARGET_DIF_CHECK_REFTAG;
|
||||
break;
|
||||
case 0x3:
|
||||
cmd->prot_checks = 0;
|
||||
break;
|
||||
case 0x4:
|
||||
cmd->prot_checks = TARGET_DIF_CHECK_GUARD;
|
||||
break;
|
||||
default:
|
||||
pr_err("Unsupported protect field %d\n", protect);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
sbc_check_prot(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb,
|
||||
u32 sectors)
|
||||
u32 sectors, bool is_write)
|
||||
{
|
||||
if (!cmd->t_prot_sg || !cmd->t_prot_nents)
|
||||
u8 protect = cdb[1] >> 5;
|
||||
|
||||
if ((!cmd->t_prot_sg || !cmd->t_prot_nents) && cmd->prot_pto)
|
||||
return true;
|
||||
|
||||
switch (dev->dev_attrib.pi_prot_type) {
|
||||
case TARGET_DIF_TYPE3_PROT:
|
||||
if (!(cdb[1] & 0xe0))
|
||||
return true;
|
||||
|
||||
cmd->reftag_seed = 0xffffffff;
|
||||
break;
|
||||
case TARGET_DIF_TYPE2_PROT:
|
||||
if (cdb[1] & 0xe0)
|
||||
if (protect)
|
||||
return false;
|
||||
|
||||
cmd->reftag_seed = cmd->t_task_lba;
|
||||
break;
|
||||
case TARGET_DIF_TYPE1_PROT:
|
||||
if (!(cdb[1] & 0xe0))
|
||||
return true;
|
||||
|
||||
cmd->reftag_seed = cmd->t_task_lba;
|
||||
break;
|
||||
case TARGET_DIF_TYPE0_PROT:
|
||||
@ -600,9 +659,15 @@ sbc_check_prot(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb,
|
||||
return true;
|
||||
}
|
||||
|
||||
if (sbc_set_prot_op_checks(protect, dev->dev_attrib.pi_prot_type,
|
||||
is_write, cmd))
|
||||
return false;
|
||||
|
||||
cmd->prot_type = dev->dev_attrib.pi_prot_type;
|
||||
cmd->prot_length = dev->prot_length * sectors;
|
||||
cmd->prot_handover = PROT_SEPERATED;
|
||||
pr_debug("%s: prot_type=%d, prot_length=%d prot_op=%d prot_checks=%d\n",
|
||||
__func__, cmd->prot_type, cmd->prot_length,
|
||||
cmd->prot_op, cmd->prot_checks);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -628,7 +693,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
|
||||
sectors = transport_get_sectors_10(cdb);
|
||||
cmd->t_task_lba = transport_lba_32(cdb);
|
||||
|
||||
if (!sbc_check_prot(dev, cmd, cdb, sectors))
|
||||
if (!sbc_check_prot(dev, cmd, cdb, sectors, false))
|
||||
return TCM_UNSUPPORTED_SCSI_OPCODE;
|
||||
|
||||
cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
|
||||
@ -639,7 +704,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
|
||||
sectors = transport_get_sectors_12(cdb);
|
||||
cmd->t_task_lba = transport_lba_32(cdb);
|
||||
|
||||
if (!sbc_check_prot(dev, cmd, cdb, sectors))
|
||||
if (!sbc_check_prot(dev, cmd, cdb, sectors, false))
|
||||
return TCM_UNSUPPORTED_SCSI_OPCODE;
|
||||
|
||||
cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
|
||||
@ -650,7 +715,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
|
||||
sectors = transport_get_sectors_16(cdb);
|
||||
cmd->t_task_lba = transport_lba_64(cdb);
|
||||
|
||||
if (!sbc_check_prot(dev, cmd, cdb, sectors))
|
||||
if (!sbc_check_prot(dev, cmd, cdb, sectors, false))
|
||||
return TCM_UNSUPPORTED_SCSI_OPCODE;
|
||||
|
||||
cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
|
||||
@ -669,7 +734,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
|
||||
sectors = transport_get_sectors_10(cdb);
|
||||
cmd->t_task_lba = transport_lba_32(cdb);
|
||||
|
||||
if (!sbc_check_prot(dev, cmd, cdb, sectors))
|
||||
if (!sbc_check_prot(dev, cmd, cdb, sectors, true))
|
||||
return TCM_UNSUPPORTED_SCSI_OPCODE;
|
||||
|
||||
if (cdb[1] & 0x8)
|
||||
@ -682,7 +747,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
|
||||
sectors = transport_get_sectors_12(cdb);
|
||||
cmd->t_task_lba = transport_lba_32(cdb);
|
||||
|
||||
if (!sbc_check_prot(dev, cmd, cdb, sectors))
|
||||
if (!sbc_check_prot(dev, cmd, cdb, sectors, true))
|
||||
return TCM_UNSUPPORTED_SCSI_OPCODE;
|
||||
|
||||
if (cdb[1] & 0x8)
|
||||
@ -695,7 +760,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
|
||||
sectors = transport_get_sectors_16(cdb);
|
||||
cmd->t_task_lba = transport_lba_64(cdb);
|
||||
|
||||
if (!sbc_check_prot(dev, cmd, cdb, sectors))
|
||||
if (!sbc_check_prot(dev, cmd, cdb, sectors, true))
|
||||
return TCM_UNSUPPORTED_SCSI_OPCODE;
|
||||
|
||||
if (cdb[1] & 0x8)
|
||||
@ -1031,6 +1096,50 @@ err:
|
||||
}
|
||||
EXPORT_SYMBOL(sbc_execute_unmap);
|
||||
|
||||
void
|
||||
sbc_dif_generate(struct se_cmd *cmd)
|
||||
{
|
||||
struct se_device *dev = cmd->se_dev;
|
||||
struct se_dif_v1_tuple *sdt;
|
||||
struct scatterlist *dsg, *psg = cmd->t_prot_sg;
|
||||
sector_t sector = cmd->t_task_lba;
|
||||
void *daddr, *paddr;
|
||||
int i, j, offset = 0;
|
||||
|
||||
for_each_sg(cmd->t_data_sg, dsg, cmd->t_data_nents, i) {
|
||||
daddr = kmap_atomic(sg_page(dsg)) + dsg->offset;
|
||||
paddr = kmap_atomic(sg_page(psg)) + psg->offset;
|
||||
|
||||
for (j = 0; j < dsg->length; j += dev->dev_attrib.block_size) {
|
||||
|
||||
if (offset >= psg->length) {
|
||||
kunmap_atomic(paddr);
|
||||
psg = sg_next(psg);
|
||||
paddr = kmap_atomic(sg_page(psg)) + psg->offset;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
sdt = paddr + offset;
|
||||
sdt->guard_tag = cpu_to_be16(crc_t10dif(daddr + j,
|
||||
dev->dev_attrib.block_size));
|
||||
if (dev->dev_attrib.pi_prot_type == TARGET_DIF_TYPE1_PROT)
|
||||
sdt->ref_tag = cpu_to_be32(sector & 0xffffffff);
|
||||
sdt->app_tag = 0;
|
||||
|
||||
pr_debug("DIF WRITE INSERT sector: %llu guard_tag: 0x%04x"
|
||||
" app_tag: 0x%04x ref_tag: %u\n",
|
||||
(unsigned long long)sector, sdt->guard_tag,
|
||||
sdt->app_tag, be32_to_cpu(sdt->ref_tag));
|
||||
|
||||
sector++;
|
||||
offset += sizeof(struct se_dif_v1_tuple);
|
||||
}
|
||||
|
||||
kunmap_atomic(paddr);
|
||||
kunmap_atomic(daddr);
|
||||
}
|
||||
}
|
||||
|
||||
static sense_reason_t
|
||||
sbc_dif_v1_verify(struct se_device *dev, struct se_dif_v1_tuple *sdt,
|
||||
const void *p, sector_t sector, unsigned int ei_lba)
|
||||
@ -1162,9 +1271,9 @@ sbc_dif_verify_write(struct se_cmd *cmd, sector_t start, unsigned int sectors,
|
||||
}
|
||||
EXPORT_SYMBOL(sbc_dif_verify_write);
|
||||
|
||||
sense_reason_t
|
||||
sbc_dif_verify_read(struct se_cmd *cmd, sector_t start, unsigned int sectors,
|
||||
unsigned int ei_lba, struct scatterlist *sg, int sg_off)
|
||||
static sense_reason_t
|
||||
__sbc_dif_verify_read(struct se_cmd *cmd, sector_t start, unsigned int sectors,
|
||||
unsigned int ei_lba, struct scatterlist *sg, int sg_off)
|
||||
{
|
||||
struct se_device *dev = cmd->se_dev;
|
||||
struct se_dif_v1_tuple *sdt;
|
||||
@ -1217,8 +1326,31 @@ sbc_dif_verify_read(struct se_cmd *cmd, sector_t start, unsigned int sectors,
|
||||
kunmap_atomic(paddr);
|
||||
kunmap_atomic(daddr);
|
||||
}
|
||||
sbc_dif_copy_prot(cmd, sectors, true, sg, sg_off);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
sense_reason_t
|
||||
sbc_dif_read_strip(struct se_cmd *cmd)
|
||||
{
|
||||
struct se_device *dev = cmd->se_dev;
|
||||
u32 sectors = cmd->prot_length / dev->prot_length;
|
||||
|
||||
return __sbc_dif_verify_read(cmd, cmd->t_task_lba, sectors, 0,
|
||||
cmd->t_prot_sg, 0);
|
||||
}
|
||||
|
||||
sense_reason_t
|
||||
sbc_dif_verify_read(struct se_cmd *cmd, sector_t start, unsigned int sectors,
|
||||
unsigned int ei_lba, struct scatterlist *sg, int sg_off)
|
||||
{
|
||||
sense_reason_t rc;
|
||||
|
||||
rc = __sbc_dif_verify_read(cmd, start, sectors, ei_lba, sg, sg_off);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
sbc_dif_copy_prot(cmd, sectors, true, sg, sg_off);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(sbc_dif_verify_read);
|
||||
|
@ -71,6 +71,7 @@ spc_emulate_inquiry_std(struct se_cmd *cmd, unsigned char *buf)
|
||||
{
|
||||
struct se_lun *lun = cmd->se_lun;
|
||||
struct se_device *dev = cmd->se_dev;
|
||||
struct se_session *sess = cmd->se_sess;
|
||||
|
||||
/* Set RMB (removable media) for tape devices */
|
||||
if (dev->transport->get_device_type(dev) == TYPE_TAPE)
|
||||
@ -101,10 +102,13 @@ spc_emulate_inquiry_std(struct se_cmd *cmd, unsigned char *buf)
|
||||
if (dev->dev_attrib.emulate_3pc)
|
||||
buf[5] |= 0x8;
|
||||
/*
|
||||
* Set Protection (PROTECT) bit when DIF has been enabled.
|
||||
* Set Protection (PROTECT) bit when DIF has been enabled on the
|
||||
* device, and the transport supports VERIFY + PASS.
|
||||
*/
|
||||
if (dev->dev_attrib.pi_prot_type)
|
||||
buf[5] |= 0x1;
|
||||
if (sess->sup_prot_ops & (TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS)) {
|
||||
if (dev->dev_attrib.pi_prot_type)
|
||||
buf[5] |= 0x1;
|
||||
}
|
||||
|
||||
buf[7] = 0x2; /* CmdQue=1 */
|
||||
|
||||
@ -473,16 +477,19 @@ static sense_reason_t
|
||||
spc_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf)
|
||||
{
|
||||
struct se_device *dev = cmd->se_dev;
|
||||
struct se_session *sess = cmd->se_sess;
|
||||
|
||||
buf[3] = 0x3c;
|
||||
/*
|
||||
* Set GRD_CHK + REF_CHK for TYPE1 protection, or GRD_CHK
|
||||
* only for TYPE3 protection.
|
||||
*/
|
||||
if (dev->dev_attrib.pi_prot_type == TARGET_DIF_TYPE1_PROT)
|
||||
buf[4] = 0x5;
|
||||
else if (dev->dev_attrib.pi_prot_type == TARGET_DIF_TYPE3_PROT)
|
||||
buf[4] = 0x4;
|
||||
if (sess->sup_prot_ops & (TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS)) {
|
||||
if (dev->dev_attrib.pi_prot_type == TARGET_DIF_TYPE1_PROT)
|
||||
buf[4] = 0x5;
|
||||
else if (dev->dev_attrib.pi_prot_type == TARGET_DIF_TYPE3_PROT)
|
||||
buf[4] = 0x4;
|
||||
}
|
||||
|
||||
/* Set HEADSUP, ORDSUP, SIMPSUP */
|
||||
buf[5] = 0x07;
|
||||
@ -762,7 +769,7 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int spc_modesense_rwrecovery(struct se_device *dev, u8 pc, u8 *p)
|
||||
static int spc_modesense_rwrecovery(struct se_cmd *cmd, u8 pc, u8 *p)
|
||||
{
|
||||
p[0] = 0x01;
|
||||
p[1] = 0x0a;
|
||||
@ -775,8 +782,11 @@ out:
|
||||
return 12;
|
||||
}
|
||||
|
||||
static int spc_modesense_control(struct se_device *dev, u8 pc, u8 *p)
|
||||
static int spc_modesense_control(struct se_cmd *cmd, u8 pc, u8 *p)
|
||||
{
|
||||
struct se_device *dev = cmd->se_dev;
|
||||
struct se_session *sess = cmd->se_sess;
|
||||
|
||||
p[0] = 0x0a;
|
||||
p[1] = 0x0a;
|
||||
|
||||
@ -868,8 +878,10 @@ static int spc_modesense_control(struct se_device *dev, u8 pc, u8 *p)
|
||||
* type, shall not modify the contents of the LOGICAL BLOCK REFERENCE
|
||||
* TAG field.
|
||||
*/
|
||||
if (dev->dev_attrib.pi_prot_type)
|
||||
p[5] |= 0x80;
|
||||
if (sess->sup_prot_ops & (TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS)) {
|
||||
if (dev->dev_attrib.pi_prot_type)
|
||||
p[5] |= 0x80;
|
||||
}
|
||||
|
||||
p[8] = 0xff;
|
||||
p[9] = 0xff;
|
||||
@ -879,8 +891,10 @@ out:
|
||||
return 12;
|
||||
}
|
||||
|
||||
static int spc_modesense_caching(struct se_device *dev, u8 pc, u8 *p)
|
||||
static int spc_modesense_caching(struct se_cmd *cmd, u8 pc, u8 *p)
|
||||
{
|
||||
struct se_device *dev = cmd->se_dev;
|
||||
|
||||
p[0] = 0x08;
|
||||
p[1] = 0x12;
|
||||
|
||||
@ -896,7 +910,7 @@ out:
|
||||
return 20;
|
||||
}
|
||||
|
||||
static int spc_modesense_informational_exceptions(struct se_device *dev, u8 pc, unsigned char *p)
|
||||
static int spc_modesense_informational_exceptions(struct se_cmd *cmd, u8 pc, unsigned char *p)
|
||||
{
|
||||
p[0] = 0x1c;
|
||||
p[1] = 0x0a;
|
||||
@ -912,7 +926,7 @@ out:
|
||||
static struct {
|
||||
uint8_t page;
|
||||
uint8_t subpage;
|
||||
int (*emulate)(struct se_device *, u8, unsigned char *);
|
||||
int (*emulate)(struct se_cmd *, u8, unsigned char *);
|
||||
} modesense_handlers[] = {
|
||||
{ .page = 0x01, .subpage = 0x00, .emulate = spc_modesense_rwrecovery },
|
||||
{ .page = 0x08, .subpage = 0x00, .emulate = spc_modesense_caching },
|
||||
@ -1050,7 +1064,7 @@ static sense_reason_t spc_emulate_modesense(struct se_cmd *cmd)
|
||||
* the only two possibilities).
|
||||
*/
|
||||
if ((modesense_handlers[i].subpage & ~subpage) == 0) {
|
||||
ret = modesense_handlers[i].emulate(dev, pc, &buf[length]);
|
||||
ret = modesense_handlers[i].emulate(cmd, pc, &buf[length]);
|
||||
if (!ten && length + ret >= 255)
|
||||
break;
|
||||
length += ret;
|
||||
@ -1063,7 +1077,7 @@ static sense_reason_t spc_emulate_modesense(struct se_cmd *cmd)
|
||||
for (i = 0; i < ARRAY_SIZE(modesense_handlers); ++i)
|
||||
if (modesense_handlers[i].page == page &&
|
||||
modesense_handlers[i].subpage == subpage) {
|
||||
length += modesense_handlers[i].emulate(dev, pc, &buf[length]);
|
||||
length += modesense_handlers[i].emulate(cmd, pc, &buf[length]);
|
||||
goto set_length;
|
||||
}
|
||||
|
||||
@ -1095,7 +1109,6 @@ set_length:
|
||||
|
||||
static sense_reason_t spc_emulate_modeselect(struct se_cmd *cmd)
|
||||
{
|
||||
struct se_device *dev = cmd->se_dev;
|
||||
char *cdb = cmd->t_task_cdb;
|
||||
bool ten = cdb[0] == MODE_SELECT_10;
|
||||
int off = ten ? 8 : 4;
|
||||
@ -1131,7 +1144,7 @@ static sense_reason_t spc_emulate_modeselect(struct se_cmd *cmd)
|
||||
if (modesense_handlers[i].page == page &&
|
||||
modesense_handlers[i].subpage == subpage) {
|
||||
memset(tbuf, 0, SE_MODE_PAGE_BUF);
|
||||
length = modesense_handlers[i].emulate(dev, 0, tbuf);
|
||||
length = modesense_handlers[i].emulate(cmd, 0, tbuf);
|
||||
goto check_contents;
|
||||
}
|
||||
|
||||
|
@ -87,14 +87,17 @@ static void core_tmr_handle_tas_abort(
|
||||
struct se_cmd *cmd,
|
||||
int tas)
|
||||
{
|
||||
bool remove = true;
|
||||
/*
|
||||
* TASK ABORTED status (TAS) bit support
|
||||
*/
|
||||
if ((tmr_nacl &&
|
||||
(tmr_nacl == cmd->se_sess->se_node_acl)) || tas)
|
||||
(tmr_nacl != cmd->se_sess->se_node_acl)) && tas) {
|
||||
remove = false;
|
||||
transport_send_task_abort(cmd);
|
||||
}
|
||||
|
||||
transport_cmd_finish_abort(cmd, 0);
|
||||
transport_cmd_finish_abort(cmd, remove);
|
||||
}
|
||||
|
||||
static int target_check_cdb_and_preempt(struct list_head *list,
|
||||
@ -127,6 +130,11 @@ void core_tmr_abort_task(
|
||||
|
||||
if (dev != se_cmd->se_dev)
|
||||
continue;
|
||||
|
||||
/* skip se_cmd associated with tmr */
|
||||
if (tmr->task_cmd == se_cmd)
|
||||
continue;
|
||||
|
||||
ref_tag = se_cmd->se_tfo->get_task_tag(se_cmd);
|
||||
if (tmr->ref_task_tag != ref_tag)
|
||||
continue;
|
||||
@ -150,18 +158,9 @@ void core_tmr_abort_task(
|
||||
|
||||
cancel_work_sync(&se_cmd->work);
|
||||
transport_wait_for_tasks(se_cmd);
|
||||
/*
|
||||
* Now send SAM_STAT_TASK_ABORTED status for the referenced
|
||||
* se_cmd descriptor..
|
||||
*/
|
||||
transport_send_task_abort(se_cmd);
|
||||
/*
|
||||
* Also deal with possible extra acknowledge reference..
|
||||
*/
|
||||
if (se_cmd->se_cmd_flags & SCF_ACK_KREF)
|
||||
target_put_sess_cmd(se_sess, se_cmd);
|
||||
|
||||
target_put_sess_cmd(se_sess, se_cmd);
|
||||
transport_cmd_finish_abort(se_cmd, true);
|
||||
|
||||
printk("ABORT_TASK: Sending TMR_FUNCTION_COMPLETE for"
|
||||
" ref_tag: %d\n", ref_tag);
|
||||
|
@ -235,7 +235,7 @@ void transport_subsystem_check_init(void)
|
||||
sub_api_initialized = 1;
|
||||
}
|
||||
|
||||
struct se_session *transport_init_session(void)
|
||||
struct se_session *transport_init_session(enum target_prot_op sup_prot_ops)
|
||||
{
|
||||
struct se_session *se_sess;
|
||||
|
||||
@ -251,6 +251,7 @@ struct se_session *transport_init_session(void)
|
||||
INIT_LIST_HEAD(&se_sess->sess_wait_list);
|
||||
spin_lock_init(&se_sess->sess_cmd_lock);
|
||||
kref_init(&se_sess->sess_kref);
|
||||
se_sess->sup_prot_ops = sup_prot_ops;
|
||||
|
||||
return se_sess;
|
||||
}
|
||||
@ -288,12 +289,13 @@ int transport_alloc_session_tags(struct se_session *se_sess,
|
||||
EXPORT_SYMBOL(transport_alloc_session_tags);
|
||||
|
||||
struct se_session *transport_init_session_tags(unsigned int tag_num,
|
||||
unsigned int tag_size)
|
||||
unsigned int tag_size,
|
||||
enum target_prot_op sup_prot_ops)
|
||||
{
|
||||
struct se_session *se_sess;
|
||||
int rc;
|
||||
|
||||
se_sess = transport_init_session();
|
||||
se_sess = transport_init_session(sup_prot_ops);
|
||||
if (IS_ERR(se_sess))
|
||||
return se_sess;
|
||||
|
||||
@ -603,6 +605,15 @@ static void transport_lun_remove_cmd(struct se_cmd *cmd)
|
||||
|
||||
void transport_cmd_finish_abort(struct se_cmd *cmd, int remove)
|
||||
{
|
||||
if (cmd->se_cmd_flags & SCF_SE_LUN_CMD)
|
||||
transport_lun_remove_cmd(cmd);
|
||||
/*
|
||||
* Allow the fabric driver to unmap any resources before
|
||||
* releasing the descriptor via TFO->release_cmd()
|
||||
*/
|
||||
if (remove)
|
||||
cmd->se_tfo->aborted_task(cmd);
|
||||
|
||||
if (transport_cmd_check_stop_to_fabric(cmd))
|
||||
return;
|
||||
if (remove)
|
||||
@ -1365,6 +1376,13 @@ int target_submit_cmd_map_sgls(struct se_cmd *se_cmd, struct se_session *se_sess
|
||||
target_put_sess_cmd(se_sess, se_cmd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rc = target_setup_cmd_from_cdb(se_cmd, cdb);
|
||||
if (rc != 0) {
|
||||
transport_generic_request_failure(se_cmd, rc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Save pointers for SGLs containing protection information,
|
||||
* if present.
|
||||
@ -1374,11 +1392,6 @@ int target_submit_cmd_map_sgls(struct se_cmd *se_cmd, struct se_session *se_sess
|
||||
se_cmd->t_prot_nents = sgl_prot_count;
|
||||
}
|
||||
|
||||
rc = target_setup_cmd_from_cdb(se_cmd, cdb);
|
||||
if (rc != 0) {
|
||||
transport_generic_request_failure(se_cmd, rc);
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* When a non zero sgl_count has been passed perform SGL passthrough
|
||||
* mapping for pre-allocated fabric memory instead of having target
|
||||
@ -1754,6 +1767,15 @@ void target_execute_cmd(struct se_cmd *cmd)
|
||||
cmd->t_state = TRANSPORT_PROCESSING;
|
||||
cmd->transport_state |= CMD_T_ACTIVE|CMD_T_BUSY|CMD_T_SENT;
|
||||
spin_unlock_irq(&cmd->t_state_lock);
|
||||
/*
|
||||
* Perform WRITE_INSERT of PI using software emulation when backend
|
||||
* device has PI enabled, if the transport has not already generated
|
||||
* PI using hardware WRITE_INSERT offload.
|
||||
*/
|
||||
if (cmd->prot_op == TARGET_PROT_DOUT_INSERT) {
|
||||
if (!(cmd->se_sess->sup_prot_ops & TARGET_PROT_DOUT_INSERT))
|
||||
sbc_dif_generate(cmd);
|
||||
}
|
||||
|
||||
if (target_handle_task_attr(cmd)) {
|
||||
spin_lock_irq(&cmd->t_state_lock);
|
||||
@ -1883,6 +1905,21 @@ static void transport_handle_queue_full(
|
||||
schedule_work(&cmd->se_dev->qf_work_queue);
|
||||
}
|
||||
|
||||
static bool target_check_read_strip(struct se_cmd *cmd)
|
||||
{
|
||||
sense_reason_t rc;
|
||||
|
||||
if (!(cmd->se_sess->sup_prot_ops & TARGET_PROT_DIN_STRIP)) {
|
||||
rc = sbc_dif_read_strip(cmd);
|
||||
if (rc) {
|
||||
cmd->pi_err = rc;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void target_complete_ok_work(struct work_struct *work)
|
||||
{
|
||||
struct se_cmd *cmd = container_of(work, struct se_cmd, work);
|
||||
@ -1947,6 +1984,22 @@ static void target_complete_ok_work(struct work_struct *work)
|
||||
cmd->data_length;
|
||||
}
|
||||
spin_unlock(&cmd->se_lun->lun_sep_lock);
|
||||
/*
|
||||
* Perform READ_STRIP of PI using software emulation when
|
||||
* backend had PI enabled, if the transport will not be
|
||||
* performing hardware READ_STRIP offload.
|
||||
*/
|
||||
if (cmd->prot_op == TARGET_PROT_DIN_STRIP &&
|
||||
target_check_read_strip(cmd)) {
|
||||
ret = transport_send_check_condition_and_sense(cmd,
|
||||
cmd->pi_err, 0);
|
||||
if (ret == -EAGAIN || ret == -ENOMEM)
|
||||
goto queue_full;
|
||||
|
||||
transport_lun_remove_cmd(cmd);
|
||||
transport_cmd_check_stop_to_fabric(cmd);
|
||||
return;
|
||||
}
|
||||
|
||||
trace_target_cmd_complete(cmd);
|
||||
ret = cmd->se_tfo->queue_data_in(cmd);
|
||||
@ -2039,6 +2092,10 @@ static inline void transport_free_pages(struct se_cmd *cmd)
|
||||
transport_free_sgl(cmd->t_bidi_data_sg, cmd->t_bidi_data_nents);
|
||||
cmd->t_bidi_data_sg = NULL;
|
||||
cmd->t_bidi_data_nents = 0;
|
||||
|
||||
transport_free_sgl(cmd->t_prot_sg, cmd->t_prot_nents);
|
||||
cmd->t_prot_sg = NULL;
|
||||
cmd->t_prot_nents = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2202,6 +2259,14 @@ transport_generic_new_cmd(struct se_cmd *cmd)
|
||||
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
|
||||
}
|
||||
|
||||
if (cmd->prot_op != TARGET_PROT_NORMAL) {
|
||||
ret = target_alloc_sgl(&cmd->t_prot_sg,
|
||||
&cmd->t_prot_nents,
|
||||
cmd->prot_length, true);
|
||||
if (ret < 0)
|
||||
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
|
||||
}
|
||||
|
||||
ret = target_alloc_sgl(&cmd->t_data_sg, &cmd->t_data_nents,
|
||||
cmd->data_length, zero_flag);
|
||||
if (ret < 0)
|
||||
@ -2770,13 +2835,17 @@ int transport_check_aborted_status(struct se_cmd *cmd, int send_status)
|
||||
if (!(cmd->transport_state & CMD_T_ABORTED))
|
||||
return 0;
|
||||
|
||||
if (!send_status || (cmd->se_cmd_flags & SCF_SENT_DELAYED_TAS))
|
||||
/*
|
||||
* If cmd has been aborted but either no status is to be sent or it has
|
||||
* already been sent, just return
|
||||
*/
|
||||
if (!send_status || !(cmd->se_cmd_flags & SCF_SEND_DELAYED_TAS))
|
||||
return 1;
|
||||
|
||||
pr_debug("Sending delayed SAM_STAT_TASK_ABORTED status for CDB: 0x%02x ITT: 0x%08x\n",
|
||||
cmd->t_task_cdb[0], cmd->se_tfo->get_task_tag(cmd));
|
||||
|
||||
cmd->se_cmd_flags |= SCF_SENT_DELAYED_TAS;
|
||||
cmd->se_cmd_flags &= ~SCF_SEND_DELAYED_TAS;
|
||||
cmd->scsi_status = SAM_STAT_TASK_ABORTED;
|
||||
trace_target_cmd_complete(cmd);
|
||||
cmd->se_tfo->queue_status(cmd);
|
||||
@ -2790,7 +2859,7 @@ 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 | SCF_SENT_DELAYED_TAS)) {
|
||||
if (cmd->se_cmd_flags & (SCF_SENT_CHECK_CONDITION)) {
|
||||
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
|
||||
return;
|
||||
}
|
||||
@ -2805,6 +2874,7 @@ void transport_send_task_abort(struct se_cmd *cmd)
|
||||
if (cmd->data_direction == DMA_TO_DEVICE) {
|
||||
if (cmd->se_tfo->write_pending_status(cmd) != 0) {
|
||||
cmd->transport_state |= CMD_T_ABORTED;
|
||||
cmd->se_cmd_flags |= SCF_SEND_DELAYED_TAS;
|
||||
smp_mb__after_atomic_inc();
|
||||
return;
|
||||
}
|
||||
|
@ -94,20 +94,19 @@ struct ft_lun {
|
||||
*/
|
||||
struct ft_tpg {
|
||||
u32 index;
|
||||
struct ft_lport_acl *lport_acl;
|
||||
struct ft_lport_wwn *lport_wwn;
|
||||
struct ft_tport *tport; /* active tport or NULL */
|
||||
struct list_head list; /* linkage in ft_lport_acl tpg_list */
|
||||
struct list_head lun_list; /* head of LUNs */
|
||||
struct se_portal_group se_tpg;
|
||||
struct workqueue_struct *workqueue;
|
||||
};
|
||||
|
||||
struct ft_lport_acl {
|
||||
struct ft_lport_wwn {
|
||||
u64 wwpn;
|
||||
char name[FT_NAMELEN];
|
||||
struct list_head list;
|
||||
struct list_head tpg_list;
|
||||
struct se_wwn fc_lport_wwn;
|
||||
struct list_head ft_wwn_node;
|
||||
struct ft_tpg *tpg;
|
||||
struct se_wwn se_wwn;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -128,7 +127,6 @@ struct ft_cmd {
|
||||
u32 sg_cnt; /* No. of item in scatterlist */
|
||||
};
|
||||
|
||||
extern struct list_head ft_lport_list;
|
||||
extern struct mutex ft_lport_lock;
|
||||
extern struct fc4_prov ft_prov;
|
||||
extern struct target_fabric_configfs *ft_configfs;
|
||||
@ -163,6 +161,7 @@ int ft_write_pending_status(struct se_cmd *);
|
||||
u32 ft_get_task_tag(struct se_cmd *);
|
||||
int ft_get_cmd_state(struct se_cmd *);
|
||||
void ft_queue_tm_resp(struct se_cmd *);
|
||||
void ft_aborted_task(struct se_cmd *);
|
||||
|
||||
/*
|
||||
* other internal functions.
|
||||
|
@ -426,6 +426,11 @@ void ft_queue_tm_resp(struct se_cmd *se_cmd)
|
||||
ft_send_resp_code(cmd, code);
|
||||
}
|
||||
|
||||
void ft_aborted_task(struct se_cmd *se_cmd)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static void ft_send_work(struct work_struct *work);
|
||||
|
||||
/*
|
||||
|
@ -50,7 +50,7 @@
|
||||
|
||||
struct target_fabric_configfs *ft_configfs;
|
||||
|
||||
LIST_HEAD(ft_lport_list);
|
||||
static LIST_HEAD(ft_wwn_list);
|
||||
DEFINE_MUTEX(ft_lport_lock);
|
||||
|
||||
unsigned int ft_debug_logging;
|
||||
@ -298,7 +298,7 @@ static struct se_portal_group *ft_add_tpg(
|
||||
struct config_group *group,
|
||||
const char *name)
|
||||
{
|
||||
struct ft_lport_acl *lacl;
|
||||
struct ft_lport_wwn *ft_wwn;
|
||||
struct ft_tpg *tpg;
|
||||
struct workqueue_struct *wq;
|
||||
unsigned long index;
|
||||
@ -318,12 +318,17 @@ static struct se_portal_group *ft_add_tpg(
|
||||
if (index > UINT_MAX)
|
||||
return NULL;
|
||||
|
||||
lacl = container_of(wwn, struct ft_lport_acl, fc_lport_wwn);
|
||||
if ((index != 1)) {
|
||||
pr_err("Error, a single TPG=1 is used for HW port mappings\n");
|
||||
return ERR_PTR(-ENOSYS);
|
||||
}
|
||||
|
||||
ft_wwn = container_of(wwn, struct ft_lport_wwn, se_wwn);
|
||||
tpg = kzalloc(sizeof(*tpg), GFP_KERNEL);
|
||||
if (!tpg)
|
||||
return NULL;
|
||||
tpg->index = index;
|
||||
tpg->lport_acl = lacl;
|
||||
tpg->lport_wwn = ft_wwn;
|
||||
INIT_LIST_HEAD(&tpg->lun_list);
|
||||
|
||||
wq = alloc_workqueue("tcm_fc", 0, 1);
|
||||
@ -342,7 +347,7 @@ static struct se_portal_group *ft_add_tpg(
|
||||
tpg->workqueue = wq;
|
||||
|
||||
mutex_lock(&ft_lport_lock);
|
||||
list_add_tail(&tpg->list, &lacl->tpg_list);
|
||||
ft_wwn->tpg = tpg;
|
||||
mutex_unlock(&ft_lport_lock);
|
||||
|
||||
return &tpg->se_tpg;
|
||||
@ -351,6 +356,7 @@ static struct se_portal_group *ft_add_tpg(
|
||||
static void ft_del_tpg(struct se_portal_group *se_tpg)
|
||||
{
|
||||
struct ft_tpg *tpg = container_of(se_tpg, struct ft_tpg, se_tpg);
|
||||
struct ft_lport_wwn *ft_wwn = tpg->lport_wwn;
|
||||
|
||||
pr_debug("del tpg %s\n",
|
||||
config_item_name(&tpg->se_tpg.tpg_group.cg_item));
|
||||
@ -361,7 +367,7 @@ static void ft_del_tpg(struct se_portal_group *se_tpg)
|
||||
synchronize_rcu();
|
||||
|
||||
mutex_lock(&ft_lport_lock);
|
||||
list_del(&tpg->list);
|
||||
ft_wwn->tpg = NULL;
|
||||
if (tpg->tport) {
|
||||
tpg->tport->tpg = NULL;
|
||||
tpg->tport = NULL;
|
||||
@ -380,15 +386,11 @@ static void ft_del_tpg(struct se_portal_group *se_tpg)
|
||||
*/
|
||||
struct ft_tpg *ft_lport_find_tpg(struct fc_lport *lport)
|
||||
{
|
||||
struct ft_lport_acl *lacl;
|
||||
struct ft_tpg *tpg;
|
||||
struct ft_lport_wwn *ft_wwn;
|
||||
|
||||
list_for_each_entry(lacl, &ft_lport_list, list) {
|
||||
if (lacl->wwpn == lport->wwpn) {
|
||||
list_for_each_entry(tpg, &lacl->tpg_list, list)
|
||||
return tpg; /* XXX for now return first entry */
|
||||
return NULL;
|
||||
}
|
||||
list_for_each_entry(ft_wwn, &ft_wwn_list, ft_wwn_node) {
|
||||
if (ft_wwn->wwpn == lport->wwpn)
|
||||
return ft_wwn->tpg;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@ -401,50 +403,49 @@ struct ft_tpg *ft_lport_find_tpg(struct fc_lport *lport)
|
||||
* Add lport to allowed config.
|
||||
* The name is the WWPN in lower-case ASCII, colon-separated bytes.
|
||||
*/
|
||||
static struct se_wwn *ft_add_lport(
|
||||
static struct se_wwn *ft_add_wwn(
|
||||
struct target_fabric_configfs *tf,
|
||||
struct config_group *group,
|
||||
const char *name)
|
||||
{
|
||||
struct ft_lport_acl *lacl;
|
||||
struct ft_lport_acl *old_lacl;
|
||||
struct ft_lport_wwn *ft_wwn;
|
||||
struct ft_lport_wwn *old_ft_wwn;
|
||||
u64 wwpn;
|
||||
|
||||
pr_debug("add lport %s\n", name);
|
||||
pr_debug("add wwn %s\n", name);
|
||||
if (ft_parse_wwn(name, &wwpn, 1) < 0)
|
||||
return NULL;
|
||||
lacl = kzalloc(sizeof(*lacl), GFP_KERNEL);
|
||||
if (!lacl)
|
||||
ft_wwn = kzalloc(sizeof(*ft_wwn), GFP_KERNEL);
|
||||
if (!ft_wwn)
|
||||
return NULL;
|
||||
lacl->wwpn = wwpn;
|
||||
INIT_LIST_HEAD(&lacl->tpg_list);
|
||||
ft_wwn->wwpn = wwpn;
|
||||
|
||||
mutex_lock(&ft_lport_lock);
|
||||
list_for_each_entry(old_lacl, &ft_lport_list, list) {
|
||||
if (old_lacl->wwpn == wwpn) {
|
||||
list_for_each_entry(old_ft_wwn, &ft_wwn_list, ft_wwn_node) {
|
||||
if (old_ft_wwn->wwpn == wwpn) {
|
||||
mutex_unlock(&ft_lport_lock);
|
||||
kfree(lacl);
|
||||
kfree(ft_wwn);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
list_add_tail(&lacl->list, &ft_lport_list);
|
||||
ft_format_wwn(lacl->name, sizeof(lacl->name), wwpn);
|
||||
list_add_tail(&ft_wwn->ft_wwn_node, &ft_wwn_list);
|
||||
ft_format_wwn(ft_wwn->name, sizeof(ft_wwn->name), wwpn);
|
||||
mutex_unlock(&ft_lport_lock);
|
||||
|
||||
return &lacl->fc_lport_wwn;
|
||||
return &ft_wwn->se_wwn;
|
||||
}
|
||||
|
||||
static void ft_del_lport(struct se_wwn *wwn)
|
||||
static void ft_del_wwn(struct se_wwn *wwn)
|
||||
{
|
||||
struct ft_lport_acl *lacl = container_of(wwn,
|
||||
struct ft_lport_acl, fc_lport_wwn);
|
||||
struct ft_lport_wwn *ft_wwn = container_of(wwn,
|
||||
struct ft_lport_wwn, se_wwn);
|
||||
|
||||
pr_debug("del lport %s\n", lacl->name);
|
||||
pr_debug("del wwn %s\n", ft_wwn->name);
|
||||
mutex_lock(&ft_lport_lock);
|
||||
list_del(&lacl->list);
|
||||
list_del(&ft_wwn->ft_wwn_node);
|
||||
mutex_unlock(&ft_lport_lock);
|
||||
|
||||
kfree(lacl);
|
||||
kfree(ft_wwn);
|
||||
}
|
||||
|
||||
static ssize_t ft_wwn_show_attr_version(
|
||||
@ -471,7 +472,7 @@ static char *ft_get_fabric_wwn(struct se_portal_group *se_tpg)
|
||||
{
|
||||
struct ft_tpg *tpg = se_tpg->se_tpg_fabric_ptr;
|
||||
|
||||
return tpg->lport_acl->name;
|
||||
return tpg->lport_wwn->name;
|
||||
}
|
||||
|
||||
static u16 ft_get_tag(struct se_portal_group *se_tpg)
|
||||
@ -536,12 +537,13 @@ static struct target_core_fabric_ops ft_fabric_ops = {
|
||||
.queue_data_in = ft_queue_data_in,
|
||||
.queue_status = ft_queue_status,
|
||||
.queue_tm_rsp = ft_queue_tm_resp,
|
||||
.aborted_task = ft_aborted_task,
|
||||
/*
|
||||
* Setup function pointers for generic logic in
|
||||
* target_core_fabric_configfs.c
|
||||
*/
|
||||
.fabric_make_wwn = &ft_add_lport,
|
||||
.fabric_drop_wwn = &ft_del_lport,
|
||||
.fabric_make_wwn = &ft_add_wwn,
|
||||
.fabric_drop_wwn = &ft_del_wwn,
|
||||
.fabric_make_tpg = &ft_add_tpg,
|
||||
.fabric_drop_tpg = &ft_del_tpg,
|
||||
.fabric_post_link = NULL,
|
||||
|
@ -51,7 +51,7 @@ static void ft_sess_delete_all(struct ft_tport *);
|
||||
* Lookup or allocate target local port.
|
||||
* Caller holds ft_lport_lock.
|
||||
*/
|
||||
static struct ft_tport *ft_tport_create(struct fc_lport *lport)
|
||||
static struct ft_tport *ft_tport_get(struct fc_lport *lport)
|
||||
{
|
||||
struct ft_tpg *tpg;
|
||||
struct ft_tport *tport;
|
||||
@ -68,6 +68,7 @@ static struct ft_tport *ft_tport_create(struct fc_lport *lport)
|
||||
|
||||
if (tport) {
|
||||
tport->tpg = tpg;
|
||||
tpg->tport = tport;
|
||||
return tport;
|
||||
}
|
||||
|
||||
@ -114,7 +115,7 @@ static void ft_tport_delete(struct ft_tport *tport)
|
||||
void ft_lport_add(struct fc_lport *lport, void *arg)
|
||||
{
|
||||
mutex_lock(&ft_lport_lock);
|
||||
ft_tport_create(lport);
|
||||
ft_tport_get(lport);
|
||||
mutex_unlock(&ft_lport_lock);
|
||||
}
|
||||
|
||||
@ -211,7 +212,8 @@ static struct ft_sess *ft_sess_create(struct ft_tport *tport, u32 port_id,
|
||||
return NULL;
|
||||
|
||||
sess->se_sess = transport_init_session_tags(TCM_FC_DEFAULT_TAGS,
|
||||
sizeof(struct ft_cmd));
|
||||
sizeof(struct ft_cmd),
|
||||
TARGET_PROT_NORMAL);
|
||||
if (IS_ERR(sess->se_sess)) {
|
||||
kfree(sess);
|
||||
return NULL;
|
||||
@ -350,7 +352,7 @@ static int ft_prli_locked(struct fc_rport_priv *rdata, u32 spp_len,
|
||||
struct ft_node_acl *acl;
|
||||
u32 fcp_parm;
|
||||
|
||||
tport = ft_tport_create(rdata->local_port);
|
||||
tport = ft_tport_get(rdata->local_port);
|
||||
if (!tport)
|
||||
goto not_target; /* not a target for this local port */
|
||||
|
||||
|
@ -1471,6 +1471,11 @@ static void usbg_queue_tm_rsp(struct se_cmd *se_cmd)
|
||||
{
|
||||
}
|
||||
|
||||
static void usbg_aborted_task(struct se_cmd *se_cmd)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static const char *usbg_check_wwn(const char *name)
|
||||
{
|
||||
const char *n;
|
||||
@ -1726,7 +1731,7 @@ static int tcm_usbg_make_nexus(struct usbg_tpg *tpg, char *name)
|
||||
pr_err("Unable to allocate struct tcm_vhost_nexus\n");
|
||||
goto err_unlock;
|
||||
}
|
||||
tv_nexus->tvn_se_sess = transport_init_session();
|
||||
tv_nexus->tvn_se_sess = transport_init_session(TARGET_PROT_NORMAL);
|
||||
if (IS_ERR(tv_nexus->tvn_se_sess))
|
||||
goto err_free;
|
||||
|
||||
@ -1897,6 +1902,7 @@ static struct target_core_fabric_ops usbg_ops = {
|
||||
.queue_data_in = usbg_send_read_response,
|
||||
.queue_status = usbg_send_status_response,
|
||||
.queue_tm_rsp = usbg_queue_tm_rsp,
|
||||
.aborted_task = usbg_aborted_task,
|
||||
.check_stop_free = usbg_check_stop_free,
|
||||
|
||||
.fabric_make_wwn = usbg_make_tport,
|
||||
|
@ -539,6 +539,11 @@ static void tcm_vhost_queue_tm_rsp(struct se_cmd *se_cmd)
|
||||
return;
|
||||
}
|
||||
|
||||
static void tcm_vhost_aborted_task(struct se_cmd *se_cmd)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static void tcm_vhost_free_evt(struct vhost_scsi *vs, struct tcm_vhost_evt *evt)
|
||||
{
|
||||
vs->vs_events_nr--;
|
||||
@ -1740,7 +1745,8 @@ static int tcm_vhost_make_nexus(struct tcm_vhost_tpg *tpg,
|
||||
*/
|
||||
tv_nexus->tvn_se_sess = transport_init_session_tags(
|
||||
TCM_VHOST_DEFAULT_TAGS,
|
||||
sizeof(struct tcm_vhost_cmd));
|
||||
sizeof(struct tcm_vhost_cmd),
|
||||
TARGET_PROT_NORMAL);
|
||||
if (IS_ERR(tv_nexus->tvn_se_sess)) {
|
||||
mutex_unlock(&tpg->tv_tpg_mutex);
|
||||
kfree(tv_nexus);
|
||||
@ -2131,6 +2137,7 @@ static struct target_core_fabric_ops tcm_vhost_ops = {
|
||||
.queue_data_in = tcm_vhost_queue_data_in,
|
||||
.queue_status = tcm_vhost_queue_status,
|
||||
.queue_tm_rsp = tcm_vhost_queue_tm_rsp,
|
||||
.aborted_task = tcm_vhost_aborted_task,
|
||||
/*
|
||||
* Setup callers for generic logic in target_core_fabric_configfs.c
|
||||
*/
|
||||
|
@ -21,6 +21,8 @@ struct iscsit_transport {
|
||||
int (*iscsit_get_dataout)(struct iscsi_conn *, struct iscsi_cmd *, bool);
|
||||
int (*iscsit_queue_data_in)(struct iscsi_conn *, struct iscsi_cmd *);
|
||||
int (*iscsit_queue_status)(struct iscsi_conn *, struct iscsi_cmd *);
|
||||
void (*iscsit_aborted_task)(struct iscsi_conn *, struct iscsi_cmd *);
|
||||
enum target_prot_op (*iscsit_get_sup_prot_ops)(struct iscsi_conn *);
|
||||
};
|
||||
|
||||
static inline void *iscsit_priv_cmd(struct iscsi_cmd *cmd)
|
||||
|
@ -73,10 +73,12 @@ sense_reason_t sbc_execute_unmap(struct se_cmd *cmd,
|
||||
sense_reason_t (*do_unmap_fn)(struct se_cmd *cmd, void *priv,
|
||||
sector_t lba, sector_t nolb),
|
||||
void *priv);
|
||||
void sbc_dif_generate(struct se_cmd *);
|
||||
sense_reason_t sbc_dif_verify_write(struct se_cmd *, sector_t, unsigned int,
|
||||
unsigned int, struct scatterlist *, int);
|
||||
sense_reason_t sbc_dif_verify_read(struct se_cmd *, sector_t, unsigned int,
|
||||
unsigned int, struct scatterlist *, int);
|
||||
sense_reason_t sbc_dif_read_strip(struct se_cmd *);
|
||||
|
||||
void transport_set_vpd_proto_id(struct t10_vpd *, unsigned char *);
|
||||
int transport_set_vpd_assoc(struct t10_vpd *, unsigned char *);
|
||||
|
@ -162,7 +162,7 @@ enum se_cmd_flags_table {
|
||||
SCF_SENT_CHECK_CONDITION = 0x00000800,
|
||||
SCF_OVERFLOW_BIT = 0x00001000,
|
||||
SCF_UNDERFLOW_BIT = 0x00002000,
|
||||
SCF_SENT_DELAYED_TAS = 0x00004000,
|
||||
SCF_SEND_DELAYED_TAS = 0x00004000,
|
||||
SCF_ALUA_NON_OPTIMIZED = 0x00008000,
|
||||
SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC = 0x00020000,
|
||||
SCF_ACK_KREF = 0x00040000,
|
||||
@ -442,19 +442,18 @@ struct se_tmr_req {
|
||||
};
|
||||
|
||||
enum target_prot_op {
|
||||
TARGET_PROT_NORMAL = 0,
|
||||
TARGET_PROT_DIN_INSERT,
|
||||
TARGET_PROT_DOUT_INSERT,
|
||||
TARGET_PROT_DIN_STRIP,
|
||||
TARGET_PROT_DOUT_STRIP,
|
||||
TARGET_PROT_DIN_PASS,
|
||||
TARGET_PROT_DOUT_PASS,
|
||||
TARGET_PROT_NORMAL = 0,
|
||||
TARGET_PROT_DIN_INSERT = (1 << 0),
|
||||
TARGET_PROT_DOUT_INSERT = (1 << 1),
|
||||
TARGET_PROT_DIN_STRIP = (1 << 2),
|
||||
TARGET_PROT_DOUT_STRIP = (1 << 3),
|
||||
TARGET_PROT_DIN_PASS = (1 << 4),
|
||||
TARGET_PROT_DOUT_PASS = (1 << 5),
|
||||
};
|
||||
|
||||
enum target_prot_ho {
|
||||
PROT_SEPERATED,
|
||||
PROT_INTERLEAVED,
|
||||
};
|
||||
#define TARGET_PROT_ALL TARGET_PROT_DIN_INSERT | TARGET_PROT_DOUT_INSERT | \
|
||||
TARGET_PROT_DIN_STRIP | TARGET_PROT_DOUT_STRIP | \
|
||||
TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS
|
||||
|
||||
enum target_prot_type {
|
||||
TARGET_DIF_TYPE0_PROT,
|
||||
@ -463,6 +462,12 @@ enum target_prot_type {
|
||||
TARGET_DIF_TYPE3_PROT,
|
||||
};
|
||||
|
||||
enum target_core_dif_check {
|
||||
TARGET_DIF_CHECK_GUARD = 0x1 << 0,
|
||||
TARGET_DIF_CHECK_APPTAG = 0x1 << 1,
|
||||
TARGET_DIF_CHECK_REFTAG = 0x1 << 2,
|
||||
};
|
||||
|
||||
struct se_dif_v1_tuple {
|
||||
__be16 guard_tag;
|
||||
__be16 app_tag;
|
||||
@ -556,13 +561,14 @@ struct se_cmd {
|
||||
/* DIF related members */
|
||||
enum target_prot_op prot_op;
|
||||
enum target_prot_type prot_type;
|
||||
u8 prot_checks;
|
||||
u32 prot_length;
|
||||
u32 reftag_seed;
|
||||
struct scatterlist *t_prot_sg;
|
||||
unsigned int t_prot_nents;
|
||||
enum target_prot_ho prot_handover;
|
||||
sense_reason_t pi_err;
|
||||
sector_t bad_sector;
|
||||
bool prot_pto;
|
||||
};
|
||||
|
||||
struct se_ua {
|
||||
@ -603,6 +609,7 @@ struct se_node_acl {
|
||||
struct se_session {
|
||||
unsigned sess_tearing_down:1;
|
||||
u64 sess_bin_isid;
|
||||
enum target_prot_op sup_prot_ops;
|
||||
struct se_node_acl *se_node_acl;
|
||||
struct se_portal_group *se_tpg;
|
||||
void *fabric_sess_ptr;
|
||||
|
@ -62,6 +62,7 @@ struct target_core_fabric_ops {
|
||||
int (*queue_data_in)(struct se_cmd *);
|
||||
int (*queue_status)(struct se_cmd *);
|
||||
void (*queue_tm_rsp)(struct se_cmd *);
|
||||
void (*aborted_task)(struct se_cmd *);
|
||||
/*
|
||||
* fabric module calls for target_core_fabric_configfs.c
|
||||
*/
|
||||
@ -83,10 +84,11 @@ struct target_core_fabric_ops {
|
||||
void (*fabric_drop_nodeacl)(struct se_node_acl *);
|
||||
};
|
||||
|
||||
struct se_session *transport_init_session(void);
|
||||
struct se_session *transport_init_session(enum target_prot_op);
|
||||
int transport_alloc_session_tags(struct se_session *, unsigned int,
|
||||
unsigned int);
|
||||
struct se_session *transport_init_session_tags(unsigned int, unsigned int);
|
||||
struct se_session *transport_init_session_tags(unsigned int, unsigned int,
|
||||
enum target_prot_op);
|
||||
void __transport_register_session(struct se_portal_group *,
|
||||
struct se_node_acl *, struct se_session *, void *);
|
||||
void transport_register_session(struct se_portal_group *,
|
||||
|
Loading…
Reference in New Issue
Block a user