Now that we are using p2pmem SG buffers we occasionally have to copy to and from this memory. For this, we add an iomem flag to sg_copy_buffer for copying with iomemcpy. We also add the sg_iocopy_ variants to use this more easily. Signed-off-by: Logan Gunthorpe <logang@xxxxxxxxxxxx> Signed-off-by: Stephen Bates <sbates@xxxxxxxxxxxx> Signed-off-by: Steve Wise <swise@xxxxxxxxxxxxxxxxxxxxx> --- drivers/scsi/scsi_debug.c | 7 ++--- include/linux/scatterlist.h | 7 ++++- lib/scatterlist.c | 64 ++++++++++++++++++++++++++++++++++++++------- 3 files changed, 65 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 17249c3..70c0d9f 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -1309,7 +1309,7 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) int lu_id_num, port_group_id, target_dev_id, len; char lu_id_str[6]; int host_no = devip->sdbg_host->shost->host_no; - + port_group_id = (((host_no + 1) & 0x7f) << 8) + (devip->channel & 0x7f); if (sdebug_vpd_use_hostno == 0) @@ -2381,14 +2381,15 @@ static int do_device_access(struct scsi_cmnd *scmd, u64 lba, u32 num, ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents, fake_storep + (block * sdebug_sector_size), - (num - rest) * sdebug_sector_size, 0, do_write); + (num - rest) * sdebug_sector_size, 0, do_write, false); if (ret != (num - rest) * sdebug_sector_size) return ret; if (rest) { ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents, fake_storep, rest * sdebug_sector_size, - (num - rest) * sdebug_sector_size, do_write); + (num - rest) * sdebug_sector_size, do_write, + false); } return ret; diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h index cb3c8fe..030b92b 100644 --- a/include/linux/scatterlist.h +++ b/include/linux/scatterlist.h @@ -267,7 +267,7 @@ int sg_alloc_table_from_pages(struct sg_table *sgt, gfp_t gfp_mask); size_t sg_copy_buffer(struct scatterlist *sgl, unsigned int nents, void *buf, - size_t buflen, off_t skip, bool to_buffer); + size_t buflen, off_t skip, bool to_buffer, bool iomem); size_t sg_copy_from_buffer(struct scatterlist *sgl, unsigned int nents, const void *buf, size_t buflen); @@ -279,6 +279,11 @@ size_t sg_pcopy_from_buffer(struct scatterlist *sgl, unsigned int nents, size_t sg_pcopy_to_buffer(struct scatterlist *sgl, unsigned int nents, void *buf, size_t buflen, off_t skip); +size_t sg_iocopy_from_buffer(struct scatterlist *sgl, unsigned int nents, + const void *buf, size_t buflen); +size_t sg_iocopy_to_buffer(struct scatterlist *sgl, unsigned int nents, + void *buf, size_t buflen); + /* * Maximum number of entries that will be allocated in one piece, if * a list larger than this is required then chaining will be utilized. diff --git a/lib/scatterlist.c b/lib/scatterlist.c index c6cf822..22abd94 100644 --- a/lib/scatterlist.c +++ b/lib/scatterlist.c @@ -647,7 +647,7 @@ EXPORT_SYMBOL(sg_miter_stop); * **/ size_t sg_copy_buffer(struct scatterlist *sgl, unsigned int nents, void *buf, - size_t buflen, off_t skip, bool to_buffer) + size_t buflen, off_t skip, bool to_buffer, bool iomem) { unsigned int offset = 0; struct sg_mapping_iter miter; @@ -668,10 +668,17 @@ size_t sg_copy_buffer(struct scatterlist *sgl, unsigned int nents, void *buf, len = min(miter.length, buflen - offset); - if (to_buffer) - memcpy(buf + offset, miter.addr, len); - else - memcpy(miter.addr, buf + offset, len); + if (iomem) { + if (to_buffer) + memcpy_fromio(buf + offset, miter.addr, len); + else + memcpy_toio(miter.addr, buf + offset, len); + } else { + if (to_buffer) + memcpy(buf + offset, miter.addr, len); + else + memcpy(miter.addr, buf + offset, len); + } offset += len; } @@ -695,7 +702,8 @@ EXPORT_SYMBOL(sg_copy_buffer); size_t sg_copy_from_buffer(struct scatterlist *sgl, unsigned int nents, const void *buf, size_t buflen) { - return sg_copy_buffer(sgl, nents, (void *)buf, buflen, 0, false); + return sg_copy_buffer(sgl, nents, (void *)buf, buflen, 0, false, + false); } EXPORT_SYMBOL(sg_copy_from_buffer); @@ -712,7 +720,7 @@ EXPORT_SYMBOL(sg_copy_from_buffer); size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents, void *buf, size_t buflen) { - return sg_copy_buffer(sgl, nents, buf, buflen, 0, true); + return sg_copy_buffer(sgl, nents, buf, buflen, 0, true, false); } EXPORT_SYMBOL(sg_copy_to_buffer); @@ -730,7 +738,8 @@ EXPORT_SYMBOL(sg_copy_to_buffer); size_t sg_pcopy_from_buffer(struct scatterlist *sgl, unsigned int nents, const void *buf, size_t buflen, off_t skip) { - return sg_copy_buffer(sgl, nents, (void *)buf, buflen, skip, false); + return sg_copy_buffer(sgl, nents, (void *)buf, buflen, skip, false, + false); } EXPORT_SYMBOL(sg_pcopy_from_buffer); @@ -748,6 +757,43 @@ EXPORT_SYMBOL(sg_pcopy_from_buffer); size_t sg_pcopy_to_buffer(struct scatterlist *sgl, unsigned int nents, void *buf, size_t buflen, off_t skip) { - return sg_copy_buffer(sgl, nents, buf, buflen, skip, true); + return sg_copy_buffer(sgl, nents, buf, buflen, skip, true, false); } EXPORT_SYMBOL(sg_pcopy_to_buffer); + +/** + * sg_iocopy_from_buffer - Copy from a linear buffer to an SG list containing + * IO memory. + * @sgl: The SG list + * @nents: Number of SG entries + * @buf: Where to copy from + * @buflen: The number of bytes to copy + * + * Returns the number of copied bytes. + * + **/ +size_t sg_iocopy_from_buffer(struct scatterlist *sgl, unsigned int nents, + const void *buf, size_t buflen) +{ + return sg_copy_buffer(sgl, nents, (void *)buf, buflen, 0, false, + true); +} +EXPORT_SYMBOL(sg_iocopy_from_buffer); + +/** + * sg_iocopy_to_buffer - Copy from an SG list containing IO memory + * to a linear buffer + * @sgl: The SG list + * @nents: Number of SG entries + * @buf: Where to copy to + * @buflen: The number of bytes to copy + * + * Returns the number of copied bytes. + * + **/ +size_t sg_iocopy_to_buffer(struct scatterlist *sgl, unsigned int nents, + void *buf, size_t buflen) +{ + return sg_copy_buffer(sgl, nents, buf, buflen, 0, true, true); +} +EXPORT_SYMBOL(sg_iocopy_to_buffer); -- 2.1.4