Date: Fri, 21 Nov 2003 02:47:32 +0100 From: Thomas Moestl <t.moestl@tu-bs.de> To: Soren Schmidt <sos@spider.deepcore.dk> Cc: sparc64@freebsd.org Subject: Re: ultra5/cmd646 hang Message-ID: <20031121014732.GA9102@timesink.dyndns.org> In-Reply-To: <200311200834.hAK8YYFh057725@spider.deepcore.dk> References: <20031120031150.GA759@timesink.dyndns.org> <200311200834.hAK8YYFh057725@spider.deepcore.dk>
next in thread | previous in thread | raw e-mail | index | archive | help
--G4iJoqBmSsgzjUCe Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Thu, 2003/11/20 at 09:34:34 +0100, Soren Schmidt wrote: > It seems Thomas Moestl wrote: > > The issue is that the chip does not set ATA_BMSTAT_INTERRUPT, even though > > it is DMA-capable. My hackaround is to add an interrupt handler for the > > CMD646 that does only check this bit if a DMA transfer is in progress, > > like it was done in pre-ATAng times. This probably isn't the best solution, > > but it works for now. On the problematic boxen, you will also have to > > set hw.ata.ata_dma=0 (they fell back to PIO before automatically anyway, > > and DMA operations time out even if all interrupts are admitted). > > I am not sure whether this is caused by some missing bit of setup that > > is required, but that the firmware doesn't do for us, or whether it > > applies only to some buggy/crippled chip revision in some machines. > > Hmm, the only 646 chip I hace sits in an alpha board which -current > hasn't been upgraded for quite some time as it broke it (might be > fixed in the meantime, I'll try to check.. > However if that bit doesn't work the chip has *serious* problems > and cannot be used in DMA mode at all. I dont recall seeing this > problem on the one in my alpha though, so it might be specific to > certain silicon (rev number cannot be trusted in old CMD chips > either, they are so crappy its unbeliveable)... I've played around some more with panther2, and managed to get it to work seemingly stable in WDMA2 mode by tweaking the initialization code a bit. I've attached the patch which I have used; the following changes in it seem to all be required: - Programming the timings before setting the transfer mode with ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, ...); - The added interrupt acking code in the chipset interrupt handler (cribbed from NetBSD) - #if 0-ing out the code that sets the PIO timings. I have not yet investigated whether this is because of the PIO initialization of the disk before DMA is tried, or causes troubles when used for the secondary master, which is a PIO3 CD-ROM. I'll do some more testing tomorrow, and try to shine some light into the PIO timing issue. - Thomas -- Thomas Moestl <t.moestl@tu-bs.de> http://www.tu-bs.de/~y0015675/ <tmm@FreeBSD.org> http://people.FreeBSD.org/~tmm/ PGP fingerprint: 1C97 A604 2BD0 E492 51D0 9C0F 1FE6 4F1D 419C 776C --G4iJoqBmSsgzjUCe Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="ata-hang-point4.diff" Index: ata-chipset.c =================================================================== RCS file: /vol/ncvs/src/sys/dev/ata/ata-chipset.c,v retrieving revision 1.46 diff -u -r1.46 ata-chipset.c --- ata-chipset.c 18 Nov 2003 15:27:28 -0000 1.46 +++ ata-chipset.c 21 Nov 2003 01:22:20 -0000 @@ -101,6 +101,7 @@ static int ata_sii_mio_allocate(device_t, struct ata_channel *); static void ata_sii_intr(void *); static void ata_cmd_intr(void *); +static void ata_nobms_intr(void *); static void ata_sii_setmode(struct ata_device *, int); static void ata_cmd_setmode(struct ata_device *, int); static int ata_sis_chipinit(device_t); @@ -1581,7 +1582,7 @@ { ATA_CMD649, 0x00, 0, SIIINTR, ATA_UDMA5, "CMD 649" }, { ATA_CMD648, 0x00, 0, SIIINTR, ATA_UDMA4, "CMD 648" }, { ATA_CMD646, 0x07, 0, 0, ATA_UDMA2, "CMD 646U2" }, - { ATA_CMD646, 0x00, 0, 0, ATA_WDMA2, "CMD 646" }, + { ATA_CMD646, 0x00, 0, SIINOBMS, ATA_WDMA2, "CMD 646" }, { 0, 0, 0, 0, 0, 0}}; char buffer[64]; @@ -1599,6 +1600,7 @@ ata_sii_chipinit(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); + void (*ih)(void *); int rid = ATA_IRQ_RID; if (!(ctlr->r_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, @@ -1637,10 +1639,14 @@ ctlr->setmode = ata_sii_setmode; } else { + if (ctlr->chip->cfg2 & SIIINTR) + ih = ata_cmd_intr; + else if (ctlr->chip->cfg2 & SIINOBMS) + ih = ata_nobms_intr; + else + ih = ata_generic_intr; if ((bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS, - ctlr->chip->cfg2 & SIIINTR ? - ata_cmd_intr : ata_generic_intr, - ctlr, &ctlr->handle))) { + ih, ctlr, &ctlr->handle))) { device_printf(dev, "unable to setup interrupt\n"); return ENXIO; } @@ -1743,6 +1749,40 @@ } static void +ata_nobms_intr(void *data) +{ + struct ata_pci_controller *ctlr = data; + struct ata_channel *ch; + int cr, conf; + 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; + /* + * The CMD646 does not always seem to set ATA_BMSTAT_INTERRUPT. + * Only check it when a transfer is active. + */ + 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); + /* Ack the interrupt. */ + cr = unit == 0 ? 0x50 : 0x57; + conf = pci_read_config(device_get_parent(ch->dev), cr, 1); + pci_write_config(device_get_parent(ch->dev), cr, + conf | (unit == 0 ? 0x04 : 0x10), 1); + } +} + +static void ata_sii_setmode(struct ata_device *atadev, int mode) { device_t parent = device_get_parent(atadev->channel->dev); @@ -1805,56 +1845,64 @@ } static void +ata_cmd_settimings(struct ata_device *atadev, device_t parent, int mode) +{ + int devno = (atadev->channel->unit << 1) + ATA_DEV(atadev->unit); + int treg = 0x54 + (devno < 3) ? (devno << 1) : 7; + int ureg = atadev->channel->unit ? 0x7b : 0x73; + + if (mode >= ATA_UDMA0) { + int udmatimings[][2] = { { 0x31, 0xc2 }, { 0x21, 0x82 }, + { 0x11, 0x42 }, { 0x25, 0x8a }, + { 0x15, 0x4a }, { 0x05, 0x0a } }; + + u_int8_t umode = pci_read_config(parent, ureg, 1); + + umode &= ~(atadev->unit == ATA_MASTER ? 0x35 : 0xca); + umode |= udmatimings[mode & ATA_MODE_MASK][ATA_DEV(atadev->unit)]; + pci_write_config(parent, ureg, umode, 1); + } + else if (mode >= ATA_WDMA0) { + int dmatimings[] = { 0x87, 0x32, 0x3f }; + + pci_write_config(parent, treg, dmatimings[mode & ATA_MODE_MASK], 1); + pci_write_config(parent, ureg, + pci_read_config(parent, ureg, 1) & + ~(atadev->unit == ATA_MASTER ? 0x35 : 0xca), 1); + } + else { +#if 0 + int piotimings[] = { 0xa9, 0x57, 0x44, 0x32, 0x3f }; + pci_write_config(parent, treg, + piotimings[(mode & ATA_MODE_MASK) - ATA_PIO0], 1); + pci_write_config(parent, ureg, + pci_read_config(parent, ureg, 1) & + ~(atadev->unit == ATA_MASTER ? 0x35 : 0xca), 1); +#endif + } + +} + +static void ata_cmd_setmode(struct ata_device *atadev, int mode) { device_t parent = device_get_parent(atadev->channel->dev); struct ata_pci_controller *ctlr = device_get_softc(parent); - int devno = (atadev->channel->unit << 1) + ATA_DEV(atadev->unit); int error; mode = ata_limit_mode(atadev, mode, ctlr->chip->max_dma); - mode = ata_check_80pin(atadev, mode); + ata_cmd_settimings(atadev, parent, mode); error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode); - if (bootverbose) ata_prtdev(atadev, "%ssetting %s on %s chip\n", (error) ? "FAILURE " : "", ata_mode2str(mode), ctlr->chip->text); - if (!error) { - int treg = 0x54 + (devno < 3) ? (devno << 1) : 7; - int ureg = atadev->channel->unit ? 0x7b : 0x73; - - if (mode >= ATA_UDMA0) { - int udmatimings[][2] = { { 0x31, 0xc2 }, { 0x21, 0x82 }, - { 0x11, 0x42 }, { 0x25, 0x8a }, - { 0x15, 0x4a }, { 0x05, 0x0a } }; - - u_int8_t umode = pci_read_config(parent, ureg, 1); - - umode &= ~(atadev->unit == ATA_MASTER ? 0x35 : 0xca); - umode |= udmatimings[mode & ATA_MODE_MASK][ATA_DEV(atadev->unit)]; - pci_write_config(parent, ureg, umode, 1); - } - else if (mode >= ATA_WDMA0) { - int dmatimings[] = { 0x87, 0x32, 0x3f }; - - pci_write_config(parent, treg, dmatimings[mode & ATA_MODE_MASK], 1); - pci_write_config(parent, ureg, - pci_read_config(parent, ureg, 1) & - ~(atadev->unit == ATA_MASTER ? 0x35 : 0xca), 1); - } - else { - int piotimings[] = { 0xa9, 0x57, 0x44, 0x32, 0x3f }; - pci_write_config(parent, treg, - piotimings[(mode & ATA_MODE_MASK) - ATA_PIO0], 1); - pci_write_config(parent, ureg, - pci_read_config(parent, ureg, 1) & - ~(atadev->unit == ATA_MASTER ? 0x35 : 0xca), 1); - } + if (error) + ata_cmd_settimings(atadev, parent, atadev->mode); + else atadev->mode = mode; - } } /* Index: ata-pci.h =================================================================== RCS file: /vol/ncvs/src/sys/dev/ata/ata-pci.h,v retrieving revision 1.18 diff -u -r1.18 ata-pci.h --- ata-pci.h 18 Nov 2003 15:27:28 -0000 1.18 +++ ata-pci.h 21 Nov 2003 00:21:00 -0000 @@ -255,6 +255,7 @@ #define SIIMEMIO 1 #define SIIINTR 0x01 #define SIISETCLK 0x02 +#define SIINOBMS 0x04 #define SIS_SOUTH 1 #define SISSATA 2 Index: ata-queue.c =================================================================== RCS file: /vol/ncvs/src/sys/dev/ata/ata-queue.c,v retrieving revision 1.11 diff -u -r1.11 ata-queue.c --- ata-queue.c 20 Oct 2003 14:28:37 -0000 1.11 +++ ata-queue.c 21 Nov 2003 00:21:00 -0000 @@ -316,6 +316,8 @@ ata_timeout(struct ata_request *request) { struct ata_channel *ch = request->device->channel; + struct ata_device *reqdev = request->device; + char *reqstr = ata_cmd2str(request); int quiet = request->flags & ATA_R_QUIET; /* clear timeout etc */ @@ -324,10 +326,11 @@ /* call hw.interrupt to try finish up the command */ ch->hw.interrupt(request->device->channel); if (ch->running != request) { + /* request might already be freed - use copies. */ if (!quiet) - ata_prtdev(request->device, + ata_prtdev(reqdev, "WARNING - %s recovered from missing interrupt\n", - ata_cmd2str(request)); + reqstr); return; } --G4iJoqBmSsgzjUCe--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20031121014732.GA9102>