/*
 * Copyright 1996 Massachusetts Institute of Technology
 *
 * Permission to use, copy, modify, and distribute this software and
 * its documentation for any purpose and without fee is hereby
 * granted, provided that both the above copyright notice and this
 * permission notice appear in all copies, that both the above
 * copyright notice and this permission notice appear in all
 * supporting documentation, and that the name of M.I.T. not be used
 * in advertising or publicity pertaining to distribution of the
 * software without specific, written prior permission.  M.I.T. makes
 * no representations about the suitability of this software for any
 * purpose.  It is provided "as is" without express or implied
 * warranty.
 * 
 * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''.  M.I.T. DISCLAIMS
 * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
 * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $FreeBSD: src/sys/pci/ide_pci.c,v 1.42 2000/01/29 16:59:53 peter Exp $
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
#include <vm/vm.h>
#include <vm/pmap.h>

#include <i386/isa/wdreg.h>
#ifdef PC98
#include <pc98/pc98/pc98.h>
#else
#include <i386/isa/isa.h>
#endif
#include <i386/isa/isa_device.h>

#include <pci/pcivar.h>
#include <pci/pcireg.h>
#include <pci/ide_pcireg.h>

#ifndef MIN
#define MIN(a,b) (((a)<(b))?(a):(b))
#endif

#define PROMISE_ULTRA33 0x4d33105a
#define CMD640B_PCI_ID	0x06401095

struct ide_pci_cookie;  /* structs vendor_fns, ide_pci_cookie are recursive */

struct vendor_fns {
	int (*vendor_dmainit)   /* initialize DMA controller and drive */
	     (struct	ide_pci_cookie *cookie,
	      struct	wdparams *wp, 
	      int	(*wdcmd)(int, void *),
	      void 	*);
	
	     void (*vendor_status) /* prints off DMA timing info */
	     (struct	ide_pci_cookie *cookie);
};

/*
 * XXX the fact that this list keeps all kinds of info on PCI controllers
 * is pretty grotty-- much of this should be replaced by a proper integration
 * of PCI probes into the wd driver.
 * XXX if we're going to support native-PCI controllers, we also need to
 * keep the address of the IDE control block register, which is something wd.c
 * needs to know, which is why this info is in the wrong place.
 */

struct ide_pci_cookie {
	LIST_ENTRY(ide_pci_cookie) le;
	int		iobase_wd;
	int		ctlr;	/* controller 0/1 on PCI IDE interface */
	int		unit;
	int		iobase_bm; /* SFF-8038 control registers */
	int		altiobase_wd;
	pcici_t		tag;
	pcidi_t		type;
	struct		ide_pci_prd *prd;
	struct		vendor_fns vs;
};

struct ide_pci_softc {
	LIST_HEAD(, ide_pci_cookie) cookies;
};

static int
generic_dmainit(struct	ide_pci_cookie *cookie, 
	struct	wdparams *wp, 
	int	(*wdcmd)(int, void *),
	void	*wdinfo);

static void
generic_status(struct ide_pci_cookie *cookie);

static int
sis_5591_dmainit(struct	ide_pci_cookie *cookie, 
	struct	wdparams *wp, 
	int	(*wdcmd)(int, void *),
	void	*wdinfo);

static void
sis_5591_status(struct ide_pci_cookie *cookie);

static void
via_571_status(struct ide_pci_cookie *cookie);

static int
via_571_dmainit(struct	ide_pci_cookie *cookie, 
	struct	wdparams *wp, 
	int	(*wdcmd)(int, void *),
	void	*wdinfo);

static void
acer_status(struct ide_pci_cookie *cookie);

static int 
acer_dmainit(struct ide_pci_cookie *cookie,
	struct  wdparams *wp,
	int	(*wdcmd)(int, void *),
	void 	*wdinfo);

static void
intel_piix_dump_drive(char	*ctlr,
	int	sitre,
	int	is_piix4,
	int	word40,
	int	word44,
	int	word48,
	int	word4a,
	int	drive);

static void
intel_piix_status(struct ide_pci_cookie *cookie);
static int
intel_piix_dmainit(struct	ide_pci_cookie *cookie, 
	struct	wdparams *wp, 
	int		(*wdcmd)(int, void *),
	void		*wdinfo);

static struct ide_pci_cookie *
mkcookie(int		iobase_wd, 
	 int		ctlr,
	 int		unit, 
	 int		iobase_bm, 
	 pcici_t	tag, 
	 pcidi_t	type, 
	 struct		vendor_fns *vp,
	 int		altiobase_wd);



static void ide_pci_attach(pcici_t tag, int unit);
static void *ide_pci_candma(int, int, int);
static int ide_pci_dmainit(void *, 
	struct wdparams *, 
	int (*)(int, void *),
	void *);

static int ide_pci_dmaverify(void *, char *, u_long, int);
static int ide_pci_dmasetup(void *, char *, u_long, int);
static void ide_pci_dmastart(void *);
static int ide_pci_dmadone(void *);
static int ide_pci_status(void *);
static int ide_pci_iobase(void *xcp);
static int ide_pci_altiobase(void *xcp);

static struct ide_pci_softc softc;

static int ide_pci_softc_cookies_initted = 0;

extern struct isa_driver wdcdriver;

/*
 * PRD_ALLOC_SIZE should be something that will not be allocated across a 64k
 * boundary.
 * PRD_MAX_SEGS is defined to be the maximum number of segments required for
 * a transfer on an IDE drive, for an xfer that is linear in virtual memory.
 * PRD_BUF_SIZE is the size of the buffer needed for a PRD table.
 */
#define	PRD_ALLOC_SIZE		PAGE_SIZE
#define PRD_MAX_SEGS		((256 * 512 / PAGE_SIZE) + 1)
#define PRD_BUF_SIZE		PRD_MAX_SEGS * 8

static void *prdbuf = 0;
static void *prdbuf_next = 0;

/* 
 * Hardware specific IDE controller code.  All vendor-specific code
 * for handling IDE timing and other chipset peculiarities should be
 * encapsulated here.
 */

/* helper funcs */

/*
 * nnn_mode() return the highest valid mode, or -1 if the mode class is
 * not supported
 */

static __inline int
pio_mode(struct wdparams *wp)
{
	if ((wp->wdp_atavalid & 2) == 2) {
		if ((wp->wdp_eidepiomodes & 2) == 2) return 4;
		if ((wp->wdp_eidepiomodes & 1) == 1) return 3;
	}
	return -1;
}

#if 0
static __inline int
dma_mode(struct wdparams *wp)
{
	/* XXX not quite sure how to verify validity on this field */
}
#endif

static __inline int
mwdma_mode(struct wdparams *wp)
{
	/* 
	 * XXX technically, using wdp_atavalid to test for validity of
	 * this field is not quite correct
	 */
	if ((wp->wdp_atavalid & 2) == 2) {
		if ((wp->wdp_dmamword & 4) == 4) return 2;
		if ((wp->wdp_dmamword & 2) == 2) return 1;
		if ((wp->wdp_dmamword & 1) == 1) return 0;
	}
	return -1;
}

static __inline int
udma_mode(struct wdparams *wp)
{
	if ((wp->wdp_atavalid & 4) == 4) {
		if ((wp->wdp_udmamode & 4) == 4) return 2;
		if ((wp->wdp_udmamode & 2) == 2) return 1;
		if ((wp->wdp_udmamode & 1) == 1) return 0;
	}
	return -1;
}


/* Generic busmastering PCI-IDE */

