[PATCH] Performance improvement, combine received data copy with CRC.


Signed-off-by: Joe Eykholt <[EMAIL PROTECTED]>

---
 drivers/scsi/ofc/openfc/openfc_scsi.c |  130 +++++++++++++++++++++++----------
 1 files changed, 90 insertions(+), 40 deletions(-)

diff --git a/drivers/scsi/ofc/openfc/openfc_scsi.c 
b/drivers/scsi/ofc/openfc/openfc_scsi.c
index 5fa0ad6..b5fc393 100644
--- a/drivers/scsi/ofc/openfc/openfc_scsi.c
+++ b/drivers/scsi/ofc/openfc/openfc_scsi.c
@@ -62,7 +62,6 @@ static void openfc_tm_done(struct fc_seq *, struct fc_frame 
*, void *);
 static void openfc_scsi_error(enum fc_event, void *);
 static int openfc_abort_internal(struct fcdev *, struct fc_scsi_pkt *,
                                 struct fc_frame *);
-int openfc_cp_to_user(struct fc_scsi_pkt *, uint, void *, int);
 void openfc_scsi_cleanup(struct fc_scsi_pkt *);
 static void openfc_timeout_error(struct fc_scsi_pkt *);
 void openfc_scsi_rec_rcv(struct fc_seq *, struct fc_frame *, void *);
@@ -102,9 +101,13 @@ static void openfc_scsi_recv_data(struct fc_scsi_pkt *fsp, 
struct fc_frame *fp)
        struct fcoe_dev_stats *sp;
        struct fc_frame_header *fh;
        size_t offset;
+       u32 crc;
+       u32 copy_len = 0;
        size_t len;
        void *buf;
 
+       if (!sc->request_buffer)
+               return;                 /* XXX possible? */
        fh = fc_frame_header_get(fp);
        offset = net32_get(&fh->fh_parm_offset);
        len = fp->fr_len - sizeof(*fh);
