From 4ee36d6512945f71f577aed3da1f1ae9188d6ad9 Mon Sep 17 00:00:00 2001 From: downsj Date: Wed, 11 Sep 1996 07:27:03 +0000 Subject: [PATCH] Rearrange much of the polling code so really, really *busted* NEC hardware mostly works, along with various other bits of cleanup. Please, people, if you have any choice in the matter at all, avoid NEC IDE CD-ROM drives like the plague upon mankind they are. Especially DO NOT connect a NEC and another brand ATAPI drive to the same controller! --- sys/dev/isa/wdc.c | 134 ++++++++++++++++++++++++++----------------- sys/dev/isa/wdlink.h | 3 +- 2 files changed, 83 insertions(+), 54 deletions(-) diff --git a/sys/dev/isa/wdc.c b/sys/dev/isa/wdc.c index 0c4f1e2b64c..f60869de2b9 100644 --- a/sys/dev/isa/wdc.c +++ b/sys/dev/isa/wdc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: wdc.c,v 1.7 1996/09/09 05:29:16 mickey Exp $ */ +/* $OpenBSD: wdc.c,v 1.8 1996/09/11 07:27:03 downsj Exp $ */ /* $NetBSD: wd.c,v 1.150 1996/05/12 23:54:03 mycroft Exp $ */ /* @@ -100,6 +100,8 @@ struct cfdriver wdc_cd = { int wdc_ata_intr __P((struct wdc_softc *,struct wdc_xfer *)); void wdcstart __P((struct wdc_softc *)); void wdc_ata_start __P((struct wdc_softc *,struct wdc_xfer *)); +int wait_for_phase __P((struct wdc_softc *, int)); +int wait_for_unphase __P((struct wdc_softc *, int)); void wdc_atapi_start __P((struct wdc_softc *,struct wdc_xfer *)); int wdcreset __P((struct wdc_softc *)); void wdcrestart __P((void *arg)); @@ -391,7 +393,7 @@ wdc_ata_start(wdc, xfer) blkno = xfer->c_blkno+xfer->c_p_offset; xfer->c_blkno = blkno / (d_link->sc_lp->d_secsize / DEV_BSIZE); } else { - WDDEBUG_PRINT((" %d)%x", xfer->c_skip, + WDDEBUG_PRINT((" %d)0x%x", xfer->c_skip, bus_io_read_1(bc, ioh, wd_altsts))); } @@ -556,6 +558,48 @@ wdc_ata_start(wdc, xfer) WDDEBUG_PRINT(("done\n")); } +int +wait_for_phase(wdc, wphase) + struct wdc_softc *wdc; + int wphase; +{ + bus_chipset_tag_t bc = wdc->sc_bc; + bus_io_handle_t ioh = wdc->sc_ioh; + int i, phase; + + for (i = 20000; i; i--) { + phase = (bus_io_read_1(bc, ioh, wd_ireason) & + (WDCI_CMD | WDCI_IN)) | + (bus_io_read_1(bc, ioh, wd_status) + & WDCS_DRQ); + if (phase == wphase) + break; + delay(10); + } + return (phase); +} + +int +wait_for_unphase(wdc, wphase) + struct wdc_softc *wdc; + int wphase; +{ + bus_chipset_tag_t bc = wdc->sc_bc; + bus_io_handle_t ioh = wdc->sc_ioh; + int i, phase; + + for (i = 20000; i; i--) { + phase = (bus_io_read_1(bc, ioh, wd_ireason) & + (WDCI_CMD | WDCI_IN)) | + (bus_io_read_1(bc, ioh, wd_status) + & WDCS_DRQ); + if (phase != wphase) + break; + delay(10); + } + return (phase); +} + void wdc_atapi_start(wdc, xfer) struct wdc_softc *wdc; @@ -591,23 +635,18 @@ wdc_atapi_start(wdc, xfer) return; } if ((acp->flags & (ACAP_DRQ_INTR|ACAP_DRQ_ACCEL)) != ACAP_DRQ_INTR) { - int i, phase; - for (i=20000; i>0; --i) { - phase = (bus_io_read_1(bc, ioh, wd_ireason) & - (WDCI_CMD | WDCI_IN)) | - (bus_io_read_1(bc, ioh, wd_status) - & WDCS_DRQ); - if (phase == PHASE_CMDOUT) - break; - delay(10); - } - if (phase != PHASE_CMDOUT ) { - printf("wdc_atapi_start: timout waiting PHASE_CMDOUT"); - printf("(0x%x)\n", phase); - acp->status = ERROR; - wdc_atapi_done(wdc, xfer); - return; - } + if (!(wdc->sc_flags & WDCF_BROKENPOLL)) { + int phase = wait_for_phase(wdc, PHASE_CMDOUT); + + if (phase != PHASE_CMDOUT) { + printf("wdc_atapi_start: timeout waiting PHASE_CMDOUT, got 0x%x\n", phase); + + /* NEC SUCKS. */ + wdc->sc_flags |= WDCF_BROKENPOLL; + } + } else + DELAY(10); /* Simply pray for the data. */ + bus_io_write_raw_multi_2(bc, ioh, wd_data, acp->command, acp->command_size); } @@ -894,7 +933,7 @@ wdcwait(wdc, mask) break; if (++timeout > WDCNDELAY) { #ifdef ATAPI_DEBUG2 - printf("wdcwait: timeout, status %x\n", status); + printf("wdcwait: timeout, status 0x%x\n", status); #endif return -1; } @@ -1379,11 +1418,11 @@ wdc_atapi_get_params(ab_link, drive, id) } /* - * If there is only one ATAPI slave ion the bus,don't probe + * If there is only one ATAPI slave on the bus, don't probe * drive 0 (master) */ - if (wdc->sc_flags & WDCF_ONESLAVE && drive != 1) + if ((wdc->sc_flags & WDCF_ONESLAVE) && (drive != 1)) return 0; #ifdef ATAPI_DEBUG_PROBE @@ -1443,10 +1482,14 @@ wdc_atapi_get_params(ab_link, drive, id) len = bus_io_read_1(bc, ioh, wd_cyl_lo) + 256 * bus_io_read_1(bc, ioh, wd_cyl_hi); if (len != sizeof(struct atapi_identify)) { - printf("Warning drive %d returned %d/%d of " - "identify device data\n", drive, len, - sizeof(struct atapi_identify)); - excess = len - sizeof(struct atapi_identify); + if (len < 142) { /* XXX */ + printf("%s: drive %d returned %d/%d of identify device data, device unusuable\n", wdc->sc_dev.dv_xname, drive, len, sizeof(struct atapi_identify)); + + error = 0; + goto end; + } + + excess = (len - sizeof(struct atapi_identify)); if (excess < 0) excess = 0; } @@ -1476,7 +1519,8 @@ wdc_atapi_send_command_packet(ab_link, acp) if (flags & A_POLLED) { /* Must use the queue and wdc_atapi_start */ struct wdc_xfer xfer_s; - int i; + int i, phase; + #ifdef ATAPI_DEBUG_WDC printf("wdc_atapi_send_cmd: " "flags %ld drive %d cmdlen %d datalen %d", @@ -1510,36 +1554,20 @@ wdc_atapi_send_command_packet(ab_link, acp) } /* Wait for cmd i/o phase. */ - for (i = 20000; i > 0; --i) { - int phase; - phase = (bus_io_read_1(bc, ioh, wd_ireason) & - (WDCI_CMD | WDCI_IN)) | - (bus_io_read_1(bc, ioh, wd_status) & WDCS_DRQ); - if (phase == PHASE_CMDOUT) - break; - delay(10); - } -#ifdef ATAPI_DEBUG_WDC - printf("Wait for cmd i/o phase: i = %d\n", i); -#endif + phase = wait_for_phase(wdc, PHASE_CMDOUT); + if (phase != PHASE_CMDOUT) + printf("wdc_atapi_intr: got wrong phase (0x%x)\n", + phase); bus_io_write_raw_multi_2(bc, ioh, wd_data, acp->command, acp->command_size); /* Wait for data i/o phase. */ - for ( i= 20000; i > 0; --i) { - int phase; - phase = (bus_io_read_1(bc, ioh, wd_ireason) & - (WDCI_CMD | WDCI_IN)) | - (bus_io_read_1(bc, ioh, wd_status) & WDCS_DRQ); - if (phase != PHASE_CMDOUT) - break; - delay(10); - } - -#ifdef ATAPI_DEBUG_WDC - printf("Wait for data i/o phase: i = %d\n", i); -#endif + phase = wait_for_unphase(wdc, PHASE_CMDOUT); + if (phase == PHASE_CMDOUT) + printf("wdc_atapi_intr: got wrong phase (0x%x)\n", + phase); + while (wdc_atapi_intr(wdc, xfer)) { for (i = 2000; i > 0; --i) if ((bus_io_read_1(bc, ioh, wd_status) & @@ -1643,7 +1671,7 @@ again: char *c = (char *)acp->command; printf("wdc_atapi_intr: cmd "); for (i = 0; i < acp->command_size; i++) - printf("%x ", c[i]); + printf("0x%x ", c[i]); printf("\n"); } #endif diff --git a/sys/dev/isa/wdlink.h b/sys/dev/isa/wdlink.h index 50ca9c39bda..d72d677447a 100644 --- a/sys/dev/isa/wdlink.h +++ b/sys/dev/isa/wdlink.h @@ -1,4 +1,4 @@ -/* $OpenBSD: wdlink.h,v 1.3 1996/08/07 01:53:03 downsj Exp $ */ +/* $OpenBSD: wdlink.h,v 1.4 1996/09/11 07:27:04 downsj Exp $ */ /* * Copyright (c) 1994, 1995 Charles M. Hannum. All rights reserved. @@ -60,6 +60,7 @@ struct wdc_softc { #define WDCF_WANTED 0x08 /* XXX locking for wd_get_parms() */ #define WDCF_IRQ_WAIT 0x10 /* controller is waiting for irq */ #define WDCF_ONESLAVE 0x20 /* ctrl. has one ATAPI slave attached */ +#define WDCF_BROKENPOLL 0x40 /* or, generally fucked up */ int sc_errors; /* errors during current transfer */ u_char sc_status; /* copy of status register */ u_char sc_error; /* copy of error register */ -- 2.20.1