static int
generic_dmainit(struct ide_pci_cookie *cookie, 
		struct wdparams *wp, 
		int(*wdcmd)(int, void *),
		void *wdinfo)
{
	/*
	 * punt on the whole timing issue by looking for either a
	 * drive programmed for both PIO4 and mDMA2 (which use similar
	 * timing) or a drive in an UltraDMA mode (hopefully all
	 * controllers have separate timing for UDMA).  one hopes that if
	 * the drive's DMA mode has been configured by the BIOS, the
	 * controller's has also.
	 *
	 * XXX there are examples where this approach is now known to be
	 * broken, at least on systems based on Intel chipsets.
	 */

	if ((pio_mode(wp) >= 4 && mwdma_mode(wp) >= 2) || 
	    (udma_mode(wp) >= 2)) {
		printf("ide_pci: generic_dmainit %04x:%d: warning, IDE controller timing not set\n",
			cookie->iobase_wd,
			cookie->unit);
		/* If we're here, then this controller is most likely not set 
		   for UDMA, even if the drive may be. Make the drive wise
		   up. */  

		if(!wdcmd(WDDMA_MDMA2, wdinfo)) 
			printf("generic_dmainit: could not set multiword DMA mode!\n");
		return 1;
	}	
#ifdef IDE_PCI_DEBUG
	printf("pio_mode: %d, mwdma_mode(wp): %d, udma_mode(wp): %d\n",
		pio_mode(wp), mwdma_mode(wp), udma_mode(wp));
#endif
	return 0;
}

static void
generic_status(struct ide_pci_cookie *cookie)
{
	printf("generic_status: no PCI IDE timing info available\n");
}

static struct vendor_fns vs_generic = 
{ 
	generic_dmainit, 
	generic_status
};

/* VIA Technologies "82C571" PCI-IDE controller core */

static void
via_571_status(struct ide_pci_cookie *cookie)
{
	int iobase_wd;
	int ctlr, unit;
	int iobase_bm;
	pcici_t tag;
	pcidi_t type;
	u_long word40[5];
	int i, unitno;

	iobase_wd = cookie->iobase_wd;
	unit = cookie->unit;
	ctlr = cookie->ctlr;
	iobase_bm = cookie->iobase_bm;
	tag = cookie->tag;
	type = cookie->type;

	unitno = ctlr * 2 + unit;

	for (i=0; i<5; i++) {
		word40[i] = pci_conf_read(tag, i * 4 + 0x40);
	}

	if (ctlr == 0)
		printf("via_571_status: Primary IDE prefetch/postwrite %s/%s\n",
		       word40[0] & 0x8000 ? "enabled" : "disabled",
		       word40[0] & 0x4000 ? "enabled" : "disabled");
	else
		printf("via_571_status: Secondary IDE prefetch/postwrite %s/%s\n",
		       word40[0] & 0x2000 ? "enabled" : "disabled",
		       word40[0] & 0x1000 ? "enabled" : "disabled");

	printf("via_571_status: busmaster status read retry %s\n",
	       (word40[1] & 0x08) ? "enabled" : "disabled");

    
	printf("via_571_status: %s drive %d data setup=%d active=%d recovery=%d\n",
	       unitno < 2 ? "primary" : "secondary", 
	       unitno & 1,
	       ((u_int)(word40[3] >> ((3 - unitno) * 2)) & 3) + 1,
	       ((u_int)(word40[2] >> (((3 - unitno) * 8) + 4)) & 0x0f) + 1,
	       ((u_int)(word40[2] >> ((3 - unitno) * 8)) & 0x0f) + 1);
    
	if (ctlr == 0)
		printf("via_571_status: primary ctrl active=%d recovery=%d\n",
		       ((u_int)(word40[3] >> 28) & 0x0f) + 1,
		       ((u_int)(word40[2] >> 24) & 0x0f) + 1);
	else
		printf("via_571_status: secondary ctrl active=%d recovery=%d\n",
		       ((u_int)(word40[3] >> 20) & 0x0f) + 1,
		       ((u_int)(word40[2] >> 16) & 0x0f) + 1);

	/* UltraDMA dump */
	{
		int foo;

		foo = word40[4] >> ((3 - unitno) * 8);
		printf("via_571_status: %s drive %d udma method=%d enable=%d PIOmode=%d cycle=%d\n",
		       i < 2 ? "primary" : "secondary", 
		       i & 1,
		       (foo >> 7) & 1,
		       (foo >> 6) & 1,
		       (foo >> 5) & 1,
		       (foo & 3) + 2);
	}
}

/*
 * XXX timing values set here are only good for 30/33MHz buses; should deal
 * with slower ones too (BTW: you overclock-- you lose)
 */

static int
via_571_dmainit(struct ide_pci_cookie *cookie, 
		struct wdparams *wp, 
		int(*wdcmd)(int, void *),
		void *wdinfo)
{
	u_long pci_revision;
	int unitno;

	pci_revision = pci_conf_read(cookie->tag, PCI_CLASS_REG) & 
		PCI_REVISION_MASK;

	unitno = cookie->ctlr * 2 + cookie->unit;

	/* If it's a UDMA drive on a '590, set it up */
	/* 
	 * XXX the revision number we check for is of dubious validity.
	 * it's extracted from the AMD 645 datasheet.
	 */
	if (pci_revision >= 1 && udma_mode(wp) >= 2) {
		unsigned int word50, mask, new;
		word50 = pci_conf_read(cookie->tag, 0x50);

		/* UDMA enable by SET FEATURES, DMA cycles, cycle time 2T */
		mask = 0xe3000000 >> (unitno * 8);
		new = 0x40000000 >> (unitno * 8);

		word50 &= ~mask;
		word50 |= new;

		pci_conf_write(cookie->tag, 0x50, word50);

		/*
		 * With the '590, drive configuration should come *after* the
		 * controller configuration, to make sure the controller sees 
		 * the SET FEATURES command and does the right thing.
		 */
		/* Set UDMA mode 2 on drive */
		if (bootverbose)
			printf("via_571_dmainit: setting ultra DMA mode 2\n");
		if (!wdcmd(WDDMA_UDMA2, wdinfo)) {
			printf("via_571_dmainit: setting DMA mode failed\n");
			return 0;
		}

		if (bootverbose)
			via_571_status(cookie);
		return 1;

	}

	/* otherwise, try and program it for MW DMA mode 2 */
	else if (mwdma_mode(wp) >= 2 && pio_mode(wp) >= 4) {
		u_long workword;

		/* Set multiword DMA mode 2 on drive */
		if (bootverbose)
			printf("via_571_dmainit: setting multiword DMA mode 2\n");
		if (!wdcmd(WDDMA_MDMA2, wdinfo)) {
			printf("via_571_dmainit: setting DMA mode failed\n");
			return 0;
		}

		/* Configure the controller appropriately for MWDMA mode 2 */

		workword = pci_conf_read(cookie->tag, 0x40);

		/* 
		 * enable prefetch/postwrite-- XXX may cause problems
		 * with CD-ROMs? 
		 */
		workword |= 0xc000 >> (cookie->ctlr * 2);

		/* FIFO configurations-- equal split, threshold 1/2 */
		workword &= 0x90ffffff;
		workword |= 0x2a000000;

		pci_conf_write(cookie->tag, 0x40, workword);

		workword = pci_conf_read(cookie->tag, 0x44);

		/* enable status read retry */
		workword |= 8;

		/* enable FIFO flush on interrupt and end of sector */
		workword &= 0xff0cffff;
		workword |= 0x00f00000;
		pci_conf_write(cookie->tag, 0x44, workword);

		workword = pci_conf_read(cookie->tag, 0x48);
		/* set Mode2 timing */
		workword &= ~(0xff000000 >> (unitno * 8));
		workword |= 0x31000000 >> (unitno * 8);
		pci_conf_write(cookie->tag, 0x48, workword);

		/* set sector size */
		pci_conf_write(cookie->tag, cookie->ctlr ? 0x68 : 0x60, 0x200);

		if (bootverbose)
			via_571_status(cookie);

		return 1;

	}
	return 0;
}


