Date: Thu, 12 Jan 2006 00:39:03 +0100 From: =?ISO-8859-1?Q?S=F8ren_Schmidt?= <sos@FreeBSD.org> To: current@FreeBSD.org Subject: PATCH: DMA enabled dump for ATA please test Message-ID: <43C59717.7000203@FreeBSD.org>
next in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format. --------------020809040703060107040900 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 8bit Evening! Originally I wanted to finally add dump functionality to ata-raid, but quickly discovered that it would be a pain todo the old way. So I decided to reuse strategy for dumping by implementing polled mode in ATA, and have dump simply call strategy. (This could be generalised for all drivers, and would make driver writing easier). Now this also gave me the chance to use DMA on dumps, and that does do wonders for dump speed. There is a few chipsets (ICH6+7 in AHCI mode and Marvell) that wont do dumps yet not even PIO but they didn't work before either. Anyhow this needs a bit testing on various HW out there before it hits the tree, so please give it a go and let me know... -Søren --------------020809040703060107040900 Content-Type: text/plain; name="dmadump-p1" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="dmadump-p1" Index: ata-all.c =================================================================== RCS file: /nfs/export/ncvs/src/sys/dev/ata/ata-all.c,v retrieving revision 1.261 diff -u -r1.261 ata-all.c --- ata-all.c 5 Jan 2006 21:27:18 -0000 1.261 +++ ata-all.c 11 Jan 2006 23:00:53 -0000 @@ -63,7 +63,6 @@ }; /* prototypes */ -static void ata_interrupt(void *); static void ata_boot_attach(void); static device_t ata_add_child(device_t, struct ata_device *, int); static int ata_getparam(struct ata_device *, int); @@ -139,7 +138,7 @@ return ENXIO; } if ((error = bus_setup_intr(dev, ch->r_irq, ATA_INTR_FLAGS, - ata_interrupt, ch, &ch->ih))) { + (driver_intr_t *)ata_interrupt, ch, &ch->ih))) { device_printf(dev, "unable to setup interrupt\n"); return error; } @@ -317,7 +316,7 @@ return error; } -static void +int ata_interrupt(void *data) { struct ata_channel *ch = (struct ata_channel *)data; @@ -325,20 +324,17 @@ mtx_lock(&ch->state_mtx); do { + /* ignore interrupt if its not for us */ + if (ch->hw.status && !ch->hw.status(ch->dev)) + break; + /* do we have a running request */ if (!(request = ch->running)) break; ATA_DEBUG_RQ(request, "interrupt"); - /* ignore interrupt if device is busy */ - if (ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_BUSY) { - DELAY(100); - if (ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_BUSY) - break; - } - - /* check for the right state */ + /* safetycheck for the right state */ if (ch->state != ATA_ACTIVE && ch->state != ATA_STALL_QUEUE) { device_printf(request->dev, "interrupt on idle channel ignored\n"); break; @@ -355,10 +351,11 @@ mtx_unlock(&ch->state_mtx); ATA_LOCKING(ch->dev, ATA_LF_UNLOCK); ata_finish(request); - return; + return 1; } } while (0); mtx_unlock(&ch->state_mtx); + return 0; } /* Index: ata-all.h =================================================================== RCS file: /nfs/export/ncvs/src/sys/dev/ata/ata-all.h,v retrieving revision 1.110 diff -u -r1.110 ata-all.h --- ata-all.h 5 Jan 2006 21:27:19 -0000 1.110 +++ ata-all.h 11 Jan 2006 23:00:53 -0000 @@ -470,6 +470,7 @@ /* structure holding lowlevel functions */ struct ata_lowlevel { + int (*status)(device_t dev); int (*begin_transaction)(struct ata_request *request); int (*end_transaction)(struct ata_request *request); int (*command)(struct ata_request *request); @@ -495,6 +496,7 @@ #define ATA_USE_16BIT 0x02 #define ATA_ATAPI_DMA_RO 0x04 #define ATA_NO_48BIT_DMA 0x08 +#define ATA_ALWAYS_DMASTAT 0x10 int devices; /* what is present */ #define ATA_ATA_MASTER 0x01 @@ -534,6 +536,7 @@ int ata_reinit(device_t dev); int ata_suspend(device_t dev); int ata_resume(device_t dev); +int ata_interrupt(void *data); int ata_device_ioctl(device_t dev, u_long cmd, caddr_t data); int ata_identify(device_t dev); void ata_default_registers(device_t dev); Index: ata-chipset.c =================================================================== RCS file: /nfs/export/ncvs/src/sys/dev/ata/ata-chipset.c,v retrieving revision 1.149 diff -u -r1.149 ata-chipset.c --- ata-chipset.c 5 Jan 2006 21:27:19 -0000 1.149 +++ ata-chipset.c 11 Jan 2006 23:00:53 -0000 @@ -82,15 +82,15 @@ static int ata_cypress_chipinit(device_t dev); static void ata_cypress_setmode(device_t dev, int mode); static int ata_highpoint_chipinit(device_t dev); -static void ata_highpoint_intr(void *data); +static int ata_highpoint_allocate(device_t dev); static void ata_highpoint_setmode(device_t dev, int mode); static int ata_highpoint_check_80pin(device_t dev, int mode); static int ata_intel_chipinit(device_t dev); +static int ata_intel_allocate(device_t dev); static int ata_intel_31244_allocate(device_t dev); static void ata_intel_31244_intr(void *data); static void ata_intel_31244_reset(device_t dev); static int ata_intel_31244_command(struct ata_request *request); -static void ata_intel_intr(void *data); static void ata_intel_reset(device_t dev); static void ata_intel_old_setmode(device_t dev, int mode); static void ata_intel_new_setmode(device_t dev, int mode); @@ -132,7 +132,6 @@ static int ata_sii_allocate(device_t dev); static void ata_sii_intr(void *data); static void ata_cmd_intr(void *data); -static void ata_cmd_old_intr(void *data); static void ata_sii_reset(device_t dev); static void ata_sii_setmode(device_t dev, int mode); static void ata_cmd_setmode(device_t dev, int mode); @@ -184,18 +183,8 @@ int unit; for (unit = 0; unit < ctlr->channels; unit++) { - if (!(ch = ctlr->interrupt[unit].argument)) - continue; - if (ch->dma && (ch->dma->flags & ATA_DMA_ACTIVE)) { - int bmstat = ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK; - - if ((bmstat & (ATA_BMSTAT_ACTIVE | ATA_BMSTAT_INTERRUPT)) != - ATA_BMSTAT_INTERRUPT) - continue; - ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, bmstat & ~ATA_BMSTAT_ERROR); - DELAY(1); - } - ctlr->interrupt[unit].function(ch); + if ((ch = ctlr->interrupt[unit].argument)) + ctlr->interrupt[unit].function(ch); } } @@ -748,18 +737,6 @@ if (ctlr->chip->cfg1 == ATPOLD && ATA_LOCKING(ch->dev, ATA_LF_WHICH) != unit) continue; - if (ch->dma && (ch->dma->flags & ATA_DMA_ACTIVE)) { - int bmstat = ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK; - - if ((bmstat & (ATA_BMSTAT_ACTIVE | ATA_BMSTAT_INTERRUPT)) != - ATA_BMSTAT_INTERRUPT) - continue; - ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, bmstat & ~ATA_BMSTAT_ERROR); - DELAY(1); - ATA_IDX_OUTB(ch, ATA_BMCMD_PORT, - ATA_IDX_INB(ch, ATA_BMCMD_PORT)&~ATA_BMCMD_START_STOP); - DELAY(1); - } ctlr->interrupt[unit].function(ch); } } @@ -903,8 +880,8 @@ device_printf(dev, "using PIO transfers above 137GB as workaround for " "48bit DMA access bug, expect reduced performance\n"); - ctlr->reset = ata_ali_reset; ctlr->allocate = ata_ali_allocate; + ctlr->reset = ata_ali_reset; ctlr->setmode = ata_ali_setmode; break; @@ -973,7 +950,7 @@ ch->flags |= ATA_NO_SLAVE; /* XXX SOS PHY handling awkward in ALI chip not supported yet */ - ata_generic_hw(dev); + ata_pci_hw(dev); return 0; } @@ -1407,18 +1384,9 @@ ata_highpoint_chipinit(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); - int rid = ATA_IRQ_RID; - if (!(ctlr->r_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, - RF_SHAREABLE | RF_ACTIVE))) { - device_printf(dev, "unable to map interrupt\n"); - return ENXIO; - } - if ((bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS, - ata_highpoint_intr, ctlr, &ctlr->handle))) { - device_printf(dev, "unable to setup interrupt\n"); + if (ata_setup_interrupt(dev)) return ENXIO; - } if (ctlr->chip->cfg2 == HPTOLD) { /* disable interrupt prediction */ @@ -1439,31 +1407,22 @@ pci_write_config(dev, 0x5b, (pci_read_config(dev, 0x5b, 1) & 0x01) | 0x20, 1); } + ctlr->allocate = ata_highpoint_allocate; ctlr->setmode = ata_highpoint_setmode; return 0; } -static void -ata_highpoint_intr(void *data) +static int +ata_highpoint_allocate(device_t dev) { - struct ata_pci_controller *ctlr = data; - struct ata_channel *ch; - int unit; + struct ata_channel *ch = device_get_softc(dev); - for (unit = 0; unit < ctlr->channels; unit++) { - if (!(ch = ctlr->interrupt[unit].argument)) - continue; - if (ch->dma) { - int bmstat = ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK; + /* setup the usual register normal pci style */ + if (ata_pci_allocate(dev)) + return ENXIO; - if ((bmstat & (ATA_BMSTAT_ACTIVE | ATA_BMSTAT_INTERRUPT)) != - ATA_BMSTAT_INTERRUPT) - continue; - ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, bmstat & ~ATA_BMSTAT_ERROR); - DELAY(1); - } - ctlr->interrupt[unit].function(ch); - } + ch->flags |= ATA_ALWAYS_DMASTAT; + return 0; } static void @@ -1603,20 +1562,9 @@ ata_intel_chipinit(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); - int rid = ATA_IRQ_RID; - if (!ata_legacy(dev)) { - if (!(ctlr->r_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, - RF_SHAREABLE | RF_ACTIVE))) { - device_printf(dev, "unable to map interrupt\n"); - return ENXIO; - } - if ((bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS, - ata_intel_intr, ctlr, &ctlr->handle))) { - device_printf(dev, "unable to setup interrupt\n"); - return ENXIO; - } - } + if (ata_setup_interrupt(dev)) + return ENXIO; /* good old PIIX needs special treatment (not implemented) */ if (ctlr->chip->chipid == ATA_I82371FB) { @@ -1640,14 +1588,15 @@ return ENXIO; } ctlr->channels = 4; - ctlr->reset = ata_intel_31244_reset; ctlr->allocate = ata_intel_31244_allocate; + ctlr->reset = ata_intel_31244_reset; } ctlr->setmode = ata_sata_setmode; } /* non SATA intel chips goes here */ else if (ctlr->chip->max_dma < ATA_SA150) { + ctlr->allocate = ata_intel_allocate; ctlr->setmode = ata_intel_new_setmode; } @@ -1656,6 +1605,7 @@ /* force all ports active "the legacy way" */ pci_write_config(dev, 0x92, pci_read_config(dev, 0x92, 2) | 0x0f,2); + ctlr->allocate = ata_intel_allocate; ctlr->reset = ata_intel_reset; /* if we have AHCI capability and BAR(5) as a memory resource */ @@ -1685,9 +1635,9 @@ ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) | ATA_AHCI_GHC_IE); + ctlr->allocate = ata_ahci_allocate; ctlr->reset = ata_ahci_reset; ctlr->dmainit = ata_ahci_dmainit; - ctlr->allocate = ata_ahci_allocate; } } } @@ -1701,6 +1651,19 @@ } static int +ata_intel_allocate(device_t dev) +{ + struct ata_channel *ch = device_get_softc(dev); + + /* setup the usual register normal pci style */ + if (ata_pci_allocate(dev)) + return ENXIO; + + ch->flags |= ATA_ALWAYS_DMASTAT; + return 0; +} + +static int ata_intel_31244_allocate(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); @@ -1732,7 +1695,7 @@ ch->r_io[ATA_BMDTP_PORT].offset = ch_offset + 0x74; ch->flags |= ATA_NO_SLAVE; - ata_generic_hw(dev); + ata_pci_hw(dev); ch->hw.command = ata_intel_31244_command; /* enable PHY state change interrupt */ @@ -1784,14 +1747,6 @@ } /* any drive action to take care of ? */ - if (ch->dma && (ch->dma->flags & ATA_DMA_ACTIVE)) { - int bmstat = ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK; - - if (!(bmstat & ATA_BMSTAT_INTERRUPT)) - continue; - ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, bmstat & ~ATA_BMSTAT_ERROR); - DELAY(1); - } ctlr->interrupt[unit].function(ch); } } @@ -1833,29 +1788,6 @@ } static void -ata_intel_intr(void *data) -{ - struct ata_pci_controller *ctlr = data; - struct ata_channel *ch; - int unit; - - for (unit = 0; unit < ctlr->channels; unit++) { - if (!(ch = ctlr->interrupt[unit].argument)) - continue; - if (ch->dma) { - int bmstat = ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK; - - if ((bmstat & (ATA_BMSTAT_ACTIVE | ATA_BMSTAT_INTERRUPT)) != - ATA_BMSTAT_INTERRUPT) - continue; - ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, bmstat & ~ATA_BMSTAT_ERROR); - DELAY(1); - } - ctlr->interrupt[unit].function(ch); - } -} - -static void ata_intel_reset(device_t dev) { device_t parent = device_get_parent(dev); @@ -2142,9 +2074,9 @@ /* mask all PCI interrupts */ ATA_OUTL(ctlr->r_res1, 0x01d5c, 0x00000000); + ctlr->allocate = ata_marvell_allocate; ctlr->reset = ata_marvell_reset; ctlr->dmainit = ata_marvell_dmainit; - ctlr->allocate = ata_marvell_allocate; ctlr->setmode = ata_sata_setmode; ctlr->channels = ctlr->chip->cfg1; @@ -2809,15 +2741,6 @@ /* any drive action to take care of ? */ if (status & (0x01 << maskshift)) { - if (ch->dma && (ch->dma->flags & ATA_DMA_ACTIVE)) { - int bmstat = - ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK; - - if (!(bmstat & ATA_BMSTAT_INTERRUPT)) - continue; - ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, bmstat&~ATA_BMSTAT_ERROR); - DELAY(1); - } ctlr->interrupt[unit].function(ch); } } @@ -3006,9 +2929,9 @@ bus_release_resource(dev, ctlr->r_type1, ctlr->r_rid1,ctlr->r_res1); return ENXIO; } + ctlr->allocate = ata_promise_mio_allocate; ctlr->reset = ata_promise_mio_reset; ctlr->dmainit = ata_promise_mio_dmainit; - ctlr->allocate = ata_promise_mio_allocate; if (ctlr->chip->cfg2 == PRSX4X) { struct ata_promise_sx4 *hpkt; @@ -3573,15 +3496,6 @@ continue; ATA_IDX_OUTB(ch, ATA_BMDEVSPEC_0, 0x0b); if (ATA_IDX_INB(ch, ATA_BMDEVSPEC_1) & 0x20) { - if (ch->dma && (ch->dma->flags & ATA_DMA_ACTIVE)) { - int bmstat = ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK; - - if ((bmstat & (ATA_BMSTAT_ACTIVE | ATA_BMSTAT_INTERRUPT)) != - ATA_BMSTAT_INTERRUPT) - continue; - ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, bmstat & ~ATA_BMSTAT_ERROR); - DELAY(1); - } ctlr->interrupt[unit].function(ch); } } @@ -3598,15 +3512,6 @@ if (!(ch = ctlr->interrupt[unit].argument)) continue; if (ATA_INL(ctlr->r_res1, 0x1c) & (ch->unit ? 0x00004000 : 0x00000400)){ - if (ch->dma && (ch->dma->flags & ATA_DMA_ACTIVE)) { - int bmstat = ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK; - - if ((bmstat & (ATA_BMSTAT_ACTIVE | ATA_BMSTAT_INTERRUPT)) != - ATA_BMSTAT_INTERRUPT) - continue; - ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, bmstat & ~ATA_BMSTAT_ERROR); - DELAY(1); - } ctlr->interrupt[unit].function(ch); } } @@ -3973,7 +3878,7 @@ else { if ((bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS, ctlr->chip->cfg2 & SIIINTR ? - ata_cmd_intr : ata_cmd_old_intr, + ata_cmd_intr : ata_generic_intr, ctlr, &ctlr->handle))) { device_printf(dev, "unable to setup interrupt\n"); return ENXIO; @@ -4036,7 +3941,7 @@ ch->dma->segsize = 15 * DEV_BSIZE; } - ata_generic_hw(dev); + ata_pci_hw(dev); return 0; } @@ -4084,14 +3989,6 @@ /* any drive action to take care of ? */ if (ATA_IDX_INB(ch, ATA_BMDEVSPEC_0) & 0x08) { - if (ch->dma && (ch->dma->flags & ATA_DMA_ACTIVE)) { - int bmstat = ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK; - - if (!(bmstat & ATA_BMSTAT_INTERRUPT)) - continue; - ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, bmstat & ~ATA_BMSTAT_ERROR); - DELAY(1); - } ctlr->interrupt[unit].function(ch); } @@ -4113,44 +4010,12 @@ (ch->unit ? 0x08 : 0x04))) { pci_write_config(device_get_parent(ch->dev), 0x71, reg71 & ~(ch->unit ? 0x04 : 0x08), 1); - if (ch->dma && (ch->dma->flags & ATA_DMA_ACTIVE)) { - int bmstat = ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK; - - if ((bmstat & (ATA_BMSTAT_ACTIVE | ATA_BMSTAT_INTERRUPT)) != - ATA_BMSTAT_INTERRUPT) - continue; - ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, bmstat & ~ATA_BMSTAT_ERROR); - DELAY(1); - } ctlr->interrupt[unit].function(ch); } } } static void -ata_cmd_old_intr(void *data) -{ - struct ata_pci_controller *ctlr = data; - struct ata_channel *ch; - int unit; - - for (unit = 0; unit < ctlr->channels; unit++) { - if (!(ch = ctlr->interrupt[unit].argument)) - continue; - if (ch->dma && (ch->dma->flags & ATA_DMA_ACTIVE)) { - int bmstat = ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK; - - if ((bmstat & (ATA_BMSTAT_ACTIVE | ATA_BMSTAT_INTERRUPT)) != - ATA_BMSTAT_INTERRUPT) - continue; - ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, bmstat & ~ATA_BMSTAT_ERROR); - DELAY(1); - } - ctlr->interrupt[unit].function(ch); - } -} - -static void ata_sii_reset(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); @@ -4661,7 +4526,7 @@ ch->r_io[i].res = ctlr->r_res1; ch->r_io[i].offset = i - ATA_BMCMD_PORT; } - ata_generic_hw(dev); + ata_pci_hw(dev); } else { if (ata_pci_allocate(dev)) Index: ata-disk.c =================================================================== RCS file: /nfs/export/ncvs/src/sys/dev/ata/ata-disk.c,v retrieving revision 1.192 diff -u -r1.192 ata-disk.c --- ata-disk.c 5 Jan 2006 21:27:19 -0000 1.192 +++ ata-disk.c 11 Jan 2006 23:00:53 -0000 @@ -289,45 +289,23 @@ static int ad_dump(void *arg, void *virtual, vm_offset_t physical, - off_t offset, size_t length) + off_t offset, size_t length) { struct disk *dp = arg; - device_t dev = dp->d_drv1; - struct ata_device *atadev = device_get_softc(dev); - struct ad_softc *adp = device_get_ivars(dev); - struct ata_channel *ch = device_get_softc(device_get_parent(dev)); - struct ata_request request; + struct bio bp; - if (!adp) - return ENXIO; - - bzero(&request, sizeof(struct ata_request)); - request.dev = dev; - - if (length) { - request.data = virtual; - request.bytecount = length; - request.transfersize = min(length, atadev->max_iosize); - request.flags = ATA_R_WRITE; - if (atadev->max_iosize > DEV_BSIZE) - request.u.ata.command = ATA_WRITE_MUL; - else - request.u.ata.command = ATA_WRITE; - request.u.ata.lba = offset / DEV_BSIZE; - request.u.ata.count = request.bytecount / DEV_BSIZE; - } - else { - request.u.ata.command = ATA_FLUSHCACHE; - request.flags = ATA_R_CONTROL; - } - if (ch->hw.begin_transaction(&request) == ATA_OP_CONTINUES) { - do { - DELAY(20); - } while (ch->hw.end_transaction(&request) == ATA_OP_CONTINUES); - } - if (request.status & ATA_S_ERROR) - return EIO; - return 0; + /* length zero is special and really means flush buffers to media */ + if (!length) + return ata_controlcmd(dp->d_drv1, ATA_FLUSHCACHE, 0, 0, 0); + + bzero(&bp, sizeof(struct bio)); + bp.bio_disk = dp; + bp.bio_pblkno = offset / DEV_BSIZE; + bp.bio_bcount = length; + bp.bio_data = virtual; + bp.bio_cmd = BIO_WRITE; + ad_strategy(&bp); + return bp.bio_error; } static void Index: ata-lowlevel.c =================================================================== RCS file: /nfs/export/ncvs/src/sys/dev/ata/ata-lowlevel.c,v retrieving revision 1.75 diff -u -r1.75 ata-lowlevel.c --- ata-lowlevel.c 5 Jan 2006 21:27:19 -0000 1.75 +++ ata-lowlevel.c 11 Jan 2006 23:00:53 -0000 @@ -48,6 +48,7 @@ /* prototypes */ static int ata_begin_transaction(struct ata_request *); static int ata_end_transaction(struct ata_request *); +static int ata_generic_status(device_t dev); static int ata_wait(struct ata_channel *ch, struct ata_device *, u_int8_t); static void ata_pio_read(struct ata_request *, int); static void ata_pio_write(struct ata_request *, int); @@ -62,6 +63,7 @@ ch->hw.begin_transaction = ata_begin_transaction; ch->hw.end_transaction = ata_end_transaction; + ch->hw.status = ata_generic_status; ch->hw.command = ata_generic_command; } @@ -470,7 +472,7 @@ return ATA_OP_CONTINUES; } -/* must be called with ATA channel locked */ +/* must be called with ATA channel locked and state_mtx held */ void ata_generic_reset(device_t dev) { @@ -605,6 +607,20 @@ "\20\4ATAPI_SLAVE\3ATAPI_MASTER\2ATA_SLAVE\1ATA_MASTER"); } +/* must be called with ATA channel locked and state_mtx held */ +int +ata_generic_status(device_t dev) +{ + struct ata_channel *ch = device_get_softc(dev); + + if (ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_BUSY) { + DELAY(100); + if (ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_BUSY) + return 0; + } + return 1; +} + static int ata_wait(struct ata_channel *ch, struct ata_device *atadev, u_int8_t mask) { Index: ata-pci.c =================================================================== RCS file: /nfs/export/ncvs/src/sys/dev/ata/ata-pci.c,v retrieving revision 1.110 diff -u -r1.110 ata-pci.c --- ata-pci.c 5 Jan 2006 21:27:19 -0000 1.110 +++ ata-pci.c 11 Jan 2006 23:00:54 -0000 @@ -60,6 +60,7 @@ /* prototypes */ static void ata_pci_dmainit(device_t); +static int ata_pci_status(device_t dev); int ata_legacy(device_t dev) @@ -203,7 +204,8 @@ RF_ACTIVE); } - ctlr->chipinit(dev); + if (ctlr->chipinit(dev)) + return ENXIO; /* attach all channels on this controller */ for (unit = 0; unit < ctlr->channels; unit++) { @@ -420,10 +422,42 @@ } } - ata_generic_hw(dev); + ata_pci_hw(dev); return 0; } +void +ata_pci_hw(device_t dev) +{ + struct ata_channel *ch = device_get_softc(dev); + + ata_generic_hw(dev); + ch->hw.status = ata_pci_status; +} + +static int +ata_pci_status(device_t dev) +{ + struct ata_channel *ch = device_get_softc(dev); + + if (ch->dma && ((ch->flags & ATA_ALWAYS_DMASTAT) || + (ch->dma->flags & ATA_DMA_ACTIVE))) { + int bmstat = ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK; + + if ((bmstat & (ATA_BMSTAT_ACTIVE | ATA_BMSTAT_INTERRUPT)) != + ATA_BMSTAT_INTERRUPT) + return 0; + ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, bmstat & ~ATA_BMSTAT_ERROR); + DELAY(1); + } + if (ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_BUSY) { + DELAY(100); + if (ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_BUSY) + return 0; + } + return 1; +} + static int ata_pci_dmastart(device_t dev) { Index: ata-pci.h =================================================================== RCS file: /nfs/export/ncvs/src/sys/dev/ata/ata-pci.h,v retrieving revision 1.59 diff -u -r1.59 ata-pci.h --- ata-pci.h 5 Jan 2006 21:27:19 -0000 1.59 +++ ata-pci.h 11 Jan 2006 23:00:54 -0000 @@ -392,6 +392,7 @@ int ata_pci_setup_intr(device_t dev, device_t child, struct resource *irq, int flags, driver_intr_t *function, void *argument, void **cookiep); int ata_pci_teardown_intr(device_t dev, device_t child, struct resource *irq, void *cookie); int ata_pci_allocate(device_t dev); +void ata_pci_hw(device_t dev); /* global prototypes ata-chipset.c */ int ata_generic_ident(device_t); Index: ata-queue.c =================================================================== RCS file: /nfs/export/ncvs/src/sys/dev/ata/ata-queue.c,v retrieving revision 1.53 diff -u -r1.53 ata-queue.c --- ata-queue.c 5 Jan 2006 21:27:19 -0000 1.53 +++ ata-queue.c 11 Jan 2006 23:22:38 -0000 @@ -94,7 +94,8 @@ /* if this is not a callback wait until request is completed */ if (!request->callback) { ATA_DEBUG_RQ(request, "wait for completition"); - while (sema_timedwait(&request->done, request->timeout * hz * 4)) { + while (!dumping && + sema_timedwait(&request->done, request->timeout * hz * 4)) { device_printf(request->dev, "req=%p %s semaphore timeout !! DANGER Will Robinson !!\n", request, ata_cmd2str(request)); @@ -200,6 +201,13 @@ ata_finish(request); return; } + if (dumping) { + mtx_unlock(&ch->state_mtx); + mtx_unlock(&ch->queue_mtx); + while (!ata_interrupt(ch)) + DELAY(10); + return; + } } mtx_unlock(&ch->state_mtx); } @@ -216,7 +224,8 @@ * if in ATA_STALL_QUEUE state or request has ATA_R_DIRECT flags set * we need to call ata_complete() directly here (no taskqueue involvement) */ - if ((ch->state & ATA_STALL_QUEUE) || (request->flags & ATA_R_DIRECT)) { + if (dumping || + (ch->state & ATA_STALL_QUEUE) || (request->flags & ATA_R_DIRECT)) { ATA_DEBUG_RQ(request, "finish directly"); ata_completed(request, 0); } Index: ata-raid.c =================================================================== RCS file: /nfs/export/ncvs/src/sys/dev/ata/ata-raid.c,v retrieving revision 1.115 diff -u -r1.115 ata-raid.c --- ata-raid.c 5 Jan 2006 21:27:19 -0000 1.115 +++ ata-raid.c 11 Jan 2006 23:28:35 -0000 @@ -111,7 +111,7 @@ /* device structures */ static disk_strategy_t ata_raid_strategy; -//static dumper_t ata_raid_dump; +static dumper_t ata_raid_dump; static void ata_raid_attach(struct ar_softc *rdp, int writeback) @@ -134,7 +134,7 @@ buffer[0] = '\0'; rdp->disk = disk_alloc(); rdp->disk->d_strategy = ata_raid_strategy; - //rdp->disk->d_dump = ata_raid_dump; + rdp->disk->d_dump = ata_raid_dump; rdp->disk->d_name = "ar"; rdp->disk->d_sectorsize = DEV_BSIZE; rdp->disk->d_mediasize = (off_t)rdp->total_sectors * DEV_BSIZE; @@ -751,6 +751,35 @@ ata_free_request(request); } +static int +ata_raid_dump(void *arg, void *virtual, vm_offset_t physical, + off_t offset, size_t length) +{ + struct disk *dp = arg; + struct ar_softc *rdp = dp->d_drv1; + struct bio bp; + + /* length zero is special and really means flush buffers to media */ + if (!length) { + int disk, error; + + for (disk = 0, error = 0; disk < rdp->total_disks; disk++) + if (rdp->disks[disk].dev) + error |= ata_controlcmd(rdp->disks[disk].dev, + ATA_FLUSHCACHE, 0, 0, 0); + return (error ? EIO : 0); + } + + bzero(&bp, sizeof(struct bio)); + bp.bio_disk = dp; + bp.bio_pblkno = offset / DEV_BSIZE; + bp.bio_bcount = length; + bp.bio_data = virtual; + bp.bio_cmd = BIO_WRITE; + ata_raid_strategy(&bp); + return bp.bio_error; +} + static void ata_raid_config_changed(struct ar_softc *rdp, int writeback) { --------------020809040703060107040900--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?43C59717.7000203>