Addition of support of the slightly rogue Promise IDE interface(Dyson), support

of multiple PCI IDE controllers(Dyson), and some updates and cleanups from
John Hood, who originally made our IDE DMA stuff work :-).

I have run tests with 7 IDE drives connected to my system, all in DMA
mode, with no errors.  Modulo any bugs, this stuff makes IDE look
really good (within it's limitations.)

Submitted by:	John Hood <cgull@smoke.marlboro.vt.us>
This commit is contained in:
John Dyson 1997-09-20 07:41:58 +00:00
parent ab71361364
commit e871e61fcf
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=29636
8 changed files with 1180 additions and 629 deletions

View file

@ -2,7 +2,7 @@
# LINT -- config file for checking all the sources, tries to pull in
# as much of the source tree as it can.
#
# $Id: LINT,v 1.366 1997/09/16 07:45:31 joerg Exp $
# $Id: LINT,v 1.367 1997/09/19 15:25:48 jmg Exp $
#
# NB: You probably don't want to try running a kernel built from this
# file. Instead, you should start from GENERIC, and add options from
@ -763,8 +763,23 @@ controller wds0 at isa? port 0x350 bio irq 15 drq 6 vector wdsintr
# allowed to probe for 32 bit transfers, but will allow multi-sector
# transfers up to the maximum that the drive supports.
#
# If you are using a PCI controller that is not running in compatibility
# mode (for example, it is a 2nd IDE PCI interface), then use config line(s)
# such as:
#
#controller wdc2 at isa? port "0" bio irq ? flags 0xa0ffa0ff vector wdintr
#disk wd4 at wdc2 drive 0
#disk wd5 at wdc2 drive 1
#
#controller wdc3 at isa? port "0" bio irq ? flags 0xa0ffa0ff vector wdintr
#disk wd6 at wdc3 drive 0
#disk wd7 at wdc3 drive 1
#
# Note that the above config would be useful for a Promise card, when used
# on a MB that already has a PIIX controller. Note the bogus irq and port
# entries. These are automatically filled in by the IDE/PCI support.
#
controller wdc0 at isa? port "IO_WD1" bio irq 14 vector wdintr
disk wd0 at wdc0 drive 0
disk wd1 at wdc0 drive 1

View file

@ -26,7 +26,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: pcireg.h,v 1.17 1997/05/28 20:37:19 se Exp $
* $Id: pcireg.h,v 1.18 1997/06/01 16:00:43 peter Exp $
*
*/
@ -241,6 +241,7 @@
#define PCI_CLASS_REG 0x08
#define PCI_CLASS_MASK 0xff000000
#define PCI_SUBCLASS_MASK 0x00ff0000
#define PCI_REVISION_MASK 0x000000ff
#define PCI_CLASS_PREHISTORIC 0x00000000
#define PCI_SUBCLASS_PREHISTORIC_VGA 0x00010000
#define PCI_CLASS_MASS_STORAGE 0x01000000

View file

@ -2,7 +2,7 @@
# LINT -- config file for checking all the sources, tries to pull in
# as much of the source tree as it can.
#
# $Id: LINT,v 1.366 1997/09/16 07:45:31 joerg Exp $
# $Id: LINT,v 1.367 1997/09/19 15:25:48 jmg Exp $
#
# NB: You probably don't want to try running a kernel built from this
# file. Instead, you should start from GENERIC, and add options from
@ -763,8 +763,23 @@ controller wds0 at isa? port 0x350 bio irq 15 drq 6 vector wdsintr
# allowed to probe for 32 bit transfers, but will allow multi-sector
# transfers up to the maximum that the drive supports.
#
# If you are using a PCI controller that is not running in compatibility
# mode (for example, it is a 2nd IDE PCI interface), then use config line(s)
# such as:
#
#controller wdc2 at isa? port "0" bio irq ? flags 0xa0ffa0ff vector wdintr
#disk wd4 at wdc2 drive 0
#disk wd5 at wdc2 drive 1
#
#controller wdc3 at isa? port "0" bio irq ? flags 0xa0ffa0ff vector wdintr
#disk wd6 at wdc3 drive 0
#disk wd7 at wdc3 drive 1
#
# Note that the above config would be useful for a Promise card, when used
# on a MB that already has a PIIX controller. Note the bogus irq and port
# entries. These are automatically filled in by the IDE/PCI support.
#
controller wdc0 at isa? port "IO_WD1" bio irq 14 vector wdintr
disk wd0 at wdc0 drive 0
disk wd1 at wdc0 drive 1

View file

@ -2,7 +2,7 @@
# LINT -- config file for checking all the sources, tries to pull in
# as much of the source tree as it can.
#
# $Id: LINT,v 1.366 1997/09/16 07:45:31 joerg Exp $
# $Id: LINT,v 1.367 1997/09/19 15:25:48 jmg Exp $
#
# NB: You probably don't want to try running a kernel built from this
# file. Instead, you should start from GENERIC, and add options from
@ -763,8 +763,23 @@ controller wds0 at isa? port 0x350 bio irq 15 drq 6 vector wdsintr
# allowed to probe for 32 bit transfers, but will allow multi-sector
# transfers up to the maximum that the drive supports.
#
# If you are using a PCI controller that is not running in compatibility
# mode (for example, it is a 2nd IDE PCI interface), then use config line(s)
# such as:
#
#controller wdc2 at isa? port "0" bio irq ? flags 0xa0ffa0ff vector wdintr
#disk wd4 at wdc2 drive 0
#disk wd5 at wdc2 drive 1
#
#controller wdc3 at isa? port "0" bio irq ? flags 0xa0ffa0ff vector wdintr
#disk wd6 at wdc3 drive 0
#disk wd7 at wdc3 drive 1
#
# Note that the above config would be useful for a Promise card, when used
# on a MB that already has a PIIX controller. Note the bogus irq and port
# entries. These are automatically filled in by the IDE/PCI support.
#
controller wdc0 at isa? port "IO_WD1" bio irq 14 vector wdintr
disk wd0 at wdc0 drive 0
disk wd1 at wdc0 drive 1

View file

@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)wd.c 7.2 (Berkeley) 5/9/91
* $Id: wd.c,v 1.137 1997/09/10 12:31:38 joerg Exp $
* $Id: wd.c,v 1.138 1997/09/13 16:12:12 joerg Exp $
*/
/* TODO:
@ -66,6 +66,7 @@
#if NWDC > 0
#include "pci.h"
#include <sys/param.h>
#include <sys/dkbad.h>
#include <sys/systm.h>
@ -157,11 +158,13 @@ struct disk {
#endif
int dk_unit; /* physical unit number */
int dk_lunit; /* logical unit number */
int dk_interface; /* interface (two ctrlrs per interface) */
char dk_state; /* control state */
u_char dk_status; /* copy of status reg. */
u_char dk_error; /* copy of error reg. */
u_char dk_timeout; /* countdown to next timeout */
int dk_port; /* i/o port base */
int dk_altport; /* altstatus port base */
#ifdef DEVFS
void *dk_bdev; /* devfs token for whole disk */
void *dk_cdev; /* devfs token for raw whole disk */
@ -204,7 +207,7 @@ static struct {
int b_active;
} wdtab[NWDC];
struct wddma wddma;
struct wddma wddma[NWDC];
#ifdef notyet
static struct buf rwdbuf[NWD]; /* buffers for raw IO */
@ -276,6 +279,8 @@ static int
wdprobe(struct isa_device *dvp)
{
int unit = dvp->id_unit;
void *cookie;
int interface;
struct disk *du;
if (unit >= NWDC)
@ -286,8 +291,21 @@ wdprobe(struct isa_device *dvp)
return (0);
bzero(du, sizeof *du);
du->dk_ctrlr = dvp->id_unit;
interface = du->dk_ctrlr / 2;
du->dk_interface = interface;
#if !defined(DISABLE_PCI_IDE) && (NPCI > 0)
if (wddma[interface].wdd_candma) {
du->dk_dmacookie = wddma[interface].wdd_candma(dvp->id_iobase, du->dk_ctrlr);
du->dk_port = dvp->id_iobase;
du->dk_altport = wddma[interface].wdd_altiobase(du->dk_dmacookie);
} else {
du->dk_port = dvp->id_iobase;
du->dk_altport = du->dk_port + wd_ctlr;
}
#else
du->dk_port = dvp->id_iobase;
du->dk_altport = du->dk_port + wd_ctlr;
#endif
/* check if we have registers that work */
outb(du->dk_port + wd_sdh, WDSD_IBM); /* set unit 0 */
@ -317,14 +335,16 @@ wdprobe(struct isa_device *dvp)
goto reset_ok;
#endif
DELAY(RECOVERYTIME);
if (wdreset(du) != 0)
if (wdreset(du) != 0) {
goto nodevice;
}
reset_ok:
/* execute a controller only command */
if (wdcommand(du, 0, 0, 0, 0, WDCC_DIAGNOSE) != 0
|| wdwait(du, 0, TIMEOUT) < 0)
|| wdwait(du, 0, TIMEOUT) < 0) {
goto nodevice;
}
/*
* drive(s) did not time out during diagnostic :
@ -338,7 +358,6 @@ wdprobe(struct isa_device *dvp)
* drive 2. (This seems to contradict the ATA spec.)
*/
du->dk_error = inb(du->dk_port + wd_error);
/* printf("Error : %x\n", du->dk_error); */
if(du->dk_error != 0x01) {
if(du->dk_error & 0x80) { /* drive 1 failure */
@ -776,7 +795,7 @@ wdstart(int ctrlr)
(bp->b_flags & B_READ) ? "read" : "write",
bp->b_bcount, blknum);
else
printf(" %d)%x", du->dk_skip, inb(du->dk_port + wd_altsts));
printf(" %d)%x", du->dk_skip, inb(du->dk_altport));
#endif
lp = &du->dk_dd;
@ -844,7 +863,7 @@ wdstart(int ctrlr)
du->dk_currentiosize = 1;
} else {
if((du->dk_flags & DKFL_USEDMA) &&
wddma.wdd_dmaverify(du->dk_dmacookie,
wddma[du->dk_interface].wdd_dmaverify(du->dk_dmacookie,
(void *)((int)bp->b_un.b_addr +
du->dk_skip * DEV_BSIZE),
du->dk_bc,
@ -893,7 +912,7 @@ wdstart(int ctrlr)
}
if ((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA) {
wddma.wdd_dmaprep(du->dk_dmacookie,
wddma[du->dk_interface].wdd_dmaprep(du->dk_dmacookie,
(void *)((int)bp->b_un.b_addr +
du->dk_skip * DEV_BSIZE),
du->dk_bc,
@ -909,7 +928,7 @@ wdstart(int ctrlr)
printf("cylin %ld head %ld sector %ld addr %x sts %x\n",
cylin, head, sector,
(int)bp->b_un.b_addr + du->dk_skip * DEV_BSIZE,
inb(du->dk_port + wd_altsts));
inb(du->dk_altport));
#endif
}
@ -937,7 +956,7 @@ wdstart(int ctrlr)
/* if this is a DMA op, start DMA and go away until it's done. */
if ((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA) {
wddma.wdd_dmastart(du->dk_dmacookie);
wddma[du->dk_interface].wdd_dmastart(du->dk_dmacookie);
return;
}
@ -1049,10 +1068,10 @@ wdintr(int unit)
/* finish off DMA */
if (du->dk_flags & (DKFL_DMA|DKFL_USEDMA)) {
/* XXX SMP boxes sometimes generate an early intr. Why? */
if ((wddma.wdd_dmastatus(du->dk_dmacookie) & WDDS_INTERRUPT)
if ((wddma[du->dk_interface].wdd_dmastatus(du->dk_dmacookie) & WDDS_INTERRUPT)
== 0)
return;
dmastat = wddma.wdd_dmadone(du->dk_dmacookie);
dmastat = wddma[du->dk_interface].wdd_dmadone(du->dk_dmacookie);
}
du->dk_timeout = 0;
@ -1834,20 +1853,22 @@ wdgetctlr(struct disk *du)
du->dk_multi = wp->wdp_nsecperint & 0xff;
wdsetmulti(du);
du->dk_dmacookie = NULL;
/*
* check drive's DMA capability
*/
if (wddma[du->dk_interface].wdd_candma) {
du->dk_dmacookie = wddma[du->dk_interface].wdd_candma(du->dk_port, du->dk_ctrlr);
/* does user want this? */
if ((du->cfg_flags & WDOPT_DMA) &&
if ((du->cfg_flags & WDOPT_DMA) &&
/* have we got a DMA controller? */
(wddma.wdd_candma &&
(du->dk_dmacookie = wddma.wdd_candma(du->dk_port,
du->dk_unit))) &&
/* can said drive do DMA? */
(wddma.wdd_dmainit(du->dk_dmacookie, wp, wdsetmode, du)))
du->dk_flags |= DKFL_USEDMA;
du->dk_dmacookie &&
/* can said drive do DMA? */
wddma[du->dk_interface].wdd_dmainit(du->dk_dmacookie, wp, wdsetmode, du)) {
du->dk_flags |= DKFL_USEDMA;
}
} else {
du->dk_dmacookie = NULL;
}
#ifdef WDDEBUG
printf(
@ -2210,28 +2231,28 @@ wdflushirq(struct disk *du, int old_ipl)
static int
wdreset(struct disk *du)
{
int wdc, err = 0;
int err = 0;
if ((du->dk_flags & (DKFL_DMA|DKFL_USEDMA)) && du->dk_dmacookie)
wddma.wdd_dmadone(du->dk_dmacookie);
wddma[du->dk_interface].wdd_dmadone(du->dk_dmacookie);
wdc = du->dk_port;
(void)wdwait(du, 0, TIMEOUT);
outb(wdc + wd_ctlr, WDCTL_IDS | WDCTL_RST);
outb(du->dk_altport, WDCTL_IDS | WDCTL_RST);
DELAY(10 * 1000);
outb(wdc + wd_ctlr, WDCTL_IDS);
outb(du->dk_altport, WDCTL_IDS);
#ifdef ATAPI
if (wdwait(du, WDCS_READY | WDCS_SEEKCMPLT, TIMEOUT) != 0)
err = 1; /* no IDE drive found */
du->dk_error = inb(wdc + wd_error);
du->dk_error = inb(du->dk_port + wd_error);
if (du->dk_error != 0x01)
err = 1; /* the drive is incompatible */
#else
if (wdwait(du, WDCS_READY | WDCS_SEEKCMPLT, TIMEOUT) != 0
|| (du->dk_error = inb(wdc + wd_error)) != 0x01)
if (wdwait(du, WDCS_READY | WDCS_SEEKCMPLT, TIMEOUT) != 0) {
printf("wdreset: error1: 0x%x\n", du->dk_error);
return (1);
}
#endif
outb(wdc + wd_ctlr, WDCTL_4BIT);
outb(du->dk_altport, WDCTL_4BIT);
return (err);
}
@ -2273,7 +2294,7 @@ wdtimeout(void *cdu)
if (du->dk_dmacookie)
printf("wd%d: wdtimeout() DMA status %b\n",
du->dk_lunit,
wddma.wdd_dmastatus(du->dk_dmacookie),
wddma[du->dk_interface].wdd_dmastatus(du->dk_dmacookie),
WDDS_BITS);
}
wdunwedge(du);
@ -2384,8 +2405,9 @@ wdwait(struct disk *du, u_char bits_wanted, int timeout)
* command completion.
*/
}
if ((status & bits_wanted) == bits_wanted)
if ((status & bits_wanted) == bits_wanted) {
return (status & WDCS_ERR);
}
}
if (timeout < TIMEOUT)
/*

View file

@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)wdreg.h 7.1 (Berkeley) 5/9/91
* $Id: wdreg.h,v 1.12.2.3 1997/01/14 17:32:07 bde Exp $
* $Id: wdreg.h,v 1.19 1997/09/04 18:49:48 sos Exp $
*/
/*
@ -260,7 +260,7 @@ int wdformat(struct buf *bp);
* WDDS_* constants below.
*/
struct wddma {
void *(*wdd_candma) /* returns a cookie if can do DMA */
void *(*wdd_candma) /* returns a cookie if PCI */
__P((int ctlr, int drive));
int (*wdd_dmaverify) /* verify that request is DMA-able */
__P((void *cookie, char *vaddr, u_long len, int direction));
@ -277,6 +277,10 @@ struct wddma {
struct wdparams *wp,
int(wdcmd)__P((int mode, void *wdinfo)),
void *wdinfo));
int (*wdd_iobase) /* returns iobase address */
__P((void *cookie));
int (*wdd_altiobase) /* returns altiobase address */
__P((void *cookie));
};
/* logical status bits returned by wdd_dmastatus */
@ -305,6 +309,6 @@ struct wddma {
#define WDDMA_UDMA1 0x41
#define WDDMA_UDMA2 0x42
extern struct wddma wddma;
extern struct wddma wddma[];
#endif /* KERNEL */

File diff suppressed because it is too large Load diff

View file

@ -26,7 +26,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: pcireg.h,v 1.17 1997/05/28 20:37:19 se Exp $
* $Id: pcireg.h,v 1.18 1997/06/01 16:00:43 peter Exp $
*
*/
@ -241,6 +241,7 @@
#define PCI_CLASS_REG 0x08
#define PCI_CLASS_MASK 0xff000000
#define PCI_SUBCLASS_MASK 0x00ff0000
#define PCI_REVISION_MASK 0x000000ff
#define PCI_CLASS_PREHISTORIC 0x00000000
#define PCI_SUBCLASS_PREHISTORIC_VGA 0x00010000
#define PCI_CLASS_MASS_STORAGE 0x01000000