summaryrefslogtreecommitdiff
path: root/drivers/scsi/libfc/fc_fcp.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/libfc/fc_fcp.c')
-rw-r--r--drivers/scsi/libfc/fc_fcp.c75
1 files changed, 70 insertions, 5 deletions
diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c
index 2a631d7dbcec..a5725f3b7ce1 100644
--- a/drivers/scsi/libfc/fc_fcp.c
+++ b/drivers/scsi/libfc/fc_fcp.c
@@ -259,12 +259,62 @@ static void fc_fcp_retry_cmd(struct fc_fcp_pkt *fsp)
}
fsp->state &= ~FC_SRB_ABORT_PENDING;
- fsp->io_status = SUGGEST_RETRY << 24;
+ fsp->io_status = 0;
fsp->status_code = FC_ERROR;
fc_fcp_complete_locked(fsp);
}
/*
+ * fc_fcp_ddp_setup - calls to LLD's ddp_setup to set up DDP
+ * transfer for a read I/O indicated by the fc_fcp_pkt.
+ * @fsp: ptr to the fc_fcp_pkt
+ *
+ * This is called in exch_seq_send() when we have a newly allocated
+ * exchange with a valid exchange id to setup ddp.
+ *
+ * returns: none
+ */
+void fc_fcp_ddp_setup(struct fc_fcp_pkt *fsp, u16 xid)
+{
+ struct fc_lport *lp;
+
+ if (!fsp)
+ return;
+
+ lp = fsp->lp;
+ if ((fsp->req_flags & FC_SRB_READ) &&
+ (lp->lro_enabled) && (lp->tt.ddp_setup)) {
+ if (lp->tt.ddp_setup(lp, xid, scsi_sglist(fsp->cmd),
+ scsi_sg_count(fsp->cmd)))
+ fsp->xfer_ddp = xid;
+ }
+}
+EXPORT_SYMBOL(fc_fcp_ddp_setup);
+
+/*
+ * fc_fcp_ddp_done - calls to LLD's ddp_done to release any
+ * DDP related resources for this I/O if it is initialized
+ * as a ddp transfer
+ * @fsp: ptr to the fc_fcp_pkt
+ *
+ * returns: none
+ */
+static void fc_fcp_ddp_done(struct fc_fcp_pkt *fsp)
+{
+ struct fc_lport *lp;
+
+ if (!fsp)
+ return;
+
+ lp = fsp->lp;
+ if (fsp->xfer_ddp && lp->tt.ddp_done) {
+ fsp->xfer_len = lp->tt.ddp_done(lp, fsp->xfer_ddp);
+ fsp->xfer_ddp = 0;
+ }
+}
+
+
+/*
* Receive SCSI data from target.
* Called after receiving solicited data.
*/
@@ -289,6 +339,9 @@ static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
len = fr_len(fp) - sizeof(*fh);
buf = fc_frame_payload_get(fp, 0);
+ /* if this I/O is ddped, update xfer len */
+ fc_fcp_ddp_done(fsp);
+
if (offset + len > fsp->data_len) {
/* this should never happen */
if ((fr_flags(fp) & FCPHF_CRC_UNCHECKED) &&
@@ -435,7 +488,13 @@ static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *seq,
* burst length (t_blen) to seq_blen, otherwise set t_blen
* to max FC frame payload previously set in fsp->max_payload.
*/
- t_blen = lp->seq_offload ? seq_blen : fsp->max_payload;
+ t_blen = fsp->max_payload;
+ if (lp->seq_offload) {
+ t_blen = min(seq_blen, (size_t)lp->lso_max);
+ FC_DEBUG_FCP("fsp=%p:lso:blen=%zx lso_max=0x%x t_blen=%zx\n",
+ fsp, seq_blen, lp->lso_max, t_blen);
+ }
+
WARN_ON(t_blen < FC_MIN_MAX_PAYLOAD);
if (t_blen > 512)
t_blen &= ~(512 - 1); /* round down to block size */
@@ -744,6 +803,9 @@ static void fc_fcp_resp(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
fsp->scsi_comp_flags = flags;
expected_len = fsp->data_len;
+ /* if ddp, update xfer len */
+ fc_fcp_ddp_done(fsp);
+
if (unlikely((flags & ~FCP_CONF_REQ) || fc_rp->fr_status)) {
rp_ex = (void *)(fc_rp + 1);
if (flags & (FCP_RSP_LEN_VAL | FCP_SNS_LEN_VAL)) {
@@ -859,7 +921,7 @@ static void fc_fcp_complete_locked(struct fc_fcp_pkt *fsp)
(!(fsp->scsi_comp_flags & FCP_RESID_UNDER) ||
fsp->xfer_len < fsp->data_len - fsp->scsi_resid)) {
fsp->status_code = FC_DATA_UNDRUN;
- fsp->io_status = SUGGEST_RETRY << 24;
+ fsp->io_status = 0;
}
}
@@ -1006,7 +1068,7 @@ static int fc_fcp_cmd_send(struct fc_lport *lp, struct fc_fcp_pkt *fsp,
}
memcpy(fc_frame_payload_get(fp, len), &fsp->cdb_cmd, len);
- fr_cmd(fp) = fsp->cmd;
+ fr_fsp(fp) = fsp;
rport = fsp->rport;
fsp->max_payload = rport->maxframe_size;
rp = rport->dd_data;
@@ -1267,7 +1329,7 @@ static void fc_fcp_rec(struct fc_fcp_pkt *fsp)
rp = rport->dd_data;
if (!fsp->seq_ptr || rp->rp_state != RPORT_ST_READY) {
fsp->status_code = FC_HRD_ERROR;
- fsp->io_status = SUGGEST_RETRY << 24;
+ fsp->io_status = 0;
fc_fcp_complete_locked(fsp);
return;
}
@@ -1740,6 +1802,9 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)
struct fc_lport *lp;
unsigned long flags;
+ /* release outstanding ddp context */
+ fc_fcp_ddp_done(fsp);
+
fsp->state |= FC_SRB_COMPL;
if (!(fsp->state & FC_SRB_FCP_PROCESSING_TMO)) {
spin_unlock_bh(&fsp->scsi_pkt_lock);