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 <helbig@ba-stuttgart.de>
This commit is contained in:
parent
cf078de007
commit
e93e9e7392
@ -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 <vm/vm_prot.h>
|
||||
#include <vm/pmap.h>
|
||||
|
||||
|
||||
#ifdef ATAPI
|
||||
#include <i386/isa/atapi.h>
|
||||
#endif
|
||||
|
||||
#ifdef CMD640
|
||||
#include <i386/isa/wdc_p.h>
|
||||
#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);
|
||||
|
24
sys/i386/isa/wdc_p.h
Normal file
24
sys/i386/isa/wdc_p.h
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 1996 Wolfgang Helbig <helbig@ba-stuttgart.de>
|
||||
* 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);
|
79
sys/pci/wdc_p.c
Normal file
79
sys/pci/wdc_p.c
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 1996 Wolfgang Helbig <helbig@ba-stuttgart.de>
|
||||
* 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 <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <pci/pcireg.h>
|
||||
#include <pci/pcivar.h>
|
||||
#include <i386/isa/wdc_p.h>
|
||||
|
||||
#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 */
|
Loading…
x
Reference in New Issue
Block a user