scsi: aha1542: convert to DMA mapping API

aha1542 is one of the last users of the legacy isa_*_to_bus APIs, which
also isn't portable enough.  Convert it to the proper DMA mapping API.

Thanks to Ondrej Zary for testing and finding and fixing a crucial bug.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
Christoph Hellwig 2018-11-10 09:28:22 +01:00 committed by Martin K. Petersen
parent 469f72ddc6
commit 1794ef2b15
1 changed files with 91 additions and 35 deletions

View File

@ -58,8 +58,15 @@ struct aha1542_hostdata {
int aha1542_last_mbi_used; int aha1542_last_mbi_used;
int aha1542_last_mbo_used; int aha1542_last_mbo_used;
struct scsi_cmnd *int_cmds[AHA1542_MAILBOXES]; struct scsi_cmnd *int_cmds[AHA1542_MAILBOXES];
struct mailbox mb[2 * AHA1542_MAILBOXES]; struct mailbox *mb;
struct ccb ccb[AHA1542_MAILBOXES]; dma_addr_t mb_handle;
struct ccb *ccb;
dma_addr_t ccb_handle;
};
struct aha1542_cmd {
struct chain *chain;
dma_addr_t chain_handle;
}; };
static inline void aha1542_intr_reset(u16 base) static inline void aha1542_intr_reset(u16 base)
@ -233,6 +240,21 @@ static int aha1542_test_port(struct Scsi_Host *sh)
return 1; return 1;
} }
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);
}
acmd->chain = NULL;
scsi_dma_unmap(cmd);
}
static irqreturn_t aha1542_interrupt(int irq, void *dev_id) static irqreturn_t aha1542_interrupt(int irq, void *dev_id)
{ {
struct Scsi_Host *sh = dev_id; struct Scsi_Host *sh = dev_id;
@ -303,7 +325,7 @@ static irqreturn_t aha1542_interrupt(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
}; };
mbo = (scsi2int(mb[mbi].ccbptr) - (isa_virt_to_bus(&ccb[0]))) / sizeof(struct ccb); mbo = (scsi2int(mb[mbi].ccbptr) - aha1542->ccb_handle) / sizeof(struct ccb);
mbistatus = mb[mbi].status; mbistatus = mb[mbi].status;
mb[mbi].status = 0; mb[mbi].status = 0;
aha1542->aha1542_last_mbi_used = mbi; aha1542->aha1542_last_mbi_used = mbi;
@ -331,8 +353,7 @@ static irqreturn_t aha1542_interrupt(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
my_done = tmp_cmd->scsi_done; my_done = tmp_cmd->scsi_done;
kfree(tmp_cmd->host_scribble); aha1542_free_cmd(tmp_cmd);
tmp_cmd->host_scribble = NULL;
/* Fetch the sense data, and tuck it away, in the required slot. The /* Fetch the sense data, and tuck it away, in the required slot. The
Adaptec automatically fetches it, and there is no guarantee that Adaptec automatically fetches it, and there is no guarantee that
we will still have it in the cdb when we come back */ we will still have it in the cdb when we come back */
@ -369,6 +390,7 @@ static irqreturn_t aha1542_interrupt(int irq, void *dev_id)
static int aha1542_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *cmd) static int aha1542_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
{ {
struct aha1542_cmd *acmd = scsi_cmd_priv(cmd);
struct aha1542_hostdata *aha1542 = shost_priv(sh); struct aha1542_hostdata *aha1542 = shost_priv(sh);
u8 direction; u8 direction;
u8 target = cmd->device->id; u8 target = cmd->device->id;
@ -378,7 +400,6 @@ static int aha1542_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
int mbo, sg_count; int mbo, sg_count;
struct mailbox *mb = aha1542->mb; struct mailbox *mb = aha1542->mb;
struct ccb *ccb = aha1542->ccb; struct ccb *ccb = aha1542->ccb;
struct chain *cptr;
if (*cmd->cmnd == REQUEST_SENSE) { if (*cmd->cmnd == REQUEST_SENSE) {
/* Don't do the command - we have the sense data already */ /* Don't do the command - we have the sense data already */
@ -398,15 +419,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); print_hex_dump_bytes("command: ", DUMP_PREFIX_NONE, cmd->cmnd, cmd->cmd_len);
} }
#endif #endif
if (bufflen) { /* allocate memory before taking host_lock */ sg_count = scsi_dma_map(cmd);
sg_count = scsi_sg_count(cmd); if (sg_count) {
cptr = kmalloc_array(sg_count, sizeof(*cptr), size_t len = sg_count * sizeof(struct chain);
GFP_KERNEL | GFP_DMA);
if (!cptr) acmd->chain = kmalloc(len, GFP_DMA);
return SCSI_MLQUEUE_HOST_BUSY; if (!acmd->chain)
} else { goto out_unmap;
sg_count = 0; acmd->chain_handle = dma_map_single(sh->dma_dev, acmd->chain,
cptr = NULL; len, DMA_TO_DEVICE);
if (dma_mapping_error(sh->dma_dev, acmd->chain_handle))
goto out_free_chain;
} }
/* Use the outgoing mailboxes in a round-robin fashion, because this /* Use the outgoing mailboxes in a round-robin fashion, because this
@ -437,7 +460,8 @@ static int aha1542_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
shost_printk(KERN_DEBUG, sh, "Sending command (%d %p)...", mbo, cmd->scsi_done); shost_printk(KERN_DEBUG, sh, "Sending command (%d %p)...", mbo, cmd->scsi_done);
#endif #endif
any2scsi(mb[mbo].ccbptr, isa_virt_to_bus(&ccb[mbo])); /* This gets trashed for some reason */ /* This gets trashed for some reason */
any2scsi(mb[mbo].ccbptr, aha1542->ccb_handle + mbo * sizeof(*ccb));
memset(&ccb[mbo], 0, sizeof(struct ccb)); memset(&ccb[mbo], 0, sizeof(struct ccb));
@ -456,21 +480,18 @@ static int aha1542_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
int i; int i;
ccb[mbo].op = 2; /* SCSI Initiator Command w/scatter-gather */ ccb[mbo].op = 2; /* SCSI Initiator Command w/scatter-gather */
cmd->host_scribble = (void *)cptr;
scsi_for_each_sg(cmd, sg, sg_count, i) { scsi_for_each_sg(cmd, sg, sg_count, i) {
any2scsi(cptr[i].dataptr, isa_page_to_bus(sg_page(sg)) any2scsi(acmd->chain[i].dataptr, sg_dma_address(sg));
+ sg->offset); any2scsi(acmd->chain[i].datalen, sg_dma_len(sg));
any2scsi(cptr[i].datalen, sg->length);
}; };
any2scsi(ccb[mbo].datalen, sg_count * sizeof(struct chain)); any2scsi(ccb[mbo].datalen, sg_count * sizeof(struct chain));
any2scsi(ccb[mbo].dataptr, isa_virt_to_bus(cptr)); any2scsi(ccb[mbo].dataptr, acmd->chain_handle);
#ifdef DEBUG #ifdef DEBUG
shost_printk(KERN_DEBUG, sh, "cptr %p: ", cptr); shost_printk(KERN_DEBUG, sh, "cptr %p: ", acmd->chain);
print_hex_dump_bytes("cptr: ", DUMP_PREFIX_NONE, cptr, 18); print_hex_dump_bytes("cptr: ", DUMP_PREFIX_NONE, acmd->chain, 18);
#endif #endif
} else { } else {
ccb[mbo].op = 0; /* SCSI Initiator Command */ ccb[mbo].op = 0; /* SCSI Initiator Command */
cmd->host_scribble = NULL;
any2scsi(ccb[mbo].datalen, 0); any2scsi(ccb[mbo].datalen, 0);
any2scsi(ccb[mbo].dataptr, 0); any2scsi(ccb[mbo].dataptr, 0);
}; };
@ -488,24 +509,29 @@ static int aha1542_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
spin_unlock_irqrestore(sh->host_lock, flags); spin_unlock_irqrestore(sh->host_lock, flags);
return 0; return 0;
out_free_chain:
kfree(acmd->chain);
acmd->chain = NULL;
out_unmap:
scsi_dma_unmap(cmd);
return SCSI_MLQUEUE_HOST_BUSY;
} }
/* Initialize mailboxes */ /* Initialize mailboxes */
static void setup_mailboxes(struct Scsi_Host *sh) static void setup_mailboxes(struct Scsi_Host *sh)
{ {
struct aha1542_hostdata *aha1542 = shost_priv(sh); struct aha1542_hostdata *aha1542 = shost_priv(sh);
int i;
struct mailbox *mb = aha1542->mb;
struct ccb *ccb = aha1542->ccb;
u8 mb_cmd[5] = { CMD_MBINIT, AHA1542_MAILBOXES, 0, 0, 0}; u8 mb_cmd[5] = { CMD_MBINIT, AHA1542_MAILBOXES, 0, 0, 0};
int i;
for (i = 0; i < AHA1542_MAILBOXES; i++) { for (i = 0; i < AHA1542_MAILBOXES; i++) {
mb[i].status = mb[AHA1542_MAILBOXES + i].status = 0; aha1542->mb[i].status = 0;
any2scsi(mb[i].ccbptr, isa_virt_to_bus(&ccb[i])); any2scsi(aha1542->mb[i].ccbptr,
aha1542->ccb_handle + i * sizeof(struct ccb));
aha1542->mb[AHA1542_MAILBOXES + i].status = 0;
}; };
aha1542_intr_reset(sh->io_port); /* reset interrupts, so they don't block */ aha1542_intr_reset(sh->io_port); /* reset interrupts, so they don't block */
any2scsi((mb_cmd + 2), isa_virt_to_bus(mb)); any2scsi(mb_cmd + 2, aha1542->mb_handle);
if (aha1542_out(sh->io_port, mb_cmd, 5)) if (aha1542_out(sh->io_port, mb_cmd, 5))
shost_printk(KERN_ERR, sh, "failed setting up mailboxes\n"); shost_printk(KERN_ERR, sh, "failed setting up mailboxes\n");
aha1542_intr_reset(sh->io_port); aha1542_intr_reset(sh->io_port);
@ -739,11 +765,26 @@ static struct Scsi_Host *aha1542_hw_init(struct scsi_host_template *tpnt, struct
if (aha1542->bios_translation == BIOS_TRANSLATION_25563) if (aha1542->bios_translation == BIOS_TRANSLATION_25563)
shost_printk(KERN_INFO, sh, "Using extended bios translation\n"); shost_printk(KERN_INFO, sh, "Using extended bios translation\n");
if (dma_set_mask_and_coherent(pdev, DMA_BIT_MASK(24)) < 0)
goto unregister;
aha1542->mb = dma_alloc_coherent(pdev,
AHA1542_MAILBOXES * 2 * sizeof(struct mailbox),
&aha1542->mb_handle, GFP_KERNEL);
if (!aha1542->mb)
goto unregister;
aha1542->ccb = dma_alloc_coherent(pdev,
AHA1542_MAILBOXES * sizeof(struct ccb),
&aha1542->ccb_handle, GFP_KERNEL);
if (!aha1542->ccb)
goto free_mb;
setup_mailboxes(sh); setup_mailboxes(sh);
if (request_irq(sh->irq, aha1542_interrupt, 0, "aha1542", sh)) { if (request_irq(sh->irq, aha1542_interrupt, 0, "aha1542", sh)) {
shost_printk(KERN_ERR, sh, "Unable to allocate IRQ.\n"); shost_printk(KERN_ERR, sh, "Unable to allocate IRQ.\n");
goto unregister; goto free_ccb;
} }
if (sh->dma_channel != 0xFF) { if (sh->dma_channel != 0xFF) {
if (request_dma(sh->dma_channel, "aha1542")) { if (request_dma(sh->dma_channel, "aha1542")) {
@ -762,11 +803,18 @@ static struct Scsi_Host *aha1542_hw_init(struct scsi_host_template *tpnt, struct
scsi_scan_host(sh); scsi_scan_host(sh);
return sh; return sh;
free_dma: free_dma:
if (sh->dma_channel != 0xff) if (sh->dma_channel != 0xff)
free_dma(sh->dma_channel); free_dma(sh->dma_channel);
free_irq: free_irq:
free_irq(sh->irq, sh); free_irq(sh->irq, sh);
free_ccb:
dma_free_coherent(pdev, AHA1542_MAILBOXES * sizeof(struct ccb),
aha1542->ccb, aha1542->ccb_handle);
free_mb:
dma_free_coherent(pdev, AHA1542_MAILBOXES * 2 * sizeof(struct mailbox),
aha1542->mb, aha1542->mb_handle);
unregister: unregister:
scsi_host_put(sh); scsi_host_put(sh);
release: release:
@ -777,9 +825,16 @@ release:
static int aha1542_release(struct Scsi_Host *sh) static int aha1542_release(struct Scsi_Host *sh)
{ {
struct aha1542_hostdata *aha1542 = shost_priv(sh);
struct device *dev = sh->dma_dev;
scsi_remove_host(sh); scsi_remove_host(sh);
if (sh->dma_channel != 0xff) if (sh->dma_channel != 0xff)
free_dma(sh->dma_channel); free_dma(sh->dma_channel);
dma_free_coherent(dev, AHA1542_MAILBOXES * sizeof(struct ccb),
aha1542->ccb, aha1542->ccb_handle);
dma_free_coherent(dev, AHA1542_MAILBOXES * 2 * sizeof(struct mailbox),
aha1542->mb, aha1542->mb_handle);
if (sh->irq) if (sh->irq)
free_irq(sh->irq, sh); free_irq(sh->irq, sh);
if (sh->io_port && sh->n_io_port) if (sh->io_port && sh->n_io_port)
@ -826,7 +881,8 @@ static int aha1542_dev_reset(struct scsi_cmnd *cmd)
aha1542->aha1542_last_mbo_used = mbo; aha1542->aha1542_last_mbo_used = mbo;
any2scsi(mb[mbo].ccbptr, isa_virt_to_bus(&ccb[mbo])); /* This gets trashed for some reason */ /* This gets trashed for some reason */
any2scsi(mb[mbo].ccbptr, aha1542->ccb_handle + mbo * sizeof(*ccb));
memset(&ccb[mbo], 0, sizeof(struct ccb)); memset(&ccb[mbo], 0, sizeof(struct ccb));
@ -901,8 +957,7 @@ static int aha1542_reset(struct scsi_cmnd *cmd, u8 reset_cmd)
*/ */
continue; continue;
} }
kfree(tmp_cmd->host_scribble); aha1542_free_cmd(tmp_cmd);
tmp_cmd->host_scribble = NULL;
aha1542->int_cmds[i] = NULL; aha1542->int_cmds[i] = NULL;
aha1542->mb[i].status = 0; aha1542->mb[i].status = 0;
} }
@ -946,6 +1001,7 @@ static struct scsi_host_template driver_template = {
.module = THIS_MODULE, .module = THIS_MODULE,
.proc_name = "aha1542", .proc_name = "aha1542",
.name = "Adaptec 1542", .name = "Adaptec 1542",
.cmd_size = sizeof(struct aha1542_cmd),
.queuecommand = aha1542_queuecommand, .queuecommand = aha1542_queuecommand,
.eh_device_reset_handler= aha1542_dev_reset, .eh_device_reset_handler= aha1542_dev_reset,
.eh_bus_reset_handler = aha1542_bus_reset, .eh_bus_reset_handler = aha1542_bus_reset,