bk://gkernel.bkbits.net/libata-2.6 jgarzik@pobox.com|ChangeSet|20050218205104|53749 jgarzik # This is a BitKeeper generated diff -Nru style patch. # # ChangeSet # 2005/02/22 14:29:10-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-libata # # drivers/scsi/libata-core.c # 2005/02/22 14:29:05-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2005/02/18 15:49:44-05:00 linville@tuxdriver.com # [PATCH] libata: fix command queue leak when xlat_func fails # # ata_scsi_translate allocates from the libata command queue by calling # ata_scsi_qc_new. If xlat_func returns non-zero, control jumps to # err_out which fails to free the allocated command. Fix is to add a # new API to free unused commands. # # Signed-off-by: John W. Linville # Signed-off-by: Jeff Garzik # # drivers/scsi/libata.h # 2005/02/18 15:49:33-05:00 linville@tuxdriver.com +1 -0 # [PATCH] libata: fix command queue leak when xlat_func fails # # ata_scsi_translate allocates from the libata command queue by calling # ata_scsi_qc_new. If xlat_func returns non-zero, control jumps to # err_out which fails to free the allocated command. Fix is to add a # new API to free unused commands. # # Signed-off-by: John W. Linville # Signed-off-by: Jeff Garzik # # drivers/scsi/libata-scsi.c # 2005/02/18 15:49:33-05:00 linville@tuxdriver.com +1 -0 # [PATCH] libata: fix command queue leak when xlat_func fails # # ata_scsi_translate allocates from the libata command queue by calling # ata_scsi_qc_new. If xlat_func returns non-zero, control jumps to # err_out which fails to free the allocated command. Fix is to add a # new API to free unused commands. # # Signed-off-by: John W. Linville # Signed-off-by: Jeff Garzik # # drivers/scsi/libata-core.c # 2005/02/18 15:49:33-05:00 linville@tuxdriver.com +18 -0 # [PATCH] libata: fix command queue leak when xlat_func fails # # ata_scsi_translate allocates from the libata command queue by calling # ata_scsi_qc_new. If xlat_func returns non-zero, control jumps to # err_out which fails to free the allocated command. Fix is to add a # new API to free unused commands. # # Signed-off-by: John W. Linville # Signed-off-by: Jeff Garzik # # ChangeSet # 2005/02/17 19:43:54-05:00 jgarzik@pobox.com # Merge pobox.com:/garz/repo/libata-dev/bmdma-cb # into pobox.com:/garz/repo/libata-2.6 # # drivers/scsi/sata_vsc.c # 2005/02/17 19:43:51-05:00 jgarzik@pobox.com +0 -0 # Auto merged # # drivers/scsi/sata_via.c # 2005/02/17 19:43:51-05:00 jgarzik@pobox.com +0 -0 # Auto merged # # drivers/scsi/sata_uli.c # 2005/02/17 19:43:51-05:00 jgarzik@pobox.com +0 -0 # Auto merged # # drivers/scsi/sata_svw.c # 2005/02/17 19:43:51-05:00 jgarzik@pobox.com +0 -0 # Auto merged # # drivers/scsi/sata_sis.c # 2005/02/17 19:43:51-05:00 jgarzik@pobox.com +0 -0 # Auto merged # # drivers/scsi/sata_sil.c # 2005/02/17 19:43:51-05:00 jgarzik@pobox.com +0 -0 # Auto merged # # drivers/scsi/sata_nv.c # 2005/02/17 19:43:51-05:00 jgarzik@pobox.com +0 -0 # Auto merged # # drivers/scsi/libata-core.c # 2005/02/17 19:43:51-05:00 jgarzik@pobox.com +0 -0 # Auto merged # # ChangeSet # 2005/02/17 19:29:23-05:00 Mat.Loikkanen@synopsys.com # [libata] add ->bmdma_{stop,status} hooks # # The timeout/error handling path was assuming that the hardware in # question was PCI IDE BMDMA-like, which is incorrect in a few cases. # # Turn direct function calls into two new hooks. # # include/linux/libata.h # 2005/02/17 19:29:16-05:00 Mat.Loikkanen@synopsys.com +5 -40 # [libata] add ->bmdma_{stop,status} hooks # # The timeout/error handling path was assuming that the hardware in # question was PCI IDE BMDMA-like, which is incorrect in a few cases. # # Turn direct function calls into two new hooks. # # drivers/scsi/sata_vsc.c # 2005/02/17 19:29:16-05:00 Mat.Loikkanen@synopsys.com +2 -0 # [libata] add ->bmdma_{stop,status} hooks # # The timeout/error handling path was assuming that the hardware in # question was PCI IDE BMDMA-like, which is incorrect in a few cases. # # Turn direct function calls into two new hooks. # # drivers/scsi/sata_via.c # 2005/02/17 19:29:16-05:00 Mat.Loikkanen@synopsys.com +3 -0 # [libata] add ->bmdma_{stop,status} hooks # # The timeout/error handling path was assuming that the hardware in # question was PCI IDE BMDMA-like, which is incorrect in a few cases. # # Turn direct function calls into two new hooks. # # drivers/scsi/sata_uli.c # 2005/02/17 19:29:16-05:00 Mat.Loikkanen@synopsys.com +2 -0 # [libata] add ->bmdma_{stop,status} hooks # # The timeout/error handling path was assuming that the hardware in # question was PCI IDE BMDMA-like, which is incorrect in a few cases. # # Turn direct function calls into two new hooks. # # drivers/scsi/sata_svw.c # 2005/02/17 19:29:16-05:00 Mat.Loikkanen@synopsys.com +2 -0 # [libata] add ->bmdma_{stop,status} hooks # # The timeout/error handling path was assuming that the hardware in # question was PCI IDE BMDMA-like, which is incorrect in a few cases. # # Turn direct function calls into two new hooks. # # drivers/scsi/sata_sis.c # 2005/02/17 19:29:16-05:00 Mat.Loikkanen@synopsys.com +2 -0 # [libata] add ->bmdma_{stop,status} hooks # # The timeout/error handling path was assuming that the hardware in # question was PCI IDE BMDMA-like, which is incorrect in a few cases. # # Turn direct function calls into two new hooks. # # drivers/scsi/sata_sil.c # 2005/02/17 19:29:16-05:00 Mat.Loikkanen@synopsys.com +2 -0 # [libata] add ->bmdma_{stop,status} hooks # # The timeout/error handling path was assuming that the hardware in # question was PCI IDE BMDMA-like, which is incorrect in a few cases. # # Turn direct function calls into two new hooks. # # drivers/scsi/sata_nv.c # 2005/02/17 19:29:16-05:00 Mat.Loikkanen@synopsys.com +2 -0 # [libata] add ->bmdma_{stop,status} hooks # # The timeout/error handling path was assuming that the hardware in # question was PCI IDE BMDMA-like, which is incorrect in a few cases. # # Turn direct function calls into two new hooks. # # drivers/scsi/libata-core.c # 2005/02/17 19:29:16-05:00 Mat.Loikkanen@synopsys.com +45 -7 # [libata] add ->bmdma_{stop,status} hooks # # The timeout/error handling path was assuming that the hardware in # question was PCI IDE BMDMA-like, which is incorrect in a few cases. # # Turn direct function calls into two new hooks. # # drivers/scsi/ata_piix.c # 2005/02/17 19:29:16-05:00 Mat.Loikkanen@synopsys.com +4 -0 # [libata] add ->bmdma_{stop,status} hooks # # The timeout/error handling path was assuming that the hardware in # question was PCI IDE BMDMA-like, which is incorrect in a few cases. # # Turn direct function calls into two new hooks. # # ChangeSet # 2005/02/17 01:15:16-05:00 lsml@rtr.ca # [PATCH] sata_qstor: new basic driver for Pacific Digital # # This is a new basic libata SATA driver # for the Pacific Digital QStor SATA/RAID card. # # It features ordinary per-drive SATA with single-request DMA # for R/W commands, and PIO for everything else. # # It currently does not implement any of the hardware RAID support, # nor hot-plug, nor the tagged/native command-queuing features. # # On the other hand, it is small and simple as a result. # # Signed-off-by: Mark Lord # Signed-off-by: Jeff Garzik # # drivers/scsi/sata_qstor.c # 2005/02/16 20:25:01-05:00 lsml@rtr.ca +700 -0 # sata_qstor: new basic driver for Pacific Digital # # drivers/scsi/sata_qstor.c # 2005/02/16 20:25:01-05:00 lsml@rtr.ca +0 -0 # BitKeeper file /garz/repo/libata-dev/qstor/drivers/scsi/sata_qstor.c # # drivers/scsi/Makefile # 2005/02/16 20:29:23-05:00 lsml@rtr.ca +1 -0 # sata_qstor: new basic driver for Pacific Digital # # drivers/scsi/Kconfig # 2005/02/16 20:29:23-05:00 lsml@rtr.ca +8 -0 # sata_qstor: new basic driver for Pacific Digital # # ChangeSet # 2005/02/14 01:28:57-08:00 akpm@bix.(none) # Merge bk://gkernel.bkbits.net/libata-2.6 # into bix.(none):/usr/src/bk-libata # # drivers/scsi/ahci.c # 2005/02/14 01:28:51-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2005/02/13 19:58:07-05:00 jgarzik@pobox.com # [libata] do not call pci_disable_device() for certain errors # # If PCI request regions fails, then someone else is using the # hardware we wish to use. For that one case, calling pci_disable_device() # is rather rude. # # drivers/scsi/sata_vsc.c # 2005/02/13 19:58:01-05:00 jgarzik@pobox.com +6 -2 # [libata] do not call pci_disable_device() for certain errors # # If PCI request regions fails, then someone else is using the # hardware we wish to use. For that one case, calling pci_disable_device() # is rather rude. # # drivers/scsi/sata_via.c # 2005/02/13 19:58:01-05:00 jgarzik@pobox.com +6 -2 # [libata] do not call pci_disable_device() for certain errors # # If PCI request regions fails, then someone else is using the # hardware we wish to use. For that one case, calling pci_disable_device() # is rather rude. # # drivers/scsi/sata_uli.c # 2005/02/13 19:58:01-05:00 jgarzik@pobox.com +6 -2 # [libata] do not call pci_disable_device() for certain errors # # If PCI request regions fails, then someone else is using the # hardware we wish to use. For that one case, calling pci_disable_device() # is rather rude. # # drivers/scsi/sata_sx4.c # 2005/02/13 19:58:01-05:00 jgarzik@pobox.com +6 -2 # [libata] do not call pci_disable_device() for certain errors # # If PCI request regions fails, then someone else is using the # hardware we wish to use. For that one case, calling pci_disable_device() # is rather rude. # # drivers/scsi/sata_svw.c # 2005/02/13 19:58:01-05:00 jgarzik@pobox.com +6 -2 # [libata] do not call pci_disable_device() for certain errors # # If PCI request regions fails, then someone else is using the # hardware we wish to use. For that one case, calling pci_disable_device() # is rather rude. # # drivers/scsi/sata_sis.c # 2005/02/13 19:58:01-05:00 jgarzik@pobox.com +6 -2 # [libata] do not call pci_disable_device() for certain errors # # If PCI request regions fails, then someone else is using the # hardware we wish to use. For that one case, calling pci_disable_device() # is rather rude. # # drivers/scsi/sata_sil.c # 2005/02/13 19:58:01-05:00 jgarzik@pobox.com +6 -2 # [libata] do not call pci_disable_device() for certain errors # # If PCI request regions fails, then someone else is using the # hardware we wish to use. For that one case, calling pci_disable_device() # is rather rude. # # drivers/scsi/sata_promise.c # 2005/02/13 19:58:01-05:00 jgarzik@pobox.com +6 -2 # [libata] do not call pci_disable_device() for certain errors # # If PCI request regions fails, then someone else is using the # hardware we wish to use. For that one case, calling pci_disable_device() # is rather rude. # # drivers/scsi/sata_nv.c # 2005/02/13 19:58:01-05:00 jgarzik@pobox.com +6 -2 # [libata] do not call pci_disable_device() for certain errors # # If PCI request regions fails, then someone else is using the # hardware we wish to use. For that one case, calling pci_disable_device() # is rather rude. # # drivers/scsi/libata-core.c # 2005/02/13 19:58:01-05:00 jgarzik@pobox.com +12 -4 # [libata] do not call pci_disable_device() for certain errors # # If PCI request regions fails, then someone else is using the # hardware we wish to use. For that one case, calling pci_disable_device() # is rather rude. # # drivers/scsi/ahci.c # 2005/02/13 19:58:01-05:00 jgarzik@pobox.com +6 -2 # [libata] do not call pci_disable_device() for certain errors # # If PCI request regions fails, then someone else is using the # hardware we wish to use. For that one case, calling pci_disable_device() # is rather rude. # # ChangeSet # 2005/02/07 14:47:54-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-libata # # drivers/scsi/ahci.c # 2005/02/07 14:47:48-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2005/02/03 12:14:36-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-libata # # drivers/pci/quirks.c # 2005/02/03 12:14:32-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2005/01/27 20:11:35-08:00 akpm@bix.(none) # Merge bk://gkernel.bkbits.net/libata-2.6 # into bix.(none):/usr/src/bk-libata # # drivers/scsi/ahci.c # 2005/01/27 20:11:29-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2005/01/10 14:23:34-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-libata # # drivers/pci/quirks.c # 2005/01/10 14:23:30-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2005/01/08 20:52:09-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-libata # # drivers/scsi/ahci.c # 2005/01/08 20:52:04-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/pci/quirks.c # 2005/01/08 20:52:04-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2005/01/08 18:28:34-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-libata # # drivers/scsi/ahci.c # 2005/01/08 18:28:24-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2005/01/07 14:18:26-08:00 akpm@bix.(none) # Merge bk://gkernel.bkbits.net/libata-2.6 # into bix.(none):/usr/src/bk-libata # # drivers/pci/quirks.c # 2005/01/07 14:18:21-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/11/16 01:35:17-05:00 jgarzik@pobox.com # [libata sata_via] add support for VT6421 SATA # # drivers/scsi/sata_via.c # 2004/11/16 01:35:11-05:00 jgarzik@pobox.com +84 -10 # [libata sata_via] add support for VT6421 SATA # # ChangeSet # 2004/11/16 01:31:58-05:00 jgarzik@pobox.com # [libata sata_via] minor cleanups # # Preparation for addition of VT6421 support. Mostly moving bits # of code into discrete functions. # # drivers/scsi/sata_via.c # 2004/11/16 01:31:52-05:00 jgarzik@pobox.com +67 -47 # [libata sata_via] minor cleanups # # Preparation for addition of VT6421 support. Mostly moving bits # of code into discrete functions. # diff -Nru a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig --- a/drivers/scsi/Kconfig 2005-02-22 18:15:48 -08:00 +++ b/drivers/scsi/Kconfig 2005-02-22 18:15:48 -08:00 @@ -457,6 +457,14 @@ If unsure, say N. +config SCSI_SATA_QSTOR + tristate "Pacific Digital SATA QStor support" + depends on SCSI_SATA && PCI + help + This option enables support for Pacific Digital Serial ATA QStor. + + If unsure, say N. + config SCSI_SATA_SX4 tristate "Promise SATA SX4 support" depends on SCSI_SATA && PCI && EXPERIMENTAL diff -Nru a/drivers/scsi/Makefile b/drivers/scsi/Makefile --- a/drivers/scsi/Makefile 2005-02-22 18:15:48 -08:00 +++ b/drivers/scsi/Makefile 2005-02-22 18:15:48 -08:00 @@ -125,6 +125,7 @@ obj-$(CONFIG_SCSI_SATA_SVW) += libata.o sata_svw.o obj-$(CONFIG_SCSI_ATA_PIIX) += libata.o ata_piix.o obj-$(CONFIG_SCSI_SATA_PROMISE) += libata.o sata_promise.o +obj-$(CONFIG_SCSI_SATA_QSTOR) += libata.o sata_qstor.o obj-$(CONFIG_SCSI_SATA_SIL) += libata.o sata_sil.o obj-$(CONFIG_SCSI_SATA_VIA) += libata.o sata_via.o obj-$(CONFIG_SCSI_SATA_VITESSE) += libata.o sata_vsc.o diff -Nru a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c --- a/drivers/scsi/ahci.c 2005-02-22 18:15:48 -08:00 +++ b/drivers/scsi/ahci.c 2005-02-22 18:15:48 -08:00 @@ -940,6 +940,7 @@ unsigned long base; void *mmio_base; unsigned int board_idx = (unsigned int) ent->driver_data; + int pci_dev_busy = 0; int rc; VPRINTK("ENTER\n"); @@ -952,8 +953,10 @@ return rc; rc = pci_request_regions(pdev, DRV_NAME); - if (rc) + if (rc) { + pci_dev_busy = 1; goto err_out; + } pci_enable_intx(pdev); @@ -1015,7 +1018,8 @@ err_out_regions: pci_release_regions(pdev); err_out: - pci_disable_device(pdev); + if (!pci_dev_busy) + pci_disable_device(pdev); return rc; } diff -Nru a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c --- a/drivers/scsi/ata_piix.c 2005-02-22 18:15:48 -08:00 +++ b/drivers/scsi/ata_piix.c 2005-02-22 18:15:48 -08:00 @@ -138,6 +138,8 @@ .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, + .bmdma_stop = ata_bmdma_stop, + .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, @@ -163,6 +165,8 @@ .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, + .bmdma_stop = ata_bmdma_stop, + .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, diff -Nru a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c --- a/drivers/scsi/libata-core.c 2005-02-22 18:15:48 -08:00 +++ b/drivers/scsi/libata-core.c 2005-02-22 18:15:48 -08:00 @@ -2601,10 +2601,10 @@ case ATA_PROT_DMA: case ATA_PROT_ATAPI_DMA: - host_stat = ata_bmdma_status(ap); + host_stat = ap->ops->bmdma_status(ap); /* before we do anything else, clear DMA-Start bit */ - ata_bmdma_stop(ap); + ap->ops->bmdma_stop(ap); /* fall through */ @@ -2613,7 +2613,7 @@ drv_stat = ata_chk_status(ap); /* ack bmdma irq events */ - ata_bmdma_ack_irq(ap); + ap->ops->irq_clear(ap); printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x host_stat 0x%x\n", ap->id, qc->tf.command, drv_stat, host_stat); @@ -2752,6 +2752,24 @@ } /** + * ata_qc_free - free unused ata_queued_cmd + * @qc: Command to complete + * + * Designed to free unused ata_queued_cmd object + * in case something prevents using it. + * + * LOCKING: + * + */ +void ata_qc_free(struct ata_queued_cmd *qc) +{ + assert(qc != NULL); /* ata_qc_from_tag _might_ return NULL */ + assert(qc->waiting == NULL); /* nothing should be waiting */ + + __ata_qc_complete(qc); +} + +/** * ata_qc_complete - Complete an active ATA command * @qc: Command to complete * @drv_stat: ATA status register contents @@ -3042,7 +3060,43 @@ void ata_bmdma_irq_clear(struct ata_port *ap) { - ata_bmdma_ack_irq(ap); + if (ap->flags & ATA_FLAG_MMIO) { + void __iomem *mmio = ((void __iomem *) ap->ioaddr.bmdma_addr) + ATA_DMA_STATUS; + writeb(readb(mmio), mmio); + } else { + unsigned long addr = ap->ioaddr.bmdma_addr + ATA_DMA_STATUS; + outb(inb(addr), addr); + } + +} + +u8 ata_bmdma_status(struct ata_port *ap) +{ + u8 host_stat; + if (ap->flags & ATA_FLAG_MMIO) { + void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr; + host_stat = readb(mmio + ATA_DMA_STATUS); + } else + host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); + return host_stat; +} + +void ata_bmdma_stop(struct ata_port *ap) +{ + if (ap->flags & ATA_FLAG_MMIO) { + void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr; + + /* clear start/stop bit */ + writeb(readb(mmio + ATA_DMA_CMD) & ~ATA_DMA_START, + mmio + ATA_DMA_CMD); + } else { + /* clear start/stop bit */ + outb(inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD) & ~ATA_DMA_START, + ap->ioaddr.bmdma_addr + ATA_DMA_CMD); + } + + /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */ + ata_altstatus(ap); /* dummy read */ } /** @@ -3072,7 +3126,7 @@ case ATA_PROT_ATAPI_DMA: case ATA_PROT_ATAPI: /* check status of DMA engine */ - host_stat = ata_bmdma_status(ap); + host_stat = ap->ops->bmdma_status(ap); VPRINTK("ata%u: host_stat 0x%X\n", ap->id, host_stat); /* if it's not our irq... */ @@ -3080,7 +3134,7 @@ goto idle_irq; /* before we do anything else, clear DMA-Start bit */ - ata_bmdma_stop(ap); + ap->ops->bmdma_stop(ap); /* fall through */ @@ -3099,7 +3153,7 @@ ap->id, qc->tf.protocol, status); /* ack bmdma irq events */ - ata_bmdma_ack_irq(ap); + ap->ops->irq_clear(ap); /* complete taskfile transaction */ ata_qc_complete(qc, status); @@ -3656,6 +3710,7 @@ struct ata_port_info *port[2]; u8 tmp8, mask; unsigned int legacy_mode = 0; + int disable_dev_on_err = 1; int rc; DPRINTK("ENTER\n"); @@ -3686,8 +3741,10 @@ return rc; rc = pci_request_regions(pdev, DRV_NAME); - if (rc) + if (rc) { + disable_dev_on_err = 0; goto err_out; + } if (legacy_mode) { if (!request_region(0x1f0, 8, "libata")) { @@ -3697,8 +3754,10 @@ conflict = ____request_resource(&ioport_resource, &res); if (!strcmp(conflict->name, "libata")) legacy_mode |= (1 << 0); - else + else { + disable_dev_on_err = 0; printk(KERN_WARNING "ata: 0x1f0 IDE port busy\n"); + } } else legacy_mode |= (1 << 0); @@ -3709,8 +3768,10 @@ conflict = ____request_resource(&ioport_resource, &res); if (!strcmp(conflict->name, "libata")) legacy_mode |= (1 << 1); - else + else { + disable_dev_on_err = 0; printk(KERN_WARNING "ata: 0x170 IDE port busy\n"); + } } else legacy_mode |= (1 << 1); } @@ -3760,7 +3821,8 @@ release_region(0x170, 8); pci_release_regions(pdev); err_out: - pci_disable_device(pdev); + if (disable_dev_on_err) + pci_disable_device(pdev); return rc; } @@ -3918,6 +3980,8 @@ EXPORT_SYMBOL_GPL(ata_bmdma_setup); EXPORT_SYMBOL_GPL(ata_bmdma_start); EXPORT_SYMBOL_GPL(ata_bmdma_irq_clear); +EXPORT_SYMBOL_GPL(ata_bmdma_status); +EXPORT_SYMBOL_GPL(ata_bmdma_stop); EXPORT_SYMBOL_GPL(ata_port_probe); EXPORT_SYMBOL_GPL(sata_phy_reset); EXPORT_SYMBOL_GPL(__sata_phy_reset); diff -Nru a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c --- a/drivers/scsi/libata-scsi.c 2005-02-22 18:15:48 -08:00 +++ b/drivers/scsi/libata-scsi.c 2005-02-22 18:15:48 -08:00 @@ -701,6 +701,7 @@ return; err_out: + ata_qc_free(qc); ata_bad_cdb(cmd, done); DPRINTK("EXIT - badcmd\n"); } diff -Nru a/drivers/scsi/libata.h b/drivers/scsi/libata.h --- a/drivers/scsi/libata.h 2005-02-22 18:15:48 -08:00 +++ b/drivers/scsi/libata.h 2005-02-22 18:15:48 -08:00 @@ -37,6 +37,7 @@ /* libata-core.c */ extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap, struct ata_device *dev); +extern void ata_qc_free(struct ata_queued_cmd *qc); extern int ata_qc_issue(struct ata_queued_cmd *qc); extern int ata_check_atapi_dma(struct ata_queued_cmd *qc); extern void ata_dev_select(struct ata_port *ap, unsigned int device, diff -Nru a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c --- a/drivers/scsi/sata_nv.c 2005-02-22 18:15:48 -08:00 +++ b/drivers/scsi/sata_nv.c 2005-02-22 18:15:48 -08:00 @@ -217,6 +217,8 @@ .phy_reset = sata_phy_reset, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, + .bmdma_stop = ata_bmdma_stop, + .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, .eng_timeout = ata_eng_timeout, @@ -332,6 +334,7 @@ struct nv_host *host; struct ata_port_info *ppi; struct ata_probe_ent *probe_ent; + int pci_dev_busy = 0; int rc; u32 bar; @@ -350,8 +353,10 @@ goto err_out; rc = pci_request_regions(pdev, DRV_NAME); - if (rc) + if (rc) { + pci_dev_busy = 1; goto err_out_disable; + } rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) @@ -427,7 +432,8 @@ err_out_regions: pci_release_regions(pdev); err_out_disable: - pci_disable_device(pdev); + if (!pci_dev_busy) + pci_disable_device(pdev); err_out: return rc; } diff -Nru a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c --- a/drivers/scsi/sata_promise.c 2005-02-22 18:15:48 -08:00 +++ b/drivers/scsi/sata_promise.c 2005-02-22 18:15:48 -08:00 @@ -556,6 +556,7 @@ unsigned long base; void *mmio_base; unsigned int board_idx = (unsigned int) ent->driver_data; + int pci_dev_busy = 0; int rc; if (!printed_version++) @@ -570,8 +571,10 @@ return rc; rc = pci_request_regions(pdev, DRV_NAME); - if (rc) + if (rc) { + pci_dev_busy = 1; goto err_out; + } rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) @@ -650,7 +653,8 @@ err_out_regions: pci_release_regions(pdev); err_out: - pci_disable_device(pdev); + if (!pci_dev_busy) + pci_disable_device(pdev); return rc; } diff -Nru a/drivers/scsi/sata_qstor.c b/drivers/scsi/sata_qstor.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/scsi/sata_qstor.c 2005-02-22 18:15:48 -08:00 @@ -0,0 +1,700 @@ +/* + * sata_qstor.c - Pacific Digital Corporation QStor SATA + * + * Maintained by: Mark Lord + * + * Copyright 2005 Pacific Digital Corporation. + * (OSL/GPL code release authorized by Jalil Fadavi). + * + * The contents of this file are subject to the Open + * Software License version 1.1 that can be found at + * http://www.opensource.org/licenses/osl-1.1.txt and is included herein + * by reference. + * + * Alternatively, the contents of this file may be used under the terms + * of the GNU General Public License version 2 (the "GPL") as distributed + * in the kernel source COPYING file, in which case the provisions of + * the GPL are applicable instead of the above. If you wish to allow + * the use of your version of this file only under the terms of the + * GPL and not to allow others to use your version of this file under + * the OSL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the GPL. + * If you do not delete the provisions above, a recipient may use your + * version of this file under either the OSL or the GPL. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "scsi.h" +#include +#include +#include + +#define DRV_NAME "sata_qstor" +#define DRV_VERSION "0.03" + +enum { + QS_PORTS = 4, + QS_MAX_PRD = LIBATA_MAX_PRD, + QS_CPB_ORDER = 6, + QS_CPB_BYTES = (1 << QS_CPB_ORDER), + QS_PRD_BYTES = QS_MAX_PRD * 16, + QS_PKT_BYTES = QS_CPB_BYTES + QS_PRD_BYTES, + + QS_DMA_BOUNDARY = ~0UL, + + /* global register offsets */ + QS_HCF_CNFG3 = 0x0003, /* host configuration offset */ + QS_HID_HPHY = 0x0004, /* host physical interface info */ + QS_HCT_CTRL = 0x00e4, /* global interrupt mask offset */ + QS_HST_SFF = 0x0100, /* host status fifo offset */ + QS_HVS_SERD3 = 0x0393, /* PHY enable offset */ + + /* global control bits */ + QS_HPHY_64BIT = (1 << 1), /* 64-bit bus detected */ + QS_CNFG3_GSRST = 0x01, /* global chip reset */ + QS_SERD3_PHY_ENA = 0xf0, /* PHY detection ENAble*/ + + /* per-channel register offsets */ + QS_CCF_CPBA = 0x0710, /* chan CPB base address */ + QS_CCF_CSEP = 0x0718, /* chan CPB separation factor */ + QS_CFC_HUFT = 0x0800, /* host upstream fifo threshold */ + QS_CFC_HDFT = 0x0804, /* host downstream fifo threshold */ + QS_CFC_DUFT = 0x0808, /* dev upstream fifo threshold */ + QS_CFC_DDFT = 0x080c, /* dev downstream fifo threshold */ + QS_CCT_CTR0 = 0x0900, /* chan control-0 offset */ + QS_CCT_CTR1 = 0x0901, /* chan control-1 offset */ + QS_CCT_CFF = 0x0a00, /* chan command fifo offset */ + + /* channel control bits */ + QS_CTR0_REG = (1 << 1), /* register mode (vs. pkt mode) */ + QS_CTR0_CLER = (1 << 2), /* clear channel errors */ + QS_CTR1_RDEV = (1 << 1), /* sata phy/comms reset */ + QS_CTR1_RCHN = (1 << 4), /* reset channel logic */ + QS_CCF_RUN_PKT = 0x107, /* RUN a new dma PKT */ + + /* pkt sub-field headers */ + QS_HCB_HDR = 0x01, /* Host Control Block header */ + QS_DCB_HDR = 0x02, /* Device Control Block header */ + + /* pkt HCB flag bits */ + QS_HF_DIRO = (1 << 0), /* data DIRection Out */ + QS_HF_DAT = (1 << 3), /* DATa pkt */ + QS_HF_IEN = (1 << 4), /* Interrupt ENable */ + QS_HF_VLD = (1 << 5), /* VaLiD pkt */ + + /* pkt DCB flag bits */ + QS_DF_PORD = (1 << 2), /* Pio OR Dma */ + QS_DF_ELBA = (1 << 3), /* Extended LBA (lba48) */ + + /* PCI device IDs */ + board_2068_idx = 0, /* QStor 4-port SATA/RAID */ +}; + +typedef enum { qs_state_idle, qs_state_pkt, qs_state_mmio } qs_state_t; + +struct qs_port_priv { + u8 *pkt; + dma_addr_t pkt_dma; + qs_state_t state; +}; + +static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg); +static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); +static int qs_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); +static irqreturn_t qs_intr (int irq, void *dev_instance, struct pt_regs *regs); +static int qs_port_start(struct ata_port *ap); +static void qs_host_stop(struct ata_host_set *host_set); +static void qs_port_stop(struct ata_port *ap); +static void qs_phy_reset(struct ata_port *ap); +static void qs_qc_prep(struct ata_queued_cmd *qc); +static int qs_qc_issue(struct ata_queued_cmd *qc); +static int qs_check_atapi_dma(struct ata_queued_cmd *qc); +static void qs_bmdma_stop(struct ata_port *ap); +static u8 qs_bmdma_status(struct ata_port *ap); +static void qs_irq_clear(struct ata_port *ap); + +static Scsi_Host_Template qs_ata_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .eh_strategy_handler = ata_scsi_error, + .can_queue = ATA_DEF_QUEUE, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = QS_MAX_PRD, + .max_sectors = ATA_MAX_SECTORS, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .emulated = ATA_SHT_EMULATED, + //FIXME .use_clustering = ATA_SHT_USE_CLUSTERING, + .use_clustering = ENABLE_CLUSTERING, + .proc_name = DRV_NAME, + .dma_boundary = QS_DMA_BOUNDARY, + .slave_configure = ata_scsi_slave_config, + .bios_param = ata_std_bios_param, +}; + +static struct ata_port_operations qs_ata_ops = { + .port_disable = ata_port_disable, + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .check_atapi_dma = qs_check_atapi_dma, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, + .phy_reset = qs_phy_reset, + .qc_prep = qs_qc_prep, + .qc_issue = qs_qc_issue, + .eng_timeout = ata_eng_timeout, + .irq_handler = qs_intr, + .irq_clear = qs_irq_clear, + .scr_read = qs_scr_read, + .scr_write = qs_scr_write, + .port_start = qs_port_start, + .port_stop = qs_port_stop, + .host_stop = qs_host_stop, + .bmdma_stop = qs_bmdma_stop, + .bmdma_status = qs_bmdma_status, +}; + +static struct ata_port_info qs_port_info[] = { + /* board_2068_idx */ + { + .sht = &qs_ata_sht, + .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_SATA_RESET | + //FIXME ATA_FLAG_SRST | + ATA_FLAG_MMIO, + .pio_mask = 0x10, /* pio4 */ + .udma_mask = 0x7f, /* udma0-6 */ + .port_ops = &qs_ata_ops, + }, +}; + +static struct pci_device_id qs_ata_pci_tbl[] = { + { PCI_VENDOR_ID_PDC, 0x2068, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + board_2068_idx }, + + { } /* terminate list */ +}; + +static struct pci_driver qs_ata_pci_driver = { + .name = DRV_NAME, + .id_table = qs_ata_pci_tbl, + .probe = qs_ata_init_one, + .remove = ata_pci_remove_one, +}; + +static int qs_check_atapi_dma(struct ata_queued_cmd *qc) +{ + return 1; /* ATAPI DMA not supported */ +} + +static void qs_bmdma_stop(struct ata_port *ap) +{ + /* nothing */ +} + +static u8 qs_bmdma_status(struct ata_port *ap) +{ + return 0; +} + +static void qs_irq_clear(struct ata_port *ap) +{ + /* nothing */ +} + +static void qs_enter_reg_mode(struct ata_port *ap) +{ + u8 __iomem *chan = ap->host_set->mmio_base + (ap->port_no * 0x4000); + + writeb(QS_CTR0_REG, chan + QS_CCT_CTR0); + readb(chan + QS_CCT_CTR0); /* flush */ +} + +static void qs_phy_reset(struct ata_port *ap) +{ + u8 __iomem *chan = ap->host_set->mmio_base + (ap->port_no * 0x4000); + struct qs_port_priv *pp = ap->private_data; + + pp->state = qs_state_idle; + writeb(QS_CTR1_RCHN, chan + QS_CCT_CTR1); + qs_enter_reg_mode(ap); + sata_phy_reset(ap); +} + +static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg) +{ + if (sc_reg > SCR_CONTROL) + return ~0U; + return readl((void __iomem *)(ap->ioaddr.scr_addr + (sc_reg * 8))); +} + +static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) +{ + if (sc_reg > SCR_CONTROL) + return; + writel(val, (void __iomem *)(ap->ioaddr.scr_addr + (sc_reg * 8))); +} + +static void qs_fill_sg(struct ata_queued_cmd *qc) +{ + struct scatterlist *sg = qc->sg; + struct ata_port *ap = qc->ap; + struct qs_port_priv *pp = ap->private_data; + unsigned int nelem; + u8 *prd = pp->pkt + QS_CPB_BYTES; + + assert(sg != NULL); + assert(qc->n_elem > 0); + + for (nelem = 0; nelem < qc->n_elem; nelem++,sg++) { + u64 addr; + u32 len; + + addr = sg_dma_address(sg); + *(u64 *)prd = cpu_to_le64(addr); + prd += sizeof(u64); + + len = sg_dma_len(sg); + *(u32 *)prd = cpu_to_le32(len); + prd += sizeof(u64); + + VPRINTK("PRD[%u] = (0x%llX, 0x%X)\n", nelem, + (unsigned long long)addr, len); + } +} + +static void qs_qc_prep(struct ata_queued_cmd *qc) +{ + struct qs_port_priv *pp = qc->ap->private_data; + u8 dflags = QS_DF_PORD, *buf = pp->pkt; + u8 hflags = QS_HF_DAT | QS_HF_IEN | QS_HF_VLD; + u64 addr; + + VPRINTK("ENTER\n"); + + qs_enter_reg_mode(qc->ap); + if (qc->tf.protocol != ATA_PROT_DMA) { + ata_qc_prep(qc); + return; + } + + qs_fill_sg(qc); + + if ((qc->tf.flags & ATA_TFLAG_WRITE)) + hflags |= QS_HF_DIRO; + if ((qc->tf.flags & ATA_TFLAG_LBA48)) + dflags |= QS_DF_ELBA; + + /* host control block (HCB) */ + buf[ 0] = QS_HCB_HDR; + buf[ 1] = hflags; + *(u32 *)(&buf[ 4]) = cpu_to_le32(qc->nsect * ATA_SECT_SIZE); + *(u32 *)(&buf[ 8]) = cpu_to_le32(qc->n_elem); + addr = ((u64)pp->pkt_dma) + QS_CPB_BYTES; + *(u64 *)(&buf[16]) = cpu_to_le64(addr); + + /* device control block (DCB) */ + buf[24] = QS_DCB_HDR; + buf[28] = dflags; + + /* frame information structure (FIS) */ + ata_tf_to_fis(&qc->tf, &buf[32], 0); +} + +static inline void qs_packet_start(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + u8 __iomem *chan = ap->host_set->mmio_base + (ap->port_no * 0x4000); + + VPRINTK("ENTER, ap %p\n", ap); + + writeb(QS_CTR0_CLER, chan + QS_CCT_CTR0); + wmb(); /* flush PRDs and pkt to memory */ + writel(QS_CCF_RUN_PKT, chan + QS_CCT_CFF); + readl(chan + QS_CCT_CFF); /* flush */ +} + +static int qs_qc_issue(struct ata_queued_cmd *qc) +{ + struct qs_port_priv *pp = qc->ap->private_data; + + switch (qc->tf.protocol) { + case ATA_PROT_DMA: + + pp->state = qs_state_pkt; + qs_packet_start(qc); + return 0; + + case ATA_PROT_ATAPI_DMA: + BUG(); + break; + + default: + break; + } + + pp->state = qs_state_mmio; + return ata_qc_issue_prot(qc); +} + +static inline unsigned int qs_intr_pkt(struct ata_host_set *host_set) +{ + unsigned int handled = 0; + u8 sFFE; + u8 __iomem *mmio_base = host_set->mmio_base; + + do { + u32 sff0 = readl(mmio_base + QS_HST_SFF); + u32 sff1 = readl(mmio_base + QS_HST_SFF + 4); + u8 sEVLD = (sff1 >> 30) & 0x01; /* valid flag */ + sFFE = sff1 >> 31; /* empty flag */ + + if (sEVLD) { + u8 sDST = sff0 >> 16; /* dev status */ + u8 sHST = sff1 & 0x3f; /* host status */ + unsigned int port_no = (sff1 >> 8) & 0x03; + struct ata_port *ap = host_set->ports[port_no]; + + DPRINTK("SFF=%08x%08x: sCHAN=%u sHST=%d sDST=%02x\n", + sff1, sff0, port_no, sHST, sDST); + handled = 1; + if (ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) { + struct ata_queued_cmd *qc; + struct qs_port_priv *pp = ap->private_data; + if (!pp || pp->state != qs_state_pkt) + continue; + qc = ata_qc_from_tag(ap, ap->active_tag); + if (qc && (!(qc->tf.ctl & ATA_NIEN))) { + switch (sHST) { + case 0: /* sucessful CPB */ + case 3: /* device error */ + pp->state = qs_state_idle; + qs_enter_reg_mode(qc->ap); + ata_qc_complete(qc, sDST); + break; + default: + break; + } + } + } + } + } while (!sFFE); + return handled; +} + +static inline unsigned int qs_intr_mmio(struct ata_host_set *host_set) +{ + unsigned int handled = 0, port_no; + + for (port_no = 0; port_no < host_set->n_ports; ++port_no) { + struct ata_port *ap; + ap = host_set->ports[port_no]; + if (ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) { + struct ata_queued_cmd *qc; + struct qs_port_priv *pp = ap->private_data; + if (!pp || pp->state != qs_state_mmio) + continue; + qc = ata_qc_from_tag(ap, ap->active_tag); + if (qc && (!(qc->tf.ctl & ATA_NIEN))) { + + /* check main status, clearing INTRQ */ + u8 status = ata_chk_status(ap); + if ((status & ATA_BUSY)) + continue; + DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n", + ap->id, qc->tf.protocol, status); + + /* complete taskfile transaction */ + pp->state = qs_state_idle; + ata_qc_complete(qc, status); + handled = 1; + } + } + } + return handled; +} + +static irqreturn_t qs_intr(int irq, void *dev_instance, struct pt_regs *regs) +{ + struct ata_host_set *host_set = dev_instance; + unsigned int handled = 0; + + VPRINTK("ENTER\n"); + + spin_lock(&host_set->lock); + handled = qs_intr_pkt(host_set) | qs_intr_mmio(host_set); + spin_unlock(&host_set->lock); + + VPRINTK("EXIT\n"); + + return IRQ_RETVAL(handled); +} + +static void qs_ata_setup_port(struct ata_ioports *port, unsigned long base) +{ + port->cmd_addr = + port->data_addr = base + 0x400; + port->error_addr = + port->feature_addr = base + 0x408; /* hob_feature = 0x409 */ + port->nsect_addr = base + 0x410; /* hob_nsect = 0x411 */ + port->lbal_addr = base + 0x418; /* hob_lbal = 0x419 */ + port->lbam_addr = base + 0x420; /* hob_lbam = 0x421 */ + port->lbah_addr = base + 0x428; /* hob_lbah = 0x429 */ + port->device_addr = base + 0x430; + port->status_addr = + port->command_addr = base + 0x438; + port->altstatus_addr = + port->ctl_addr = base + 0x440; + port->scr_addr = base + 0xc00; +} + +static int qs_port_start(struct ata_port *ap) +{ + struct device *dev = ap->host_set->dev; + struct qs_port_priv *pp; + void __iomem *mmio_base = ap->host_set->mmio_base; + void __iomem *chan = mmio_base + (ap->port_no * 0x4000); + u64 addr; + int rc; + + rc = ata_port_start(ap); + if (rc) + return rc; + qs_enter_reg_mode(ap); + pp = kcalloc(1, sizeof(*pp), GFP_KERNEL); + if (!pp) { + rc = -ENOMEM; + goto err_out; + } + pp->pkt = dma_alloc_coherent(dev, QS_PKT_BYTES, &pp->pkt_dma, + GFP_KERNEL); + if (!pp->pkt) { + rc = -ENOMEM; + goto err_out_kfree; + } + memset(pp->pkt, 0, QS_PKT_BYTES); + ap->private_data = pp; + + addr = (u64)pp->pkt_dma; + writel((u32) addr, chan + QS_CCF_CPBA); + writel((u32)(addr >> 32), chan + QS_CCF_CPBA + 4); + return 0; + +err_out_kfree: + kfree(pp); +err_out: + ata_port_stop(ap); + return rc; +} + +static void qs_port_stop(struct ata_port *ap) +{ + struct device *dev = ap->host_set->dev; + struct qs_port_priv *pp = ap->private_data; + + if (pp != NULL) { + ap->private_data = NULL; + if (pp->pkt != NULL) + dma_free_coherent(dev, QS_PKT_BYTES, pp->pkt, + pp->pkt_dma); + kfree(pp); + } + ata_port_stop(ap); +} + +static void qs_host_stop(struct ata_host_set *host_set) +{ + void __iomem *mmio_base = host_set->mmio_base; + + writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */ + writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */ +} + +static void qs_host_init(unsigned int chip_id, struct ata_probe_ent *pe) +{ + void __iomem *mmio_base = pe->mmio_base; + unsigned int port_no; + + writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */ + writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */ + + /* reset each channel in turn */ + for (port_no = 0; port_no < pe->n_ports; ++port_no) { + u8 __iomem *chan = mmio_base + (port_no * 0x4000); + writeb(QS_CTR1_RDEV|QS_CTR1_RCHN, chan + QS_CCT_CTR1); + writeb(QS_CTR0_REG, chan + QS_CCT_CTR0); + readb(chan + QS_CCT_CTR0); /* flush */ + } + writeb(QS_SERD3_PHY_ENA, mmio_base + QS_HVS_SERD3); /* enable phy */ + + for (port_no = 0; port_no < pe->n_ports; ++port_no) { + u8 __iomem *chan = mmio_base + (port_no * 0x4000); + /* set FIFO depths to same settings as Windows driver */ + writew(32, chan + QS_CFC_HUFT); + writew(32, chan + QS_CFC_HDFT); + writew(10, chan + QS_CFC_DUFT); + writew( 8, chan + QS_CFC_DDFT); + /* set CPB size in bytes, as a power of two */ + writeb(QS_CPB_ORDER, chan + QS_CCF_CSEP); + } + writeb(1, mmio_base + QS_HCT_CTRL); /* enable host interrupts */ +} + +/* + * The QStor understands 64-bit buses, and uses 64-bit fields + * for DMA pointers regardless of bus width. We just have to + * make sure our DMA masks are set appropriately for whatever + * bridge lies between us and the QStor, and then the DMA mapping + * code will ensure we only ever "see" appropriate buffer addresses. + * If we're 32-bit limited somewhere, then our 64-bit fields will + * just end up with zeros in the upper 32-bits, without any special + * logic required outside of this routine (below). + */ +static int qs_set_dma_masks(struct pci_dev *pdev, void __iomem *mmio_base) +{ + u32 bus_info = readl(mmio_base + QS_HID_HPHY); + int rc, have_64bit_bus = (bus_info & QS_HPHY_64BIT); + + if (have_64bit_bus && + !pci_set_dma_mask(pdev, 0xffffffffffffffffULL)) { + rc = pci_set_consistent_dma_mask(pdev, 0xffffffffffffffffULL); + if (rc) { + rc = pci_set_consistent_dma_mask(pdev, 0xffffffffULL); + if (rc) { + printk(KERN_ERR DRV_NAME + "(%s): 64-bit DMA enable failed\n", + pci_name(pdev)); + return rc; + } + } + } else { + rc = pci_set_dma_mask(pdev, 0xffffffffULL); + if (rc) { + printk(KERN_ERR DRV_NAME + "(%s): 32-bit DMA enable failed\n", + pci_name(pdev)); + return rc; + } + rc = pci_set_consistent_dma_mask(pdev, 0xffffffffULL); + if (rc) { + printk(KERN_ERR DRV_NAME + "(%s): 32-bit consistent DMA enable failed\n", + pci_name(pdev)); + return rc; + } + } + return 0; +} + +static int qs_ata_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + static int printed_version; + struct ata_probe_ent *probe_ent = NULL; + void __iomem *mmio_base; + unsigned int board_idx = (unsigned int) ent->driver_data; + int rc, port_no; + + if (!printed_version++) + printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); + + rc = pci_enable_device(pdev); + if (rc) + return rc; + + rc = pci_request_regions(pdev, DRV_NAME); + if (rc) + goto err_out; + + if ((pci_resource_flags(pdev, 4) & IORESOURCE_MEM) == 0) { + rc = -ENODEV; + goto err_out_regions; + } + + mmio_base = ioremap(pci_resource_start(pdev, 4), + pci_resource_len(pdev, 4)); + if (mmio_base == NULL) { + rc = -ENOMEM; + goto err_out_regions; + } + + rc = qs_set_dma_masks(pdev, mmio_base); + if (rc) + goto err_out_iounmap; + + probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); + if (probe_ent == NULL) { + rc = -ENOMEM; + goto err_out_iounmap; + } + + memset(probe_ent, 0, sizeof(*probe_ent)); + probe_ent->dev = pci_dev_to_dev(pdev); + INIT_LIST_HEAD(&probe_ent->node); + + probe_ent->sht = qs_port_info[board_idx].sht; + probe_ent->host_flags = qs_port_info[board_idx].host_flags; + probe_ent->pio_mask = qs_port_info[board_idx].pio_mask; + probe_ent->mwdma_mask = qs_port_info[board_idx].mwdma_mask; + probe_ent->udma_mask = qs_port_info[board_idx].udma_mask; + probe_ent->port_ops = qs_port_info[board_idx].port_ops; + + probe_ent->irq = pdev->irq; + probe_ent->irq_flags = SA_SHIRQ; + probe_ent->mmio_base = mmio_base; + probe_ent->n_ports = QS_PORTS; + + for (port_no = 0; port_no < probe_ent->n_ports; ++port_no) { + unsigned long chan = (unsigned long)mmio_base + + (port_no * 0x4000); + qs_ata_setup_port(&probe_ent->port[port_no], chan); + } + + pci_set_master(pdev); + + /* initialize adapter */ + qs_host_init(board_idx, probe_ent); + + rc = ata_device_add(probe_ent); + kfree(probe_ent); + if (rc != QS_PORTS) + goto err_out_iounmap; + return 0; + +err_out_iounmap: + iounmap(mmio_base); +err_out_regions: + pci_release_regions(pdev); +err_out: + pci_disable_device(pdev); + return rc; +} + +static int __init qs_ata_init(void) +{ + return pci_module_init(&qs_ata_pci_driver); +} + +static void __exit qs_ata_exit(void) +{ + pci_unregister_driver(&qs_ata_pci_driver); +} + +MODULE_AUTHOR("Mark Lord"); +MODULE_DESCRIPTION("Pacific Digital Corporation QStor SATA low-level driver"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, qs_ata_pci_tbl); +MODULE_VERSION(DRV_VERSION); + +module_init(qs_ata_init); +module_exit(qs_ata_exit); diff -Nru a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c --- a/drivers/scsi/sata_sil.c 2005-02-22 18:15:48 -08:00 +++ b/drivers/scsi/sata_sil.c 2005-02-22 18:15:48 -08:00 @@ -139,6 +139,8 @@ .post_set_mode = sil_post_set_mode, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, + .bmdma_stop = ata_bmdma_stop, + .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, .eng_timeout = ata_eng_timeout, @@ -336,6 +338,7 @@ void *mmio_base; int rc; unsigned int i; + int pci_dev_busy = 0; u32 tmp, irq_mask; if (!printed_version++) @@ -350,8 +353,10 @@ return rc; rc = pci_request_regions(pdev, DRV_NAME); - if (rc) + if (rc) { + pci_dev_busy = 1; goto err_out; + } rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) @@ -438,7 +443,8 @@ err_out_regions: pci_release_regions(pdev); err_out: - pci_disable_device(pdev); + if (!pci_dev_busy) + pci_disable_device(pdev); return rc; } diff -Nru a/drivers/scsi/sata_sis.c b/drivers/scsi/sata_sis.c --- a/drivers/scsi/sata_sis.c 2005-02-22 18:15:48 -08:00 +++ b/drivers/scsi/sata_sis.c 2005-02-22 18:15:48 -08:00 @@ -102,6 +102,8 @@ .phy_reset = sata_phy_reset, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, + .bmdma_stop = ata_bmdma_stop, + .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, .eng_timeout = ata_eng_timeout, @@ -200,14 +202,17 @@ int rc; u32 genctl; struct ata_port_info *ppi; + int pci_dev_busy = 0; rc = pci_enable_device(pdev); if (rc) return rc; rc = pci_request_regions(pdev, DRV_NAME); - if (rc) + if (rc) { + pci_dev_busy = 1; goto err_out; + } rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) @@ -259,7 +264,8 @@ pci_release_regions(pdev); err_out: - pci_disable_device(pdev); + if (!pci_dev_busy) + pci_disable_device(pdev); return rc; } diff -Nru a/drivers/scsi/sata_svw.c b/drivers/scsi/sata_svw.c --- a/drivers/scsi/sata_svw.c 2005-02-22 18:15:48 -08:00 +++ b/drivers/scsi/sata_svw.c 2005-02-22 18:15:48 -08:00 @@ -301,6 +301,8 @@ .phy_reset = sata_phy_reset, .bmdma_setup = k2_bmdma_setup_mmio, .bmdma_start = k2_bmdma_start_mmio, + .bmdma_stop = ata_bmdma_stop, + .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, .eng_timeout = ata_eng_timeout, @@ -338,6 +340,7 @@ struct ata_probe_ent *probe_ent = NULL; unsigned long base; void *mmio_base; + int pci_dev_busy = 0; int rc; if (!printed_version++) @@ -359,8 +362,10 @@ /* Request PCI regions */ rc = pci_request_regions(pdev, DRV_NAME); - if (rc) + if (rc) { + pci_dev_busy = 1; goto err_out; + } rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) @@ -433,7 +438,8 @@ err_out_regions: pci_release_regions(pdev); err_out: - pci_disable_device(pdev); + if (!pci_dev_busy) + pci_disable_device(pdev); return rc; } diff -Nru a/drivers/scsi/sata_sx4.c b/drivers/scsi/sata_sx4.c --- a/drivers/scsi/sata_sx4.c 2005-02-22 18:15:48 -08:00 +++ b/drivers/scsi/sata_sx4.c 2005-02-22 18:15:48 -08:00 @@ -1366,6 +1366,7 @@ void *mmio_base, *dimm_mmio = NULL; struct pdc_host_priv *hpriv = NULL; unsigned int board_idx = (unsigned int) ent->driver_data; + int pci_dev_busy = 0; int rc; if (!printed_version++) @@ -1380,8 +1381,10 @@ return rc; rc = pci_request_regions(pdev, DRV_NAME); - if (rc) + if (rc) { + pci_dev_busy = 1; goto err_out; + } rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) @@ -1471,7 +1474,8 @@ err_out_regions: pci_release_regions(pdev); err_out: - pci_disable_device(pdev); + if (!pci_dev_busy) + pci_disable_device(pdev); return rc; } diff -Nru a/drivers/scsi/sata_uli.c b/drivers/scsi/sata_uli.c --- a/drivers/scsi/sata_uli.c 2005-02-22 18:15:48 -08:00 +++ b/drivers/scsi/sata_uli.c 2005-02-22 18:15:48 -08:00 @@ -97,6 +97,8 @@ .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, + .bmdma_stop = ata_bmdma_stop, + .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, @@ -185,14 +187,17 @@ struct ata_port_info *ppi; int rc; unsigned int board_idx = (unsigned int) ent->driver_data; + int pci_dev_busy = 0; rc = pci_enable_device(pdev); if (rc) return rc; rc = pci_request_regions(pdev, DRV_NAME); - if (rc) + if (rc) { + pci_dev_busy = 1; goto err_out; + } rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) @@ -260,7 +265,8 @@ pci_release_regions(pdev); err_out: - pci_disable_device(pdev); + if (!pci_dev_busy) + pci_disable_device(pdev); return rc; } diff -Nru a/drivers/scsi/sata_via.c b/drivers/scsi/sata_via.c --- a/drivers/scsi/sata_via.c 2005-02-22 18:15:48 -08:00 +++ b/drivers/scsi/sata_via.c 2005-02-22 18:15:48 -08:00 @@ -24,6 +24,11 @@ If you do not delete the provisions above, a recipient may use your version of this file under either the OSL or the GPL. + ---------------------------------------------------------------------- + + To-do list: + * VT6421 PATA support + */ #include @@ -38,11 +43,14 @@ #include #define DRV_NAME "sata_via" -#define DRV_VERSION "1.0" +#define DRV_VERSION "1.1" -enum { - via_sata = 0, +enum board_ids_enum { + vt6420, + vt6421, +}; +enum { SATA_CHAN_ENAB = 0x40, /* SATA channel enable */ SATA_INT_GATE = 0x41, /* SATA interrupt gating */ SATA_NATIVE_MODE = 0x42, /* Native mode enable */ @@ -50,10 +58,8 @@ PORT0 = (1 << 1), PORT1 = (1 << 0), - - ENAB_ALL = PORT0 | PORT1, - - INT_GATE_ALL = PORT0 | PORT1, + ALL_PORTS = PORT0 | PORT1, + N_PORTS = 2, NATIVE_MODE_ALL = (1 << 7) | (1 << 6) | (1 << 5) | (1 << 4), @@ -66,7 +72,8 @@ static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); static struct pci_device_id svia_pci_tbl[] = { - { 0x1106, 0x3149, PCI_ANY_ID, PCI_ANY_ID, 0, 0, via_sata }, + { 0x1106, 0x3149, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6420 }, + { 0x1106, 0x3249, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6421 }, { } /* terminate list */ }; @@ -110,6 +117,9 @@ .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, + .bmdma_stop = ata_bmdma_stop, + .bmdma_status = ata_bmdma_status, + .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, @@ -158,18 +168,132 @@ 8, 4, 8, 4, 16, 256 }; +static const unsigned int vt6421_bar_sizes[] = { + 16, 16, 16, 16, 32, 128 +}; + static unsigned long svia_scr_addr(unsigned long addr, unsigned int port) { return addr + (port * 128); } +static unsigned long vt6421_scr_addr(unsigned long addr, unsigned int port) +{ + return addr + (port * 64); +} + +static void vt6421_init_addrs(struct ata_probe_ent *probe_ent, + struct pci_dev *pdev, + unsigned int port) +{ + unsigned long reg_addr = pci_resource_start(pdev, port); + unsigned long bmdma_addr = pci_resource_start(pdev, 4) + (port * 8); + unsigned long scr_addr; + + probe_ent->port[port].cmd_addr = reg_addr; + probe_ent->port[port].altstatus_addr = + probe_ent->port[port].ctl_addr = (reg_addr + 8) | ATA_PCI_CTL_OFS; + probe_ent->port[port].bmdma_addr = bmdma_addr; + + scr_addr = vt6421_scr_addr(pci_resource_start(pdev, 5), port); + probe_ent->port[port].scr_addr = scr_addr; + + ata_std_ports(&probe_ent->port[port]); +} + +static struct ata_probe_ent *vt6420_init_probe_ent(struct pci_dev *pdev) +{ + struct ata_probe_ent *probe_ent; + struct ata_port_info *ppi = &svia_port_info; + + probe_ent = ata_pci_init_native_mode(pdev, &ppi); + if (!probe_ent) + return NULL; + + probe_ent->port[0].scr_addr = + svia_scr_addr(pci_resource_start(pdev, 5), 0); + probe_ent->port[1].scr_addr = + svia_scr_addr(pci_resource_start(pdev, 5), 1); + + return probe_ent; +} + +static struct ata_probe_ent *vt6421_init_probe_ent(struct pci_dev *pdev) +{ + struct ata_probe_ent *probe_ent; + unsigned int i; + + probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); + if (!probe_ent) + return NULL; + + memset(probe_ent, 0, sizeof(*probe_ent)); + probe_ent->dev = pci_dev_to_dev(pdev); + INIT_LIST_HEAD(&probe_ent->node); + + probe_ent->sht = &svia_sht; + probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_SATA_RESET | + ATA_FLAG_NO_LEGACY; + probe_ent->port_ops = &svia_sata_ops; + probe_ent->n_ports = N_PORTS; + probe_ent->irq = pdev->irq; + probe_ent->irq_flags = SA_SHIRQ; + probe_ent->pio_mask = 0x1f; + probe_ent->mwdma_mask = 0x07; + probe_ent->udma_mask = 0x7f; + + for (i = 0; i < N_PORTS; i++) + vt6421_init_addrs(probe_ent, pdev, i); + + return probe_ent; +} + +static void svia_configure(struct pci_dev *pdev) +{ + u8 tmp8; + + pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &tmp8); + printk(KERN_INFO DRV_NAME "(%s): routed to hard irq line %d\n", + pci_name(pdev), + (int) (tmp8 & 0xf0) == 0xf0 ? 0 : tmp8 & 0x0f); + + /* make sure SATA channels are enabled */ + pci_read_config_byte(pdev, SATA_CHAN_ENAB, &tmp8); + if ((tmp8 & ALL_PORTS) != ALL_PORTS) { + printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channels (0x%x)\n", + pci_name(pdev), (int) tmp8); + tmp8 |= ALL_PORTS; + pci_write_config_byte(pdev, SATA_CHAN_ENAB, tmp8); + } + + /* make sure interrupts for each channel sent to us */ + pci_read_config_byte(pdev, SATA_INT_GATE, &tmp8); + if ((tmp8 & ALL_PORTS) != ALL_PORTS) { + printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channel interrupts (0x%x)\n", + pci_name(pdev), (int) tmp8); + tmp8 |= ALL_PORTS; + pci_write_config_byte(pdev, SATA_INT_GATE, tmp8); + } + + /* make sure native mode is enabled */ + pci_read_config_byte(pdev, SATA_NATIVE_MODE, &tmp8); + if ((tmp8 & NATIVE_MODE_ALL) != NATIVE_MODE_ALL) { + printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channel native mode (0x%x)\n", + pci_name(pdev), (int) tmp8); + tmp8 |= NATIVE_MODE_ALL; + pci_write_config_byte(pdev, SATA_NATIVE_MODE, tmp8); + } +} + static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version; unsigned int i; int rc; - struct ata_port_info *ppi; struct ata_probe_ent *probe_ent; + int board_id = (int) ent->driver_data; + const int *bar_sizes; + int pci_dev_busy = 0; u8 tmp8; if (!printed_version++) @@ -180,20 +304,28 @@ return rc; rc = pci_request_regions(pdev, DRV_NAME); - if (rc) + if (rc) { + pci_dev_busy = 1; goto err_out; + } - pci_read_config_byte(pdev, SATA_PATA_SHARING, &tmp8); - if (tmp8 & SATA_2DEV) { - printk(KERN_ERR DRV_NAME "(%s): SATA master/slave not supported (0x%x)\n", - pci_name(pdev), (int) tmp8); - rc = -EIO; - goto err_out_regions; + if (board_id == vt6420) { + pci_read_config_byte(pdev, SATA_PATA_SHARING, &tmp8); + if (tmp8 & SATA_2DEV) { + printk(KERN_ERR DRV_NAME "(%s): SATA master/slave not supported (0x%x)\n", + pci_name(pdev), (int) tmp8); + rc = -EIO; + goto err_out_regions; + } + + bar_sizes = &svia_bar_sizes[0]; + } else { + bar_sizes = &vt6421_bar_sizes[0]; } for (i = 0; i < ARRAY_SIZE(svia_bar_sizes); i++) if ((pci_resource_start(pdev, i) == 0) || - (pci_resource_len(pdev, i) < svia_bar_sizes[i])) { + (pci_resource_len(pdev, i) < bar_sizes[i])) { printk(KERN_ERR DRV_NAME "(%s): invalid PCI BAR %u (sz 0x%lx, val 0x%lx)\n", pci_name(pdev), i, pci_resource_start(pdev, i), @@ -209,8 +341,11 @@ if (rc) goto err_out_regions; - ppi = &svia_port_info; - probe_ent = ata_pci_init_native_mode(pdev, &ppi); + if (board_id == vt6420) + probe_ent = vt6420_init_probe_ent(pdev); + else + probe_ent = vt6421_init_probe_ent(pdev); + if (!probe_ent) { printk(KERN_ERR DRV_NAME "(%s): out of memory\n", pci_name(pdev)); @@ -218,42 +353,7 @@ goto err_out_regions; } - probe_ent->port[0].scr_addr = - svia_scr_addr(pci_resource_start(pdev, 5), 0); - probe_ent->port[1].scr_addr = - svia_scr_addr(pci_resource_start(pdev, 5), 1); - - pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &tmp8); - printk(KERN_INFO DRV_NAME "(%s): routed to hard irq line %d\n", - pci_name(pdev), - (int) (tmp8 & 0xf0) == 0xf0 ? 0 : tmp8 & 0x0f); - - /* make sure SATA channels are enabled */ - pci_read_config_byte(pdev, SATA_CHAN_ENAB, &tmp8); - if ((tmp8 & ENAB_ALL) != ENAB_ALL) { - printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channels (0x%x)\n", - pci_name(pdev), (int) tmp8); - tmp8 |= ENAB_ALL; - pci_write_config_byte(pdev, SATA_CHAN_ENAB, tmp8); - } - - /* make sure interrupts for each channel sent to us */ - pci_read_config_byte(pdev, SATA_INT_GATE, &tmp8); - if ((tmp8 & INT_GATE_ALL) != INT_GATE_ALL) { - printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channel interrupts (0x%x)\n", - pci_name(pdev), (int) tmp8); - tmp8 |= INT_GATE_ALL; - pci_write_config_byte(pdev, SATA_INT_GATE, tmp8); - } - - /* make sure native mode is enabled */ - pci_read_config_byte(pdev, SATA_NATIVE_MODE, &tmp8); - if ((tmp8 & NATIVE_MODE_ALL) != NATIVE_MODE_ALL) { - printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channel native mode (0x%x)\n", - pci_name(pdev), (int) tmp8); - tmp8 |= NATIVE_MODE_ALL; - pci_write_config_byte(pdev, SATA_NATIVE_MODE, tmp8); - } + svia_configure(pdev); pci_set_master(pdev); @@ -266,7 +366,8 @@ err_out_regions: pci_release_regions(pdev); err_out: - pci_disable_device(pdev); + if (!pci_dev_busy) + pci_disable_device(pdev); return rc; } diff -Nru a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c --- a/drivers/scsi/sata_vsc.c 2005-02-22 18:15:48 -08:00 +++ b/drivers/scsi/sata_vsc.c 2005-02-22 18:15:48 -08:00 @@ -217,6 +217,8 @@ .phy_reset = sata_phy_reset, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, + .bmdma_stop = ata_bmdma_stop, + .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, .eng_timeout = ata_eng_timeout, @@ -255,6 +257,7 @@ static int printed_version; struct ata_probe_ent *probe_ent = NULL; unsigned long base; + int pci_dev_busy = 0; void *mmio_base; int rc; @@ -274,8 +277,10 @@ } rc = pci_request_regions(pdev, DRV_NAME); - if (rc) + if (rc) { + pci_dev_busy = 1; goto err_out; + } /* * Use 32 bit DMA mask, because 64 bit address support is poor. @@ -352,7 +357,8 @@ err_out_regions: pci_release_regions(pdev); err_out: - pci_disable_device(pdev); + if (!pci_dev_busy) + pci_disable_device(pdev); return rc; } diff -Nru a/include/linux/libata.h b/include/linux/libata.h --- a/include/linux/libata.h 2005-02-22 18:15:48 -08:00 +++ b/include/linux/libata.h 2005-02-22 18:15:48 -08:00 @@ -360,6 +360,9 @@ void (*port_stop) (struct ata_port *ap); void (*host_stop) (struct ata_host_set *host_set); + + void (*bmdma_stop) (struct ata_port *ap); + u8 (*bmdma_status) (struct ata_port *ap); }; struct ata_port_info { @@ -415,6 +418,8 @@ unsigned int ofs, unsigned int len); extern void ata_bmdma_setup (struct ata_queued_cmd *qc); extern void ata_bmdma_start (struct ata_queued_cmd *qc); +extern void ata_bmdma_stop(struct ata_port *ap); +extern u8 ata_bmdma_status(struct ata_port *ap); extern void ata_bmdma_irq_clear(struct ata_port *ap); extern void ata_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat); extern void ata_eng_timeout(struct ata_port *ap); @@ -593,46 +598,6 @@ static inline unsigned int sata_dev_present(struct ata_port *ap) { return ((scr_read(ap, SCR_STATUS) & 0xf) == 0x3) ? 1 : 0; -} - -static inline void ata_bmdma_stop(struct ata_port *ap) -{ - if (ap->flags & ATA_FLAG_MMIO) { - void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr; - - /* clear start/stop bit */ - writeb(readb(mmio + ATA_DMA_CMD) & ~ATA_DMA_START, - mmio + ATA_DMA_CMD); - } else { - /* clear start/stop bit */ - outb(inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD) & ~ATA_DMA_START, - ap->ioaddr.bmdma_addr + ATA_DMA_CMD); - } - - /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */ - ata_altstatus(ap); /* dummy read */ -} - -static inline void ata_bmdma_ack_irq(struct ata_port *ap) -{ - if (ap->flags & ATA_FLAG_MMIO) { - void __iomem *mmio = ((void __iomem *) ap->ioaddr.bmdma_addr) + ATA_DMA_STATUS; - writeb(readb(mmio), mmio); - } else { - unsigned long addr = ap->ioaddr.bmdma_addr + ATA_DMA_STATUS; - outb(inb(addr), addr); - } -} - -static inline u8 ata_bmdma_status(struct ata_port *ap) -{ - u8 host_stat; - if (ap->flags & ATA_FLAG_MMIO) { - void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr; - host_stat = readb(mmio + ATA_DMA_STATUS); - } else - host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); - return host_stat; } static inline int ata_try_flush_cache(struct ata_device *dev)