From e93e9e73927f48b89239dda88ddf67ca82fdea3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20E=C3=9Fer?= Date: Tue, 11 Mar 1997 23:17:28 +0000 Subject: [PATCH] Add support for the buggy CMD640B PCI EIDE controller chip, which can't perform overlapping commands on both of its channels. To enable the CMD640B work-around, the kernel must be compiled with "options CMD640". Without that option there should be no difference in the code produced compared to the previous revision of wd.c. Submitted by: Wolfgang Helbig --- sys/i386/isa/wd.c | 121 ++++++++++++++++++++++++++++++++++++++++++- sys/i386/isa/wdc_p.h | 24 +++++++++ sys/pci/wdc_p.c | 79 ++++++++++++++++++++++++++++ 3 files changed, 223 insertions(+), 1 deletion(-) create mode 100644 sys/i386/isa/wdc_p.h create mode 100644 sys/pci/wdc_p.c diff --git a/sys/i386/isa/wd.c b/sys/i386/isa/wd.c index 3f978a6c99a0..a693780277c1 100644 --- a/sys/i386/isa/wd.c +++ b/sys/i386/isa/wd.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)wd.c 7.2 (Berkeley) 5/9/91 - * $Id$ + * $Id: wd.c,v 1.125 1997/02/22 09:37:25 peter Exp $ */ /* TODO: @@ -96,10 +96,15 @@ #include #include + #ifdef ATAPI #include #endif +#ifdef CMD640 +#include +#endif /*CMD640*/ + extern void wdstart(int ctrlr); #define TIMEOUT 10000 @@ -128,6 +133,8 @@ extern void wdstart(int ctrlr); #define RECAL 2 /* doing restore */ #define OPEN 3 /* done with open */ +#define PRIMARY 0 + /* * Disk geometry. A small part of struct disklabel. * XXX disklabel.5 contains an old clone of disklabel.h. @@ -149,6 +156,9 @@ struct disk { long dk_bc; /* byte count left */ short dk_skip; /* blocks already transferred */ int dk_ctrlr; /* physical controller number */ +#ifdef CMD640 + int dk_ctrlr_cmd640;/* controller number for CMD640 quirk */ +#endif int dk_unit; /* physical unit number */ int dk_lunit; /* logical unit number */ char dk_state; /* control state */ @@ -238,6 +248,26 @@ static struct bdevsw wd_bdevsw = { wdopen, wdclose, wdstrategy, wdioctl, /*0*/ wddump, wdsize, D_DISK, "wd", &wd_cdevsw, -1 }; +#ifdef CMD640 +static int atapictrlr; +static int eide_quirks; +#endif + + +/* + * Here we use the pci-subsystem to find out, whether there is + * a cmd640b-chip attached on this pci-bus. This public routine + * will be called by wdc_p.c . + */ + +#ifdef CMD640 +void +wdc_pci(int quirks) +{ + eide_quirks = quirks; +} +#endif + /* * Probe for controller. */ @@ -360,7 +390,18 @@ wdattach(struct isa_device *dvp) if (dvp->id_unit >= NWDC) return (0); +#ifdef CMD640 + if (eide_quirks & Q_CMD640B) { + if (dvp->id_unit == PRIMARY) { + printf("wdc0: CMD640B workaround enabled\n"); + TAILQ_INIT( &wdtab[PRIMARY].controller_queue); + } + } else + TAILQ_INIT( &wdtab[dvp->id_unit].controller_queue); + +#else TAILQ_INIT( &wdtab[dvp->id_unit].controller_queue); +#endif for (wdup = isa_biotab_wdc; wdup->id_driver != 0; wdup++) { if (wdup->id_iobase != dvp->id_iobase) @@ -380,6 +421,13 @@ wdattach(struct isa_device *dvp) TAILQ_INIT( &drive_queue[lunit]); bzero(du, sizeof *du); du->dk_ctrlr = dvp->id_unit; +#ifdef CMD640 + if (eide_quirks & Q_CMD640B) { + du->dk_ctrlr_cmd640 = PRIMARY; + } else { + du->dk_ctrlr_cmd640 = du->dk_ctrlr; + } +#endif du->dk_unit = unit; du->dk_lunit = lunit; du->dk_port = dvp->id_iobase; @@ -467,14 +515,23 @@ wdattach(struct isa_device *dvp) if (wddrives[lunit]->dk_ctrlr == dvp->id_unit && wddrives[lunit]->dk_unit == unit) goto next; +#ifdef CMD640 + if (atapi_attach (dvp->id_unit, unit, dvp->id_iobase)) + atapictrlr = dvp->id_unit; +#else atapi_attach (dvp->id_unit, unit, dvp->id_iobase); +#endif next: } #endif /* * Discard any interrupts generated by wdgetctlr(). wdflushirq() * doesn't work now because the ambient ipl is too high. */ +#ifdef CMD640 + wdtab[du->dk_ctrlr_cmd640].b_active = 2; +#else wdtab[dvp->id_unit].b_active = 2; +#endif return (1); } @@ -549,7 +606,11 @@ wdstrategy(register struct buf *bp) du->dk_state = WANTOPEN; } +#ifdef CMD640 + if (wdtab[du->dk_ctrlr_cmd640].b_active == 0) +#else if (wdtab[du->dk_ctrlr].b_active == 0) +#endif wdstart(du->dk_ctrlr); /* start controller */ if (du->dk_dkunit >= 0) { @@ -597,7 +658,11 @@ static void wdustart(register struct disk *du) { register struct buf *bp; +#ifdef CMD640 + int ctrlr = du->dk_ctrlr_cmd640; +#else int ctrlr = du->dk_ctrlr; +#endif /* unit already active? */ if (wdutab[du->dk_lunit].b_active) @@ -635,6 +700,16 @@ wdstart(int ctrlr) long secpertrk, secpercyl; int lunit; int count; +#ifdef CMD640 + int ctrlr_atapi; + + if (eide_quirks & Q_CMD640B) { + ctrlr = PRIMARY; + ctrlr_atapi = atapictrlr; + } else { + ctrlr_atapi = ctrlr; + } +#endif #ifdef ATAPI if (wdtab[ctrlr].b_active == 2) @@ -646,9 +721,14 @@ wdstart(int ctrlr) bp = wdtab[ctrlr].controller_queue.tqh_first; if (bp == NULL) { #ifdef ATAPI +#ifdef CMD640 + if (atapi_start && atapi_start (ctrlr_atapi)) + wdtab[ctrlr].b_active = 3; +#else if (atapi_start && atapi_start (ctrlr)) /* mark controller active in ATAPI mode */ wdtab[ctrlr].b_active = 3; +#endif #endif return; } @@ -864,6 +944,17 @@ wdintr(int unit) register struct disk *du; register struct buf *bp; +#ifdef CMD640 + int ctrlr_atapi; + + if (eide_quirks & Q_CMD640B) { + unit = PRIMARY; + ctrlr_atapi = atapictrlr; + } else { + ctrlr_atapi = unit; + } +#endif + if (wdtab[unit].b_active == 2) return; /* intr in wdflushirq() */ if (!wdtab[unit].b_active) { @@ -880,7 +971,11 @@ wdintr(int unit) #ifdef ATAPI if (wdtab[unit].b_active == 3) { /* process an ATAPI interrupt */ +#ifdef CMD640 + if (atapi_intr && atapi_intr (ctrlr_atapi)) +#else if (atapi_intr && atapi_intr (unit)) +#endif /* ATAPI op continues */ return; /* controller is free, start new op */ @@ -1074,8 +1169,13 @@ wdopen(dev_t dev, int flags, int fmt, struct proc *p) return (ENXIO); /* Finish flushing IRQs left over from wdattach(). */ +#ifdef CMD640 + if (wdtab[du->dk_ctrlr_cmd640].b_active == 2) + wdtab[du->dk_ctrlr_cmd640].b_active = 0; +#else if (wdtab[du->dk_ctrlr].b_active == 2) wdtab[du->dk_ctrlr].b_active = 0; +#endif du->dk_flags &= ~DKFL_BADSCAN; @@ -1240,7 +1340,11 @@ wdcontrol(register struct buf *bp) int ctrlr; du = wddrives[dkunit(bp->b_dev)]; +#ifdef CMD640 + ctrlr = du->dk_ctrlr_cmd640; +#else ctrlr = du->dk_ctrlr; +#endif switch (du->dk_state) { case WANTOPEN: @@ -1373,7 +1477,11 @@ wdsetctlr(struct disk *du) error = 1; } if (error) { +#ifdef CMD640 + wdtab[du->dk_ctrlr_cmd640].b_errcnt += RETRIES; +#else wdtab[du->dk_ctrlr].b_errcnt += RETRIES; +#endif return (1); } if (wdcommand(du, du->dk_dd.d_ncylinders, du->dk_dd.d_ntracks - 1, 0, @@ -1900,10 +2008,17 @@ wderror(struct buf *bp, struct disk *du, char *mesg) static void wdflushirq(struct disk *du, int old_ipl) { +#ifdef CMD640 + wdtab[du->dk_ctrlr_cmd640].b_active = 2; + splx(old_ipl); + (void)splbio(); + wdtab[du->dk_ctrlr_cmd640].b_active = 0; +#else wdtab[du->dk_ctrlr].b_active = 2; splx(old_ipl); (void)splbio(); wdtab[du->dk_ctrlr].b_active = 0; +#endif } /* @@ -1943,6 +2058,10 @@ static void wdsleep(int ctrlr, char *wmesg) { int s = splbio(); +#ifdef CMD640 + if (eide_quirks & Q_CMD640B) + ctrlr = PRIMARY; +#endif while (wdtab[ctrlr].b_active) tsleep((caddr_t)&wdtab[ctrlr].b_active, PZERO - 1, wmesg, 1); splx(s); diff --git a/sys/i386/isa/wdc_p.h b/sys/i386/isa/wdc_p.h new file mode 100644 index 000000000000..4ef4b5629549 --- /dev/null +++ b/sys/i386/isa/wdc_p.h @@ -0,0 +1,24 @@ +/* + * + * Copyright (c) 1996 Wolfgang Helbig + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice immediately at the beginning of the file, without modification, + * this list of conditions, and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Absolutely no warranty of function or purpose is made by the author. + * 4. Modifications may be freely made to this file if the above conditions + * are met. + * + * $Id$ + */ + +#define Q_CMD640B 0x00000001 /* CMD640B quirk: serialize IDE channels */ + +void wdc_pci(int quirks); diff --git a/sys/pci/wdc_p.c b/sys/pci/wdc_p.c new file mode 100644 index 000000000000..7f2cd707703c --- /dev/null +++ b/sys/pci/wdc_p.c @@ -0,0 +1,79 @@ +/* + * + * Copyright (c) 1996 Wolfgang Helbig + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice immediately at the beginning of the file, without modification, + * this list of conditions, and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Absolutely no warranty of function or purpose is made by the author. + * 4. Modifications may be freely made to this file if the above conditions + * are met. + * + * $Id$ + */ + +/* + * The sole purpose of this code currently is to tell the ISA wdc driver, + * whether there is a CMD640 IDE chip attached to the PCI bus. + */ + +#include "pci.h" +#if NPCI > 0 +#ifdef CMD640 + +#include +#include +#include +#include +#include +#include +#include + +#include "wdc.h" + +/* + * PCI-ID's of IDE-Controller + */ + +#define CMD640B_PCI_ID 0x06401095 + +static char* wdc_pci_probe __P((pcici_t tag, pcidi_t type)); +static void wdc_pci_attach __P((pcici_t config_id, int unit)); + +static u_long wdc_pci_count = 0; + +static struct pci_device wdc_pci_driver = { + "wdc", + wdc_pci_probe, + wdc_pci_attach, + &wdc_pci_count, + NULL +}; + +DATA_SET (pcidevice_set, wdc_pci_driver); + +static char* +wdc_pci_probe (pcici_t tag, pcidi_t type) +{ + if (type == CMD640B_PCI_ID) + return "CMD 640B IDE"; + + return NULL; +} + +static void +wdc_pci_attach(pcici_t config_id, int unit) +{ + if (pci_conf_read(config_id, PCI_ID_REG) == CMD640B_PCI_ID) + wdc_pci(Q_CMD640B); +} + +#endif /* CMD640 */ +#endif /* NPCI > 0 */