static struct vendor_fns vs_via_571 = 
{ 
	via_571_dmainit, 
	via_571_status
};

/* Cyrix Cx5530 Courtesy of Whistle Communications */

/*
 * Verify that controller can handle a dma request for cp.  Should
 * not affect any hardware or driver state.
 * Special version for 5530 that allows only transfers on 16 byte boundaries.(!)
 * (Yes the Cyrix 5530 can only UDMA to cache-line boundaries.(bleh!))
 * Luckily nearly all disk IO is to kernel bufers which are page alligned.
 * They may fix this in some other version of the chip, but it's in the latest
 * at this time (Jan 1999).
 */
static int
cyrix_5530_dmaverify(void *xcp, char *vaddr, u_long count, int dir)
{
	int badfu;

	/*
	 * check for nonaligned or odd-length Stuff
	 */
	badfu = ((unsigned int)vaddr & 0xf) || (count & 0xf);
#ifdef DIAGNOSTIC
	if (badfu) {
		printf("ide_pci: dmaverify odd vaddr or length, ");
		printf("vaddr = %p length = %08lx\n", (void *)vaddr, count);
	}
#endif
	return (!badfu);
}

/*
 * XXX Unit number handling  may be broken in the Cx5530 modules.
 * It has only been checked with a single drive.
 * 12MByte/Sec transfer rates were seen with Quantum Fireball drives
 * with negligable CPU usage.
 */
static void
cyrix_5530_status(struct ide_pci_cookie *cookie)
{
	int iobase_wd;
	int ctlr, unit;
	int iobase_bm;
	pcici_t tag;
	pcidi_t type;
	u_long	PIO_config;
	u_long	DMA_config;
	int unitno;

	iobase_wd = cookie->iobase_wd;
	unit = cookie->unit;
	ctlr = cookie->ctlr;
	iobase_bm = cookie->iobase_bm;
	tag = cookie->tag;
	type = cookie->type;

	unitno = ctlr * 2 + unit;

	PIO_config = inl(iobase_bm + (unit * 0x10) + 0x20);
	DMA_config = inl(iobase_bm + (unit * 0x10) + 0x24);


	printf("cyrix_5530_status: %s:%u IDE PIO cfg: 0x%08lx\n",
	       (ctlr ? "Secondary" : "Primary"), unit, PIO_config);
	printf("cyrix_5530_status: %s:%u IDE DMA cfg: 0x%08lx\n",
	       (ctlr ? "Secondary" : "Primary"), unit, DMA_config);
}

/*
 * XXX timing values set here are only good for 30/33MHz buses; should deal
 * with slower ones too (BTW: you overclock-- you lose)
 */

static int
cyrix_5530_dmainit(struct ide_pci_cookie *cookie, 
		struct wdparams *wp, 
		int(*wdcmd)(int, void *),
		void *wdinfo)
{
	u_long	pci_revision;
	int	unitno;
	int	iobase_bm;
	int	unit;
	int drivemode;
	int mode;
	int regval;

	/*cookie->unit = 0; */	/* XXX */
	unit = cookie->unit;
	pci_revision = pci_conf_read(cookie->tag, PCI_CLASS_REG) & 
		PCI_REVISION_MASK;

	unitno = cookie->ctlr * 2 + unit;
	iobase_bm = cookie->iobase_bm;

	printf("Setting using 0x%x\n", iobase_bm);
	if ((cookie->ctlr == 0) && (unit == 0))	/* XXX */
		outb(iobase_bm + (unit * 0x10) + BMISTA_PORT, 0xe6);
	/* If it's a UDMA drive on a '5530, set it up */
	/* 
	 * depending on what the drive can do,
	 * set the correct modes,
	 */
	printf("wd%d: mw=0x%x, pio=0x%x, pcirev=0x%lx, udma=0x%x\n",
		unitno,
		mwdma_mode(wp), pio_mode(wp),
		pci_revision, udma_mode(wp));
	if (/* pci_revision >= 1 && */ udma_mode(wp) >= 0) {
		switch(udma_mode(wp)) {
		case 0:
			mode = 0;
			drivemode = WDDMA_UDMA0;
			regval = 0x00921250;
			break;
		default: /* newer modes not supported */
		case 2:
#if 0
/*
 * XXX The 5530 can do mode 2 but if you do use it, it will block all 
 * access to the PCI bus (and thus the ISA bus, PICs, PIT, etc. etc.) until the
 * transfer is complete. Mode 2 swamps the 5530 so much it can't really cope
 * with any other operations. Therefore, use mode 1 for drives that can
 * do mode 2 (or more). (FALL THROUGH)
 */


			mode = 2;
			drivemode = WDDMA_UDMA2;
			regval = 0x00911030;
			break;
#endif
		case 1:
			mode = 1;
			drivemode = WDDMA_UDMA1;
			regval = 0x00911140;
			break;
		}
		/*
		 * With the Cx5530, drive configuration
		 * should come *after* the controller configuration,
		 * to make sure the controller sees 
		 * the command and does the right thing.
		 */
		/* Set UDMA mode on drive */
		if (bootverbose)
			printf("cyrix_5530_dmainit: set UDMA mode %d\n", mode);
		outl(iobase_bm+0x24 + (unit * 16), regval);
		if (!wdcmd(drivemode, wdinfo)) {
			printf("cyrix_5530_dmainit: setting DMA mode failed\n");
			return 0;
		}

		if (bootverbose)
			cyrix_5530_status(cookie);
		return 1;

	}

	/* otherwise, try and program it for MW DMA mode 2 */
	else if (mwdma_mode(wp) >= 0 && pio_mode(wp) >= 4) {

		switch(mwdma_mode(wp)) {
		case 0:
			mode = 0;
			drivemode = WDDMA_MDMA0;
			regval = 0x00017771;
			break;
		case 1:
			mode = 1;
			drivemode = WDDMA_MDMA1;
			regval = 0x00012121;
			break;
		default: /* newer modes not supported */
		case 2:
			mode = 2;
			drivemode = WDDMA_MDMA2;
			regval = 0x00002020;

			break;
		}
		/* Set multiword DMA mode 2 on drive */
		if (bootverbose)
			printf("cyrix_5530_dmainit: multiword DMA mode %d\n",
							mode);
		if (!wdcmd(drivemode, wdinfo)) {
			printf("cyrix_5530_dmainit: setting DMA mode failed\n");
			return 0;
		}

		/* Configure the controller appropriately for MWDMA mode */

		outl(iobase_bm + 0x24 + (unit * 16), regval);

		if (bootverbose)
			cyrix_5530_status(cookie);

		return 1;

	}
	/*
	 * Always set the PIO mode values.
	 */
	switch(pio_mode(wp)) {
	case 0:
		mode = 0;
		drivemode = WDDMA_MDMA0;
		regval = 0x0000E132;
		break;
	case 1:
		mode = 1;
		drivemode = WDDMA_MDMA1;
		regval = 0x00001812;
		break;
	case 2:
		mode = 2;
		drivemode = WDDMA_MDMA1;
		regval = 0x00024020;
		break;
	case 3:
		mode = 3;
		drivemode = WDDMA_MDMA1;
		regval = 0x00032010;
		break;
	default: /* newer modes not supported */
	case 4:
		mode = 4;
		drivemode = WDDMA_MDMA2;
		regval = 0x00040010;

		break;
	}
	outl(iobase_bm + 0x20 + (unit * 16), regval);
	printf("cyrix_5530_dmainit: setting PIO mode %d\n", mode);
	return 0;
}


