diff options
Diffstat (limited to 'drivers/scsi/libfc/fc_fcp.c')
-rw-r--r-- | drivers/scsi/libfc/fc_fcp.c | 61 |
1 files changed, 60 insertions, 1 deletions
diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index 48adb89..a5725f3 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -265,6 +265,56 @@ static void fc_fcp_retry_cmd(struct fc_fcp_pkt *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) && @@ -750,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)) { @@ -1012,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; @@ -1746,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); |