@@ -115,13 +118,8 @@ static void openfc_scsi_recv_data(struct fc_scsi_pkt *fsp, 
struct fc_frame *fp)
                 * this should never happen
                 */
                if ((fp->fr_flags & FCPHF_CRC_UNCHECKED) &&
-                   fc_frame_crc_check(fp)) {
-                       sp = openfcp->fd.dev_stats[smp_processor_id()];
-                       sp->ErrorFrames++;
-                       if (sp->InvalidCRCCount++ < 5)
-                               SA_LOG("CRC error on data frame");
-                       return; /* just ignore the frame */
-               }
+                   fc_frame_crc_check(fp))
+                       goto crc_err;
                if (openfc_debug) {
                        SA_LOG("data received past end.  "
                               "len %zx offset %zx "
@@ -130,42 +128,95 @@ static void openfc_scsi_recv_data(struct fc_scsi_pkt 
*fsp, struct fc_frame *fp)
                openfc_scsi_retry(fsp);
                return;
        }
-
-       /*
-        * Eventually, do scatter/gather buffer system to avoid
-        * this copy.  A NULL buffer means we discard the data.
-        */
+       crc = 0;
        if (sc->use_sg) {
-               len = openfc_cp_to_user(fsp, offset, buf, len);
-               ASSERT_NOTIMPL(len > 0);
-       } else if (sc->request_buffer != NULL) {
-               __memcpy((void *)sc->request_buffer + offset, buf, len);
-       }
+               struct scatterlist *sg;
+               struct scatterlist *sg_limit;
+               size_t remaining, sg_bytes;
+               size_t off;
+               void *page_addr;
 
-       /*
-        * If the lower layer didn't do the CRC check, do it here.
-        * This is the only type of frame the transport might not check.
-        * Eventually we could do the CRC calculation during the copy above.
-        */
-       if ((fp->fr_flags & FCPHF_CRC_UNCHECKED) && fc_frame_crc_check(fp)) {
-               sp = openfcp->fd.dev_stats[smp_processor_id()];
-               sp->ErrorFrames++;
-               if (sp->InvalidCRCCount++ < 5)
-                       SA_LOG("CRC error on data frame");
+               if (fp->fr_flags & FCPHF_CRC_UNCHECKED)
+                       crc = crc32_sb8_64_bit(~0, (u8 *) fh, sizeof(*fh));
 
-               /*
-                * Assume the frame is total garbage.
-                * We may have copied it over the good part of the buffer.
-                * If so, we need to retry the entire operation.
-                * Otherwise, ignore it.
-                */
-               if (offset < fsp->xfer_len)
-                       openfc_scsi_retry(fsp);
-               return;
-       }
+               sg = (struct scatterlist *)sc->request_buffer;
+               sg_limit = sg + sc->use_sg;
+               remaining = len;
 
-       fsp->xfer_len += len;
+               while (remaining > 0 && sg < sg_limit) {
+                       if (offset >= sg->length) {
+                               offset -= sg->length;
+                               sg++;
+                               continue;
+                       }
+                       sg_bytes = min(remaining, sg->length - offset);
 
+                       /*
+                        * The scatterlist item may be bigger than PAGE_SIZE,
+                        * but we are limited to mapping PAGE_SIZE at a time.
+                        */
+                       off = offset + sg->offset;
+                       sg_bytes = min(sg_bytes,
+                                      (PAGE_SIZE - (off & ~PAGE_MASK)));
+                       page_addr = kmap_atomic(sg_page(sg) +
+                                               (off >> PAGE_SHIFT),
+                                               KM_SOFTIRQ0);
+                       if (!page_addr)
+                               break;          /* XXX panic? */
+
+                       if (fsp->state != OPENFC_SRB_ABORT_PENDING) {
+                               if (fp->fr_flags & FCPHF_CRC_UNCHECKED) {
+                                       crc = crc32_copy(crc,
+                                                        (char *)page_addr +
+                                                        (off & ~PAGE_MASK),
+                                                        buf, sg_bytes);
+                               } else {
+                                       __memcpy((char *)page_addr +
+                                                (off & ~PAGE_MASK),
+                                                buf, sg_bytes);
+                               }
+                       }
+                       kunmap_atomic(page_addr, KM_SOFTIRQ0);
+                       buf += sg_bytes;
+                       offset += sg_bytes;
+                       remaining -= sg_bytes;
+                       copy_len += sg_bytes;
+               }
+               if (fp->fr_flags & FCPHF_CRC_UNCHECKED)
+                       goto crc_check;
+       } else if (fp->fr_flags & FCPHF_CRC_UNCHECKED) {
+               crc = crc32_sb8_64_bit(~0, (u8 *)fh, sizeof(*fh));
+               crc = crc32_copy(crc, (void *)sc->request_buffer + offset,
+                                buf, len);
+               copy_len = len;
+crc_check:
+               buf = fc_frame_payload_get(fp, 0);
+               if (len % 4) {
+                       crc = crc32_sb8_64_bit(crc, buf + len, 4 - (len % 4));
+                       len += 4 - (len % 4);
+               }
+               if (~crc != le32_to_cpu(*(__le32 *)(buf + len))) {
+crc_err:
+                       sp = openfcp->fd.dev_stats[smp_processor_id()];
+                       sp->ErrorFrames++;
+                       if (sp->InvalidCRCCount++ < 5)
+                               SA_LOG("CRC error on data frame");
+                       /*
+                        * Assume the frame is total garbage.
+                        * We may have copied it over the good part
+                        * of the buffer.
+                        * If so, we need to retry the entire operation.
+                        * Otherwise, ignore it.
+                        */
+                       if (offset < fsp->xfer_len)
+                               openfc_scsi_retry(fsp);
+                       return;
+               }
+       } else {
+               __memcpy((void *)sc->request_buffer + offset, buf, len);
+               copy_len = len;
+       }
+       fsp->xfer_len += copy_len;
        if (fsp->xfer_len == fsp->data_len)
                fsp->state = OPENFC_SRB_WAIT_FOR_STATUS;
 }
@@ -317,7 +368,6 @@ static void openfc_scsi_send_data(struct fc_scsi_pkt *fsp, 
struct fc_seq *sp,
 
        if (fsp->xfer_len == fsp->data_len)
                fsp->state = OPENFC_SRB_WAIT_FOR_STATUS;
-       return;
 }
 
 /*


-
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to