static struct vendor_fns vs_cyrix_5530 = 
{ 
	cyrix_5530_dmainit, 
	cyrix_5530_status
};


static void
promise_status(struct ide_pci_cookie *cookie)
{
    pcici_t tag;
    int i;
    u_int32_t port0_command, port0_altstatus;
    u_int32_t port1_command, port1_altstatus;
    u_int32_t dma_block;

    u_int32_t lat_and_interrupt;
    u_int32_t drivetiming;
    int pa, pb, mb, mc;

    tag = cookie->tag;
    port0_command = pci_conf_read(tag, 0x10);
    port0_altstatus = pci_conf_read(tag, 0x14);
    port1_command = pci_conf_read(tag, 0x18);
    port1_altstatus = pci_conf_read(tag, 0x1c);

    dma_block = pci_conf_read(tag, 0x20);
    lat_and_interrupt = pci_conf_read(tag, 0x3c);

    printf("promise_status: port0: 0x%lx, port0_alt: 0x%lx, port1: 0x%lx, port1_alt: 0x%lx\n",
	(u_long)port0_command, (u_long)port0_altstatus, (u_long)port1_command,
	(u_long)port1_altstatus);
    printf(
	"promise_status: dma control blk address: 0x%lx, int: %d, irq: %d\n",
	(u_long)dma_block, (u_int)(lat_and_interrupt >> 8) & 0xff,
	(u_int)lat_and_interrupt & 0xff);

    for(i=0;i<4;i+=2) {
		drivetiming = pci_conf_read(tag, 0x60 + i * 4);
		printf("drivebits%d-%d: %b\n", i, i+1, drivetiming,
			"\020\05Prefetch\06Iordy\07Errdy\010Sync\025DmaW\026DmaR");
	pa = drivetiming & 0xf;
	pb = (drivetiming >> 8) & 0x1f;
	mb = (drivetiming >> 13) & 0x7;
	mc = (drivetiming >> 16) & 0xf;
	printf("drivetiming%d: pa: 0x%x, pb: 0x%x, mb: 0x%x, mc: 0x%x\n",
		i, pa, pb, mb, mc);

	drivetiming = pci_conf_read(tag, 0x60 + (i + 1) * 4);
	pa = drivetiming & 0xf;
	pb = (drivetiming >> 8) & 0x1f;
	mb = (drivetiming >> 13) & 0x7;
	mc = (drivetiming >> 16) & 0xf;
	printf("drivetiming%d: pa: 0x%x, pb: 0x%x, mb: 0x%x, mc: 0x%x\n",
		i + 1, pa, pb, mb, mc);
    }
}

static struct vendor_fns vs_promise = 
{ 
    generic_dmainit, 
    promise_status
};

/* Intel PIIX, PIIX3, and PIIX4 IDE controller subfunctions */
static void
intel_piix_dump_drive(char *ctlr,
		      int sitre,
		      int is_piix4,
		      int word40,
		      int word44,
		      int word48,
		      int word4a,
		      int drive)
{
	char *ms;

	if (!sitre)
		ms = "master/slave";
	else if (drive == 0)
		ms = "master";
	else
		ms = "slave";

	printf("intel_piix_status: %s %s sample = %d, %s recovery = %d\n", 
	       ctlr, 
	       ms, 
	       5 - ((sitre && drive) ?
		    ((word44 >> 2) & 3) :
		    ((word40 >> 12) & 3)),
	       ms,
	       4 - ((sitre && drive) ?
		    ((word44 >> 0) & 3) :
		    ((word40 >> 8) & 3)));

	word40 >>= (drive * 4);
	printf("intel_piix_status: %s %s fastDMAonly %s, pre/post %s,\n\
intel_piix_status:  IORDY sampling %s,\n\
intel_piix_status:  fast PIO %s%s\n", 
	       ctlr,
	       (drive == 0) ? "master" : "slave",
	       (word40 & 8) ? "enabled" : "disabled",
	       (word40 & 4) ? "enabled" : "disabled",
	       (word40 & 2) ? "enabled" : "disabled",
	       (word40 & 1) ? "enabled" : "disabled",
	       ((word40 & 9) == 9) ? " (overridden by fastDMAonly)" : "" );

	if (is_piix4)
		printf("intel_piix_status: UltraDMA %s, CT/RP = %d/%d\n",
		       word48 ? "enabled": "disabled",
		       4 - (word4a & 3),
		       6 - (word4a & 3));
}

static void
intel_piix_status(struct ide_pci_cookie *cookie)
{
	int iobase_wd;
	int unit;
	int iobase_bm;
	pcici_t tag;
	pcidi_t type;
	int ctlr;
	u_long word40, word44, word48;
	int sitre, is_piix4;

	iobase_wd = cookie->iobase_wd;
	unit = cookie->unit;
	iobase_bm = cookie->iobase_bm;
	tag = cookie->tag;
	type = cookie->type;
	ctlr = cookie->ctlr;

	word40 = pci_conf_read(tag, 0x40);
	word44 = pci_conf_read(tag, 0x44);
	word48 = pci_conf_read(tag, 0x48);

	/* 
	 * XXX will not be right for the *next* generation of upward-compatible
	 * intel IDE controllers...
	 */
	is_piix4 = pci_conf_read(tag, PCI_CLASS_REG) == 0x71118086;

	sitre = word40 & 0x4000;

	switch (ctlr * 2 + unit) {
	case 0:
		intel_piix_dump_drive("primary", 
				      sitre, 
				      is_piix4,
				      word40 & 0xffff, 
				      word44 & 0x0f, 
				      word48,
				      word48 >> 16,
				      0);
		break;
	case 1:
		intel_piix_dump_drive("primary", 
				      sitre, 
				      is_piix4,
				      word40 & 0xffff, 
				      word44 & 0x0f, 
				      word48 >> 1,
				      word48 >> 20,
				      1);
		break;
	case 2:
		intel_piix_dump_drive("secondary", 
				      sitre, 
				      is_piix4,
				      (word40 >> 16) & 0xffff, 
				      (word44 >> 4) & 0x0f,
				      word48 >> 2,
				      word48 >> 24,
				      0);
		break;
	case 3:
		intel_piix_dump_drive("secondary", 
				      sitre, 
				      is_piix4,
				      (word40 >> 16) & 0xffff, 
				      (word44 >> 4) & 0x0f,
				      word48 >> 3,
				      word48 >> 28,
				      1);
		break;
	default:
		printf("intel_piix_status: bad drive or controller number\n");
	}
}

/*
 * XXX timing values set hereare only good for 30/33MHz buses; should deal
 * with slower ones too (BTW: you overclock-- you lose)
 */

