NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
kern/47389: lost interrupt messages with VT6421A and sata atapi device
>Number: 47389
>Category: kern
>Synopsis: lost interrupt messages with viaide(4) and sata atapi device
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: kern-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Tue Jan 01 09:45:01 +0000 2013
>Originator: Onno van der Linden
>Release: NetBSD 6.99.16
>Organization:
>Environment:
System: NetBSD sheep 6.99.16 NetBSD 6.99.16 (SHEEP) #38: Tue Jan 1 09:50:29 MET
2013 root@sheep:/usr/src/sys/arch/i386/compile/SHEEP i386
Architecture: i386
Machine: i386
>Description:
With cd0 an atapi drive attached to the sata port of a via VT6421A
scsictl cd0 identify
results in
viaide0:1:0: lost interrupt
type: atapi tc_bcount: 0 tc_skip: 74
>How-To-Repeat:
scsictl cd0 identify
>Fix:
Somehow the VT6421A doesn't like doing a PIO transfer with
both 32-bit and 16-bit I/O intructions as done in wdc_datain_pio
en wdc_dataout_pio. Fix it by checking the alignment
of the len parameter and do 32/16/8 - bit pio instructions all the way.
*** /sys/dev/pci/viaide.c.orig Mon Dec 31 20:38:58 2012
--- /sys/dev/pci/viaide.c Tue Jan 1 09:47:42 2013
***************
*** 58,63 ****
--- 58,68 ----
const struct pci_attach_args *);
static void via_setup_channel(struct ata_channel *);
+ static void via_datain_pio(struct ata_channel *chp,
+ int flags, void *bf, size_t len);
+ static void via_dataout_pio(struct ata_channel *chp,
+ int flags, void *bf, size_t len);
+
static int viaide_match(device_t, cfdata_t, void *);
static void viaide_attach(device_t, device_t, void *);
static const struct pciide_product_desc *
***************
*** 1118,1123 ****
--- 1123,1130 ----
sc->sc_wdcdev.sc_atac.atac_dma_cap = 2;
sc->sc_wdcdev.sc_atac.atac_udma_cap = 6;
}
+ sc->sc_wdcdev.datain_pio = via_datain_pio;
+ sc->sc_wdcdev.dataout_pio = via_dataout_pio;
sc->sc_wdcdev.sc_atac.atac_set_modes = sata_setup_channel;
sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanarray;
***************
*** 1211,1213 ****
--- 1218,1398 ----
wdcattach(wdc_cp);
}
}
+
+ static void
+ via_datain_pio(struct ata_channel *chp, int flags, void *bf, size_t len)
+ {
+ struct wdc_regs *wdr = CHAN_TO_WDC_REGS(chp);
+
+ #ifndef __NO_STRICT_ALIGNMENT
+ if ((uintptr_t)bf & 1)
+ goto unaligned;
+ if ((flags & ATA_DRIVE_CAP32) && ((uintptr_t)bf & 3))
+ goto unaligned;
+ #endif
+
+ if (flags & ATA_DRIVE_NOSTREAM) {
+ if ((flags & ATA_DRIVE_CAP32) && (len & 3) == 0) {
+ bus_space_read_multi_4(wdr->data32iot,
+ wdr->data32ioh, 0, bf, len >> 2);
+ }
+ else if ((len & 1) == 0) {
+ bus_space_read_multi_2(wdr->cmd_iot,
+ wdr->cmd_iohs[wd_data], 0, bf, len >> 1);
+ }
+ else {
+ bus_space_read_multi_1(wdr->cmd_iot,
+ wdr->cmd_iohs[wd_data], 0, bf, len);
+ }
+ } else {
+ if ((flags & ATA_DRIVE_CAP32) && (len & 3) == 0) {
+ bus_space_read_multi_stream_4(wdr->data32iot,
+ wdr->data32ioh, 0, bf, len >> 2);
+ }
+ else if ((len & 1) == 0) {
+ bus_space_read_multi_stream_2(wdr->cmd_iot,
+ wdr->cmd_iohs[wd_data], 0, bf, len >> 1);
+ }
+ else {
+ bus_space_read_multi_stream_1(wdr->cmd_iot,
+ wdr->cmd_iohs[wd_data], 0, bf, len);
+ }
+ }
+ return;
+
+ #ifndef __NO_STRICT_ALIGNMENT
+ unaligned:
+ if (flags & ATA_DRIVE_NOSTREAM) {
+ if ((flags & ATA_DRIVE_CAP32) && (len & 3) == 0) {
+ while (len > 3) {
+ uint32_t val;
+
+ val = bus_space_read_4(wdr->data32iot,
+ wdr->data32ioh, 0);
+ memcpy(bf, &val, 4);
+ bf = (char *)bf + 4;
+ len -= 4;
+ }
+ }
+ else {
+ while (len > 1) {
+ uint16_t val;
+
+ val = bus_space_read_2(wdr->cmd_iot,
+ wdr->cmd_iohs[wd_data], 0);
+ memcpy(bf, &val, 2);
+ bf = (char *)bf + 2;
+ len -= 2;
+ }
+ }
+ } else {
+ if ((flags & ATA_DRIVE_CAP32) && (len & 3) == 0) {
+ while (len > 3) {
+ uint32_t val;
+
+ val = bus_space_read_stream_4(wdr->data32iot,
+ wdr->data32ioh, 0);
+ memcpy(bf, &val, 4);
+ bf = (char *)bf + 4;
+ len -= 4;
+ }
+ }
+ else {
+ while (len > 1) {
+ uint16_t val;
+
+ val = bus_space_read_stream_2(wdr->cmd_iot,
+ wdr->cmd_iohs[wd_data], 0);
+ memcpy(bf, &val, 2);
+ bf = (char *)bf + 2;
+ len -= 2;
+ }
+ }
+ }
+ #endif
+ }
+
+ static void
+ via_dataout_pio(struct ata_channel *chp, int flags, void *bf, size_t len)
+ {
+ struct wdc_regs *wdr = CHAN_TO_WDC_REGS(chp);
+
+ #ifndef __NO_STRICT_ALIGNMENT
+ if ((uintptr_t)bf & 1)
+ goto unaligned;
+ if ((flags & ATA_DRIVE_CAP32) && ((uintptr_t)bf & 3))
+ goto unaligned;
+ #endif
+
+ if (flags & ATA_DRIVE_NOSTREAM) {
+ if ((flags & ATA_DRIVE_CAP32) && (len & 3) == 0) {
+ bus_space_write_multi_4(wdr->data32iot,
+ wdr->data32ioh, 0, bf, len >> 2);
+ }
+ else {
+ bus_space_write_multi_2(wdr->cmd_iot,
+ wdr->cmd_iohs[wd_data], 0, bf, len >> 1);
+ }
+ } else {
+ if ((flags & ATA_DRIVE_CAP32) && (len & 3) == 0) {
+ bus_space_write_multi_stream_4(wdr->data32iot,
+ wdr->data32ioh, 0, bf, len >> 2);
+ }
+ else {
+ bus_space_write_multi_stream_2(wdr->cmd_iot,
+ wdr->cmd_iohs[wd_data], 0, bf, len >> 1);
+ }
+ }
+ return;
+
+ #ifndef __NO_STRICT_ALIGNMENT
+ unaligned:
+ if (flags & ATA_DRIVE_NOSTREAM) {
+ if ((flags & ATA_DRIVE_CAP32) && (len & 3) == 0) {
+ while (len > 3) {
+ uint32_t val;
+
+ memcpy(&val, bf, 4);
+ bus_space_write_4(wdr->data32iot,
+ wdr->data32ioh, 0, val);
+ bf = (char *)bf + 4;
+ len -= 4;
+ }
+ }
+ else {
+ while (len > 1) {
+ uint16_t val;
+
+ memcpy(&val, bf, 2);
+ bus_space_write_2(wdr->cmd_iot,
+ wdr->cmd_iohs[wd_data], 0, val);
+ bf = (char *)bf + 2;
+ len -= 2;
+ }
+ }
+ } else {
+ if ((flags & ATA_DRIVE_CAP32) && (len & 3) == 0) {
+ while (len > 3) {
+ uint32_t val;
+
+ memcpy(&val, bf, 4);
+ bus_space_write_stream_4(wdr->data32iot,
+ wdr->data32ioh, 0, val);
+ bf = (char *)bf + 4;
+ len -= 4;
+ }
+ }
+ else {
+ while (len > 1) {
+ uint16_t val;
+
+ memcpy(&val, bf, 2);
+ bus_space_write_stream_2(wdr->cmd_iot,
+ wdr->cmd_iohs[wd_data], 0, val);
+ bf = (char *)bf + 2;
+ len -= 2;
+ }
+ }
+ }
+ #endif
+ }
>Unformatted:
Home |
Main Index |
Thread Index |
Old Index