From owner-freebsd-current@FreeBSD.ORG Tue May 4 11:25:44 2004 Return-Path: Delivered-To: freebsd-current@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 4166C16A4CF for ; Tue, 4 May 2004 11:25:44 -0700 (PDT) Received: from mail.ambrisko.com (adsl-64-174-51-43.dsl.snfc21.pacbell.net [64.174.51.43]) by mx1.FreeBSD.org (Postfix) with ESMTP id E25FB43D5E for ; Tue, 4 May 2004 11:25:42 -0700 (PDT) (envelope-from ambrisko@ambrisko.com) Received: from server2.ambrisko.com (HELO www.ambrisko.com) (192.168.1.2) by mail.ambrisko.com with ESMTP; 04 May 2004 11:25:42 -0700 Received: from ambrisko.com (localhost [127.0.0.1]) by www.ambrisko.com (8.12.9p2/8.12.9) with ESMTP id i44IPgjd021574 for ; Tue, 4 May 2004 11:25:42 -0700 (PDT) (envelope-from ambrisko@ambrisko.com) Received: (from ambrisko@localhost) by ambrisko.com (8.12.9p2/8.12.9/Submit) id i44IPgVa021573 for current@freebsd.org; Tue, 4 May 2004 11:25:42 -0700 (PDT) (envelope-from ambrisko) From: Doug Ambrisko Message-Id: <200405041825.i44IPgVa021573@ambrisko.com> To: current@freebsd.org Date: Tue, 4 May 2004 11:25:42 -0700 (PDT) X-Mailer: ELM [version 2.4ME+ PL94b (25)] MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=US-ASCII Subject: Updated SATA support patches for Intel ICH & Promise cards X-BeenThere: freebsd-current@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: Discussions about the use of FreeBSD-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 04 May 2004 18:25:44 -0000 These patches have been updated to -current as of the past weekend. They increase the robustness of SATA disk errors (media errors and drive going away such as drives that spin up and down). Also has code to support hot swap on both controllers. This is only HW support and does not address other ata/FreeBSD issues. That isn't quite right ... some ata changes have been made to avoid panics in probes etc. to support the HW changes. It would be nice to get this into FreeBSD in some form then I can help with other issues. I have -stable code to read and write the Intel RAID meta-data but not Adaptec. My latest -stable patches supports Intel/ Promise SATA hot-swap and the Intel RAID meta-data with ata-raid. Doug A. Index: sys/dev/ata/ata-all.c =================================================================== RCS file: /cvs/src/sys/dev/ata/ata-all.c,v retrieving revision 1.208 diff -u -p -r1.208 ata-all.c --- sys/dev/ata/ata-all.c 13 Apr 2004 09:44:20 -0000 1.208 +++ sys/dev/ata/ata-all.c 4 May 2004 18:16:49 -0000 @@ -119,7 +119,6 @@ ata_probe(device_t dev) ch->device[SLAVE].channel = ch; ch->device[SLAVE].unit = ATA_SLAVE; ch->device[SLAVE].mode = ATA_PIO; - ch->dev = dev; ch->state = ATA_IDLE; /* initialise device(s) on this channel */ @@ -308,6 +307,19 @@ ata_reinit(struct ata_channel *ch) return 0; } +static void +ata_reinit_task(void *data, int dummy) +{ + ata_reinit(data); +} + +void +ata_queue_reinit(struct ata_channel *ch) +{ + TASK_INIT(&ch->task, 0, ata_reinit_task, ch); + taskqueue_enqueue(taskqueue_thread, &ch->task); +} + int ata_suspend(device_t dev) { Index: sys/dev/ata/ata-all.h =================================================================== RCS file: /cvs/src/sys/dev/ata/ata-all.h,v retrieving revision 1.78 diff -u -p -r1.78 ata-all.h --- sys/dev/ata/ata-all.h 13 Apr 2004 09:44:20 -0000 1.78 +++ sys/dev/ata/ata-all.h 4 May 2004 18:16:49 -0000 @@ -363,6 +363,10 @@ struct ata_channel { struct mtx queue_mtx; /* queue lock */ TAILQ_HEAD(, ata_request) ata_queue; /* head of ATA queue */ struct ata_request *running; /* currently running request */ + int sata_master_idx; + int sata_slave_idx; + struct task task; /* task management */ + struct callout_handle timeout_handle; /* poll channel */ }; /* disk bay/enclosure related */ @@ -398,6 +402,7 @@ int ata_limit_mode(struct ata_device *at /* ata-queue.c: */ int ata_reinit(struct ata_channel *ch); +void ata_queue_reinit(struct ata_channel *ch); void ata_start(struct ata_channel *ch); int ata_controlcmd(struct ata_device *atadev, u_int8_t command, u_int16_t feature, u_int64_t lba, u_int16_t count); int ata_atapicmd(struct ata_device *atadev, u_int8_t *ccb, caddr_t data, int count, int flags, int timeout); Index: sys/dev/ata/ata-chipset.c =================================================================== RCS file: /cvs/src/sys/dev/ata/ata-chipset.c,v retrieving revision 1.70 diff -u -p -r1.70 ata-chipset.c --- sys/dev/ata/ata-chipset.c 24 Apr 2004 15:54:20 -0000 1.70 +++ sys/dev/ata/ata-chipset.c 4 May 2004 18:16:49 -0000 @@ -81,6 +81,11 @@ static int ata_highpoint_check_80pin(str static int ata_intel_chipinit(device_t); static void ata_intel_old_setmode(struct ata_device *, int); static void ata_intel_new_setmode(struct ata_device *, int); +static int ata_intel_sata_allocate(device_t, struct ata_channel *); +static void ata_intel_map_sata_ports(device_t, struct ata_channel *); +static void ata_intel_sata_intr(void *); +static void ata_intel_sata_status(struct ata_channel *); +static void ata_intel_sata_reset(struct ata_channel *); static int ata_national_chipinit(device_t); static void ata_national_setmode(struct ata_device *, int); static int ata_nvidia_chipinit(device_t); @@ -827,11 +832,11 @@ ata_intel_ident(device_t dev) { ATA_I82801DB, 0, 0, 0x00, ATA_UDMA5, "Intel ICH4" }, { ATA_I82801DB_1, 0, 0, 0x00, ATA_UDMA5, "Intel ICH4" }, { ATA_I82801EB, 0, 0, 0x00, ATA_UDMA5, "Intel ICH5" }, - { ATA_I82801EB_1, 0, 0, 0x00, ATA_SA150, "Intel ICH5" }, - { ATA_I82801EB_2, 0, 0, 0x00, ATA_SA150, "Intel ICH5" }, - { ATA_I6300ESB, 0, 0, 0x00, ATA_UDMA5, "Intel ICH5" }, - { ATA_I6300ESB_1, 0, 0, 0x00, ATA_SA150, "Intel ICH5" }, - { ATA_I6300ESB_2, 0, 0, 0x00, ATA_SA150, "Intel ICH5" }, + { ATA_I82801EB_1, 0, 0, ISATA, ATA_SA150, "Intel ICH5" }, + { ATA_I82801EB_2, 0, 0, ISATA, ATA_SA150, "Intel ICH5" }, + { ATA_I6300ESB, 0, 0, 0x00, ATA_UDMA5, "Intel ICH6" }, + { ATA_I6300ESB_1, 0, 0, ISATA, ATA_SA150, "Intel ICH6" }, + { ATA_I6300ESB_2, 0, 0, ISATA, ATA_SA150, "Intel ICH6" }, { 0, 0, 0, 0, 0, 0}}; char buffer[64]; @@ -849,6 +854,35 @@ static int ata_intel_chipinit(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); + int rid = ATA_IRQ_RID; + + if (ctlr->chip->cfg2 & ISATA) { + ctlr->allocate = ata_intel_sata_allocate; + + /* Clear SATA error registers */ + pci_write_config(dev, 0xa0, 0x54, 4); + pci_write_config(dev, 0xa4, pci_read_config(dev, 0xa4, 4), 4); + pci_write_config(dev, 0xa0, 0x64, 4); + pci_write_config(dev, 0xa4, pci_read_config(dev, 0xa4, 4), 4); + + 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_sata_intr, ctlr, &ctlr->handle))) { + device_printf(dev, "unable to setup interrupt\n"); + return ENXIO; + } + } + + ctlr->setmode = ata_sata_setmode; + + return 0; + } if (ata_setup_interrupt(dev)) return ENXIO; @@ -944,6 +978,228 @@ ata_intel_new_setmode(struct ata_device atadev->mode = mode; } +static int +ata_intel_sata_allocate(device_t dev, struct ata_channel *ch) +{ + struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); + struct resource *io = NULL, *altio = NULL; + int i, rid; + + rid = ATA_IOADDR_RID; + io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, + 0, ~0, ATA_IOSIZE, RF_ACTIVE); + if (!io) + return ENXIO; + + rid = ATA_ALTADDR_RID; + altio = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, + 0, ~0, ATA_ALTIOSIZE, RF_ACTIVE); + if (!altio) { + bus_release_resource(dev, SYS_RES_IOPORT, ATA_IOADDR_RID, io); + return ENXIO; + } + + for (i = ATA_DATA; i <= ATA_STATUS; i ++) { + ch->r_io[i].res = io; + ch->r_io[i].offset = i; + } + ch->r_io[ATA_ALTSTAT].res = altio; + ch->r_io[ATA_ALTSTAT].offset = ata_legacy(device_get_parent(dev)) ? 0 : 2; + ch->r_io[ATA_IDX_ADDR].res = io; + + if (ctlr->r_res1) { + for (i = ATA_BMCMD_PORT; i <= ATA_BMDTP_PORT; i++) { + ch->r_io[i].res = ctlr->r_res1; + ch->r_io[i].offset = (i - ATA_BMCMD_PORT)+(ch->unit * ATA_BMIOSIZE); + } + + /* if simplex controller, only allow DMA on primary channel */ + ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & + (ATA_BMSTAT_DMA_MASTER | ATA_BMSTAT_DMA_SLAVE)); + if (ch->unit > 0 && + (ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & ATA_BMSTAT_DMA_SIMPLEX)) + device_printf(dev, "simplex device, DMA on primary only\n"); + else + ctlr->dmainit(ch); + } + + ch->reset = ata_intel_sata_reset; + ata_intel_map_sata_ports(dev, ch); + + ata_generic_hw(ch); + + return 0; +} + +void +ata_intel_map_sata_ports(device_t dev, struct ata_channel *ch) +{ + device_t parent = device_get_parent(dev); + int unit = ch->unit; + int sata_config; + + sata_config = pci_read_config(parent, 0x90, 1); + + switch (sata_config & 7) { + case 0: /* SATA P0 on pri master SATA P1 on sec master */ + if (unit == 0) { + ch->sata_master_idx = 1; + device_printf(dev, "SATA P0 primary master\n"); + } + if (unit == 1) { + ch->sata_master_idx = 2; + device_printf(dev, "SATA P1 secondary master\n"); + } + break; + case 1: /* SATA P0 on sec master SATA P1 on pri master */ + if (unit == 0) { + ch->sata_master_idx = 2; + device_printf(dev, "SATA P0 secondary master\n"); + } + if (unit == 1) { + ch->sata_master_idx = 0; + device_printf(dev, "SATA P1 primary master\n"); + } + break; + case 4: /* SATA P0 on pri master SATA P1 on pri slave */ + if (unit == 0) { + ch->sata_master_idx = 1; + ch->sata_slave_idx = 2; + device_printf(dev, "SATA P0 primary master\n"); + device_printf(dev, "SATA P1 primary slave\n"); + } + break; + case 5: /* SATA P0 on pri slave SATA P1 on pri master */ + if (unit == 0) { + ch->sata_master_idx = 2; + ch->sata_slave_idx = 1; + device_printf(dev, "SATA P0 primary slave\n"); + device_printf(dev, "SATA P1 primary master\n"); + } + break; + case 6: /* SATA P0 on sec master SATA P1 on sec slave */ + if (unit == 1) { + ch->sata_master_idx = 1; + ch->sata_slave_idx = 2; + device_printf(dev, "SATA P0 secondary master\n"); + device_printf(dev, "SATA P1 secondary slave\n"); + } + break; + case 7: /* SATA P0 on sec slave SATA P1 on sec master */ + if (unit == 1) { + ch->sata_master_idx = 2; + ch->sata_slave_idx = 1; + device_printf(dev, "SATA P0 secondary slave\n"); + device_printf(dev, "SATA P1 secondary master\n"); + } + break; + } +} + +static void +ata_intel_sata_status(struct ata_channel *ch) +{ + device_t parent; + struct ata_pci_controller *ctlr; + u_int32_t sstatus, serror, scontrol; + int index = 0, device, base; + + if (!ch->dev) /* Channel not ready */ + return; + parent = device_get_parent(ch->dev); + ctlr = device_get_softc(parent); + + ch->locking(ch, ATA_LF_LOCK); + untimeout((timeout_t *)ata_intel_sata_status, ch, ch->timeout_handle); + + index = ch->sata_master_idx | ch->sata_slave_idx;; + + for (device = 1; device <= 2; device++) { + if (index & device) { + if (device == 1) + base = 0x50; + else + base = 0x60; + + pci_write_config(parent, 0xa0, base, 4); + sstatus = pci_read_config(parent, 0xa4, 4); + + pci_write_config(parent, 0xa0, base + 4, 4); + serror = pci_read_config(parent, 0xa4, 4); + + pci_write_config(parent, 0xa0, base + 8, 4); + scontrol = pci_read_config(parent, 0xa4, 4); + + if (serror) { + if (sstatus == 0x05) { /* Drive left reset port */ + pci_write_config(parent, 0x92, + pci_read_config(parent, 0x92, 2) & ~device, 2); + pci_write_config(parent, 0x92, + pci_read_config(parent, 0x92, 2) | device, 2); + } + + /* Loop until SATA port is okay otherwise we can hang */ + for (;;) { + pci_write_config(parent, 0xa0, base, 4); + sstatus = pci_read_config(parent, 0xa4, 4); + + pci_write_config(parent, 0xa0, base + 4, 4); + serror = pci_read_config(parent, 0xa4, 4); + /* Acknowledge serror */ + pci_write_config(parent, 0xa4, serror, 4); + + pci_write_config(parent, 0xa0, base + 8, 4); + scontrol = pci_read_config(parent, 0xa4, 4); + device_printf(ch->dev, + "Intel SATA P%d status %x error %x scontrol %x %d %x\n", + device - 1, sstatus, serror, scontrol, + ch->unit, ch->devices); + if (!serror && sstatus != 5) + break; + + DELAY(100000); + } + ata_queue_reinit(ch); + } + } + } + ch->timeout_handle = timeout((timeout_t*)ata_intel_sata_status, + ch, 10 * hz); + + ch->locking(ch, ATA_LF_UNLOCK); +} + +static void +ata_intel_sata_intr(void *data) +{ + struct ata_pci_controller *ctlr = data; + struct ata_channel *ch; + int unit; + + /* implement this as a toggle instead to balance load XXX */ + for (unit = 0; unit < 2; unit++) { + if (!(ch = ctlr->interrupt[unit].argument)) + continue; + ata_intel_sata_status(ch); + 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_intel_sata_reset(struct ata_channel *ch) +{ + ata_intel_sata_status(ch); +} + /* * National chipset support functions */ @@ -1182,6 +1438,8 @@ ata_promise_chipinit(device_t dev) struct ata_pci_controller *ctlr = device_get_softc(dev); int rid = ATA_IRQ_RID; + mtx_init(&ctlr->mtx, "ATA controller lock", MTX_DEF, 0); + 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"); @@ -1238,7 +1496,7 @@ ata_promise_chipinit(device_t dev) ((ATA_INL(ctlr->r_res2, 0x48) & 0x02) > 0) + 2; } else if (ctlr->chip->cfg2 & PRSATA) { - ATA_OUTL(ctlr->r_res2, 0x06c, 0x00ff0033); + ATA_OUTL(ctlr->r_res2, 0x06c, 0x000000ff); ctlr->channels = ((ATA_INL(ctlr->r_res2, 0x48) & 0x02) > 0) + 3; } else @@ -1302,6 +1560,7 @@ ata_promise_mio_allocate(device_t dev, s ch->r_io[ATA_IDX_ADDR].res = ctlr->r_res2; ch->flags |= ATA_USE_16BIT; ch->reset = ata_promise_mio_reset; + ch->reset(ch); ctlr->dmainit(ch); ata_generic_hw(ch); @@ -1317,13 +1576,50 @@ ata_promise_mio_intr(void *data) { struct ata_pci_controller *ctlr = data; struct ata_channel *ch; - u_int32_t vector = ATA_INL(ctlr->r_res2, 0x00040); + u_int32_t vector, plug_status; + int offset = (ctlr->chip->cfg2 & PRSX4X) ? 0x000c0000 : 0; int unit; + if (ctlr->chip->cfg2 & PRSATA) { + /* Check for all drive changes first */ + plug_status = ATA_INL(ctlr->r_res2, 0x06c); + for (unit = 0; unit < ctlr->channels; unit++) { + if (plug_status & (1 << unit)) { + /* drive gone */ + ATA_OUTL(ctlr->r_res2, 0x06c, 1 << unit); + if ((ch = ctlr->interrupt[unit].argument)) { + device_printf(ch->dev, + "device on port %d gone\n", unit + 1); + ata_queue_reinit(ch); + } + } + + if (plug_status & (1 << (unit + 4))) { + /* drive connected */ + ATA_OUTL(ctlr->r_res2, 0x06c, 1 << (unit + 4)); + if ((ch = ctlr->interrupt[unit].argument)) { + device_printf(ch->dev, + "device on port %d connected\n", unit + 1); + ata_queue_reinit(ch); + } + } + } + } + + vector = ATA_INL(ctlr->r_res2, 0x00040); for (unit = 0; unit < ctlr->channels; unit++) { if (vector & (1 << (unit + 1))) { if ((ch = ctlr->interrupt[unit].argument)) + if (ATA_INL(ctlr->r_res2, offset + ((ch->unit + 1) << 2)) + & 1 << (ch->unit + 16)) + ch->reset(ch); ctlr->interrupt[unit].function(ch); + ATA_OUTL(ctlr->r_res2, offset + 0x0260 + (ch->unit << 7), + (ATA_INL(ctlr->r_res2, + offset + 0x0260 + (ch->unit << 7)) & + ~0x00003f9f) | (ch->unit + 1)); + + ATA_OUTL(ctlr->r_res2, offset + ((ch->unit + 1) << 2), 0x1); } } } @@ -1389,7 +1685,32 @@ ata_promise_mio_reset(struct ata_channel struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(ch->dev)); int offset = (ctlr->chip->cfg2 & PRSX4X) ? 0x000c0000 : 0; + u_int32_t control; + + mtx_lock(&ctlr->mtx); + control = ATA_INL(ctlr->r_res2, 0x0048); + /* channel reset */ + control &= ~(1 << (ch->unit + 12)); + ATA_OUTL(ctlr->r_res2, 0x0048, control); + control |= 1 << (ch->unit + 12); + ATA_OUTL(ctlr->r_res2, 0x0048, control); + + DELAY(1000); /* DJA XXX */ + mtx_unlock(&ctlr->mtx); + + if (ctlr->chip->cfg2 & PRSATA) { + /* clear plug status that bounces during hard reset */ + ATA_OUTL(ctlr->r_res2, 0x06c, (1 << ch->unit) | (1 << (ch->unit + 4))); + } + + /* ATA module reset */ + ATA_OUTL(ctlr->r_res2, offset + 0x0260 + (ch->unit << 7), 0x800); + + /* Define which sequencer to interrupt on */ + ATA_OUTL(ctlr->r_res2, offset + 0x0260 + (ch->unit << 7), + 0x80008000 | (ch->unit + 1)); + /* Define which sequencer to interrupt on */ ATA_OUTL(ctlr->r_res2, offset + 0x0260 + (ch->unit << 7), (ATA_INL(ctlr->r_res2, offset + 0x0260 + (ch->unit << 7)) & ~0x00003f9f) | (ch->unit + 1)); Index: sys/dev/ata/ata-lowlevel.c =================================================================== RCS file: /cvs/src/sys/dev/ata/ata-lowlevel.c,v retrieving revision 1.34 diff -u -p -r1.34 ata-lowlevel.c --- sys/dev/ata/ata-lowlevel.c 27 Apr 2004 15:52:08 -0000 1.34 +++ sys/dev/ata/ata-lowlevel.c 4 May 2004 18:16:49 -0000 @@ -573,6 +573,10 @@ ata_generic_reset(struct ata_channel *ch if (!mask) return; + /* reset host end of channel (if supported) */ + if (ch->reset) + ch->reset(ch); + /* reset (both) devices on this channel */ ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER); DELAY(10); Index: sys/dev/ata/ata-pci.c =================================================================== RCS file: /cvs/src/sys/dev/ata/ata-pci.c,v retrieving revision 1.82 diff -u -p -r1.82 ata-pci.c --- sys/dev/ata/ata-pci.c 27 Apr 2004 12:54:59 -0000 1.82 +++ sys/dev/ata/ata-pci.c 4 May 2004 18:16:49 -0000 @@ -523,12 +523,15 @@ ata_pcisub_probe(device_t dev) } free(children, M_TEMP); + ch->dev = dev; if ((error = ctlr->allocate(dev, ch))) return error; ch->device[MASTER].setmode = ctlr->setmode; ch->device[SLAVE].setmode = ctlr->setmode; ch->locking = ctlr->locking; + if (ch->reset) + ch->reset(ch); return ata_probe(dev); } Index: sys/dev/ata/ata-pci.h =================================================================== RCS file: /cvs/src/sys/dev/ata/ata-pci.h,v retrieving revision 1.30 diff -u -p -r1.30 ata-pci.h --- sys/dev/ata/ata-pci.h 21 Apr 2004 20:03:26 -0000 1.30 +++ sys/dev/ata/ata-pci.h 4 May 2004 18:16:49 -0000 @@ -61,6 +61,7 @@ struct ata_pci_controller { void *argument; } interrupt[8]; /* SOS max ch# for now XXX */ void *driver; + struct mtx mtx; }; /* defines for known chipset PCI id's */ @@ -251,6 +252,8 @@ struct ata_pci_controller { #define HPT374 3 #define HPTOLD 0x01 +#define ISATA 1 + #define PROLD 0 #define PRNEW 1 #define PRTX 2 Index: sys/dev/ata/ata-queue.c =================================================================== RCS file: /cvs/src/sys/dev/ata/ata-queue.c,v retrieving revision 1.26 diff -u -p -r1.26 ata-queue.c --- sys/dev/ata/ata-queue.c 13 Apr 2004 09:44:20 -0000 1.26 +++ sys/dev/ata/ata-queue.c 4 May 2004 18:16:49 -0000 @@ -454,6 +454,7 @@ ata_timeout(struct ata_request *request) printf("\n"); } + request->device->channel->hw.reset(request->device->channel); /* now simulate the missing interrupt */ request->flags |= ATA_R_TIMEOUT; request->device->channel->hw.interrupt(request->device->channel);