static int
intel_piix_dmainit(struct ide_pci_cookie *cookie, 
		   struct wdparams *wp, 
		   int(*wdcmd)(int, void *),
		   void *wdinfo)
{

	/* If it's a UDMA drive and a PIIX4, set it up */
	if (cookie->type == 0x71118086 && udma_mode(wp) >= 2) {
		/* Set UDMA mode 2 on controller */
		int unitno, mask, new;

		if (bootverbose)
			printf("intel_piix_dmainit: setting ultra DMA mode 2\n");

		if (!wdcmd(WDDMA_UDMA2, wdinfo)) {
			printf("intel_piix_dmainit: setting DMA mode failed\n");
			return 0;
		}

		unitno = cookie->ctlr * 2 + cookie->unit;

		mask = (1 << unitno) + (3 << (16 + unitno * 4));
		new  = (1 << unitno) + (2 << (16 + unitno * 4));

		pci_conf_write(cookie->tag, 0x48, 
			(pci_conf_read(cookie->tag, 0x48) & ~mask) | new);

		if (bootverbose)
			intel_piix_status(cookie);
		return 1;
	}
	/* 
	 * if it's an 82371FB, which can't do independent programming of
	 * drive timing, we punt; we're not going to fuss with trying to
	 * coordinate timing modes between drives.  if this is you, get a
	 * new motherboard.  or contribute patches :)
	 *
	 * we do now at least see if the modes set are OK to use.  this should
	 * satisfy the majority of people, with mwdma mode2 drives.
	 */
	else if (cookie->type == 0x12308086)
	{
		u_long word40;

		/* can drive do PIO 4 and MW DMA 2? */
		if (!(mwdma_mode(wp) >= 2 && pio_mode(wp) >= 4)) 
			return 0;

		word40 = pci_conf_read(cookie->tag, 0x40);
		word40 >>= cookie->ctlr * 16;

		/* Check for timing config usable for DMA on controller */
		if (!((word40 & 0x3300) == 0x2300 && 
		      ((word40 >> (cookie->unit * 4)) & 1) == 1))
			return 0;

		/* Set multiword DMA mode 2 on drive */
		if (bootverbose)
			printf("intel_piix_dmainit: setting multiword DMA mode 2\n");
		if (!wdcmd(WDDMA_MDMA2, wdinfo)) {
			printf("intel_piix_dmainit: setting DMA mode failed\n");
			return 0;
		}
		return 1;
	}

	/* otherwise, treat it as a PIIX3 and program it for MW DMA mode 2 */
	else if (mwdma_mode(wp) >= 2 && pio_mode(wp) >= 4) {
		u_long mask40, mask44, new40, new44;

		/* 
		 * If SITRE is not set, set it and copy the
		 * appropriate bits into the secondary registers.  Do
		 * both controllers at once.
		 */
		if (((pci_conf_read(cookie->tag, 0x40) >> (16 * cookie->ctlr)) 
		     & 0x4000) == 0) {
			unsigned int word40, word44;

			word40 = pci_conf_read(cookie->tag, 0x40);

			/* copy bits to secondary register */
			word44 = pci_conf_read(cookie->tag, 0x44);
			/*
			 * I've got a Biostar motherboard with Award
			 * BIOS that sets SITRE and secondary timing
			 * on one controller but not the other.
			 * Bizarre.
			 */
			if ((word40 & 0x4000) == 0) {
				word44 &= ~0xf;
				word44 |= ((word40 & 0x3000) >> 10) | 
					((word40 & 0x0300) >> 8);
			}
			if ((word40 & 0x40000000) == 0) {
				word44 &= ~0xf0;
				word44 |= ((word40 & 0x30000000) >> 22) | 
					((word40 & 0x03000000) >> 20);
			}
			/* set SITRE */
			word40 |= 0x40004000;

			pci_conf_write(cookie->tag, 0x40, word40);
			pci_conf_write(cookie->tag, 0x44, word44);
		}

		/* Set multiword DMA mode 2 on drive */
		if (bootverbose)
			printf("intel_piix_dmainit: setting multiword DMA mode 2\n");

		if (!wdcmd(WDDMA_MDMA2, wdinfo)) {
			printf("intel_piix_dmainit: setting DMA mode failed\n");
			return 0;
		}

		/* 
		 * backward compatible hardware leaves us with such
		 * twisted masses of software (aka twiddle the
		 * extremely weird register layout on a PIIX3, setting
		 * PIO mode 4 and MWDMA mode 2)
		 */
		if (cookie->unit == 0) {
			mask40 = 0x330f;
			new40 = 0x2307;
			mask44 = 0;
			new44 = 0;
		} else {
			mask40 = 0x00f0;
			new40 = 0x0070;
			mask44 = 0x000f;
			new44 = 0x000b;
		}

		if (cookie->ctlr) {
			mask40 <<= 16;
			new40 <<= 16;
			mask44 <<= 4;
			new44 <<= 4;
		}

		pci_conf_write(cookie->tag, 0x40, 
			       (pci_conf_read(cookie->tag, 0x40) & ~mask40) | new40);
		pci_conf_write(cookie->tag, 0x44, 
			       (pci_conf_read(cookie->tag, 0x44) & ~mask44) | new44);

		if (bootverbose)
			intel_piix_status(cookie);
		return 1;
	}
	return 0;
}

static struct vendor_fns vs_intel_piix = 
{ 
	intel_piix_dmainit, 
	intel_piix_status
};


static void
acer_status(struct ide_pci_cookie *cookie) {
	/* XXX does not do anything right now */
}

static int
acer_dmainit(struct ide_pci_cookie *cookie,
                   struct wdparams *wp,
                   int(*wdcmd)(int, void *),
                   void *wdinfo)
{
	/* Acer Aladdin DMA setup code. UDMA looks to be sinfully easy to set
	   on this thing - just one register. */
	
	u_long word54 = pci_conf_read(cookie->tag, 0x54);
	
	/* Set the default Acer FIFO settings (0x55 = 13-word depth and
	   slave operation mode 1) */
	
	word54 |= 0x5555;
	
	/* Is this drive UDMA? Set it up if so... */
	if(udma_mode(wp) >= 2) {
		/* This is really easy to do. Just write 0xa (enable 
		   UDMA mode with 2T timing) into the word at the right
		   places. */
		word54 |= (0xA << (16 + (cookie->ctlr * 8) + (cookie->unit * 4)));
		
		/* Now set the drive for UDMA2. */
		if(!wdcmd(WDDMA_UDMA2, wdinfo)) {
			printf("acer_dmainit: could not set UDMA2 mode on wdc%d:%d!\n", cookie->ctlr, cookie->unit);
			return 0;
		}
		
		/* Write the new config into the registers. I'm not 
		   sure if I'm doing this in the right order. */
		
		pci_conf_write(cookie->tag, 0x54, word54);
		
	} else if(mwdma_mode(wp) >= 2 && pio_mode(wp) >=4) {
	
	
		/* Otherwise, we're already set for regular DMA. */

		if(!wdcmd(WDDMA_MDMA2, wdinfo)) {
			printf("acer_dmainit: could not set MWDMA2 mode on wdc%d:%d!\n", 
			     cookie->ctlr, cookie->unit);
			return 0;
		}
		return 1;
	}
	
	return 0;
}
 
static struct vendor_fns vs_acer = 
{
	acer_dmainit,
	acer_status
};
	
/* SiS 5591 */

