When handling the multi-frame responses of fc pass-thru requests, a code segment similar to fc_fcp_recv_data (routine to receive inbound SCSI data) is used in the response handler. This patch is to add an inline routine, called copy_buffer_to_sglist(), to handle the common function of copying data from a buffer to a scatter-gather list in order to avoid code duplication.
Signed-off-by: Steve Ma <[email protected]> --- drivers/scsi/libfc/fc_fcp.c | 41 +++--------------------------- include/scsi/libfc.h | 59 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 37 deletions(-) diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index a172375..75f3dee 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -331,7 +331,7 @@ static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp) size_t len; void *buf; struct scatterlist *sg; - size_t remaining; + u32 nents; fh = fc_frame_header_get(fp); offset = ntohl(fh->fh_parm_offset); @@ -362,43 +362,10 @@ static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp) crc = crc32(~0, (u8 *) fh, sizeof(*fh)); sg = scsi_sglist(sc); - remaining = len; - - while (remaining > 0 && sg) { - size_t off; - void *page_addr; - size_t sg_bytes; - - if (offset >= sg->length) { - offset -= sg->length; - sg = sg_next(sg); - continue; - } - sg_bytes = min(remaining, sg->length - offset); + nents = scsi_sg_count(sc); - /* - * 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, (size_t) - (PAGE_SIZE - (off & ~PAGE_MASK))); - page_addr = kmap_atomic(sg_page(sg) + (off >> PAGE_SHIFT), - KM_SOFTIRQ0); - if (!page_addr) - break; /* XXX panic? */ - - if (fr_flags(fp) & FCPHF_CRC_UNCHECKED) - crc = crc32(crc, buf, sg_bytes); - 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; - } + copy_len = copy_buffer_to_sglist(buf, len, &sg, &nents, &offset, + KM_SOFTIRQ0, (fr_flags(fp) & FCPHF_CRC_UNCHECKED) ? &crc : 0); if (fr_flags(fp) & FCPHF_CRC_UNCHECKED) { buf = fc_frame_payload_get(fp, 0); diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index f7314ea..f0977a9 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -22,6 +22,7 @@ #include <linux/timer.h> #include <linux/if.h> +#include <linux/crc32.h> #include <scsi/scsi_transport.h> #include <scsi/scsi_transport_fc.h> @@ -823,6 +824,64 @@ void fc_fcp_destroy(struct fc_lport *); void fc_fcp_ddp_setup(struct fc_fcp_pkt *fsp, u16 xid); /** + * copy_buffer_to_sglist() - This routine copies the data of a buffer + * into a scatter-gather list (SG list). + * + * @buf: pointer to the data buffer. + * @len: the byte-length of the data buffer. + * @sg: pointer to the pointer of the SG list. + * @nents: pointer to the remaining number of entries in the SG list. + * @offset: pointer to the current offset in the SG list. + * @km_type: dedicated page table slot type for kmap_atomic. + * @crc: pointer to the 32-bit crc value. + * If crc is NULL, CRC is not calculated. + */ +static inline u32 copy_buffer_to_sglist(void *buf, size_t len, + struct scatterlist **sg, u32 *nents, size_t *offset, + enum km_type km_type, u32 *crc) +{ + size_t remaining = len; + u32 copy_len = 0; + + while (remaining > 0 && *sg) { + size_t off, sg_bytes; + void *page_addr; + + if (*offset >= (*sg)->length) { + /* + * Check for end and drop resources + * from the last iteration. + */ + if (!(*nents)) + break; + --(*nents); + *offset -= (*sg)->length; + *sg = sg_next(*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_type); + if (crc) + *crc = crc32(*crc, buf, sg_bytes); + memcpy((char *)page_addr + (off & ~PAGE_MASK), buf, sg_bytes); + kunmap_atomic(page_addr, km_type); + buf += sg_bytes; + *offset += sg_bytes; + remaining -= sg_bytes; + copy_len += sg_bytes; + } + return copy_len; +} + +/** * ELS/CT interface *****************************/ /* _______________________________________________ devel mailing list [email protected] http://www.open-fcoe.org/mailman/listinfo/devel
