aboutsummaryrefslogtreecommitdiff
path: root/drivers/target/tcm_fc/tfc_io.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/target/tcm_fc/tfc_io.c')
-rw-r--r--drivers/target/tcm_fc/tfc_io.c57
1 files changed, 43 insertions, 14 deletions
diff --git a/drivers/target/tcm_fc/tfc_io.c b/drivers/target/tcm_fc/tfc_io.c
index d8cabc21036..97b486c3dda 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 <generated/utsrelease.h>
#include <linux/utsname.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -81,6 +80,12 @@ int ft_queue_data_in(struct se_cmd *se_cmd)
void *from;
void *to = NULL;
+ if (cmd->aborted)
+ return 0;
+
+ if (se_cmd->scsi_status == SAM_STAT_TASK_SET_FULL)
+ goto queue_status;
+
ep = fc_seq_exch(cmd->seq);
lport = ep->lp;
cmd->seq = lport->tt.seq_start_next(cmd->seq);
@@ -102,6 +107,13 @@ int ft_queue_data_in(struct se_cmd *se_cmd)
use_sg = !(remaining % 4);
while (remaining) {
+ struct fc_seq *seq = cmd->seq;
+
+ if (!seq) {
+ pr_debug("%s: Command aborted, xid 0x%x\n",
+ __func__, ep->xid);
+ break;
+ }
if (!mem_len) {
sg = sg_next(sg);
mem_len = min((size_t)sg->length, remaining);
@@ -146,14 +158,13 @@ int ft_queue_data_in(struct se_cmd *se_cmd)
PAGE_SIZE << compound_order(page);
} else {
BUG_ON(!page);
- from = kmap_atomic(page + (mem_off >> PAGE_SHIFT),
- KM_SOFTIRQ0);
+ from = kmap_atomic(page + (mem_off >> PAGE_SHIFT));
page_addr = from;
from += mem_off & ~PAGE_MASK;
tlen = min(tlen, (size_t)(PAGE_SIZE -
(mem_off & ~PAGE_MASK)));
memcpy(to, from, tlen);
- kunmap_atomic(page_addr, KM_SOFTIRQ0);
+ kunmap_atomic(page_addr);
to += tlen;
}
@@ -169,19 +180,35 @@ int ft_queue_data_in(struct se_cmd *se_cmd)
f_ctl |= FC_FC_END_SEQ;
fc_fill_fc_hdr(fp, FC_RCTL_DD_SOL_DATA, ep->did, ep->sid,
FC_TYPE_FCP, f_ctl, fh_off);
- error = lport->tt.seq_send(lport, cmd->seq, fp);
+ error = lport->tt.seq_send(lport, seq, fp);
if (error) {
- /* XXX For now, initiator will retry */
- pr_err_ratelimited("%s: Failed to send frame %p, "
+ pr_info_ratelimited("%s: Failed to send frame %p, "
"xid <0x%x>, remaining %zu, "
"lso_max <0x%x>\n",
__func__, fp, ep->xid,
remaining, lport->lso_max);
+ /*
+ * Go ahead and set TASK_SET_FULL status ignoring the
+ * rest of the DataIN, and immediately attempt to
+ * send the response via ft_queue_status() in order
+ * to notify the initiator that it should reduce it's
+ * per LUN queue_depth.
+ */
+ se_cmd->scsi_status = SAM_STAT_TASK_SET_FULL;
+ break;
}
}
+queue_status:
return ft_queue_status(se_cmd);
}
+static void ft_execute_work(struct work_struct *work)
+{
+ struct ft_cmd *cmd = container_of(work, struct ft_cmd, work);
+
+ target_execute_cmd(&cmd->se_cmd);
+}
+
/*
* Receive write data frame.
*/
@@ -227,7 +254,7 @@ void ft_recv_write_data(struct ft_cmd *cmd, struct fc_frame *fp)
"payload, Frame will be dropped if"
"'Sequence Initiative' bit in f_ctl is"
"not set\n", __func__, ep->xid, f_ctl,
- cmd->sg, cmd->sg_cnt);
+ se_cmd->t_data_sg, se_cmd->t_data_nents);
/*
* Invalidate HW DDP context if it was setup for respective
* command. Invalidation of HW DDP context is requited in both
@@ -291,14 +318,13 @@ void ft_recv_write_data(struct ft_cmd *cmd, struct fc_frame *fp)
tlen = min(mem_len, frame_len);
- to = kmap_atomic(page + (mem_off >> PAGE_SHIFT),
- KM_SOFTIRQ0);
+ to = kmap_atomic(page + (mem_off >> PAGE_SHIFT));
page_addr = to;
to += mem_off & ~PAGE_MASK;
tlen = min(tlen, (size_t)(PAGE_SIZE -
(mem_off & ~PAGE_MASK)));
memcpy(to, from, tlen);
- kunmap_atomic(page_addr, KM_SOFTIRQ0);
+ kunmap_atomic(page_addr);
from += tlen;
frame_len -= tlen;
@@ -307,8 +333,10 @@ void ft_recv_write_data(struct ft_cmd *cmd, struct fc_frame *fp)
cmd->write_data_len += tlen;
}
last_frame:
- if (cmd->write_data_len == se_cmd->data_length)
- transport_generic_handle_data(se_cmd);
+ if (cmd->write_data_len == se_cmd->data_length) {
+ INIT_WORK(&cmd->work, ft_execute_work);
+ queue_work(cmd->sess->tport->tpg->workqueue, &cmd->work);
+ }
drop:
fc_frame_free(fp);
}
@@ -319,11 +347,12 @@ drop:
*/
void ft_invl_hw_context(struct ft_cmd *cmd)
{
- struct fc_seq *seq = cmd->seq;
+ struct fc_seq *seq;
struct fc_exch *ep = NULL;
struct fc_lport *lport = NULL;
BUG_ON(!cmd);
+ seq = cmd->seq;
/* Cleanup the DDP context in HW if DDP was setup */
if (cmd->was_ddp_setup && seq) {