static void
sis_5591_status(struct ide_pci_cookie *cookie)
{
	int iobase_wd;
	int ctlr, unit;
	int iobase_bm;
	pcici_t tag;
	pcidi_t type;
	u_int word40[5];
	int i, unitno;
	int DRTC, DATC;
	int val;

	iobase_wd = cookie->iobase_wd;
	unit = cookie->unit;
	ctlr = cookie->ctlr;
	iobase_bm = cookie->iobase_bm;
	tag = cookie->tag;
	type = cookie->type;

	unitno = ctlr * 2 + unit;

	for (i=0; i<5; i++) {
		word40[i] = pci_conf_read(tag, i * 4 + 0x40);
	}

	DRTC = word40[ctlr] >> (16 * unit);
	DATC = word40[ctlr] >> (8 + 16*unit);

	if (unitno == 0) {
		if ((word40[4] & 0x80000) == 0) {
			val = word40[2] & 0xf;
			if (val == 0)
				val = 12;
			else if (val > 11)
				val++;
			printf ("SiS 5591 status: CRTC %d PCICLK, ", val);
			val = (word40[2] >> 8) & 0x7;
			if (val == 0)
				val = 8 ;
			else if (val > 6)
				val = 12;
			printf ("CATC %d PCICLK, applies to all IDE devices\n", val);
		} else {
			printf ("SiS 5591 status: CRTC and CATC timings are per device, taken from DRTC and DATC\n");
		}
		printf ("SiS 5591 status: burst cycles %s, fast post write control %s\n",
			((word40[2] >> 16) & 0x80) ? "enabled" : "disabled",
			((word40[2] >> 16) & 0x20) ? "enabled" : "disabled");

	}
        val = DRTC & 0xf;
        if (val == 0)
		val = 12;
	else if (val > 11)
		val++;
	printf ("SiS 5591 status: %s drive %d DRTC %d PCICLK,",
		unitno < 2 ? "primary" : "secondary", 
		unitno & 1,
		val);
        val = DATC & 0x7;
        if (val == 0)
		val = 8 ;
	else if (val > 6)
		val = 12;
	printf (" DATC %d PCICLK\n", val);
	printf ("SiS 5591 status: %s drive %d Ultra DMA %s",
		unitno < 2 ? "primary" : "secondary", 
		unitno & 1,
		(DATC & 0x80) ? "disabled\n" : "enabled");
	if ((DATC & 0x80) == 0)
		printf (", %d PCICLK data out\n", ((DATC >> 5) & 0x3) + 1);
	printf ("SiS 5591 status: %s drive %d postwrite %s, prefetch %s prefetch count is %d\n",
		unitno < 2 ? "primary" : "secondary", 
		unitno & 1,
		((word40[2] >> (28 + unitno)) & 1) ? "enabled" : "disabled",
		((word40[2] >> (24 + unitno)) & 1) ? "enabled" : "disabled",
		(word40[3] >> (16 * ctlr)) & 0xffff);
	printf ("SiS 5591 status: %s drive %d has%s been configured for DMA\n",
		unitno < 2 ? "primary" : "secondary", 
		unitno & 1,
		(inb(iobase_bm + BMISTA_PORT) & ((unit == 0) ? BMISTA_DMA0CAP : BMISTA_DMA1CAP)) ?
		" " : " not");
}

static int
sis_5591_dmainit(struct ide_pci_cookie *cookie, 
		struct wdparams *wp, 
		int(*wdcmd)(int, void *),
		void *wdinfo)
{
	int r;
	unsigned int workword, new, mask;
	int ctlr, unit;
	int iobase_bm;
	pcici_t tag;
	int unitno;

	unit = cookie->unit;
	ctlr = cookie->ctlr;
	iobase_bm = cookie->iobase_bm;
	tag = cookie->tag;

	unitno = ctlr * 2 + unit;

	if (udma_mode(wp) >= 2) {
		workword = pci_conf_read(tag, ctlr * 4 + 0x40);

		/* These settings are a little arbitrary.  They're taken from my
		 * system, where the BIOS has already set the values, but where 
		 * we don't detect that we're initialized because the
		 * BMISTA_DMA?CAP values aren't set by the BIOS.
		 * 0x8000 turns on UDMA
		 * 0x2000 sets UDMA cycle time to 2 PCI clocks for data out
		 * 0x0300 sets DATC to 3 PCI clocks
		 * 0x0001 sets DRTC to 1 PCI clock
		 */
		if (unit) {
			mask = 0x0000ffff;
			new  = 0xa3010000;
		} else {
			mask = 0xffff0000;
			new  = 0x0000a301;
		}

		workword &= mask;
		workword |= new;

		pci_conf_write(tag, ctlr * 4 + 0x40, workword);

		outb(iobase_bm + BMISTA_PORT,
		     (inb(iobase_bm + BMISTA_PORT) | ((unit == 0) ? BMISTA_DMA0CAP : BMISTA_DMA1CAP)));

		if (bootverbose)
			printf("SiS 5591 dmainit: %s drive %d setting ultra DMA mode 2\n",
			       unitno < 2 ? "primary" : "secondary", 
			       unitno & 1);
		r = wdcmd(WDDMA_UDMA2, wdinfo);
		if (!r) {
			printf("SiS 5591 dmainit: %s drive %d setting DMA mode failed\n",
			       unitno < 2 ? "primary" : "secondary", 
			       unitno & 1);
			return 0;
		}

		if (bootverbose)
			sis_5591_status(cookie);

		return 1;

	}

	/* otherwise, try and program it for MW DMA mode 2 */
	else if (mwdma_mode(wp) >= 2 && pio_mode(wp) >= 4) {
		workword = pci_conf_read(tag, ctlr * 4 + 0x40);

		/* These settings are a little arbitrary.  They're taken from my
		 * system, where the BIOS has already set the values, but where 
		 * we don't detect that we're initialized because the
		 * BMISTA_DMA?CAP values aren't set by the BIOS.
		 * 0x0300 sets DATC to 3 PCI clocks
		 * 0x0001 sets DRTC to 1 PCI clock
		 */
		if (unit) {
			mask = 0x0000ffff;
			new  = 0x03010000;
		} else {
			mask = 0xffff0000;
			new  = 0x00000301;
		}

		workword &= mask;
		workword |= new;

		pci_conf_write(tag, ctlr * 4 + 0x40, workword);

		outb(iobase_bm + BMISTA_PORT,
		     (inb(iobase_bm + BMISTA_PORT) | ((unit == 0) ? BMISTA_DMA0CAP : BMISTA_DMA1CAP)));

		/* Set multiword DMA mode 2 on drive */
		if (bootverbose)
			printf("SiS 5591 dmainit: %s drive %d setting multiword DMA mode 2\n",
			       unitno < 2 ? "primary" : "secondary", 
			       unitno & 1);
		r = wdcmd(WDDMA_MDMA2, wdinfo);
		if (!r) {
			printf("SiS 5591 dmainit: %s drive %d setting DMA mode failed\n",
			       unitno < 2 ? "primary" : "secondary", 
			       unitno & 1);
			return 0;
		}

		if (bootverbose)
			sis_5591_status(cookie);

		return 1;

	}
	return 0;
}

static struct vendor_fns vs_sis_5591 = 
{ 
	sis_5591_dmainit, 
	sis_5591_status
};

/* Generic SFF-8038i code-- all code below here, except for PCI probes,
 * more or less conforms to the SFF-8038i spec as extended for PCI.
 * There should be no code that goes beyond that feature set below.
 */

/* XXX mkcookie is overloaded with too many parameters */

static struct ide_pci_cookie *
mkcookie(int iobase_wd, 
	int ctlr,
	int unit, 
	int iobase_bm, 
	pcici_t tag, 
	pcidi_t type, 
	struct vendor_fns *vp,
	int altiobase_wd)
{
	struct ide_pci_cookie *cp;

	cp = malloc(sizeof *cp, M_DEVBUF, M_NOWAIT);
	if (!cp) return 0;

	cp->iobase_wd = iobase_wd;
	cp->ctlr = ctlr;
	cp->unit = unit;
	cp->tag = tag;
	cp->type = type;
	cp->iobase_bm = iobase_bm;
	cp->altiobase_wd = altiobase_wd;
	bcopy(vp, &cp->vs, sizeof(struct vendor_fns));

	if (!prdbuf) {
		prdbuf = malloc(PRD_ALLOC_SIZE, M_DEVBUF, M_NOWAIT);
		if (!prdbuf) {
			FREE(cp, M_DEVBUF);
			return 0;
		}
		if (((int)prdbuf >> PAGE_SHIFT) ^
		    (((int)prdbuf + PRD_ALLOC_SIZE - 1) >> PAGE_SHIFT)) {
			printf("ide_pci: prdbuf straddles page boundary, no DMA\n");
			FREE(cp, M_DEVBUF);
			FREE(prdbuf, M_DEVBUF);
			return 0;
		}

		prdbuf_next = prdbuf;
	}
	if (((char *)prdbuf_next + PRD_BUF_SIZE) > 
	    ((char *)prdbuf + PRD_ALLOC_SIZE)) {
		printf("ide_pci: mkcookie %04x:%d: no more space for PRDs, no DMA\n",
		       iobase_wd, unit);
		FREE(cp, M_DEVBUF);
		return 0;
	}

	cp->prd = prdbuf_next;
	(char *)prdbuf_next += PRD_BUF_SIZE;

	LIST_INSERT_HEAD(&softc.cookies, cp, le);
	return cp;
}

