aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2021-03-31 09:29:54 +0200
committerJens Axboe <axboe@kernel.dk>2021-04-06 09:28:17 -0600
commit2f2fef022c3e7a29680cb5cb45c460d0ae786d05 (patch)
treeac9ad82bbd8ee4fbb7848a286069282d3e8c98cd
parentblk-mq: Always use blk_mq_is_sbitmap_shared (diff)
downloadlinux-dev-2f2fef022c3e7a29680cb5cb45c460d0ae786d05.tar.xz
linux-dev-2f2fef022c3e7a29680cb5cb45c460d0ae786d05.zip
aha1542: use a local bounce buffer
To remove the last user of the unchecked_isa_dma flag and thus the block layer ISA bounce buffering switch this driver to use its own local bounce buffer. This has the effect of not needing the chain indirection and supporting and unlimited number of segments. It does however limit the transfer size for each command to something that can be reasonable allocated by dma_alloc_coherent like 8K. Signed-off-by: Christoph Hellwig <hch@lst.de> Acked-by: Martin K. Petersen <martin.petersen@oracle.com> Reviewed-by: Hannes Reinecke <hare@suse.de> Link: https://lore.kernel.org/r/20210331073001.46776-2-hch@lst.de Signed-off-by: Jens Axboe <axboe@kernel.dk>
-rw-r--r--drivers/scsi/aha1542.c105
1 files changed, 57 insertions, 48 deletions
diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c
index 21aab9f5b117..1210e61afb18 100644
--- a/drivers/scsi/aha1542.c
+++ b/drivers/scsi/aha1542.c
@@ -65,9 +65,12 @@ struct aha1542_hostdata {
dma_addr_t ccb_handle;
};
+#define AHA1542_MAX_SECTORS 16
+
struct aha1542_cmd {
- struct chain *chain;
- dma_addr_t chain_handle;
+ /* bounce buffer */
+ void *data_buffer;
+ dma_addr_t data_buffer_handle;
};
static inline void aha1542_intr_reset(u16 base)
@@ -257,15 +260,19 @@ static int aha1542_test_port(struct Scsi_Host *sh)
static void aha1542_free_cmd(struct scsi_cmnd *cmd)
{
struct aha1542_cmd *acmd = scsi_cmd_priv(cmd);
- struct device *dev = cmd->device->host->dma_dev;
- size_t len = scsi_sg_count(cmd) * sizeof(struct chain);
- if (acmd->chain) {
- dma_unmap_single(dev, acmd->chain_handle, len, DMA_TO_DEVICE);
- kfree(acmd->chain);
+ if (cmd->sc_data_direction == DMA_FROM_DEVICE) {
+ void *buf = acmd->data_buffer;
+ struct req_iterator iter;
+ struct bio_vec bv;
+
+ rq_for_each_segment(bv, cmd->request, iter) {
+ memcpy_to_page(bv.bv_page, bv.bv_offset, buf,
+ bv.bv_len);
+ buf += bv.bv_len;
+ }
}
- acmd->chain = NULL;
scsi_dma_unmap(cmd);
}
@@ -416,7 +423,7 @@ static int aha1542_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
u8 lun = cmd->device->lun;
unsigned long flags;
int bufflen = scsi_bufflen(cmd);
- int mbo, sg_count;
+ int mbo;
struct mailbox *mb = aha1542->mb;
struct ccb *ccb = aha1542->ccb;
@@ -438,17 +445,17 @@ static int aha1542_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
print_hex_dump_bytes("command: ", DUMP_PREFIX_NONE, cmd->cmnd, cmd->cmd_len);
}
#endif
- sg_count = scsi_dma_map(cmd);
- if (sg_count) {
- size_t len = sg_count * sizeof(struct chain);
-
- acmd->chain = kmalloc(len, GFP_DMA);
- if (!acmd->chain)
- goto out_unmap;
- acmd->chain_handle = dma_map_single(sh->dma_dev, acmd->chain,
- len, DMA_TO_DEVICE);
- if (dma_mapping_error(sh->dma_dev, acmd->chain_handle))
- goto out_free_chain;
+
+ if (cmd->sc_data_direction == DMA_TO_DEVICE) {
+ void *buf = acmd->data_buffer;
+ struct req_iterator iter;
+ struct bio_vec bv;
+
+ rq_for_each_segment(bv, cmd->request, iter) {
+ memcpy_from_page(buf, bv.bv_page, bv.bv_offset,
+ bv.bv_len);
+ buf += bv.bv_len;
+ }
}
/*
@@ -496,27 +503,12 @@ static int aha1542_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
direction = 16;
memcpy(ccb[mbo].cdb, cmd->cmnd, ccb[mbo].cdblen);
-
- if (bufflen) {
- struct scatterlist *sg;
- int i;
-
- ccb[mbo].op = 2; /* SCSI Initiator Command w/scatter-gather */
- scsi_for_each_sg(cmd, sg, sg_count, i) {
- any2scsi(acmd->chain[i].dataptr, sg_dma_address(sg));
- any2scsi(acmd->chain[i].datalen, sg_dma_len(sg));
- };
- any2scsi(ccb[mbo].datalen, sg_count * sizeof(struct chain));
- any2scsi(ccb[mbo].dataptr, acmd->chain_handle);
-#ifdef DEBUG
- shost_printk(KERN_DEBUG, sh, "cptr %p: ", acmd->chain);
- print_hex_dump_bytes("cptr: ", DUMP_PREFIX_NONE, acmd->chain, 18);
-#endif
- } else {
- ccb[mbo].op = 0; /* SCSI Initiator Command */
- any2scsi(ccb[mbo].datalen, 0);
+ ccb[mbo].op = 0; /* SCSI Initiator Command */
+ any2scsi(ccb[mbo].datalen, bufflen);
+ if (bufflen)
+ any2scsi(ccb[mbo].dataptr, acmd->data_buffer_handle);
+ else
any2scsi(ccb[mbo].dataptr, 0);
- };
ccb[mbo].idlun = (target & 7) << 5 | direction | (lun & 7); /*SCSI Target Id */
ccb[mbo].rsalen = 16;
ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0;
@@ -531,12 +523,6 @@ static int aha1542_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
spin_unlock_irqrestore(sh->host_lock, flags);
return 0;
-out_free_chain:
- kfree(acmd->chain);
- acmd->chain = NULL;
-out_unmap:
- scsi_dma_unmap(cmd);
- return SCSI_MLQUEUE_HOST_BUSY;
}
/* Initialize mailboxes */
@@ -1027,6 +1013,27 @@ static int aha1542_biosparam(struct scsi_device *sdev,
}
MODULE_LICENSE("GPL");
+static int aha1542_init_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
+{
+ struct aha1542_cmd *acmd = scsi_cmd_priv(cmd);
+
+ acmd->data_buffer = dma_alloc_coherent(shost->dma_dev,
+ SECTOR_SIZE * AHA1542_MAX_SECTORS,
+ &acmd->data_buffer_handle, GFP_KERNEL);
+ if (!acmd->data_buffer)
+ return -ENOMEM;
+ return 0;
+}
+
+static int aha1542_exit_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
+{
+ struct aha1542_cmd *acmd = scsi_cmd_priv(cmd);
+
+ dma_free_coherent(shost->dma_dev, SECTOR_SIZE * AHA1542_MAX_SECTORS,
+ acmd->data_buffer, acmd->data_buffer_handle);
+ return 0;
+}
+
static struct scsi_host_template driver_template = {
.module = THIS_MODULE,
.proc_name = "aha1542",
@@ -1037,10 +1044,12 @@ static struct scsi_host_template driver_template = {
.eh_bus_reset_handler = aha1542_bus_reset,
.eh_host_reset_handler = aha1542_host_reset,
.bios_param = aha1542_biosparam,
+ .init_cmd_priv = aha1542_init_cmd_priv,
+ .exit_cmd_priv = aha1542_exit_cmd_priv,
.can_queue = AHA1542_MAILBOXES,
.this_id = 7,
- .sg_tablesize = 16,
- .unchecked_isa_dma = 1,
+ .max_sectors = AHA1542_MAX_SECTORS,
+ .sg_tablesize = SG_ALL,
};
static int aha1542_isa_match(struct device *pdev, unsigned int ndev)