Skip to content

Commit

Permalink
aha1542: use a local bounce buffer
Browse files Browse the repository at this point in the history
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 <[email protected]>
Acked-by: Martin K. Petersen <[email protected]>
Reviewed-by: Hannes Reinecke <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Jens Axboe <[email protected]>
  • Loading branch information
Christoph Hellwig authored and axboe committed Apr 6, 2021
1 parent 39aa56d commit 2f2fef0
Showing 1 changed file with 57 additions and 48 deletions.
105 changes: 57 additions & 48 deletions drivers/scsi/aha1542.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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;

Expand All @@ -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;
}
}

/*
Expand Down Expand Up @@ -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;
Expand All @@ -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 */
Expand Down Expand Up @@ -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",
Expand All @@ -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)
Expand Down

0 comments on commit 2f2fef0

Please sign in to comment.