static const char *
ide_pci_probe(pcici_t tag, pcidi_t type)
{
	u_long data;

	data = pci_conf_read(tag, PCI_CLASS_REG);

	if ((data & PCI_CLASS_MASK) == PCI_CLASS_MASS_STORAGE &&
	    ((data & PCI_SUBCLASS_MASK) == 0x00010000 ||
	    ((data & PCI_SUBCLASS_MASK) == 0x00040000))) {
		if (type == 0x71118086)
			return ("Intel PIIX4 Bus-master IDE controller");
		if (type == 0x70108086)
			return ("Intel PIIX3 Bus-master IDE controller");
		if (type == 0x12308086)
			return ("Intel PIIX Bus-master IDE controller");
		if (type == PROMISE_ULTRA33)
	    		return ("Promise Ultra/33 IDE controller");
		if (type == 0x05711106)
		      return ("VIA 82C586x (Apollo) Bus-master IDE controller");
		if (type == 0x01021078)
			return ("Cyrix 5530 Bus-master IDE controller");
		if (type == 0x522910b9)
			return ("Acer Aladdin IV/V (M5229) Bus-master IDE controller");
	        if (type == 0x55131039)
			return ("SiS 5591 Bus-master IDE Controller");
		if (type == CMD640B_PCI_ID)
			return "CMD 640B IDE controller";
		if (data & 0x8000)
			return ("PCI IDE controller (busmaster capable)");
		else
			return ("PCI IDE controller (not busmaster capable)");
	};
	return ((char*)0);
}

static void
ide_pci_attach(pcici_t tag, int unit)
{
	u_long class = 0, cmd;
	int bmista_1, bmista_2;
	int iobase_wd_1, iobase_wd_2, iobase_bm_1, iobase_bm_2;
	int altiobase_wd_1, altiobase_wd_2;
	struct vendor_fns *vp;
	pcidi_t type;
	struct ide_pci_cookie *cookie;
	int ctlridx;

	ctlridx = unit * 2;

	/* set up vendor-specific stuff */
	type = pci_conf_read(tag, PCI_ID_REG);

	if (type == CMD640B_PCI_ID) {
		wdc_pci(Q_CMD640B);
		return;
	}

	if (type != PROMISE_ULTRA33) {
	/* is it busmaster capable?  bail if not */
		class = pci_conf_read(tag, PCI_CLASS_REG);
		if (!(class & 0x8000)) {
			return;
		}

	/* is it enabled and is busmastering turned on? */
		cmd = pci_conf_read(tag, PCI_COMMAND_STATUS_REG);
		if ((cmd & 5) != 5) {
			return;
		}
	}

	switch (type) {
	case 0x71118086:
	case 0x70108086:
	case 0x12308086:
		/* Intel PIIX, PIIX3, PIIX4 */
		vp = &vs_intel_piix;
		break;

	case 0x5711106:
		/* VIA Apollo chipset family */
		vp = &vs_via_571;
		break;

	case PROMISE_ULTRA33:
		/* Promise controllers */
		vp = &vs_promise;
		break;

	case 0x01021078: /* cyrix 5530 */
		printf("cyrix 5530\n");
		vp = &vs_cyrix_5530;
		break;
	case 0x522910B9: /* Acer Aladdin IV/V (M5229) */
		vp = &vs_acer;
		break;
	case 0x55131039: /* SiS 5591 */
		vp = &vs_sis_5591;
		break;
	default:
		/* everybody else */
		vp = &vs_generic;
		break;
	}

	if (type != PROMISE_ULTRA33) {
		if ((class & 0x100) == 0) {
			iobase_wd_1 = IO_WD1;
			altiobase_wd_1 = iobase_wd_1 + wd_altsts;
		} else {
			iobase_wd_1 = pci_conf_read(tag, 0x10) & 0xfffc;
			altiobase_wd_1 = pci_conf_read(tag, 0x14) & 0xfffc;
		}

		if ((class & 0x400) == 0) {
			iobase_wd_2 = IO_WD2;
			altiobase_wd_2 = iobase_wd_2 + wd_altsts;
		} else {
			iobase_wd_2 = pci_conf_read(tag, 0x18) & 0xfffc;
			altiobase_wd_2 = pci_conf_read(tag, 0x1c) & 0xfffc;
		}
	} else {
		iobase_wd_1 = pci_conf_read(tag, 0x10) & 0xfffc;
		altiobase_wd_1 = pci_conf_read(tag, 0x14) & 0xfffc;
		iobase_wd_2 = pci_conf_read(tag, 0x18) & 0xfffc;
		altiobase_wd_2 = pci_conf_read(tag, 0x1c) & 0xfffc;
	}

	iobase_bm_1 = pci_conf_read(tag, 0x20) & 0xfffc;
	if (iobase_bm_1 == 0) {
		printf("ide_pci: BIOS has not configured busmaster"
			"I/O address,\n ide_pci:  giving up\n");
		return;
	}
	iobase_bm_2 = iobase_bm_1 + SFF8038_CTLR_1;

	wddma[unit].wdd_candma = ide_pci_candma;
	wddma[unit].wdd_dmainit = ide_pci_dmainit;
	if (type == 0x01021078 /*CYRIX_5530*/)
		wddma[unit].wdd_dmaverify = cyrix_5530_dmaverify;
	else
		wddma[unit].wdd_dmaverify = ide_pci_dmaverify;
	wddma[unit].wdd_dmaprep = ide_pci_dmasetup;
	wddma[unit].wdd_dmastart = ide_pci_dmastart;
	wddma[unit].wdd_dmadone = ide_pci_dmadone;
	wddma[unit].wdd_dmastatus = ide_pci_status;
	wddma[unit].wdd_iobase = ide_pci_iobase;
	wddma[unit].wdd_altiobase = ide_pci_altiobase;

	bmista_1 = inb(iobase_bm_1 + BMISTA_PORT);
	bmista_2 = inb(iobase_bm_2 + BMISTA_PORT);
		
	if (!ide_pci_softc_cookies_initted) {
		LIST_INIT(&softc.cookies);
		ide_pci_softc_cookies_initted = 1;
	}

	if (iobase_wd_1 != 0) {
		cookie = mkcookie(iobase_wd_1,
				  ctlridx, 
				  0, 
				  iobase_bm_1, 
				  tag, 
				  type, 
				  vp,
				  altiobase_wd_1);
		if (bootverbose)
			vp->vendor_status(cookie);
		cookie = mkcookie(iobase_wd_1,
				  ctlridx,
				  1,
				  iobase_bm_1, 
				  tag,
				  type,
				  vp,
				  altiobase_wd_1);
		if (bootverbose) {
			vp->vendor_status(cookie);

	bmista_1 = inb(iobase_bm_1 + BMISTA_PORT);
	bmista_2 = inb(iobase_bm_2 + BMISTA_PORT);
			printf("ide_pci: busmaster 0 status: %02x from port: %08x\n", 
			       bmista_1, iobase_bm_1+BMISTA_PORT);

			if (bmista_1 & BMISTA_DMA0CAP)
				printf("ide_pci: ide0:0 has been configured for DMA by BIOS\n");
			if (bmista_1 & BMISTA_DMA1CAP)
				printf("ide_pci: ide0:1 has been configured for DMA by BIOS\n");
		}
	}

	if (iobase_wd_2 != 0) {
		cookie = mkcookie(iobase_wd_2,
				  ctlridx + 1,
				  0, 
				  iobase_bm_2,
				  tag,
				  type, 
				  vp,
				  altiobase_wd_2);
		if (bootverbose)
			vp->vendor_status(cookie);
		cookie = mkcookie(iobase_wd_2,
				  ctlridx + 1,
				  1, 
				  iobase_bm_2, 
				  tag, 
				  type,
				  vp,
				  altiobase_wd_2);
		if (bootverbose) {
			vp->vendor_status(cookie);

	bmista_1 = inb(iobase_bm_1 + BMISTA_PORT);
	bmista_2 = inb(iobase_bm_2 + BMISTA_PORT);
			printf("ide_pci: busmaster 1 status: %02x from port: %08x\n",
			       bmista_2, iobase_bm_2+BMISTA_PORT);

			if (bmista_2 & BMISTA_DMA0CAP)
				printf("ide_pci: ide1:0 has been configured for DMA by BIOS\n");
			if (bmista_2 & BMISTA_DMA1CAP)
				printf("ide_pci: ide1:1 has been configured for DMA by BIOS\n");
		}
	}
}

