[SCSI] libfc: add support of large receive offload by ddp in fc_fcp
[safe/jmp/linux-2.6] / drivers / scsi / libfc / fc_fcp.c
index 48adb89..a5725f3 100644 (file)
@@ -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);