[SCSI] libfc: add support of large receive offload by ddp in fc_fcp

When LLD supports direct data placement (ddp) for large receive of an scsi
i/o coming into fc_fcp, we call into libfc_function_template's ddp_setup()
to prepare for a ddp of large receive for this read I/O. When I/O is complete,
we call the corresponding ddp_done() to get the length of data ddped as well
as to let LLD do clean up.

fc_fcp_ddp_setup()/fc_fcp_ddp_done() are added to setup and complete a ddped
read I/O described by the given fc_fcp_pkt. They would call into corresponding
ddp_setup/ddp_done implemented by the fcoe layer. Eventually, fcoe layer calls
into LLD's ddp_setup/ddp_done provided through net_device

Signed-off-by: Yi Zou <yi.zou@intel.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
This commit is contained in:
Yi Zou
2009-02-27 14:07:21 -08:00
committed by James Bottomley
parent 39ca9a065a
commit b277d2aa9a
5 changed files with 95 additions and 37 deletions

View File

@@ -264,6 +264,56 @@ static void fc_fcp_retry_cmd(struct fc_fcp_pkt *fsp)
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) &&
@@ -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);