static u_long ide_pci_count;

static struct pci_device ide_pci_device = {
	"ide_pci",
	ide_pci_probe,
	ide_pci_attach,
	&ide_pci_count,
	0
};

COMPAT_PCI_DRIVER(ide_pci, ide_pci_device);

/*
 * Return a cookie if we may be able to do DMA on the specified
 * (iobase_wd, ctlr, unit).
 */
static void *
ide_pci_candma(int iobase_wd, int ctlr, int unit)
{
	struct ide_pci_cookie *cp;

	cp = softc.cookies.lh_first;
	while(cp) {
		if (cp->ctlr == ctlr && cp->unit == unit &&
			((iobase_wd == 0) || (cp->iobase_wd == iobase_wd)))
			break;
		cp = cp->le.le_next;
	}

	return cp;
}

/*
 * Initialize controller and drive for DMA operation, including timing modes.
 * Uses data passed from the wd driver and a callback function to initialize
 * timing modes on the drive.
 */
static int
ide_pci_dmainit(void *cookie,
		struct wdparams *wp,
		int(*wdcmd)(int, void *),
		void *wdinfo)
{
	struct ide_pci_cookie *cp = cookie;
	/* 
	 * If the controller status indicates that DMA is configured already,
	 * we flounce happily away
	 */
	if (inb(cp->iobase_bm + BMISTA_PORT) & 
	    ((cp->unit == 0) ? BMISTA_DMA0CAP : BMISTA_DMA1CAP))
		return 1;
    
	/* We take a stab at it with device-dependent code */
	return(cp->vs.vendor_dmainit(cp, wp, wdcmd, wdinfo));
}

/*
 * Verify that controller can handle a dma request for cp.  Should
 * not affect any hardware or driver state.
 */
static int
ide_pci_dmaverify(void *xcp, char *vaddr, u_long count, int dir)
{
	int badfu;

	/*
	 * check for nonaligned or odd-length Stuff
	 */
	badfu = ((unsigned int)vaddr & 1) || (count & 1);
#ifdef DIAGNOSTIC
	if (badfu) {
		printf("ide_pci: dmaverify odd vaddr or length, ");
		printf("vaddr = %p length = %08lx\n", (void *)vaddr, count);
	}
#endif
	return (!badfu);
}

/*
 * Set up DMA for cp.  It is the responsibility of the caller
 * to ensure that the controller is idle before this routine
 * is called.
 */
static int
ide_pci_dmasetup(void *xcp, char *vaddr, u_long vcount, int dir)
{
	struct ide_pci_cookie *cp = xcp;
	struct ide_pci_prd *prd;
	int i;
	u_long firstpage;
	u_long prd_base, prd_count;
	u_long nbase, ncount, nend;
	int iobase_bm;
	u_long count;

	prd = cp->prd;

	count = vcount;

	i = 0;

	iobase_bm = cp->iobase_bm;

	if (count == 0) {
		printf("ide_pci: dmasetup 0-length transfer, ");
		printf("vaddr = %p length = %08lx\n", (void *)vaddr, count);
		return 1;
	}

	/* Generate first PRD entry, which may be non-aligned. */

	firstpage = PAGE_SIZE - ((uintptr_t)vaddr & PAGE_MASK);

	prd_base = vtophys(vaddr);
	prd_count = MIN(count,  firstpage);

	vaddr += prd_count;
	count -= prd_count;

	/*
	 * Step through virtual pages.
	 * Note that it is not worth trying to coalesce pages that are 
	 * next to each other physically, and some DMA engines (e.g.
	 * Cyrix Cx5530) actually blow up if you do.
	 */
	while (count) {
		nbase = vtophys(vaddr);
		ncount = MIN(count, PAGE_SIZE);
		nend = nbase + ncount;

		prd[i].prd_base = prd_base;
		prd[i].prd_count = (prd_count & 0xffff);
		i++;
		if (i >= PRD_MAX_SEGS) {
			printf("wd82371: too many segments in PRD table\n");
			return 1;
		}
		prd_base = nbase;
		prd_count = ncount;
		vaddr += ncount;
		count -= ncount;
	}

	/* Write last PRD entry. */
	prd[i].prd_base = prd_base;
	prd[i].prd_count = (prd_count & 0xffff) | PRD_EOT_BIT;

	/* Set up PRD base register */
	outl(iobase_bm + BMIDTP_PORT, vtophys(prd));

	/* Set direction of transfer */
	outb(iobase_bm + BMICOM_PORT, (dir == B_READ) ? BMICOM_READ_WRITE : 0);

	/* Clear interrupt and error bits */
	outb(iobase_bm + BMISTA_PORT,
	     (inb(iobase_bm + BMISTA_PORT) 
	      | (BMISTA_INTERRUPT | BMISTA_DMA_ERROR)));

	return 0;
}		

static void
ide_pci_dmastart(void *xcp)
{
	struct ide_pci_cookie *cp = xcp;
	int iobase_bm;

	iobase_bm = cp->iobase_bm;

	outb(iobase_bm + BMICOM_PORT,
	     inb(iobase_bm + BMICOM_PORT) | BMICOM_STOP_START);

}

static int
ide_pci_dmadone(void *xcp)
{
	struct ide_pci_cookie *cp = xcp;
	int iobase_bm, status;

	status = ide_pci_status(xcp);
	iobase_bm = cp->iobase_bm;

	outb(iobase_bm + BMICOM_PORT,
	     inb(iobase_bm + BMICOM_PORT) & ~BMICOM_STOP_START);

	return status;
}

static int
ide_pci_status(void *xcp)
{
	int iobase_bm, status, bmista;

	status = 0;
	iobase_bm = ((struct ide_pci_cookie *)xcp)->iobase_bm;

	bmista = inb(iobase_bm + BMISTA_PORT);

	if (bmista & BMISTA_INTERRUPT)
		status |= WDDS_INTERRUPT;
	if (bmista & BMISTA_DMA_ERROR)
		status |= WDDS_ERROR;
	if (bmista & BMISTA_DMA_ACTIVE)
		status |= WDDS_ACTIVE;
	return status;
}

static int
ide_pci_altiobase(void *xcp)
{
	struct ide_pci_cookie *cp = xcp;
	if (cp == 0) {
		return 0;
	} else {
		return cp->altiobase_wd;
	}
}

static int
ide_pci_iobase(void *xcp)
{
	struct ide_pci_cookie *cp = xcp;
	if (cp == 0) {
		return 0;
	} else {
		return cp->iobase_wd;
	}
}
