diff -c -r -N --exclude exp --exclude compile sys/arch/arm32.orig/arm32/autoconf.c sys/arch/arm32/arm32/autoconf.c
*** sys/arch/arm32.orig/arm32/autoconf.c	Wed Jun 12 20:37:59 1996
--- sys/arch/arm32/arm32/autoconf.c	Thu Jun 13 02:56:50 1996
***************
*** 59,64 ****
--- 59,65 ----
  #include "rd.h"
  #include "sd.h"
  #include "cd.h"
+ #include "acd.h"
  #include "podulebus.h"
  
  extern dev_t rootdev;
***************
*** 92,97 ****
--- 93,101 ----
  #endif
  #if NSD > 0
  	{ "sd", 0x18 },
+ #endif
+ #if NCD > 0
+ 	{ "acd", 0x14 },
  #endif
  #if NCD > 0
  	{ "cd", 0x1a },
diff -c -r -N --exclude exp --exclude compile sys/arch/arm32.orig/arm32/autoconf.c.orig sys/arch/arm32/arm32/autoconf.c.orig
*** sys/arch/arm32.orig/arm32/autoconf.c.orig	Thu Jan  1 01:00:00 1970
--- sys/arch/arm32/arm32/autoconf.c.orig	Wed Jun 12 20:37:59 1996
***************
*** 0 ****
--- 1,295 ----
+ /* $NetBSD: autoconf.c,v 1.7 1996/06/12 19:42:23 mark Exp $ */
+ 
+ /*
+  * Copyright (c) 1994,1995 Mark Brinicombe.
+  * Copyright (c) 1994 Brini.
+  * 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, 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. All advertising materials mentioning features or use of this software
+  *    must display the following acknowledgement:
+  *	This product includes software developed by Mark Brinicombe for
+  *      the NetBSD project.
+  * 4. The name of the company nor the name of the author may be used to
+  *    endorse or promote products derived from this software without specific
+  *    prior written permission.
+  *
+  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+  * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 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.
+  *
+  * RiscBSD kernel project
+  *
+  * autoconf.c
+  *
+  * Autoconfiguration functions
+  *
+  * Created      : 08/10/94
+  */
+ 
+ #include <sys/param.h>
+ #include <sys/systm.h>
+ #include <sys/reboot.h>
+ #include <sys/disklabel.h>
+ #include <sys/device.h>
+ #include <sys/conf.h>
+ #include <sys/kernel.h>
+ #include <sys/malloc.h>
+ 
+ #include <machine/irqhandler.h>
+ #include <machine/bootconfig.h>
+ 
+ #include "wdc.h"
+ #include "fdc.h"
+ #include "rd.h"
+ #include "sd.h"
+ #include "cd.h"
+ #include "podulebus.h"
+ 
+ extern dev_t rootdev;
+ extern dev_t swapdev;
+ extern dev_t dumpdev;
+ extern dev_t argdev;
+ 
+ extern struct swdevt swdevt[];
+ 
+ extern char *boot_args;
+ extern int pmap_debug_level;
+ 
+ char *	strstr	__P((char */*s1*/, char */*s2*/));
+ long	strtoul __P((const char *, char **, int));
+ void	dumpconf __P(());
+ 
+ /* Table major numbers for the device names, NULL terminated */
+ 
+ struct {
+     char *name;
+     dev_t dev;
+ } rootdevices[] = {
+ #if NWDC > 0
+ 	{ "wd", 0x10 },
+ #endif
+ #if NFDC > 0
+ 	{ "fd", 0x11 },
+ #endif
+ #if NRD > 0
+ 	{ "rd", 0x12 },
+ #endif
+ #if NSD > 0
+ 	{ "sd", 0x18 },
+ #endif
+ #if NCD > 0
+ 	{ "cd", 0x1a },
+ #endif
+ 	{ NULL, 0x00 },
+ };
+ 
+ /* Decode a device name to a major and minor number */
+ 
+ dev_t
+ get_device(name)
+ 	char *name;
+ {
+ 	int loop;
+ 	int unit;
+ 	int part;
+     
+ 	if (strncmp(name, "/dev/", 5) == 0)
+ 		name += 5;
+ 
+ 	for (loop = 0; rootdevices[loop].name; ++loop) {
+ 		if (strncmp(name, rootdevices[loop].name,
+ 		    strlen(rootdevices[loop].name)) == 0) {
+ 			name += strlen(rootdevices[loop].name);
+ 
+ 			if (name[0] >= '0' && name[0] <= '9')
+ 				unit = name[0] - '0';
+ 			else if (name[0] == 0 || name[0] == ' ')
+ 				unit = 0;
+ 			else
+ 				unit = -1;
+ 			if (name[1] >= 'a' && name[1] <= 'z')
+ 				part = name[1] - 'a';
+ 			else if (name[1] == 0 || name[1] == ' ')
+ 				part = 0;
+ 			else
+ 				part = -1;
+ 
+ 			if (unit < 0 || unit > 9)
+ 				return(NODEV);
+ 			if (part < 0 || part > MAXPARTITIONS)
+ 				return(NODEV);
+ 			return(makedev(rootdevices[loop].dev,
+ 			    unit * MAXPARTITIONS + part));
+ 		}
+ 	} 
+ 	return(NODEV);  
+ }
+ 
+ 
+ /* Set the rootdev variable from the root specifier in the boot args */
+ 
+ void
+ set_root_device()
+ {
+ 	char *ptr;
+             
+ 	if (boot_args) {
+ 		ptr = strstr(boot_args, "root=");
+ 		if (ptr) {
+ 			ptr += 5;
+ 			rootdev = get_device(ptr);
+ 
+ #ifdef DEBUG              
+ 			if (pmap_debug_level >= 0)
+ 				printf("rootdev = %08x\n", rootdev);
+ #endif
+ 		}
+ 	}
+ 
+ 	if (rootdev == NODEV)
+ 		panic("No root device specified in boot config\n");
+ }
+ 
+ 
+ /* Set the swap devices from the swap specifiers in the boot ars */
+ 
+ void
+ set_swap_device()
+ {
+ 	char *ptr;
+ 	int nswap = 0;
+             
+ 	if (boot_args) {
+ 		ptr = boot_args;
+ 		do {
+ 			ptr = strstr(ptr, "swap=");
+ 			if (ptr) {
+ 				ptr += 5;
+ 				swdevt[nswap].sw_dev = get_device(ptr);
+ 
+ 				/*
+ 				 * Remember the first swap device
+ 				 */
+ 
+ 				if (nswap == 0)
+ 					swapdev = get_device(ptr);
+ 				++nswap;
+ 			}
+ 		} while (ptr);
+ 	}
+ }
+ 
+ 
+ /*
+  * Configure swap space and related parameters.
+  */
+ 
+ void
+ swapconf()
+ {
+ 	register struct swdevt *swp;
+ 	register int nblks;
+ 	int swapsize = -1;
+ 	int maj;
+ 	int s;		/* The spl stuff was here for debugging reaons */
+ 
+ 	/*
+ 	 * Loop round all the defined swap device configuring them.
+ 	 */
+ 
+ 	for (swp = swdevt; swp->sw_dev != NODEV; swp++) {
+ 		maj = major(swp->sw_dev);
+ 		if (maj > nblkdev)
+ 			break;
+ 		if (bdevsw[maj].d_psize) {
+ 			s = spltty();
+ 			printf("swap dev %04x ", swp->sw_dev);
+ 			(void)splx(s);
+ 			if (swapsize == -1)
+ 				nblks = (*bdevsw[maj].d_psize)(swp->sw_dev);
+   		  	else
+ 				nblks = swapsize;
+ 			s = spltty();
+ 			if (nblks == -1)
+ 				printf("-> device not configured for swap\n");
+ 			else
+ 				printf("-> %d bytes\n", nblks*DEV_BSIZE);
+ 			(void)splx(s);
+ 			if (nblks != -1 &&
+ 			    (swp->sw_nblks == 0 || swp->sw_nblks > nblks))
+ 				swp->sw_nblks = nblks;
+ 			swp->sw_nblks = ctod(dtoc(swp->sw_nblks));
+ 		}
+ 	}
+ }
+ 
+ 
+ /* Set up the root and swap device numbers, configure the swap space and dump space */
+ 
+ void
+ set_boot_devs()
+ {
+ 	set_root_device();
+ 	set_swap_device();
+ 
+ 	if (swapdev == NODEV && minor(rootdev) < (MAXPARTITIONS - 2))
+ 		swapdev = makedev(major(rootdev), minor(rootdev) + 1);
+ 
+ 	dumpdev = swapdev;
+ 	argdev = swapdev;
+ 	swdevt[0].sw_dev = swapdev;
+ 
+ 	swapconf();
+ 	dumpconf();
+ }
+ 
+ 
+ /*
+  * void configure()
+  *
+  * Configure all the root devices
+  * The root devices are expected to configure their own children
+  */
+ 
+ void
+ configure()
+ {
+ 
+ /*
+  * Configure all the roots.
+  * We have to have a mainbus
+  */
+ 
+ 	config_rootfound("mainbus", NULL);
+ #if NPODULEBUS > 0
+ 	config_rootfound("podulebus", NULL);
+ #endif
+ 
+ /* Debugging information */
+ 
+ 	printf("ipl_bio=%08x ipl_net=%08x ipl_tty=%08x ipl_clock=%08x ipl_imp=%08x ipl_none=%08x\n",
+ 	    irqmasks[IPL_BIO], irqmasks[IPL_NET], irqmasks[IPL_TTY],
+ 	    irqmasks[IPL_CLOCK], irqmasks[IPL_IMP], irqmasks[IPL_NONE]);
+ 
+ /* Time to start taking interrupts so lets open the flood gates .... */
+          
+ 	(void)spl0();
+ }
+ 
+ /* End of autoconf.c */
diff -c -r -N --exclude exp --exclude compile sys/arch/arm32.orig/arm32/conf.c sys/arch/arm32/arm32/conf.c
*** sys/arch/arm32.orig/arm32/conf.c	Mon Jun  3 22:33:15 1996
--- sys/arch/arm32/arm32/conf.c	Thu Jun 13 02:56:51 1996
***************
*** 77,82 ****
--- 77,84 ----
  bdev_decl(vnd);
  #include "ccd.h"
  bdev_decl(ccd);
+ #include "acd.h"
+ bdev_decl(acd);
  
  /* Block devices */
  
***************
*** 101,107 ****
  	bdev_disk_init(NFDC, fd),	/* 17: floppy diskette */
  	bdev_disk_init(NRD, rd),	/* 18: ramdisk */
  	bdev_disk_init(NVND,vnd),	/* 19: vnode disk driver */
! 	bdev_lkm_dummy(),		/* 20: */
   	bdev_disk_init(NCCD,ccd),	/* 21: concatenated disk driver */
  	bdev_lkm_dummy(),		/* 22: */
  	bdev_lkm_dummy(),		/* 23: */
--- 103,109 ----
  	bdev_disk_init(NFDC, fd),	/* 17: floppy diskette */
  	bdev_disk_init(NRD, rd),	/* 18: ramdisk */
  	bdev_disk_init(NVND,vnd),	/* 19: vnode disk driver */
! 	bdev_disk_init(NACD,acd),	/* 20: ATAPI CD-ROM */
   	bdev_disk_init(NCCD,ccd),	/* 21: concatenated disk driver */
  	bdev_lkm_dummy(),		/* 22: */
  	bdev_lkm_dummy(),		/* 23: */
***************
*** 244,249 ****
--- 246,252 ----
  cdev_decl(tun);
  cdev_decl(vnd);
  cdev_decl(ccd);
+ cdev_decl(acd);
  #include "quadmouse.h"
  cdev_decl(quadmouse);
  #include "pms.h"
***************
*** 284,290 ****
  	cdev_disk_init(NFDC, fd),       /* 17: floppy diskette */
  	cdev_disk_init(NRD, rd),        /* 18: ram disk driver */
  	cdev_disk_init(NVND,vnd),       /* 19: vnode disk driver */
! 	cdev_lkm_dummy(),		/* 20: */
   	cdev_disk_init(NCCD,ccd),	/* 21: concatenated disk driver */
  	cdev_lkm_dummy(),		/* 22: */
  	cdev_lkm_dummy(),		/* 23: */
--- 287,293 ----
  	cdev_disk_init(NFDC, fd),       /* 17: floppy diskette */
  	cdev_disk_init(NRD, rd),        /* 18: ram disk driver */
  	cdev_disk_init(NVND,vnd),       /* 19: vnode disk driver */
! 	cdev_disk_init(NACD,acd),	/* 20: ATAPI CD-ROM */
   	cdev_disk_init(NCCD,ccd),	/* 21: concatenated disk driver */
  	cdev_lkm_dummy(),		/* 22: */
  	cdev_lkm_dummy(),		/* 23: */
***************
*** 359,365 ****
      /* 17 */        17,
      /* 18 */        18,
      /* 19 */        19,
!     /* 20 */        NODEV,
      /* 21 */        21,
      /* 22 */        NODEV,
      /* 23 */        NODEV,
--- 362,368 ----
      /* 17 */        17,
      /* 18 */        18,
      /* 19 */        19,
!     /* 20 */        20,
      /* 21 */        21,
      /* 22 */        NODEV,
      /* 23 */        NODEV,
diff -c -r -N --exclude exp --exclude compile sys/arch/arm32.orig/arm32/conf.c.orig sys/arch/arm32/arm32/conf.c.orig
*** sys/arch/arm32.orig/arm32/conf.c.orig	Thu Jan  1 01:00:00 1970
--- sys/arch/arm32/arm32/conf.c.orig	Mon Jun  3 22:33:15 1996
***************
*** 0 ****
--- 1,430 ----
+ /* $NetBSD: conf.c,v 1.8 1996/06/03 21:36:14 mark Exp $ */
+ 
+ /*
+  * Copyright (c) 1994 Mark Brinicombe.
+  * Copyright (c) 1994 Brini.
+  * 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, 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. All advertising materials mentioning features or use of this software
+  *    must display the following acknowledgement:
+  *	This product includes software developed by Mark Brinicombe.
+  * 4. The name of the company nor the name of the author may be used to
+  *    endorse or promote products derived from this software without specific
+  *    prior written permission.
+  *
+  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+  * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 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.
+  *
+  * RiscBSD kernel project
+  *
+  * conf.c
+  *
+  * Character and Block Device configuration
+  * Console configuration
+  *
+  * Defines the structures cdevsw and constab
+  *
+  * Created      : 17/09/94
+  */
+  
+ #include <sys/param.h>
+ #include <sys/systm.h>
+ #include <sys/buf.h>
+ #include <sys/ioctl.h>
+ #include <sys/tty.h>
+ #include <sys/conf.h>
+ #include <sys/vnode.h>
+ 
+ int     ttselect        __P((dev_t, int, struct proc *));
+ 
+ #ifndef LKM
+ #define lkmenodev       enodev
+ #else
+ int     lkmenodev();
+ #endif
+ 
+ #include "wdc.h"
+ bdev_decl(wd);
+ bdev_decl(sw);
+ #include "fdc.h"
+ bdev_decl(fd);
+ #include "rd.h"
+ bdev_decl(rd);
+ #include "sd.h"
+ bdev_decl(sd);
+ #include "st.h"
+ bdev_decl(st);
+ #include "cd.h"
+ bdev_decl(cd);
+ #include "vnd.h"
+ bdev_decl(vnd);
+ #include "ccd.h"
+ bdev_decl(ccd);
+ 
+ /* Block devices */
+ 
+ struct bdevsw bdevsw[] = {
+ 	bdev_lkm_dummy(),		/*  0: */
+ 	bdev_swap_init(1, sw),		/*  1: swap pseudo-device */
+ 	bdev_lkm_dummy(),		/*  2: */
+ 	bdev_lkm_dummy(),		/*  3: */
+ 	bdev_lkm_dummy(),		/*  4: */
+ 	bdev_lkm_dummy(),		/*  5: */
+ 	bdev_lkm_dummy(),		/*  6: */
+ 	bdev_lkm_dummy(),		/*  7: */
+ 	bdev_lkm_dummy(),		/*  8: */
+ 	bdev_lkm_dummy(),		/*  9: */
+ 	bdev_lkm_dummy(),		/* 10: */
+ 	bdev_lkm_dummy(),		/* 11: */
+ 	bdev_lkm_dummy(),		/* 12: */
+ 	bdev_lkm_dummy(),		/* 13: */
+ 	bdev_lkm_dummy(),		/* 14: */
+ 	bdev_lkm_dummy(),		/* 15: */
+ 	bdev_disk_init(NWDC, wd),	/* 16: Internal IDE disk */
+ 	bdev_disk_init(NFDC, fd),	/* 17: floppy diskette */
+ 	bdev_disk_init(NRD, rd),	/* 18: ramdisk */
+ 	bdev_disk_init(NVND,vnd),	/* 19: vnode disk driver */
+ 	bdev_lkm_dummy(),		/* 20: */
+  	bdev_disk_init(NCCD,ccd),	/* 21: concatenated disk driver */
+ 	bdev_lkm_dummy(),		/* 22: */
+ 	bdev_lkm_dummy(),		/* 23: */
+ 	bdev_disk_init(NSD,sd),		/* 24: SCSI disk */
+ 	bdev_tape_init(NST,st),		/* 25: SCSI tape */
+ 	bdev_disk_init(NCD,cd),		/* 26: SCSI cdrom */
+ 	bdev_lkm_dummy(),		/* 27: */
+ 	bdev_lkm_dummy(),		/* 28: */
+ 	bdev_lkm_dummy(),		/* 29: */
+ 	bdev_lkm_dummy(),		/* 30: */
+ 	bdev_lkm_dummy(),		/* 31: */
+ 	bdev_lkm_dummy(),		/* 32: */
+ 	bdev_lkm_dummy(),		/* 33: */
+ 	bdev_lkm_dummy(),		/* 34: */
+ 	bdev_lkm_dummy(),		/* 35: */
+ 	bdev_lkm_dummy(),		/* 36: */
+ 	bdev_lkm_dummy(),		/* 37: */
+ 	bdev_lkm_dummy(),		/* 38: */
+ 	bdev_lkm_dummy(),		/* 39: */
+ 	bdev_lkm_dummy(),		/* 40: */
+ 	bdev_lkm_dummy(),		/* 41: */
+ 	bdev_lkm_dummy(),		/* 42: */
+ 	bdev_lkm_dummy(),		/* 43: */
+   };
+ 
+ int nblkdev = sizeof(bdevsw) / sizeof(bdevsw[0]);
+ 
+ 
+ /* Character device declarations */
+ 
+ /* open, close, read, write, ioctl, tty, mmap */
+ #define cdev_physcon_init(c,n) { \
+ 	dev_init(c,n,open), dev_init(c,n,close), dev_init(c,n,read), \
+ 	dev_init(c,n,write), dev_init(c,n,ioctl), dev_init(c,n,stop), \
+ 	dev_init(c,n,tty), ttselect, dev_init(c,n,mmap), 0 }
+ 
+ /* open, close, write, ioctl */
+ #define cdev_lpt_init(c,n) { \
+ 	dev_init(c,n,open), dev_init(c,n,close), (dev_type_read((*))) enodev, \
+ 	dev_init(c,n,write), dev_init(c,n,ioctl), (dev_type_stop((*))) enodev, \
+ 	0, seltrue, (dev_type_mmap((*))) enodev, 0 }
+ 
+ /* open, close, write, ioctl */
+ #define cdev_beep_init(c,n) { \
+ 	dev_init(c,n,open), dev_init(c,n,close), (dev_type_read((*))) enodev, \
+ 	(dev_type_write((*))) enodev, dev_init(c,n,ioctl), \
+ 	(dev_type_stop((*))) enodev, \
+ 	0, seltrue, (dev_type_mmap((*))) enodev, 0 }
+ 
+ /* open, close, write, ioctl */
+ #define cdev_kbd_init(c,n) { \
+ 	dev_init(c,n,open), dev_init(c,n,close), dev_init(c,n,read), \
+ 	(dev_type_write((*))) enodev, dev_init(c,n,ioctl), \
+ 	(dev_type_stop((*))) enodev, \
+ 	0, dev_init(c,n,select), (dev_type_mmap((*))) enodev, 0 }
+ 
+ /* open, close, write, ioctl */
+ #define cdev_cpu_init(c,n) { \
+ 	dev_init(c,n,open), dev_init(c,n,close), (dev_type_read((*))) enodev, \
+ 	(dev_type_write((*))) enodev, dev_init(c,n,ioctl), \
+ 	(dev_type_stop((*))) enodev, \
+ 	0, seltrue, (dev_type_mmap((*))) enodev, 0 }
+ 
+ /* open, close, write, ioctl */
+ #define cdev_vidcvid_init(c,n) { \
+ 	dev_init(c,n,open), dev_init(c,n,close), (dev_type_read((*))) enodev, \
+ 	(dev_type_write((*))) enodev, dev_init(c,n,ioctl), \
+ 	(dev_type_stop((*))) enodev, \
+ 	0, seltrue, dev_init(c,n,mmap), 0 }
+ 
+ /* open, close, write, ioctl */
+ #define cdev_uk_init(c,n) { \
+ 	dev_init(c,n,open), dev_init(c,n,close), dev_init(c,n,read), \
+ 	dev_init(c,n,write), dev_init(c,n,ioctl), \
+ 	(dev_type_stop((*))) enodev, \
+ 	0, seltrue, (dev_type_mmap((*))) enodev, 0 }
+ 
+ /* open, close, read, ioctl */
+ #define cdev_ss_init(c,n) { \
+ 	dev_init(c,n,open), dev_init(c,n,close), dev_init(c,n,read), \
+ 	(dev_type_write((*))) enodev, dev_init(c,n,ioctl), \
+ 	(dev_type_stop((*))) enodev, 0, seltrue, \
+ 	(dev_type_mmap((*))) enodev }
+ 
+ /* open, close, write, ioctl */
+ #define cdev_iic_init(c,n) { \
+ 	dev_init(c,n,open), dev_init(c,n,close), dev_init(c,n,read), \
+ 	dev_init(c,n,write), dev_init(c,n,ioctl), (dev_type_stop((*))) enodev, \
+ 	0, seltrue, (dev_type_mmap((*))) enodev, 0 }
+ 
+ /* open, close, write, ioctl */
+ #define cdev_rtc_init(c,n) { \
+ 	dev_init(c,n,open), dev_init(c,n,close), dev_init(c,n,read), \
+ 	dev_init(c,n,write), dev_init(c,n,ioctl), (dev_type_stop((*))) enodev, \
+ 	0, seltrue, (dev_type_mmap((*))) enodev, 0 }
+ 
+ cdev_decl(cn);
+ cdev_decl(ctty);
+ #include "vt.h"                                 
+ cdev_decl(physcon);
+ cdev_decl(vidcvideo);
+ #define mmread  mmrw
+ #define mmwrite mmrw
+ cdev_decl(mm);
+ cdev_decl(wd);
+ cdev_decl(sw);
+ #include "pty.h"
+ #define ptstty          ptytty
+ #define ptsioctl        ptyioctl
+ cdev_decl(pts);
+ #define ptctty          ptytty
+ #define ptcioctl        ptyioctl
+ cdev_decl(ptc);
+ cdev_decl(log);
+ #include "com.h"
+ cdev_decl(com);
+ #include "lpt.h"
+ cdev_decl(lpt);
+ cdev_decl(fd);
+ dev_decl(filedesc,open);
+ cdev_decl(rd);
+ #include "bpfilter.h"
+ cdev_decl(bpf);
+ cdev_decl(sd);
+ cdev_decl(st);
+ cdev_decl(cd);
+ #include "ch.h"
+ cdev_decl(ch);
+ #include "uk.h"
+ cdev_decl(uk);
+ #include "ss.h"
+ cdev_decl(ss);
+ #ifdef LKM
+ #define	NLKM	1
+ #else
+ #define	NLKM	0
+ #endif
+ cdev_decl(lkm);
+ #include "tun.h"
+ cdev_decl(tun);
+ cdev_decl(vnd);
+ cdev_decl(ccd);
+ #include "quadmouse.h"
+ cdev_decl(quadmouse);
+ #include "pms.h"
+ cdev_decl(pms);
+ #include "beep.h"
+ cdev_decl(beep);
+ #include "kbd.h"
+ cdev_decl(kbd);
+ #include "audio.h"
+ cdev_decl(audio);
+ #include "cpu.h"
+ cdev_decl(cpu);
+ #include "iic.h"
+ cdev_decl(iic);
+ #include "rtc.h"
+ cdev_decl(rtc);
+ 
+ /* Character devices */
+ 
+ struct cdevsw cdevsw[] = {
+ 	cdev_mm_init(1, mm),            /*  0: /dev/{null,mem,kmem,...} */
+ 	cdev_swap_init(1, sw),          /*  1: /dev/drum (swap pseudo-device) */
+ 	cdev_cn_init(1, cn),            /*  2: virtual console */
+ 	cdev_ctty_init(1,ctty),         /*  3: controlling terminal */
+ 	cdev_physcon_init(NVT, physcon),  /*  4: RPC console */
+         cdev_log_init(1,log),           /*  5: /dev/klog */
+ 	cdev_ptc_init(NPTY,ptc),        /*  6: pseudo-tty master */
+ 	cdev_tty_init(NPTY,pts),        /*  7: pseudo-tty slave */
+ 	cdev_lpt_init(NLPT,lpt),        /*  8: parallel printer */
+ 	cdev_mouse_init(NQUADMOUSE,quadmouse),       /* 9: quadmouse driver */
+ 	cdev_beep_init(NBEEP,beep),	/* 10: simple beep device */
+ 	cdev_kbd_init(NKBD,kbd),	/* 11: kbd device */
+ 	cdev_tty_init(NCOM,com),        /* 12: serial port */
+ 	cdev_lkm_dummy(),		/* 13: */
+ 	cdev_lkm_dummy(),		/* 14: */
+ 	cdev_lkm_dummy(),		/* 15: */
+ 	cdev_disk_init(NWDC, wd),       /* 16: ST506/ESDI/IDE disk */
+ 	cdev_disk_init(NFDC, fd),       /* 17: floppy diskette */
+ 	cdev_disk_init(NRD, rd),        /* 18: ram disk driver */
+ 	cdev_disk_init(NVND,vnd),       /* 19: vnode disk driver */
+ 	cdev_lkm_dummy(),		/* 20: */
+  	cdev_disk_init(NCCD,ccd),	/* 21: concatenated disk driver */
+ 	cdev_lkm_dummy(),		/* 22: */
+ 	cdev_lkm_dummy(),		/* 23: */
+ 	cdev_disk_init(NSD,sd),	    	/* 24: SCSI disk */
+ 	cdev_tape_init(NST,st),	   	/* 25: SCSI tape */
+ 	cdev_disk_init(NCD,cd),	    	/* 26: SCSI CD-ROM */
+ 	cdev_ch_init(NCH,ch),	 	/* 27: SCSI autochanger */
+ 	cdev_ch_init(NUK,uk),	 	/* 28: SCSI unknown */
+ 	cdev_ss_init(NSS,ss),	 	/* 29: SCSI scanner */
+ 	cdev_lkm_dummy(),		/* 30: */
+ 	cdev_lkm_dummy(),		/* 31: */
+ 	cdev_bpftun_init(NBPFILTER,bpf),/* 32: Berkeley packet filter */
+         cdev_bpftun_init(NTUN,tun),     /* 33: network tunnel */
+         cdev_fd_init(1,filedesc),       /* 34: file descriptor pseudo-device */
+ 	cdev_lkm_init(NLKM,lkm),        /* 35: loadable module driver */
+ 	cdev_audio_init(NAUDIO,audio),	/* 36: generic audio I/O */
+ 	cdev_vidcvid_init(1,vidcvideo),	/* 37: vidcvideo device */
+ 	cdev_cpu_init(NCPU,cpu),	/* 38: cpu device */
+ 	cdev_lkm_dummy(),		/* 39: */
+ 	cdev_mouse_init(NPMS,pms),      /* 40: PS2 mouse driver */
+ 	cdev_lkm_dummy(),		/* 41: */
+ 	cdev_iic_init(NIIC, iic),	/* 42: IIC bus driver */
+ 	cdev_rtc_init(NRTC, rtc),	/* 43: RTC driver */
+ };
+ 
+ int nchrdev = sizeof(cdevsw) / sizeof(cdevsw[0]);
+ 
+ int mem_no = 0; 	/* major device number of memory special file */
+ 
+ 
+ /*
+  * Returns true if dev is /dev/mem or /dev/kmem.
+  */
+ int
+ iskmemdev(dev)
+ 	dev_t dev;
+ {
+ 	return (major(dev) == mem_no && minor(dev) < 2);
+ }
+ 
+ /*
+  * Returns true if dev is /dev/zero.
+  */
+ int
+ iszerodev(dev)
+ 	dev_t dev;
+ {
+ 	return (major(dev) == mem_no && minor(dev) == 3);
+ }
+ 
+ 
+ static int chrtoblktbl[] = {
+ /* XXXX This needs to be dynamic for LKMs. */
+     /*VCHR*/        /*VBLK*/
+     /*  0 */        NODEV,
+     /*  1 */        1,
+     /*  2 */        NODEV,
+     /*  3 */        NODEV,
+     /*  4 */        NODEV,
+     /*  5 */        NODEV,
+     /*  6 */        NODEV,
+     /*  7 */        NODEV,
+     /*  8 */        NODEV,
+     /*  9 */        NODEV,
+     /* 10 */        NODEV,
+     /* 11 */        NODEV,
+     /* 12 */        NODEV,
+     /* 13 */        NODEV,
+     /* 14 */        NODEV,
+     /* 15 */        NODEV,
+     /* 16 */        16,
+     /* 17 */        17,
+     /* 18 */        18,
+     /* 19 */        19,
+     /* 20 */        NODEV,
+     /* 21 */        21,
+     /* 22 */        NODEV,
+     /* 23 */        NODEV,
+     /* 24 */        24,
+     /* 25 */        25,
+     /* 26 */        26,
+     /* 27 */        NODEV,
+     /* 28 */        NODEV,
+     /* 29 */        NODEV,
+     /* 30 */        NODEV,
+     /* 31 */        NODEV,
+     /* 32 */        NODEV,
+     /* 33 */        NODEV,
+     /* 34 */        NODEV,
+     /* 35 */        NODEV,
+     /* 36 */        NODEV,
+     /* 37 */        NODEV,
+     /* 38 */        NODEV,
+     /* 39 */        NODEV,
+     /* 40 */        NODEV,
+     /* 41 */        NODEV,
+     /* 42 */        NODEV,
+     /* 43 */        NODEV,
+ };
+ 
+ /*
+  * Convert a character device number to a block device number.
+  */
+  
+ dev_t
+ chrtoblk(dev)
+ 	dev_t dev;
+ {
+ 	int blkmaj;
+                   
+ 	if (major(dev) >= nchrdev)
+ 		return (NODEV);
+ 
+ 	blkmaj = chrtoblktbl[major(dev)];
+ 	if (blkmaj == NODEV)
+ 		return (NODEV);
+ 	return (makedev(blkmaj, minor(dev)));
+ }
+                                                                                    
+ /*
+  * This entire table could be autoconfig()ed but that would mean that
+  * the kernel's idea of the console would be out of sync with that of
+  * the standalone boot.  I think it best that they both use the same
+  * known algorithm unless we see a pressing need otherwise.
+  */
+ 
+ #include <dev/cons.h>
+ 
+ cons_decl(rpcconsole);
+ cons_decl(com);   
+        
+ struct consdev constab[] = {
+ #if (NVT + NRPC > 0)
+ 	cons_init(rpcconsole),
+ #endif
+ 
+ /*#if (NCOM > 0)
+ 	cons_init(com),
+ #endif*/
+ 	{ 0 },
+ };
+                            
+ /* End of conf.c */
diff -c -r -N --exclude exp --exclude compile sys/arch/arm32.orig/conf/VOYAGER sys/arch/arm32/conf/VOYAGER
*** sys/arch/arm32.orig/conf/VOYAGER	Thu Jun 13 02:08:19 1996
--- sys/arch/arm32/conf/VOYAGER	Thu Jun 13 02:56:51 1996
***************
*** 124,129 ****
--- 124,132 ----
  wdc0    at mainbus? base 0x002107c0 irq 9
  wd*     at wdc? drive ?
  
+ atapibus* at wdc?
+ acd* at atapibus? drive?
+ 
  # Floppy disk controller
  fdc0    at mainbus? base 0x00210fc0 irq 12 dack 0x00002000
  fd0     at fdc? drive ?
diff -c -r -N --exclude exp --exclude compile sys/arch/arm32.orig/conf/VOYAGER.orig sys/arch/arm32/conf/VOYAGER.orig
*** sys/arch/arm32.orig/conf/VOYAGER.orig	Thu Jan  1 01:00:00 1970
--- sys/arch/arm32/conf/VOYAGER.orig	Thu Jun 13 02:08:19 1996
***************
*** 0 ****
--- 1,201 ----
+ #
+ #	VOYAGER -- Mark's master development machine
+ #
+ 
+ include	"std.arm32"
+ 
+ # estimated number of users
+ 
+ maxusers	32
+ 
+ # Standard system options
+ 
+ options		TIMEZONE=0	# time zone to adjust RTC time by
+ options		DST=0		# daylight savings time used by RTC
+ options		SWAPPAGER	# paging; REQUIRED
+ options		VNODEPAGER	# mmap() of files
+ options		DEVPAGER	# mmap() of devices
+ 
+ # CPU options
+ 
+ options		CPU_ARM6
+ options		CPU_LATE_ABORT	# ARM7XX compatibility
+ 
+ # FPA options
+ 
+ #options		FPE		# Single precision FPE
+ options		ARMFPE		# ARM Ltd FPE
+ 
+ # File system options
+ 
+ options		FFS		# UFS
+ #options	QUOTA		# UFS quotas
+ #options	LFS		# log-structured file system
+ options		MFS		# memory file system
+ 
+ options		CD9660		# ISO 9660 + Rock Ridge file system
+ options		MSDOSFS		# MS-DOS file system
+ options		FDESC		# /dev/fd
+ options		FIFO		# FIFOs; RECOMMENDED
+ options		KERNFS		# /kern
+ options		NULLFS		# loopback file system
+ #options	PORTAL		# portal filesystem (still experimental)
+ options		PROCFS		# /proc
+ options		UMAPFS		# NULLFS + uid and gid remapping
+ options		UNION		# union file system
+ 
+ # Networking options
+ 
+ options		NFSCLIENT
+ options		NFSSERVER
+ options		GATEWAY		# packet forwarding
+ options		INET		# IP + ICMP + TCP + UDP
+ #options	NS		# XNS
+ #options	ISO,TPIP	# OSI
+ #options	EON		# OSI tunneling over IP
+ #options	CCITT,LLC,HDLC	# X.25
+ 
+ # Compatibility options
+ 
+ options		COMPAT_43
+ options		COMPAT_10
+ options		COMPAT_09
+ options         TCP_COMPAT_42   # TCP bug compatibility with 4.2BSD
+ 
+ # Shared memory options
+ 
+ options		SYSVMSG		# System V-like message queues
+ options		SYSVSEM		# System V-like semaphores
+ options		SYSVSHM		# System V-like memory sharing
+ options		SHMMAXPGS=1024	# 1024 pages is the default
+ 
+ # Device options
+ 
+ options		RAMDISK_HOOKS	# boottime setup of ramdisk
+ options		RAMDISK_SIZE=0	# Size in KBytes
+ options		PLIP		# Build plip device into lpt driver
+ 
+ # Development options
+ 
+ #options	ARM700BUGTRACK	# track the ARM700 swi bug
+ options		HYDRA		# Experimental hydra support
+ options		MPSUPPORT	# Experimental MP support
+ options		DIAGNOSTIC	# internally consistency checks
+ options		KTRACE		# system call tracing, a la ktrace(1)
+ options		IRQSTATS	# IRQ statistics
+ options		POSTMORTEM	# perform postmortem on panic
+ #options	ROTTEN_INNARDS	# show the gory bit of the postmortem
+ options		KSHELL		# kernel developemnt shell (debug)
+ options		LKM		# loadable kernel modules
+ #options	DEBUGTERM	# create a debug console
+ #options	KGDB		# remote kernel debugging
+ options		DDB		# in-kernel debugger
+ #makeoptions	DEBUG="-g"	# compile full symbol table
+ 
+ config		netbsd	swap generic
+ options		GENERIC
+ 
+ # The main bus device
+ mainbus0 at root
+ 
+ # The boot cpu
+ cpu0 at mainbus?
+ 
+ # The hydra multiprocessor device
+ hydrabus0 at mainbus?
+ 
+ #hcpu0 at hydrabus?
+ #hcpu1 at hydrabus? slot 0
+ #hcpu2 at hydrabus?
+ #hcpu3 at hydrabus?
+ 
+ # The vidc
+ vidcvideo0	at mainbus?
+ 
+ # generic VT console device
+ vt0     at mainbus?
+ vt1     at mainbus?
+ vt2     at mainbus?
+ vt3     at mainbus?
+ vt4     at mainbus?
+ vt5     at mainbus?
+ 
+ # IDE disk controller
+ wdc0    at mainbus? base 0x002107c0 irq 9
+ wd*     at wdc? drive ?
+ 
+ # Floppy disk controller
+ fdc0    at mainbus? base 0x00210fc0 irq 12 dack 0x00002000
+ fd0     at fdc? drive ?
+ 
+ # kbd via IOMD
+ kbd0	at mainbus? base 0x00000000
+ 
+ # quadrature mouse
+ quadmouse0	at mainbus? base 0x00000000 irq 6	# TMR1
+ #quadmouse0	at mainbus? base 0x00000000 irq 3	# VSYNC
+ 
+ # PS2 mouse
+ pms0	at mainbus? base 0x00000000
+ 
+ # Serial ports
+ com0    at mainbus? base 0x00210fe0 irq 10
+ #com1    at mainbus? base 0x00210be0
+ 
+ # Parallel ports
+ lpt0    at mainbus? base 0x002109e0 irq 0
+ 
+ # Crude sound device
+ beep0	at mainbus? base 0x00000000
+ 
+ # IIC bus device
+ iic0	at mainbus?
+ 
+ # RTC device
+ rtc0	at iic? addr 0xa0
+ 
+ # Podule bus device
+ podulebus0	at root
+ 
+ asc0	at podulebus?			# Acorn SCSI card
+ scsibus* at asc?
+ 
+ csc0	at podulebus?			# Cumana SCSI II card
+ scsibus* at csc?
+ 
+ ptsc0	at podulebus?			# Power-Tec SCSI II card
+ scsibus* at ptsc?
+ 
+ oak0	at podulebus?			# Oak SCSI I card
+ scsibus* at oak?
+ 
+ sd*	at scsibus? target ? lun ?	# SCSI disk drives
+ st*	at scsibus? target ? lun ?	# SCSI tape drives
+ cd*	at scsibus? target ? lun ?	# SCSI CD-ROM drives
+ ch*	at scsibus? target ? lun ?	# SCSI auto-changers
+ uk*	at scsibus? target ? lun ?	# SCSI unknown device
+ ss*	at scsibus? target ? lun ?	# SCSI scanner
+ 
+ #kie*	at podulebus? slot ? offset ?
+ 
+ ea0	at podulebus?			# Ether3 podules
+ eb0	at podulebus?			# EtherB network slot cards
+ eh0	at podulebus?			# EtherH network slot cards
+ ie0	at podulebus?			# Ether1 podules
+ 
+ pseudo-device	loop	1               # network loopback
+ pseudo-device   bpfilter 8              # packet filter
+ pseudo-device	sl	2               # CSLIP
+ pseudo-device	ppp	2		# PPP
+ pseudo-device	tun	2		# network tunneling over tty
+ 
+ pseudo-device   pty     32              # pseudo-terminals
+ pseudo-device	tb	1		# tablet line discipline
+ pseudo-device   vnd     4               # paging to files
+ pseudo-device	ccd	2		# concatenated disk devices
+ 
+ pseudo-device	rd	1		# Ramdisk device
+ 
+ makeoptions MONITOR="Taxan875+LR"
+ #makeoptions MONITOR="AKF60"
+ makeoptions MODES="1024,768,60 1024,768,70 800,600,60 640,480,60 1280,1024 1152,900"
diff -c -r -N --exclude exp --exclude compile sys/arch/arm32.orig/conf/files.arm32 sys/arch/arm32/conf/files.arm32
*** sys/arch/arm32.orig/conf/files.arm32	Thu Jun 13 02:17:41 1996
--- sys/arch/arm32/conf/files.arm32	Thu Jun 13 02:56:55 1996
***************
*** 39,50 ****
  file	arch/arm32/arm32/kgdb_glue.c		kgdb needs-flag
  file	arch/arm32/arm32/kgdb_step.c		kgdb
  
  # Standard NetBSD wd driver
! device  wdc {drive = -1}
  attach	wdc at mainbus
  device  wd: disk
! attach	wd at wdc
  file    arch/arm32/mainbus/wd.c			wdc needs-flag
  major   {wd = 16}
  
  # Standard NetBSD fd driver
--- 39,57 ----
  file	arch/arm32/arm32/kgdb_glue.c		kgdb needs-flag
  file	arch/arm32/arm32/kgdb_step.c		kgdb
  
+ #
+ # Machine-independent ATAPI drivers
+ #
+ include "../../../atapi/files.atapi"
+ 
  # Standard NetBSD wd driver
! define ata {drive=-1}
! device  wdc: atapi, ata 
  attach	wdc at mainbus
  device  wd: disk
! attach  wd at ata
  file    arch/arm32/mainbus/wd.c			wdc needs-flag
+ file    arch/arm32/mainbus/wdc.c		wdc needs-flag
  major   {wd = 16}
  
  # Standard NetBSD fd driver
diff -c -r -N --exclude exp --exclude compile sys/arch/arm32.orig/conf/files.arm32.orig sys/arch/arm32/conf/files.arm32.orig
*** sys/arch/arm32.orig/conf/files.arm32.orig	Thu Jan  1 01:00:00 1970
--- sys/arch/arm32/conf/files.arm32.orig	Thu Jun 13 02:17:41 1996
***************
*** 0 ****
--- 1,276 ----
+ #
+ # First try for arm-specific configuration info
+ #
+ 
+ maxpartitions	8
+ maxusers 2 8 64
+ 
+ device mainbus { [base = -1], [dack = -1], [irq = -1] }
+ attach mainbus at root
+ file	arch/arm32/mainbus/mainbus.c		mainbus
+ 
+ device cpu
+ attach cpu at mainbus
+ file	arch/arm32/mainbus/cpu.c		cpu needs-flag
+ major	{cpu = 38}
+ 
+ device hydrabus { [slot = -1] }
+ attach hydrabus at mainbus
+ file	arch/arm32/mainbus/exp/hydrabus.c	hydrabus needs-flag
+ 
+ device hcpu
+ attach hcpu at hydrabus
+ file	arch/arm32/mainbus/exp/hcpu.c		hcpu needs-count
+ 
+ file	arch/arm32/mainbus/exp/hydraboot.S	hydrabus | hcpu
+ file	arch/arm32/mainbus/exp/hydra.c		hydrabus | hcpu
+ 
+ #
+ # Machine-independent KGDB support
+ #
+ #include "../../../kgdb/files.kgdb"
+ define	kgdb
+ device	kgdbslip: kgdb
+ device	kgdbppp: kgdb
+ 
+ #device kie
+ #attach kie at podule
+ #file	arch/arm32/podulebus/kgdb_ie.c		kie
+ file	arch/arm32/arm32/kgdb_glue.c		kgdb needs-flag
+ file	arch/arm32/arm32/kgdb_step.c		kgdb
+ 
+ # Standard NetBSD wd driver
+ device  wdc {drive = -1}
+ attach	wdc at mainbus
+ device  wd: disk
+ attach	wd at wdc
+ file    arch/arm32/mainbus/wd.c			wdc needs-flag
+ major   {wd = 16}
+ 
+ # Standard NetBSD fd driver
+ device  fdc {drive = -1}
+ attach	fdc at mainbus
+ device  fd: disk
+ attach	fd at fdc
+ file    arch/arm32/mainbus/fd.c			fdc needs-flag
+ major   {fd = 17}
+ 
+ # RAM disk driver
+ pseudo-device	rd
+ file	dev/ramdisk.c				rd needs-count
+ file	arch/arm32/dev/rd_hooks.c		rd | ramdisk_hooks
+ major   {rd = 18}
+ 
+ # Standard parallal driver
+ device  lpt: tty, ether, ifnet
+ attach	lpt at mainbus
+ file    arch/arm32/mainbus/lpt.c		lpt needs-flag
+ major   {lpt = 8}
+ 
+ # Standard serial driver
+ define	kgdbcom {[ disable = 0], [ address = 0x12345678 ], [ speed = 9600 ]}
+ device  com: tty, kgdbcom
+ attach  com at mainbus
+ file    arch/arm32/mainbus/com.c		com | kgdb_cslp | kgdb_cppp needs-flag
+ major   {com = 12}
+ 
+ attach	kgdbslip at kgdbcom with kgdb_cslp
+ attach	kgdbppp at kgdbcom with kgdb_cppp
+ 
+ # Mouse devices
+ device  quadmouse: tty
+ attach	quadmouse at mainbus
+ file    arch/arm32/mainbus/qmouse.c		quadmouse needs-flag
+ major   {quadmouse = 9}
+ 
+ device  pms: tty
+ attach	pms at mainbus
+ file    arch/arm32/mainbus/pms.c		pms needs-flag
+ major   {pms = 40}
+ 
+ # Audio devices
+ device	beep
+ attach	beep at mainbus
+ file    arch/arm32/mainbus/beep.c		beep needs-flag
+ major   {beep = 10}
+ 
+ device	audio: audio
+ attach	audio at mainbus
+ file	arch/arm32/mainbus/vidcaudio.c		vidcaudio needs-flag
+ major   {audio = 36}
+ 
+ # Standard keyboard driver
+ device	kbd
+ attach	kbd at mainbus
+ file    arch/arm32/mainbus/kbd.c		kbd needs-flag
+ major   {kbd = 11}
+ 
+ # Podule bus device
+ device podulebus { [slot = -1] }
+ attach podulebus at root
+ file	arch/arm32/podulebus/podulebus.c	podulebus needs-flag
+ 
+ # Ethernet devices
+ device ea: ether, ifnet
+ attach ea at podulebus
+ file	arch/arm32/podulebus/if_ea.c		ea
+ 
+ device eb: ether, ifnet
+ attach eb at podulebus
+ file	arch/arm32/podulebus/if_eb.c		eb
+ 
+ device eh: ether, ifnet
+ attach eh at podulebus
+ file	arch/arm32/podulebus/if_eh.c		eh
+ 
+ device ie: ether, ifnet
+ attach ie at podulebus
+ file	arch/arm32/podulebus/if_ie.c		ie
+ 
+ device es: ether, ifnet
+ attach es at mainbus
+ file  arch/arm32/mainbus/if_es.c              es
+ 
+ # IIC/RTC files
+ device iic { addr = -1 }
+ attach iic at mainbus
+ file	arch/arm32/mainbus/iic_asm.S		iic
+ file	arch/arm32/mainbus/iic.c		iic	needs-flag
+ 
+ device rtc
+ attach rtc at iic
+ file	arch/arm32/mainbus/rtc.c		rtc	needs-count
+ 
+ #
+ # Machine-independent SCSI drivers
+ #
+ 
+ include "../../../scsi/files.scsi"
+ major   {sd = 24}
+ major   {st = 25}
+ major   {cd = 26}
+ major   {ch = 27}
+ major	{uk = 28}
+ major	{ss = 29}
+ 
+ # Generic sbic (WD3393) driver
+ define	sbic
+ file	arch/arm32/podulebus/sbic.c		sbic
+ 
+ # Acorn SCSI I specific layer for sbic
+ device  asc: scsi, sbic
+ attach	asc at podulebus
+ file	arch/arm32/podulebus/asc.c		asc needs-flag
+ 
+ # Generic fas216 + esp216 driver
+ define	sfas
+ file	arch/arm32/podulebus/sfas.c		sfas
+ 
+ # Cumana specific layer for sfas
+ device	csc: scsi, sfas
+ attach	csc at podulebus
+ file	arch/arm32/podulebus/exp/csc.c		csc
+ 
+ device	ptsc: scsi, sfas
+ attach	ptsc at podulebus
+ file	arch/arm32/podulebus/ptsc.c		ptsc
+ 
+ # Generic NCR driver
+ define	ncr
+ file	arch/arm32/podulebus/ncr5380sbc.c	ncr
+ 
+ # Oak specific layer for ncr
+ device	oak: scsi, ncr
+ attach	oak at podulebus
+ file	arch/arm32/podulebus/oak.c	oak
+ 
+ device  vidcvideo
+ attach	vidcvideo at mainbus
+ major	{vidcvideo = 37}
+ device  vt: tty
+ attach	vt at mainbus
+ file    arch/arm32/dev/console/console.c	vt needs-count
+ file    arch/arm32/dev/console/vidcconsole.c	vt needs-count
+ file	arch/arm32/dev/console/vidc_mc.S	vt needs-count
+ file    arch/arm32/dev/console/vidc.c		vt needs-count
+ file    arch/arm32/dev/console/vt220.c		vt needs-count
+ file	arch/arm32/dev/console/debugconsole.c 	vt needs-count
+ file	arch/arm32/dev/console/dumb.c 		vt needs-count
+ 
+ file	arch/arm32/arm32/autoconf.c
+ file	arch/arm32/arm32/blockio.S
+ file	arch/arm32/arm32/clock.c
+ file	arch/arm32/arm32/conf.c
+ file	arch/arm32/arm32/cpuswitch.S
+ file	arch/arm32/arm32/disksubr.c		disk
+ file	arch/arm32/arm32/stubs.c
+ file	arch/arm32/arm32/exception.S
+ file	arch/arm32/arm32/syscall.c
+ file	arch/arm32/arm32/ast.c
+ file	arch/arm32/arm32/fault.c
+ file	arch/arm32/arm32/undefined.c
+ file	arch/arm32/arm32/mem.c
+ file	arch/arm32/arm32/scratch.S
+ file	arch/arm32/arm32/process_machdep.c
+ file	arch/arm32/arm32/machdep.c
+ file	arch/arm32/arm32/sys_machdep.c
+ file	arch/arm32/arm32/vm_machdep.c
+ file	arch/arm32/arm32/pmap.c
+ file	arch/arm32/arm32/fusu.c
+ 
+ file	netinet/in_cksum.c			inet
+ file	netns/ns_cksum.c			ns
+ 
+ # IRQ/FIQ files
+ file	arch/arm32/arm32/spl.S
+ file	arch/arm32/arm32/irq.S
+ file	arch/arm32/arm32/irqhandler.c
+ file	arch/arm32/arm32/fiq.S
+ 
+ # library functions
+ file	arch/arm32/arm32/strstr.c
+ file	arch/arm32/arm32/strtoul.c
+ file	arch/arm32/arm32/memset.S
+ file	arch/arm32/arm32/bcopy_page.S
+ file	arch/arm32/arm32/bcopy.S
+ file	arch/arm32/arm32/bcopyinout.S
+ file	arch/arm32/arm32/copystr.S
+ file	arch/arm32/arm32/coproc15.S
+ file	arch/arm32/arm32/setcpsr.S
+ file	arch/arm32/arm32/setstack.S
+ 
+ # files related to the shell
+ file	arch/arm32/kshell/shell_input.c		kshell
+ file	arch/arm32/kshell/shell_shell.c		kshell
+ file	arch/arm32/kshell/shell_disassem.c	kshell
+ file	arch/arm32/kshell/strchr.c		kshell
+ file	arch/arm32/kshell/dumphex.c		kshell
+ 
+ # files related to debugging
+ file	arch/arm32/arm32/debug.c
+ file	arch/arm32/arm32/disassem.c
+ file	arch/arm32/arm32/postmortem.c
+  
+ file    dev/cons.c
+ file	dev/cninit.c
+ 
+ # Signal precision FPE
+ file	arch/arm32/fpe-sp/fpe.c			fpe
+ file	arch/arm32/fpe-sp/fpeadd.S		fpe
+ file	arch/arm32/fpe-sp/fpesub.S		fpe
+ file	arch/arm32/fpe-sp/fpemul.S		fpe
+ file	arch/arm32/fpe-sp/fpediv.S		fpe
+ file	arch/arm32/fpe-sp/fpefix.S		fpe
+ file	arch/arm32/fpe-sp/fpecmf.S		fpe
+ file	arch/arm32/fpe-sp/fpetoe.S		fpe
+ 
+ # ARM FPE
+ file	arch/arm32/fpe-arm/armfpe_glue.S	armfpe
+ file	arch/arm32/fpe-arm/armfpe_init.c	armfpe
+ file	arch/arm32/fpe-arm/armfpe.s		armfpe
+ 
+ # DDB
+ file	arch/arm32/arm32/db_disasm.c		ddb
+ file	arch/arm32/arm32/db_interface.c		ddb
+ file	arch/arm32/arm32/db_trace.c		ddb
+ file	arch/arm32/arm32/db_machdep.c		ddb
diff -c -r -N --exclude exp --exclude compile sys/arch/arm32.orig/mainbus/wd.c sys/arch/arm32/mainbus/wd.c
*** sys/arch/arm32.orig/mainbus/wd.c	Wed Jun 12 22:41:10 1996
--- sys/arch/arm32/mainbus/wd.c	Thu Jun 13 03:11:10 1996
***************
*** 57,76 ****
  #include <machine/io.h>
  #include <machine/katelib.h>
  
- #include <arm32/mainbus/wdreg.h>
  #include <arm32/mainbus/mainbus.h>
! 
! extern int wdresethack;
! 
  #define	WAITTIME	(4 * hz)	/* time to wait for a completion */
- #define	RECOVERYTIME	(hz / 2)	/* time to recover from an error */
- 
- #define WDCDELAY	100
- #define WDCNDELAY	100000		/* delay = 100us; so 10s for a controller state change */
- #if 0
- /* If you enable this, it will report any delays more than 100us * N long. */
- #define WDCNDELAY_DEBUG	10
- #endif
  
  #define	WDIORETRIES	5		/* number of retries before giving up */
  
--- 57,67 ----
  #include <machine/io.h>
  #include <machine/katelib.h>
  
  #include <arm32/mainbus/mainbus.h>
! #include <arm32/mainbus/wdreg.h>
! #include <arm32/mainbus/wdlink.h>
!   
  #define	WAITTIME	(4 * hz)	/* time to wait for a completion */
  
  #define	WDIORETRIES	5		/* number of retries before giving up */
  
***************
*** 83,303 ****
  struct wd_softc {
  	struct device sc_dev;
  	struct disk sc_dk;
! 
! 	/* Information about the current transfer: */
! 	daddr_t sc_blkno;	/* starting block number */
! 	int sc_bcount;		/* byte count left */
! 	int sc_skip;		/* bytes already transferred */
! 	int sc_nblks;		/* number of blocks currently transferring */
! 	int sc_nbytes;		/* number of bytes currently transferring */
! 
! 	/* Long-term state: */
! 	int sc_drive;			/* physical unit number */
! 	int sc_state;			/* control state */
! #define	RECAL		0		/* recalibrate */
! #define	RECAL_WAIT	1		/* done recalibrating */
! #define	GEOMETRY	2		/* upload geometry */
! #define	GEOMETRY_WAIT	3		/* done uploading geometry */
! #define	MULTIMODE	4		/* set multiple mode */
! #define	MULTIMODE_WAIT	5		/* done setting multiple mode */
! #define	OPEN		6		/* done with open */
! 	int sc_mode;			/* transfer mode */
! #define	WDM_PIOSINGLE	0		/* single-sector PIO */
! #define	WDM_PIOMULTI	1		/* multi-sector PIO */
! #define	WDM_DMA		2		/* DMA */
! 	int sc_multiple;		/* multiple for WDM_PIOMULTI */
! 	int sc_flags;			/* drive characteistics found */
! #define	WDF_LOCKED	0x01
! #define	WDF_WANTED	0x02
! #define	WDF_WLABEL	0x04		/* label is writable */
! #define	WDF_LABELLING	0x08		/* writing label */
! /* XXX Nothing resets this yet, but disk change sensing will when ATAPI is
!    implemented. */
! #define	WDF_LOADED	0x10		/* parameters loaded */
! #define	WDF_32BIT	0x20		/* can do 32-bit transfer */
! 
! 	struct wdparams sc_params;	/* ESDI/ATA drive parameters */
! 	daddr_t	sc_badsect[127];	/* 126 plus trailing -1 marker */
! 
! 	TAILQ_ENTRY(wd_softc) sc_drivechain;
  	struct buf sc_q;
  };
  
! struct wdc_softc {
! 	struct device sc_dev;
! 	irqhandler_t sc_ih;
! 
! 	int sc_iobase;			/* I/O port base */
! 	int sc_drq;			/* DMA channel */
! 
! 	TAILQ_HEAD(drivehead, wd_softc) sc_drives;
! 	int sc_flags;
! #define	WDCF_ACTIVE	0x01		/* controller is active */
! #define	WDCF_SINGLE	0x02		/* sector at a time mode */
! #define	WDCF_ERROR	0x04		/* processing a disk error */
! #define	WDCF_WANTED	0x08		/* XXX locking for wd_get_parms() */
! 	int sc_errors;			/* errors during current transfer */
! 	u_char sc_status;		/* copy of status register */
! 	u_char sc_error;		/* copy of error register */
! };
! 
! int	wdcprobe 	__P((struct device *, void *, void *));
! void	wdcattach 	__P((struct device *, struct device *, void *));
! int	wdcintr		__P((void *));
! 
! struct cfattach wdc_ca = {
! 	sizeof(struct wdc_softc), wdcprobe, wdcattach
! };
  
! struct cfdriver wdc_cd = {
! 	NULL, "wdc", DV_DULL
  };
  
- int	wdprobe		__P((struct device *, void *, void *));
- void	wdattach	__P((struct device *, struct device *, void *));
- int	wdprint		__P((void *, char *));
- 
  struct cfattach wd_ca = {
  	sizeof(struct wd_softc), wdprobe, wdattach
  };
  
- struct cfdriver wd_cd = {
- 	NULL, "wd", DV_DISK
- };
  
! void	wdgetdisklabel	__P((struct wd_softc *));
! int	wd_get_parms	__P((struct wd_softc *));
! void	wdstrategy	__P((struct buf *));
! void	wdstart		__P((struct wd_softc *));
  
  struct dkdriver wddkdriver = { wdstrategy };
  
! /* XXX: these should go elsewhere */
! cdev_decl(wd);
! bdev_decl(wd);
! 
! void	wdfinish	__P((struct wd_softc *, struct buf *));
! int 	dcintr		__P((void *));
! void	wdcstart	__P((struct wdc_softc *));
! int	wdcommand	__P((struct wd_softc *, int, int, int, int, int));
! int	wdcommandshort	__P((struct wdc_softc *, int, int));
! int	wdcontrol	__P((struct wd_softc *));
! int	wdsetctlr	__P((struct wd_softc *));
! static void bad144intern __P((struct wd_softc *));
! int	wdcreset	__P((struct wdc_softc *));
! void	wdcrestart	__P((void *arg));
! void	wdcunwedge	__P((struct wdc_softc *));
! void	wdctimeout	__P((void *arg));
! void	wderror		__P((void *, struct buf *, char *));
! int	wdcwait		__P((struct wdc_softc *, int));
! int	wdlock		__P((struct wd_softc *));
! void	wdunlock	__P((struct wd_softc *));
! 
! /* ST506 spec says that if READY or SEEKCMPLT go off, then the read or write
!    command is aborted. */
! #define	wait_for_drq(d)		wdcwait(d, WDCS_DRDY | WDCS_DSC | WDCS_DRQ)
! #define	wait_for_ready(d)	wdcwait(d, WDCS_DRDY | WDCS_DSC)
! #define	wait_for_unbusy(d)	wdcwait(d, 0)
! 
! int
! wdcprobe(parent, match, aux)
! 	struct device *parent;
! 	void *match, *aux;
! {
! 	struct wdc_softc *wdc = match;
! 	struct mainbus_attach_args *mb = aux;
! 	int iobase;
! 
! 	wdc->sc_iobase = iobase = mb->mb_iobase;
! 
! 	/* Check if we have registers that work. */
! 	outb(iobase+wd_error, 0x5a);	/* Error register not writable, */
! 	outb(iobase+wd_cyl_lo, 0xa5);	/* but all of cyllo are. */
! 	if (inb(iobase+wd_error) == 0x5a || inb(iobase+wd_cyl_lo) != 0xa5)
! 		return 0;
! 
! 	if (wdcreset(wdc) != 0) {
! 		delay(500000);
! 		if (wdcreset(wdc) != 0)
! 			return 0;
! 	}
! 
! 	/* Select drive 0. */
! 	outb(iobase+wd_sdh, WDSD_IBM | 0);
! 
! 	/* Wait for controller to become ready. */
! 	if (wait_for_unbusy(wdc) < 0)
! 		return 0;
!     
! 	/* Start drive diagnostics. */
! 	outb(iobase+wd_command, WDCC_DIAGNOSE);
! 
! 	/* Wait for command to complete. */
! 	if (wait_for_unbusy(wdc) < 0)
! 		return 0;
! 
! 	mb->mb_iosize = 32;
! 	return 1;
! }
! 
! struct wdc_attach_args {
! 	int wa_drive;
! };
  
! int
! wdprint(aux, wdc)
! 	void *aux;
! 	char *wdc;
! {
! 	struct wdc_attach_args *wa = aux;
! 
! 	if (!wdc)
! 		printf(" drive %d", wa->wa_drive);
! 	return QUIET;
! }
! 
! void
! wdcattach(parent, self, aux)
! 	struct device *parent, *self;
! 	void *aux;
! {
! 	struct wdc_softc *wdc = (void *)self;
! 	struct mainbus_attach_args *mb = aux;
! 	struct wdc_attach_args wa;
! 
! 	TAILQ_INIT(&wdc->sc_drives);
! 	wdc->sc_drq = mb->mb_drq;
! 
! 	printf("\n");
! 
!   	wdc->sc_ih.ih_func = wdcintr;
!    	wdc->sc_ih.ih_arg = wdc;
!    	wdc->sc_ih.ih_level = IPL_BIO;
!    	wdc->sc_ih.ih_name = "wdc";
! 	if (irq_claim(mb->mb_irq, &wdc->sc_ih))
! 		panic("Cannot claim IRQ %d for wdc%d\n", mb->mb_irq, parent->dv_unit);
! 
! 	for (wa.wa_drive = 0; wa.wa_drive < 2; wa.wa_drive++)
! 		(void)config_found(self, (void *)&wa, wdprint);
! }
  
  int
  wdprobe(parent, match, aux)
  	struct device *parent;
  	void *match, *aux;
  {
! 	struct wdc_softc *wdc = (void *)parent;
  	struct cfdata *cf = match;
! 	struct wdc_attach_args *wa = aux;
! 	int drive = wa->wa_drive;
! 
! 	if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != drive)
! 		return 0;
  	
! 	if (wdcommandshort(wdc, drive, WDCC_RECAL) != 0 ||
! 	    wait_for_ready(wdc) != 0)
  		return 0;
- 
  	return 1;
  }
  
--- 74,123 ----
  struct wd_softc {
  	struct device sc_dev;
  	struct disk sc_dk;
! 	struct wd_link *d_link;
  	struct buf sc_q;
  };
  
! int wdprobe	__P((struct device *, void *, void *));
! void wdattach	__P((struct device *, struct device *, void *));
  
! struct cfdriver wd_cd = {
! 	NULL, "wd", DV_DISK
  };
  
  struct cfattach wd_ca = {
  	sizeof(struct wd_softc), wdprobe, wdattach
  };
  
  
! void wdgetdisklabel __P((struct wd_softc *));
! void wdstrategy __P((struct buf *));
! void wdstart __P((struct wd_softc *));
  
  struct dkdriver wddkdriver = { wdstrategy };
  
! int wdlock __P((struct wd_link *));
! void wdunlock __P((struct wd_link *));
  
! int wdsetctlr __P((struct wd_link *));
! static void bad144intern __P((struct wd_softc *));
! int wdcdump __P((struct wd_link *, daddr_t blkno, int nblks, caddr_t va));
  
  int
  wdprobe(parent, match, aux)
  	struct device *parent;
  	void *match, *aux;
  {
! /*	caddr_t *wdc = (void *)parent;*/
  	struct cfdata *cf = match;
! 	struct wd_link *d_link = aux;
! 	int drive;
  	
! 	if (d_link == NULL ) return 0;
! 	if (d_link-> type != DRIVE) return 0;
! 	drive = d_link->sc_drive;
! 	if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != drive)
  		return 0;
  	return 1;
  }
  
***************
*** 307,329 ****
  	void *aux;
  {
  	struct wd_softc *wd = (void *)self;
! 	struct wdc_softc *wdc = (void *)parent;
! 	struct wdc_attach_args *wa = aux;
  	int i, blank;
  	char buf[41], c, *p, *q;
  
! 	wd->sc_drive = wa->wa_drive;
  
! 	/*
! 	 * Initialize and attach the disk structure.
  	 */
  	wd->sc_dk.dk_driver = &wddkdriver;
  	wd->sc_dk.dk_name = wd->sc_dev.dv_xname;
  	disk_attach(&wd->sc_dk);
  
! 	wd_get_parms(wd);
! 	for (blank = 0, p = wd->sc_params.wdp_model, q = buf, i = 0;
! 	     i < sizeof(wd->sc_params.wdp_model); i++) {
  		c = *p++;
  		if (c == '\0')
  			break;
--- 127,153 ----
  	void *aux;
  {
  	struct wd_softc *wd = (void *)self;
! /*	struct caddr_t *wdc = (void *)parent;*/
! 	struct wd_link *d_link= aux;
  	int i, blank;
  	char buf[41], c, *p, *q;
  
! 	wd->d_link = d_link;
! 	d_link->openings = 1;
! 	d_link->wd_softc = (caddr_t)wd;
  
!  	/*
!     	 * Initialize and attach the disk structure.
  	 */
  	wd->sc_dk.dk_driver = &wddkdriver;
  	wd->sc_dk.dk_name = wd->sc_dev.dv_xname;
  	disk_attach(&wd->sc_dk);
  
! 	d_link->sc_lp = wd->sc_dk.dk_label;
! 
! 	wdc_get_parms(d_link);
! 	for (blank = 0, p = d_link->sc_params.wdp_model, q = buf, i = 0;
! 	     i < sizeof(d_link->sc_params.wdp_model); i++) {
  		c = *p++;
  		if (c == '\0')
  			break;
***************
*** 339,371 ****
  	*q++ = '\0';
  
  	printf(": %dMB, %d cyl, %d head, %d sec, %d bytes/sec <%s>\n",
! 	    wd->sc_params.wdp_cylinders *
! 	    (wd->sc_params.wdp_heads * wd->sc_params.wdp_sectors) /
  	    (1048576 / DEV_BSIZE),
! 	    wd->sc_params.wdp_cylinders,
! 	    wd->sc_params.wdp_heads,
! 	    wd->sc_params.wdp_sectors,
  	    DEV_BSIZE,
  	    buf);
  
! 	if ((wd->sc_params.wdp_capabilities & WD_CAP_DMA) != 0 &&
! 	    wdc->sc_drq != DRQUNK) {
! 		wd->sc_mode = WDM_DMA;
! 	} else if (wd->sc_params.wdp_maxmulti > 1) {
! 		wd->sc_mode = WDM_PIOMULTI;
! 		wd->sc_multiple = min(wd->sc_params.wdp_maxmulti, 16);
  	} else {
! 		wd->sc_mode = WDM_PIOSINGLE;
! 		wd->sc_multiple = 1;
  	}
  
  	printf("%s: using", wd->sc_dev.dv_xname);
! 	if (wd->sc_mode == WDM_DMA)
  		printf(" dma transfers,");
  	else
  		printf(" %d-sector %d-bit pio transfers,",
! 		    wd->sc_multiple, (wd->sc_flags & WDF_32BIT) == 0 ? 16 : 32);
! 	if ((wd->sc_params.wdp_capabilities & WD_CAP_LBA) != 0)
  		printf(" lba addressing\n");
  	else
  		printf(" chs addressing\n");
--- 163,195 ----
  	*q++ = '\0';
  
  	printf(": %dMB, %d cyl, %d head, %d sec, %d bytes/sec <%s>\n",
! 	    d_link->sc_params.wdp_cylinders *
! 	    (d_link->sc_params.wdp_heads * d_link->sc_params.wdp_sectors) /
  	    (1048576 / DEV_BSIZE),
! 	    d_link->sc_params.wdp_cylinders,
! 	    d_link->sc_params.wdp_heads,
! 	    d_link->sc_params.wdp_sectors,
  	    DEV_BSIZE,
  	    buf);
  
! 	if ((d_link->sc_params.wdp_capabilities & WD_CAP_DMA) != 0 &&
! 	    d_link->sc_mode == WDM_DMA) {
! 		d_link->sc_mode = WDM_DMA;
! 	} else if (d_link->sc_params.wdp_maxmulti > 1) {
! 		d_link->sc_mode = WDM_PIOMULTI;
! 		d_link->sc_multiple = min(d_link->sc_params.wdp_maxmulti, 16);
  	} else {
! 		d_link->sc_mode = WDM_PIOSINGLE;
! 		d_link->sc_multiple = 1;
  	}
  
  	printf("%s: using", wd->sc_dev.dv_xname);
! 	if (d_link->sc_mode == WDM_DMA)
  		printf(" dma transfers,");
  	else
  		printf(" %d-sector %d-bit pio transfers,",
! 		    d_link->sc_multiple, (d_link->sc_flags & WDF_32BIT) == 0 ? 16 : 32);
! 	if ((d_link->sc_params.wdp_capabilities & WD_CAP_LBA) != 0)
  		printf(" lba addressing\n");
  	else
  		printf(" chs addressing\n");
***************
*** 380,385 ****
--- 204,210 ----
  	struct buf *bp;
  {
  	struct wd_softc *wd = wd_cd.cd_devs[WDUNIT(bp->b_dev)];
+ 	struct wd_link *d_link= wd->d_link;
  	int s;
      
  	/* Valid request?  */
***************
*** 391,397 ****
  	}
      
  	/* If device invalidated (e.g. media change, door open), error. */
! 	if ((wd->sc_flags & WDF_LOADED) == 0) {
  		bp->b_error = EIO;
  		goto bad;
  	}
--- 216,222 ----
  	}
      
  	/* If device invalidated (e.g. media change, door open), error. */
! 	if ((d_link->sc_flags & WDF_LOADED) == 0) {
  		bp->b_error = EIO;
  		goto bad;
  	}
***************
*** 406,428 ****
  	 */
  	if (WDPART(bp->b_dev) != RAW_PART &&
  	    bounds_check_with_label(bp, wd->sc_dk.dk_label,
! 	    (wd->sc_flags & (WDF_WLABEL|WDF_LABELLING)) != 0) <= 0)
  		goto done;
      
  	/* Queue transfer on drive, activate drive and controller if idle. */
  	s = splbio();
  	disksort(&wd->sc_q, bp);
! 	if (!wd->sc_q.b_active)
! 		wdstart(wd);
! #if 0
! 	else {
! 		struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
! 		if ((wdc->sc_flags & (WDCF_ACTIVE|WDCF_ERROR)) == 0) {
! 			printf("wdstrategy: controller inactive\n");
! 			wdcstart(wdc);
! 		}
! 	}
! #endif
  	splx(s);
  	return;
      
--- 231,243 ----
  	 */
  	if (WDPART(bp->b_dev) != RAW_PART &&
  	    bounds_check_with_label(bp, wd->sc_dk.dk_label,
! 	    (d_link->sc_flags & (WDF_WLABEL|WDF_LABELLING)) != 0) <= 0)
  		goto done;
      
  	/* Queue transfer on drive, activate drive and controller if idle. */
  	s = splbio();
  	disksort(&wd->sc_q, bp);
! 	wdstart(wd);
  	splx(s);
  	return;
      
***************
*** 441,497 ****
  wdstart(wd)
  	struct wd_softc *wd;
  {
! 	struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
! 	int active = wdc->sc_drives.tqh_first != 0;
! 
! 	/* Link onto controller queue. */
! 	wd->sc_q.b_active = 1;
! 	TAILQ_INSERT_TAIL(&wdc->sc_drives, wd, sc_drivechain);
! 
! 	disk_busy(&wd->sc_dk);
!     
! 	/* If controller not already active, start it. */
! 	if (!active)
! 		wdcstart(wdc);
! }
! 
! /*
!  * Finish an I/O operation.  Clean up the drive and controller state, set the
!  * residual count, and inform the upper layers that the operation is complete.
!  */
! void
! wdfinish(wd, bp)
! 	struct wd_softc *wd;
! 	struct buf *bp;
! {
! 	struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
! 
! 	wdc->sc_flags &= ~(WDCF_SINGLE | WDCF_ERROR);
! 	wdc->sc_errors = 0;
! 	/*
! 	 * Move this drive to the end of the queue to give others a `fair'
! 	 * chance.
! 	 */
! 	if (wd->sc_drivechain.tqe_next) {
! 		TAILQ_REMOVE(&wdc->sc_drives, wd, sc_drivechain);
! 		if (bp->b_actf) {
! 			TAILQ_INSERT_TAIL(&wdc->sc_drives, wd, sc_drivechain);
! 		} else
! 			wd->sc_q.b_active = 0;
! 	}
! 	bp->b_resid = wd->sc_bcount;
! 	wd->sc_skip = 0;
! 	wd->sc_q.b_actf = bp->b_actf;
! 
! 	disk_unbusy(&wd->sc_dk, (bp->b_bcount - bp->b_resid));
  
! 	if (!wd->sc_q.b_actf) {
! 		TAILQ_REMOVE(&wdc->sc_drives, wd, sc_drivechain);
! 		wd->sc_q.b_active = 0;
! 	} else
  		disk_busy(&wd->sc_dk);
! 
! 	biodone(bp);
  }
  
  int
--- 256,297 ----
  wdstart(wd)
  	struct wd_softc *wd;
  {
! 	struct buf *dp, *bp=0;
! 	struct wd_link *d_link = wd->d_link;
! 	struct wdc_link *ctlr_link = d_link->ctlr_link;
! 	struct wdc_xfer *xfer;
! /*	int blkno, nblks;*/
! 	u_long p_offset; 
! 
! 	while (d_link->openings > 0) {
! 
! 		/* Is there a buf for us ? */
! 		dp = &wd->sc_q;
! 		if ((bp = dp->b_actf) == NULL)  /* yes, an assign */
!                  	return;
! 		dp->b_actf = bp->b_actf;
! 		
! 		/* 
!          * Make the command. First lock the device
! 		 */
! 		d_link->openings--;
! 		if (WDPART(bp->b_dev) != RAW_PART)
! 			p_offset=wd->sc_dk.dk_label->d_partitions[WDPART(bp->b_dev)].p_offset;
! 		else p_offset=0;
! 		xfer = wdc_get_xfer(ctlr_link,0);
! 		if (xfer == NULL) panic("wdc_xfer");
! 		xfer->d_link = d_link;
! 		xfer->c_bp = bp;
! 		xfer->c_p_offset = p_offset;
! 		xfer->databuf = bp->b_data;
! 		xfer->c_bcount = bp->b_bcount;
! 		xfer->c_flags |= bp->b_flags & (B_READ|B_WRITE);
! 		xfer->c_blkno = bp->b_blkno;
  
! 		/* Instrumentation. */
  		disk_busy(&wd->sc_dk);
! 		wdc_exec_xfer(wd->d_link,xfer);
! 	}
  }
  
  int
***************
*** 500,506 ****
  	struct uio *uio;
  	int flags;
  {
! 
  	return (physio(wdstrategy, NULL, dev, B_READ, minphys, uio));
  }
  
--- 300,308 ----
  	struct uio *uio;
  	int flags;
  {
! #ifdef WDDEBUG
! 	printf("wdread\n");
! #endif
  	return (physio(wdstrategy, NULL, dev, B_READ, minphys, uio));
  }
  
***************
*** 510,884 ****
  	struct uio *uio;
  	int flags;
  {
- 
- 	return (physio(wdstrategy, NULL, dev, B_WRITE, minphys, uio));
- }
- 
- /*
-  * Start I/O on a controller.  This does the calculation, and starts a read or
-  * write operation.  Called to from wdstart() to start a transfer, from
-  * wdcintr() to continue a multi-sector transfer or start the next transfer, or
-  * wdcrestart() after recovering from an error.
-  */
- void
- wdcstart(wdc)
- 	struct wdc_softc *wdc;
- {
- 	struct wd_softc *wd;
- 	struct buf *bp;
- 	struct disklabel *lp;
- 	int nblks;
- 
- #ifdef DIAGNOSTIC
- 	if ((wdc->sc_flags & WDCF_ACTIVE) != 0)
- 		panic("wdcstart: controller still active");
- #endif
- 
- 	/*
- 	 * XXX
- 	 * This is a kluge.  See comments in wd_get_parms().
- 	 */
- 	if ((wdc->sc_flags & WDCF_WANTED) != 0) {
- 		wdc->sc_flags &= ~WDCF_WANTED;
- 		wakeup(wdc);
- 		return;
- 	}
- 
- loop:
- 	/* Is there a drive for the controller to do a transfer with? */
- 	wd = wdc->sc_drives.tqh_first;
- 	if (wd == NULL)
- 		return;
-     
- 	/* Is there a transfer to this drive?  If not, deactivate drive. */
- 	bp = wd->sc_q.b_actf;
-     
- 	if (wdc->sc_errors >= WDIORETRIES) {
- 		wderror(wd, bp, "hard error");
- 		bp->b_error = EIO;
- 		bp->b_flags |= B_ERROR;
- 		wdfinish(wd, bp);
- 		goto loop;
- 	}
- 
- 	/* Do control operations specially. */
- 	if (wd->sc_state < OPEN) {
- 		/*
- 		 * Actually, we want to be careful not to mess with the control
- 		 * state if the device is currently busy, but we can assume
- 		 * that we never get to this point if that's the case.
- 		 */
- 		if (wdcontrol(wd) == 0) {
- 			/* The drive is busy.  Wait. */
- 			return;
- 		}
- 	}
- 
- 	/*
- 	 * WDCF_ERROR is set by wdcunwedge() and wdcintr() when an error is
- 	 * encountered.  If we are in multi-sector mode, then we switch to
- 	 * single-sector mode and retry the operation from the start.
- 	 */
- 	if (wdc->sc_flags & WDCF_ERROR) {
- 		wdc->sc_flags &= ~WDCF_ERROR;
- 		if ((wdc->sc_flags & WDCF_SINGLE) == 0) {
- 			wdc->sc_flags |= WDCF_SINGLE;
- 			wd->sc_skip = 0;
- 		}
- 	}
- 
- 	lp = wd->sc_dk.dk_label;
- 
- 	/* When starting a transfer... */
- 	if (wd->sc_skip == 0) {
- 		int part = WDPART(bp->b_dev);
- 		daddr_t blkno;
- 
- #ifdef WDDEBUG
- 		printf("\n%s: wdcstart %s %d@%d; map ", wd->sc_dev.dv_xname,
- 		    (bp->b_flags & B_READ) ? "read" : "write", bp->b_bcount,
- 		    bp->b_blkno);
- #endif
- 		wd->sc_bcount = bp->b_bcount;
- 		blkno = bp->b_blkno;
- 		if (part != RAW_PART)
- 			blkno += lp->d_partitions[part].p_offset;
- 		wd->sc_blkno = blkno / (lp->d_secsize / DEV_BSIZE);
- 	} else {
- #ifdef WDDEBUG
- 		printf(" %d)%x", wd->sc_skip, inb(wd->sc_iobase+wd_altsts));
- #endif
- 	}
- 
- 	/* When starting a multi-sector transfer, or doing single-sector
- 	    transfers... */
- 	if (wd->sc_skip == 0 || (wdc->sc_flags & WDCF_SINGLE) != 0 ||
- 	    wd->sc_mode == WDM_DMA) {
- 		daddr_t blkno = wd->sc_blkno;
- 		long cylin, head, sector;
- 		int command;
- 
- 		if ((wdc->sc_flags & WDCF_SINGLE) != 0)
- 			nblks = 1;
- 		else if (wd->sc_mode != WDM_DMA)
- 			nblks = wd->sc_bcount / lp->d_secsize;
- 		else
- 			nblks = min(wd->sc_bcount / lp->d_secsize, 8);
- 
- 		/* Check for bad sectors and adjust transfer, if necessary. */
- 		if ((lp->d_flags & D_BADSECT) != 0
- #ifdef B_FORMAT
- 		    && (bp->b_flags & B_FORMAT) == 0
- #endif
- 		    ) {
- 			long blkdiff;
- 			int i;
- 
- 			for (i = 0; (blkdiff = wd->sc_badsect[i]) != -1; i++) {
- 				blkdiff -= blkno;
- 				if (blkdiff < 0)
- 					continue;
- 				if (blkdiff == 0) {
- 					/* Replace current block of transfer. */
- 					blkno =
- 					    lp->d_secperunit - lp->d_nsectors - i - 1;
- 				}
- 				if (blkdiff < nblks) {
- 					/* Bad block inside transfer. */
- 					wdc->sc_flags |= WDCF_SINGLE;
- 					nblks = 1;
- 				}
- 				break;
- 			}
- 			/* Tranfer is okay now. */
- 		}
- 
- 		if ((wd->sc_params.wdp_capabilities & WD_CAP_LBA) != 0) {
- 			sector = (blkno >> 0) & 0xff;
- 			cylin = (blkno >> 8) & 0xffff;
- 			head = (blkno >> 24) & 0xf;
- 			head |= WDSD_LBA;
- 		} else {
- 			sector = blkno % lp->d_nsectors;
- 			sector++;	/* Sectors begin with 1, not 0. */
- 			blkno /= lp->d_nsectors;
- 			head = blkno % lp->d_ntracks;
- 			blkno /= lp->d_ntracks;
- 			cylin = blkno;
- 			head |= WDSD_CHS;
- 		}
- 
- 		if (wd->sc_mode == WDM_PIOSINGLE ||
- 		    (wdc->sc_flags & WDCF_SINGLE) != 0)
- 			wd->sc_nblks = 1;
- 		else if (wd->sc_mode == WDM_PIOMULTI)
- 			wd->sc_nblks = min(nblks, wd->sc_multiple);
- 		else
- 			wd->sc_nblks = nblks;
- 		wd->sc_nbytes = wd->sc_nblks * lp->d_secsize;
-     
- #ifdef B_FORMAT
- 		if (bp->b_flags & B_FORMAT) {
- 			sector = lp->d_gap3;
- 			nblks = lp->d_nsectors;
- 			command = WDCC_FORMAT;
- 		} else
- #endif
- 		switch (wd->sc_mode) {
- 		case WDM_DMA:
- #if 0
- 			command = (bp->b_flags & B_READ) ?
- 			    WDCC_READDMA : WDCC_WRITEDMA;
- 			/* Start the DMA channel and bounce the buffer if
- 			   necessary. */
- 			isa_dmastart(
- 			    bp->b_flags & B_READ ? DMAMODE_READ : DMAMODE_WRITE,
- 			    bp->b_data + wd->sc_skip,
- 			    wd->sc_nbytes, wdc->sc_drq);
- #endif
- 			panic("wd cannot do DMA yet\n");
- 			break;
- 		case WDM_PIOMULTI:
- 			command = (bp->b_flags & B_READ) ?
- 			    WDCC_READMULTI : WDCC_WRITEMULTI;
- 			break;
- 		case WDM_PIOSINGLE:
- 			command = (bp->b_flags & B_READ) ?
- 			    WDCC_READ : WDCC_WRITE;
- 			break;
- 		default:
- #ifdef DIAGNOSTIC
- 			panic("bad wd mode");
- #endif
- 			return;
- 		}
- 	
- 		/* Initiate command! */
- 		if (wdcommand(wd, command, cylin, head, sector, nblks) != 0) {
- 			wderror(wd, NULL,
- 			    "wdcstart: timeout waiting for unbusy");
- 			wdcunwedge(wdc);
- 			return;
- 		}
- 
  #ifdef WDDEBUG
! 		printf("sector %d cylin %d head %d addr %x sts %x\n", sector,
! 		    cylin, head, bp->b_data, 0/*inb(wd->sc_iobase+wd_altsts*/));
! #endif
! 	} else if (wd->sc_nblks > 1) {
! 		/* The number of blocks in the last stretch may be smaller. */
! 		nblks = wd->sc_bcount / lp->d_secsize;
! 		if (wd->sc_nblks > nblks) {
! 			wd->sc_nblks = nblks;
! 			wd->sc_nbytes = wd->sc_bcount;
! 		}
! 	}
! 
! 	/* If this was a write and not using DMA, push the data. */
! 	if (wd->sc_mode != WDM_DMA &&
! 	    (bp->b_flags & (B_READ|B_WRITE)) == B_WRITE) {
! 		if (wait_for_drq(wdc) < 0) {
! 			wderror(wd, NULL, "wdcstart: timeout waiting for drq");
! 			wdcunwedge(wdc);
! 			return;
! 		}
! 
! 		/* Push out data. */
! 		if ((wd->sc_flags & WDF_32BIT) == 0)
! 			outsw(wdc->sc_iobase+wd_data, bp->b_data + wd->sc_skip,
! 			    wd->sc_nbytes >> 1);
! 		else
! 			outsl(wdc->sc_iobase+wd_data, bp->b_data + wd->sc_skip,
! 			    wd->sc_nbytes >> 2);
! 	}
! 
! 	wdc->sc_flags |= WDCF_ACTIVE;
! 	timeout(wdctimeout, wdc, WAITTIME);
! }
! 
! /*
!  * Interrupt routine for the controller.  Acknowledge the interrupt, check for
!  * errors on the current operation, mark it done if necessary, and start the
!  * next request.  Also check for a partially done transfer, and continue with
!  * the next chunk if so.
!  */
! int
! wdcintr(arg)
! 	void *arg;
! {
! 	struct wdc_softc *wdc = arg;
! 	struct wd_softc *wd;
! 	struct buf *bp;
! 
! 	if ((wdc->sc_flags & WDCF_ACTIVE) == 0) {
! 		/* Clear the pending interrupt and abort. */
! 		(void) inb(wdc->sc_iobase+wd_status);
! 		return 0;
! 	}
! 
! 	wdc->sc_flags &= ~WDCF_ACTIVE;
! 	untimeout(wdctimeout, wdc);
! 
! 	wd = wdc->sc_drives.tqh_first;
! 	bp = wd->sc_q.b_actf;
! 
! #ifdef WDDEBUG
! 	printf("I%d ", ctrlr);
! #endif
! 
! 	if (wait_for_unbusy(wdc) < 0) {
! 		wderror(wd, NULL, "wdcintr: timeout waiting for unbusy");
! 		wdc->sc_status |= WDCS_ERR;	/* XXX */
! 	}
!     
! 	/* Is it not a transfer, but a control operation? */
! 	if (wd->sc_state < OPEN) {
! 		if (wdcontrol(wd) == 0) {
! 			/* The drive is busy.  Wait. */
! 			return 1;
! 		}
! 		wdcstart(wdc);
! 		return 1;
! 	}
! 
! 	/* Turn off the DMA channel and unbounce the buffer. */
! 	if (wd->sc_mode == WDM_DMA)
! 		panic("wd cannot do DMA\n");
! #if 0
! 		isa_dmadone(bp->b_flags & B_READ ? DMAMODE_READ : DMAMODE_WRITE,
! 		    bp->b_data + wd->sc_skip, wd->sc_nbytes, wdc->sc_drq);
! #endif
! 	/* Have we an error? */
! 	if (wdc->sc_status & WDCS_ERR) {
! #ifdef WDDEBUG
! 		wderror(wd, NULL, "wdcintr");
! #endif
! 		if ((wdc->sc_flags & WDCF_SINGLE) == 0) {
! 			wdc->sc_flags |= WDCF_ERROR;
! 			goto restart;
! 		}
! 
! #ifdef B_FORMAT
! 		if (bp->b_flags & B_FORMAT)
! 			goto bad;
! #endif
! 	
! 		if (++wdc->sc_errors < WDIORETRIES)
! 			goto restart;
! 		wderror(wd, bp, "hard error");
! 
! #ifdef B_FORMAT
! 	bad:
  #endif
- 		bp->b_error = EIO;
- 		bp->b_flags |= B_ERROR;
- 		goto done;
- 	}
- 
- 	/* If this was a read and not using DMA, fetch the data. */
- 	if (wd->sc_mode != WDM_DMA &&
- 	    (bp->b_flags & (B_READ|B_WRITE)) == B_READ) {
- 		if ((wdc->sc_status & (WDCS_DRDY | WDCS_DSC | WDCS_DRQ))
- 		    != (WDCS_DRDY | WDCS_DSC | WDCS_DRQ)) {
- 			wderror(wd, NULL, "wdcintr: read intr before drq");
- 			wdcunwedge(wdc);
- 			return 1;
- 		}
- 
- 		/* Pull in data. */
- 		if ((wd->sc_flags & WDF_32BIT) == 0)
- 			insw(wdc->sc_iobase+wd_data, bp->b_data + wd->sc_skip, 
- 			    wd->sc_nbytes >> 1);
- 		else
- 			insl(wdc->sc_iobase+wd_data, bp->b_data + wd->sc_skip, 
- 			    wd->sc_nbytes >> 2);
- 	}
-     
- 	/* If we encountered any abnormalities, flag it as a soft error. */
- 	if (wdc->sc_errors > 0 ||
- 	    (wdc->sc_status & WDCS_CORR) != 0) {
- 		wderror(wd, bp, "soft error (corrected)");
- 		wdc->sc_errors = 0;
- 	}
-     
- 	/* Adjust pointers for the next block, if any. */
- 	wd->sc_blkno += wd->sc_nblks;
- 	wd->sc_skip += wd->sc_nbytes;
- 	wd->sc_bcount -= wd->sc_nbytes;
- 
- 	/* See if this transfer is complete. */
- 	if (wd->sc_bcount > 0)
- 		goto restart;
- 
- done:
- 	/* Done with this transfer, with or without error. */
- 	wdfinish(wd, bp);
- 
- restart:
- 	/* Start the next operation, if any. */
- 	wdcstart(wdc);
  
! 	return 1;
  }
  
  /*
--- 312,322 ----
  	struct uio *uio;
  	int flags;
  {
  #ifdef WDDEBUG
!     printf("wdwrite\n");
  #endif
  
! 	return (physio(wdstrategy, NULL, dev, B_WRITE, minphys, uio));
  }
  
  /*
***************
*** 888,904 ****
   * Several drivers do this; it should be abstracted and made MP-safe.
   */
  int
! wdlock(wd)
! 	struct wd_softc *wd;
  {
  	int error;
  
! 	while ((wd->sc_flags & WDF_LOCKED) != 0) {
! 		wd->sc_flags |= WDF_WANTED;
! 		if ((error = tsleep(wd, PRIBIO | PCATCH, "wdlck", 0)) != 0)
  			return error;
  	}
! 	wd->sc_flags |= WDF_LOCKED;
  	return 0;
  }
  
--- 326,351 ----
   * Several drivers do this; it should be abstracted and made MP-safe.
   */
  int
! wdlock(d_link)
! 	struct wd_link *d_link;
  {
  	int error;
+ 	int s;
  
! #ifdef WDDEBUG
! 	printf("wdlock\n");
! #endif
! 	s=splbio();
! 
! 	while ((d_link->sc_flags & WDF_LOCKED) != 0) {
! 		d_link->sc_flags |= WDF_WANTED;
! 		if ((error = tsleep(d_link, PRIBIO | PCATCH, "wdlck", 0)) != 0) {
! 			splx(s);
  			return error;
+ 		}
  	}
! 	d_link->sc_flags |= WDF_LOCKED;
! 	splx(s);
  	return 0;
  }
  
***************
*** 906,919 ****
   * Unlock and wake up any waiters.
   */
  void
! wdunlock(wd)
! 	struct wd_softc *wd;
  {
  
! 	wd->sc_flags &= ~WDF_LOCKED;
! 	if ((wd->sc_flags & WDF_WANTED) != 0) {
! 		wd->sc_flags &= ~WDF_WANTED;
! 		wakeup(wd);
  	}
  }
  
--- 353,369 ----
   * Unlock and wake up any waiters.
   */
  void
! wdunlock(d_link)
! 	struct wd_link *d_link;
  {
+ #ifdef WDDEBUG
+     printf("wdunlock\n");
+ #endif
  
! 	d_link->sc_flags &= ~WDF_LOCKED;
! 	if ((d_link->sc_flags & WDF_WANTED) != 0) {
! 		d_link->sc_flags &= ~WDF_WANTED;
! 		wakeup(d_link);
  	}
  }
  
***************
*** 924,931 ****
--- 374,387 ----
  	struct proc *p;
  {
  	struct wd_softc *wd;
+ 	struct wd_link *d_link;
  	int unit, part;
  	int error;
+ 
+ #ifdef WDDEBUG
+     printf("wdopen\n");
+ #endif
+ 
      
  	unit = WDUNIT(dev);
  	if (unit >= wd_cd.cd_ndevs)
***************
*** 934,957 ****
  	if (wd == 0)
  		return ENXIO;
      
! 	if ((error = wdlock(wd)) != 0)
  		return error;
- 
  	if (wd->sc_dk.dk_openmask != 0) {
  		/*
  		 * If any partition is open, but the disk has been invalidated,
  		 * disallow further opens.
  		 */
! 		if ((wd->sc_flags & WDF_LOADED) == 0) {
  			error = EIO;
  			goto bad3;
  		}
  	} else {
! 		if ((wd->sc_flags & WDF_LOADED) == 0) {
! 			wd->sc_flags |= WDF_LOADED;
  
  			/* Load the physical device parameters. */
! 			if (wd_get_parms(wd) != 0) {
  				error = ENXIO;
  				goto bad2;
  			}
--- 390,413 ----
  	if (wd == 0)
  		return ENXIO;
      
! 	d_link = wd->d_link;
! 	if ((error = wdlock(d_link)) != 0)
  		return error;
  	if (wd->sc_dk.dk_openmask != 0) {
  		/*
  		 * If any partition is open, but the disk has been invalidated,
  		 * disallow further opens.
  		 */
! 		if ((d_link->sc_flags & WDF_LOADED) == 0) {
  			error = EIO;
  			goto bad3;
  		}
  	} else {
! 		if ((d_link->sc_flags & WDF_LOADED) == 0) {
! 			d_link->sc_flags |= WDF_LOADED;
  
  			/* Load the physical device parameters. */
! 			if (wdc_get_parms(d_link) != 0) {
  				error = ENXIO;
  				goto bad2;
  			}
***************
*** 982,999 ****
  	}
  	wd->sc_dk.dk_openmask = wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask;
  
! 	wdunlock(wd);
  	return 0;
  
  bad2:
! 	wd->sc_flags &= ~WDF_LOADED;
  
  bad:
  	if (wd->sc_dk.dk_openmask == 0) {
  	}
  
  bad3:
! 	wdunlock(wd);
  	return error;
  }
  
--- 438,455 ----
  	}
  	wd->sc_dk.dk_openmask = wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask;
  
! 	wdunlock(d_link);
  	return 0;
  
  bad2:
! 	d_link->sc_flags &= ~WDF_LOADED;
  
  bad:
  	if (wd->sc_dk.dk_openmask == 0) {
  	}
  
  bad3:
! 	wdunlock(d_link);
  	return error;
  }
  
***************
*** 1007,1013 ****
  	int part = WDPART(dev);
  	int error;
      
! 	if ((error = wdlock(wd)) != 0)
  		return error;
  
  	switch (fmt) {
--- 463,469 ----
  	int part = WDPART(dev);
  	int error;
      
! 	if ((error = wdlock(wd->d_link)) != 0)
  		return error;
  
  	switch (fmt) {
***************
*** 1024,1030 ****
  		/* XXXX Must wait for I/O to complete! */
  	}
  
! 	wdunlock(wd);
  	return 0;
  }
  
--- 480,486 ----
  		/* XXXX Must wait for I/O to complete! */
  	}
  
! 	wdunlock(wd->d_link);
  	return 0;
  }
  
***************
*** 1036,1057 ****
  	struct wd_softc *wd;
  {
  	struct disklabel *lp = wd->sc_dk.dk_label;
  	char *errstring;
  
  	bzero(lp, sizeof(struct disklabel));
  	bzero(wd->sc_dk.dk_cpulabel, sizeof(struct cpu_disklabel));
  
  	lp->d_secsize = DEV_BSIZE;
! 	lp->d_ntracks = wd->sc_params.wdp_heads;
! 	lp->d_nsectors = wd->sc_params.wdp_sectors;
! 	lp->d_ncylinders = wd->sc_params.wdp_cylinders;
  	lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
  
  #if 0
  	strncpy(lp->d_typename, "ST506 disk", 16);
  	lp->d_type = DTYPE_ST506;
  #endif
! 	strncpy(lp->d_packname, wd->sc_params.wdp_model, 16);
  	lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders;
  	lp->d_rpm = 3600;
  	lp->d_interleave = 1;
--- 492,518 ----
  	struct wd_softc *wd;
  {
  	struct disklabel *lp = wd->sc_dk.dk_label;
+ 	struct wd_link *d_link = wd->d_link;
  	char *errstring;
  
+ #ifdef WDDEBUG
+     printf("wdgetdisklabel\n");
+ #endif
+ 
  	bzero(lp, sizeof(struct disklabel));
  	bzero(wd->sc_dk.dk_cpulabel, sizeof(struct cpu_disklabel));
  
  	lp->d_secsize = DEV_BSIZE;
! 	lp->d_ntracks = d_link->sc_params.wdp_heads;
! 	lp->d_nsectors = d_link->sc_params.wdp_sectors;
! 	lp->d_ncylinders = d_link->sc_params.wdp_cylinders;
  	lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
  
  #if 0
  	strncpy(lp->d_typename, "ST506 disk", 16);
  	lp->d_type = DTYPE_ST506;
  #endif
! 	strncpy(lp->d_packname, d_link->sc_params.wdp_model, 16);
  	lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders;
  	lp->d_rpm = 3600;
  	lp->d_interleave = 1;
***************
*** 1067,1076 ****
  	lp->d_magic2 = DISKMAGIC;
  	lp->d_checksum = dkcksum(lp);
  
! 	wd->sc_badsect[0] = -1;
  
! 	if (wd->sc_state > RECAL)
! 		wd->sc_state = RECAL;
  	errstring = readdisklabel(MAKEWDDEV(0, wd->sc_dev.dv_unit, RAW_PART),
  	    wdstrategy, lp, wd->sc_dk.dk_cpulabel);
  	if (errstring) {
--- 528,537 ----
  	lp->d_magic2 = DISKMAGIC;
  	lp->d_checksum = dkcksum(lp);
  
! 	d_link->sc_badsect[0] = -1;
  
! 	if (d_link->sc_state > RECAL)
! 		d_link->sc_state = RECAL;
  	errstring = readdisklabel(MAKEWDDEV(0, wd->sc_dev.dv_unit, RAW_PART),
  	    wdstrategy, lp, wd->sc_dk.dk_cpulabel);
  	if (errstring) {
***************
*** 1080,1087 ****
  		 * assume the DOS geometry is now in the label and try
  		 * again.  XXX This is a kluge.
  		 */
! 		if (wd->sc_state > GEOMETRY)
! 			wd->sc_state = GEOMETRY;
  		errstring = readdisklabel(MAKEWDDEV(0, wd->sc_dev.dv_unit, RAW_PART),
  		    wdstrategy, lp, wd->sc_dk.dk_cpulabel);
  	}
--- 541,548 ----
  		 * assume the DOS geometry is now in the label and try
  		 * again.  XXX This is a kluge.
  		 */
! 		if (d_link->sc_state > GEOMETRY)
! 			d_link->sc_state = GEOMETRY;
  		errstring = readdisklabel(MAKEWDDEV(0, wd->sc_dev.dv_unit, RAW_PART),
  		    wdstrategy, lp, wd->sc_dk.dk_cpulabel);
  	}
***************
*** 1090,1359 ****
  		return;
  	}
  
! 	if (wd->sc_state > GEOMETRY)
! 		wd->sc_state = GEOMETRY;
  	if ((lp->d_flags & D_BADSECT) != 0)
  		bad144intern(wd);
  }
  
- /*
-  * Implement operations needed before read/write.
-  * Returns 0 if operation still in progress, 1 if completed.
-  */
- int
- wdcontrol(wd)
- 	struct wd_softc *wd;
- {
- 	struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
-     
- 	switch (wd->sc_state) {
- 	case RECAL:			/* Set SDH, step rate, do recal. */
- 		if (wdcommandshort(wdc, wd->sc_drive, WDCC_RECAL) != 0) {
- 			wderror(wd, NULL, "wdcontrol: recal failed (1)");
- 			goto bad;
- 		}
- 		wd->sc_state = RECAL_WAIT;
- 		break;
- 
- 	case RECAL_WAIT:
- 		if (wdc->sc_status & WDCS_ERR) {
- 			wderror(wd, NULL, "wdcontrol: recal failed (2)");
- 			goto bad;
- 		}
- 		/* fall through */
- 	case GEOMETRY:
- 		if ((wd->sc_params.wdp_capabilities & WD_CAP_LBA) != 0)
- 			goto multimode;
- 		if (wdsetctlr(wd) != 0) {
- 			/* Already printed a message. */
- 			goto bad;
- 		}
- 		wd->sc_state = GEOMETRY_WAIT;
- 		break;
- 
- 	case GEOMETRY_WAIT:
- 		if (wdc->sc_status & WDCS_ERR) {
- 			wderror(wd, NULL, "wdcontrol: geometry failed");
- 			goto bad;
- 		}
- 		/* fall through */
- 	case MULTIMODE:
- 	multimode:
- 		if (wd->sc_mode != WDM_PIOMULTI)
- 			goto open;
- 		outb(wdc->sc_iobase+wd_seccnt, wd->sc_multiple);
- 		if (wdcommandshort(wdc, wd->sc_drive, WDCC_SETMULTI) != 0) {
- 			wderror(wd, NULL, "wdcontrol: setmulti failed (1)");
- 			goto bad;
- 		}
- 		wd->sc_state = MULTIMODE_WAIT;
- 		break;
- 
- 	case MULTIMODE_WAIT:
- 		if (wdc->sc_status & WDCS_ERR) {
- 			wderror(wd, NULL, "wdcontrol: setmulti failed (2)");
- 			goto bad;
- 		}
- 		/* fall through */
- 	case OPEN:
- 	open:
- 		wdc->sc_errors = 0;
- 		wd->sc_state = OPEN;
- 		/*
- 		 * The rest of the initialization can be done by normal means.
- 		 */
- 		return 1;
- 
- 	bad:
- 		wdcunwedge(wdc);
- 		return 0;
- 	}
- 
- 	wdc->sc_flags |= WDCF_ACTIVE;
- 	timeout(wdctimeout, wdc, WAITTIME);
- 	return 0;
- }
- 
- /*
-  * Wait for the drive to become ready and send a command.
-  * Return -1 if busy for too long or 0 otherwise.
-  * Assumes interrupts are blocked.
-  */
- int
- wdcommand(wd, command, cylin, head, sector, count)
- 	struct wd_softc *wd;
- 	int command;
- 	int cylin, head, sector, count;
- {
- 	struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
- 	int iobase = wdc->sc_iobase;
- 	int stat;
-     
- 	/* Select drive, head, and addressing mode. */
- 	outb(iobase+wd_sdh, WDSD_IBM | (wd->sc_drive << 4) | head);
- 
- 	/* Wait for it to become ready to accept a command. */
- 	if (command == WDCC_IDP)
- 		stat = wait_for_unbusy(wdc);
- 	else
- 		stat = wdcwait(wdc, WDCS_DRDY);
- 	if (stat < 0)
- 		return -1;
-     
- 	/* Load parameters. */
- 	if (wd->sc_dk.dk_label->d_type == DTYPE_ST506)
- 		outb(iobase+wd_precomp, wd->sc_dk.dk_label->d_precompcyl / 4);
- 	else
- 		outb(iobase+wd_features, 0);
- 	outb(iobase+wd_cyl_lo, cylin);
- 	outb(iobase+wd_cyl_hi, cylin >> 8);
- 	outb(iobase+wd_sector, sector);
- 	outb(iobase+wd_seccnt, count);
- 
- 	/* Send command. */
- 	outb(iobase+wd_command, command);
- 
- 	return 0;
- }
- 
- /*
-  * Simplified version of wdcommand().
-  */
- int
- wdcommandshort(wdc, drive, command)
- 	struct wdc_softc *wdc;
- 	int drive;
- 	int command;
- {
- 	int iobase = wdc->sc_iobase;
- 
- 	/* Select drive. */
- 	outb(iobase+wd_sdh, WDSD_IBM | (drive << 4));
- 
- 	if (wdcwait(wdc, WDCS_DRDY) < 0)
- 		return -1;
- 
- 	outb(iobase+wd_command, command);
- 
- 	return 0;
- }
  
  /*
   * Tell the drive what geometry to use.
   */
  int
! wdsetctlr(wd)
! 	struct wd_softc *wd;
  {
  
  #ifdef WDDEBUG
! 	printf("wd(%d,%d) C%dH%dS%d\n", wd->sc_dev.dv_unit, wd->sc_drive,
  	    wd->sc_dk.dk_label->d_ncylinders, wd->sc_dk.dk_label->d_ntracks,
  	    wd->sc_dk.dk_label->d_nsectors);
  #endif
      
! 	if (wdcommand(wd, WDCC_IDP, wd->sc_dk.dk_label->d_ncylinders,
! 	    wd->sc_dk.dk_label->d_ntracks - 1, 0,
! 	    wd->sc_dk.dk_label->d_nsectors) != 0) {
! 		wderror(wd, NULL, "wdsetctlr: geometry upload failed");
  		return -1;
  	}
  
  	return 0;
  }
  
- /*
-  * Get the drive parameters, if ESDI or ATA, or create fake ones for ST506.
-  */
  int
! wd_get_parms(wd)
! 	struct wd_softc *wd;
! {
! 	struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
! 	int i;
! 	char tb[DEV_BSIZE];
! 	int s, error;
! 
! 	/*
! 	 * XXX
! 	 * The locking done here, and the length of time this may keep the rest
! 	 * of the system suspended, is a kluge.  This should be rewritten to
! 	 * set up a transfer and queue it through wdstart(), but it's called
! 	 * infrequently enough that this isn't a pressing matter.
! 	 */
! 
! 	s = splbio();
! 
! 	while ((wdc->sc_flags & WDCF_ACTIVE) != 0) {
! 		wdc->sc_flags |= WDCF_WANTED;
! 		if ((error = tsleep(wdc, PRIBIO | PCATCH, "wdprm", 0)) != 0) {
! 			splx(s);
! 			return error;
! 		}
! 	}
! 
! 	if (wdcommandshort(wdc, wd->sc_drive, WDCC_IDENTIFY) != 0 ||
! 	    wait_for_drq(wdc) != 0) {
! 		/*
! 		 * We `know' there's a drive here; just assume it's old.
! 		 * This geometry is only used to read the MBR and print a
! 		 * (false) attach message.
! 		 */
! 		strncpy(wd->sc_dk.dk_label->d_typename, "ST506",
! 		    sizeof wd->sc_dk.dk_label->d_typename);
! 		wd->sc_dk.dk_label->d_type = DTYPE_ST506;
! 
! 		strncpy(wd->sc_params.wdp_model, "unknown",
! 		    sizeof wd->sc_params.wdp_model);
! 		wd->sc_params.wdp_config = WD_CFG_FIXED;
! 		wd->sc_params.wdp_cylinders = 1024;
! 		wd->sc_params.wdp_heads = 8;
! 		wd->sc_params.wdp_sectors = 17;
! 		wd->sc_params.wdp_maxmulti = 0;
! 		wd->sc_params.wdp_usedmovsd = 0;
! 		wd->sc_params.wdp_capabilities = 0;
! 	} else {
! 		strncpy(wd->sc_dk.dk_label->d_typename, "ESDI/IDE",
! 		    sizeof wd->sc_dk.dk_label->d_typename);
! 		wd->sc_dk.dk_label->d_type = DTYPE_ESDI;
! 
! 		/* Read in parameter block. */
! 		insw(wdc->sc_iobase+wd_data, tb, sizeof(tb) / sizeof(short));
! 		bcopy(tb, &wd->sc_params, sizeof(struct wdparams));
! 
! 		/* Shuffle string byte order. */
! 		for (i = 0; i < sizeof(wd->sc_params.wdp_model); i += 2) {
! 			u_short *p;
! 			p = (u_short *)(wd->sc_params.wdp_model + i);
! 			*p = ntohs(*p);
! 		}
! 	}
! 
! 	/* Clear any leftover interrupt. */
! 	(void) inb(wdc->sc_iobase+wd_status);
! 
! 	/* Restart the queue. */
! 	wdcstart(wdc);
! 
! 	splx(s);
! 	return 0;
! }
! 
! int
! wdioctl(dev, cmd, addr, flag, p)
  	dev_t dev;
! 	u_long cmd;
  	caddr_t addr;
  	int flag;
  	struct proc *p;
  {
  	struct wd_softc *wd = wd_cd.cd_devs[WDUNIT(dev)];
  	int error;
!     
! 	if ((wd->sc_flags & WDF_LOADED) == 0)
  		return EIO;
  
! 	switch (cmd) {
  	case DIOCSBAD:
  		if ((flag & FWRITE) == 0)
  			return EBADF;
--- 551,607 ----
  		return;
  	}
  
! 	if (d_link->sc_state > GEOMETRY)
! 		d_link->sc_state = GEOMETRY;
  	if ((lp->d_flags & D_BADSECT) != 0)
  		bad144intern(wd);
  }
  
  
  /*
   * Tell the drive what geometry to use.
   */
  int
! wdsetctlr(d_link)
! 	struct wd_link *d_link;
  {
+ 	struct wd_softc *wd=(struct wd_softc *)d_link->wd_softc;
  
  #ifdef WDDEBUG
! 	printf("wd(%d,%d) C%dH%dS%d\n", wd->sc_dev.dv_unit, d_link->sc_drive,
  	    wd->sc_dk.dk_label->d_ncylinders, wd->sc_dk.dk_label->d_ntracks,
  	    wd->sc_dk.dk_label->d_nsectors);
  #endif
      
! 	if (wdccommand(d_link, WDCC_IDP, d_link->sc_drive, wd->sc_dk.dk_label->d_ncylinders,
! 	    wd->sc_dk.dk_label->d_ntracks - 1, 0, wd->sc_dk.dk_label->d_nsectors)
! 	    != 0) {
! 		wderror(d_link, NULL, "wdsetctlr: geometry upload failed");
  		return -1;
  	}
  
  	return 0;
  }
  
  int
! wdioctl(dev, xfer, addr, flag, p)
  	dev_t dev;
! 	u_long xfer;
  	caddr_t addr;
  	int flag;
  	struct proc *p;
  {
  	struct wd_softc *wd = wd_cd.cd_devs[WDUNIT(dev)];
+ 	struct wd_link *d_link = wd->d_link;
  	int error;
! #ifdef WDDEBUG
!     printf("wdioctl\n");
! #endif
! 
! 	if ((d_link->sc_flags & WDF_LOADED) == 0)
  		return EIO;
  
! 	switch (xfer) {
  	case DIOCSBAD:
  		if ((flag & FWRITE) == 0)
  			return EBADF;
***************
*** 1377,1409 ****
  		if ((flag & FWRITE) == 0)
  			return EBADF;
  
! 		if ((error = wdlock(wd)) != 0)
  			return error;
! 		wd->sc_flags |= WDF_LABELLING;
  
  		error = setdisklabel(wd->sc_dk.dk_label,
  		    (struct disklabel *)addr, /*wd->sc_dk.dk_openmask : */0,
  		    wd->sc_dk.dk_cpulabel);
  		if (error == 0) {
! 			if (wd->sc_state > GEOMETRY)
! 				wd->sc_state = GEOMETRY;
! 			if (cmd == DIOCWDINFO)
  				error = writedisklabel(WDLABELDEV(dev),
  				    wdstrategy, wd->sc_dk.dk_label,
  				    wd->sc_dk.dk_cpulabel);
  		}
  
! 		wd->sc_flags &= ~WDF_LABELLING;
! 		wdunlock(wd);
  		return error;
  	
  	case DIOCWLABEL:
  		if ((flag & FWRITE) == 0)
  			return EBADF;
  		if (*(int *)addr)
! 			wd->sc_flags |= WDF_WLABEL;
  		else
! 			wd->sc_flags &= ~WDF_WLABEL;
  		return 0;
  	
  #ifdef notyet
--- 625,657 ----
  		if ((flag & FWRITE) == 0)
  			return EBADF;
  
! 		if ((error = wdlock(wd->d_link)) != 0)
  			return error;
! 		d_link->sc_flags |= WDF_LABELLING;
  
  		error = setdisklabel(wd->sc_dk.dk_label,
  		    (struct disklabel *)addr, /*wd->sc_dk.dk_openmask : */0,
  		    wd->sc_dk.dk_cpulabel);
  		if (error == 0) {
! 			if (d_link->sc_state > GEOMETRY)
! 				d_link->sc_state = GEOMETRY;
! 			if (xfer == DIOCWDINFO)
  				error = writedisklabel(WDLABELDEV(dev),
  				    wdstrategy, wd->sc_dk.dk_label,
  				    wd->sc_dk.dk_cpulabel);
  		}
  
! 		d_link->sc_flags &= ~WDF_LABELLING;
! 		wdunlock(d_link);
  		return error;
  	
  	case DIOCWLABEL:
  		if ((flag & FWRITE) == 0)
  			return EBADF;
  		if (*(int *)addr)
! 			d_link->sc_flags |= WDF_WLABEL;
  		else
! 			d_link->sc_flags &= ~WDF_WLABEL;
  		return 0;
  	
  #ifdef notyet
***************
*** 1433,1439 ****
  		return error;
  	}
  #endif
! 
  	default:
  		return ENOTTY;
  	}
--- 681,687 ----
  		return error;
  	}
  #endif
! 	
  	default:
  		return ENOTTY;
  	}
***************
*** 1460,1466 ****
  	struct wd_softc *wd;
  	int part;
  	int size;
!     
  	if (wdopen(dev, 0, S_IFBLK, NULL) != 0)
  		return -1;
  	wd = wd_cd.cd_devs[WDUNIT(dev)];
--- 708,717 ----
  	struct wd_softc *wd;
  	int part;
  	int size;
! #ifdef WDDEBUG
!     printf("wdsize\n");
! #endif
! 
  	if (wdopen(dev, 0, S_IFBLK, NULL) != 0)
  		return -1;
  	wd = wd_cd.cd_devs[WDUNIT(dev)];
***************
*** 1476,1484 ****
  
  
  #ifndef __BDEVSW_DUMP_OLD_TYPE
- /* #define WD_DUMP_NOT_TRUSTED if you just want to watch */
  static int wddoingadump;
! static int wddumprecalibrated;
  
  /*
   * Dump core after a system crash.
--- 727,734 ----
  
  
  #ifndef __BDEVSW_DUMP_OLD_TYPE
  static int wddoingadump;
! /*static int wddumprecalibrated;*/
  
  /*
   * Dump core after a system crash.
***************
*** 1491,1500 ****
          size_t size;
  {
  	struct wd_softc *wd;	/* disk unit to do the I/O */
! 	struct wdc_softc *wdc;	/* disk controller to do the I/O */
  	struct disklabel *lp;	/* disk's disklabel */
  	int	unit, part;
  	int	nblks;		/* total number of sectors left to write */
  
  	/* Check if recursive dump; if so, punt. */
  	if (wddoingadump)
--- 741,751 ----
          size_t size;
  {
  	struct wd_softc *wd;	/* disk unit to do the I/O */
! 	struct wd_link *d_link; /* link struct for this disk */
  	struct disklabel *lp;	/* disk's disklabel */
  	int	unit, part;
  	int	nblks;		/* total number of sectors left to write */
+ 	int err;
  
  	/* Check if recursive dump; if so, punt. */
  	if (wddoingadump)
***************
*** 1505,1521 ****
  	if (unit >= wd_cd.cd_ndevs)
  		return ENXIO;
  	wd = wd_cd.cd_devs[unit];
  	if (wd == 0)
  		return ENXIO;
  
  	part = WDPART(dev);
  
  	/* Make sure it was initialized. */
! 	if (wd->sc_state < OPEN)
  		return ENXIO;
  
- 	wdc = (void *)wd->sc_dev.dv_parent;
- 
          /* Convert to disk sectors.  Request must be a multiple of size. */
  	lp = wd->sc_dk.dk_label;
  	if ((size % lp->d_secsize) != 0)
--- 756,771 ----
  	if (unit >= wd_cd.cd_ndevs)
  		return ENXIO;
  	wd = wd_cd.cd_devs[unit];
+ 	d_link = wd->d_link;
  	if (wd == 0)
  		return ENXIO;
  
  	part = WDPART(dev);
  
  	/* Make sure it was initialized. */
! 	if (d_link->sc_state < OPEN)
  		return ENXIO;
  
          /* Convert to disk sectors.  Request must be a multiple of size. */
  	lp = wd->sc_dk.dk_label;
  	if ((size % lp->d_secsize) != 0)
***************
*** 1530,1614 ****
  	/* Offset block number to start of partition. */
  	blkno += lp->d_partitions[part].p_offset;
  
! 	/* Recalibrate, if first dump transfer. */
! 	if (wddumprecalibrated == 0) {
! 		wddumprecalibrated = 1;
! 		if (wdcommandshort(wdc, wd->sc_drive, WDCC_RECAL) != 0 ||
! 		    wait_for_ready(wdc) != 0 || wdsetctlr(wd) != 0 ||
! 		    wait_for_ready(wdc) != 0) {
! 			wderror(wd, NULL, "wddump: recal failed");
! 			return EIO;
! 		}
  	}
!    
! 	while (nblks > 0) {
! 		daddr_t xlt_blkno = blkno;
! 		long cylin, head, sector;
! 
! 		if ((lp->d_flags & D_BADSECT) != 0) {
! 			long blkdiff;
! 			int i;
! 
! 			for (i = 0; (blkdiff = wd->sc_badsect[i]) != -1; i++) {
! 				blkdiff -= xlt_blkno;
! 				if (blkdiff < 0)
! 					continue;
! 				if (blkdiff == 0) {
! 					/* Replace current block of transfer. */
! 					xlt_blkno = lp->d_secperunit -
! 					    lp->d_nsectors - i - 1;
! 				}
! 				break;
! 			}
! 			/* Tranfer is okay now. */
! 		}
! 
! 		if ((wd->sc_params.wdp_capabilities & WD_CAP_LBA) != 0) {
! 			sector = (xlt_blkno >> 0) & 0xff;
! 			cylin = (xlt_blkno >> 8) & 0xffff;
! 			head = (xlt_blkno >> 24) & 0xf;
! 			head |= WDSD_LBA;
! 		} else {
! 			sector = xlt_blkno % lp->d_nsectors;
! 			sector++;	/* Sectors begin with 1, not 0. */
! 			xlt_blkno /= lp->d_nsectors;
! 			head = xlt_blkno % lp->d_ntracks;
! 			xlt_blkno /= lp->d_ntracks;
! 			cylin = xlt_blkno;
! 			head |= WDSD_CHS;
! 		}
! 
! #ifndef WD_DUMP_NOT_TRUSTED
! 		if (wdcommand(wd, WDCC_WRITE, cylin, head, sector, 1) != 0 ||
! 		    wait_for_drq(wdc) != 0) {
! 			wderror(wd, NULL, "wddump: write failed");
! 			return EIO;
! 		}
! 	
! 		outsw(wdc->sc_iobase+wd_data, va, lp->d_secsize >> 1);
! 	
! 		/* Check data request (should be done). */
! 		if (wait_for_ready(wdc) != 0) {
! 			wderror(wd, NULL, "wddump: timeout waiting for ready");
! 			return EIO;
! 		}
! #else	/* WD_DUMP_NOT_TRUSTED */
! 		/* Let's just talk about this first... */
! 		printf("wd%d: dump addr 0x%x, cylin %d, head %d, sector %d\n",
! 		    unit, va, cylin, head, sector);
! 		delay(500 * 1000);	/* half a second */
! #endif
! 
! 		/* update block count */
! 		nblks -= 1;
! 		blkno += 1;
! 		va += lp->d_secsize;
! 	}
! 
! 	wddoingadump = 0;
! 	return 0;
  }
  #else /* __BDEVSW_DUMP_NEW_TYPE */
  int
  wddump(dev, blkno, va, size)
          dev_t dev;
--- 780,794 ----
  	/* Offset block number to start of partition. */
  	blkno += lp->d_partitions[part].p_offset;
  
! 	err =  wdcdump(d_link, blkno, nblks, va);
! 	if (err == 0) {
! 		wddoingadump = 0;
  	}
! 	return err;
  }
  #else /* __BDEVSW_DUMP_NEW_TYPE */
+ 
+ 
  int
  wddump(dev, blkno, va, size)
          dev_t dev;
***************
*** 1631,1789 ****
  {
  	struct dkbad *bt = &wd->sc_dk.dk_cpulabel->bad;
  	struct disklabel *lp = wd->sc_dk.dk_label;
  	int i = 0;
  
  	for (; i < 126; i++) {
  		if (bt->bt_bad[i].bt_cyl == 0xffff)
  			break;
! 		wd->sc_badsect[i] =
  		    bt->bt_bad[i].bt_cyl * lp->d_secpercyl +
  		    (bt->bt_bad[i].bt_trksec >> 8) * lp->d_nsectors +
  		    (bt->bt_bad[i].bt_trksec & 0xff);
  	}
  	for (; i < 127; i++)
! 		wd->sc_badsect[i] = -1;
! }
! 
! int
! wdcreset(wdc)
! 	struct wdc_softc *wdc;
! {
! 	int iobase = wdc->sc_iobase;
! 
! 	/* Reset the device. */
! 	if (wdresethack) {
! 		outb(iobase+wd_ctlr, WDCTL_RST | WDCTL_IDS);
! 		delay(1000);
! 		outb(iobase+wd_ctlr, WDCTL_IDS);
! 		delay(1000);
! 		(void) inb(iobase+wd_error);
! 		outb(iobase+wd_ctlr, WDCTL_4BIT);
! 	}
! 
! 	if (wait_for_unbusy(wdc) < 0) {
! 		printf("%s: reset failed\n", wdc->sc_dev.dv_xname);
! 		return 1;
! 	}
! 
! 	return 0;
! }
! 
! void
! wdcrestart(arg)
! 	void *arg;
! {
! 	struct wdc_softc *wdc = arg;
! 	int s;
! 
! 	s = splbio();
! 	wdcstart(wdc);
! 	splx(s);
  }
  
- /*
-  * Unwedge the controller after an unexpected error.  We do this by resetting
-  * it, marking all drives for recalibration, and stalling the queue for a short
-  * period to give the reset time to finish.
-  * NOTE: We use a timeout here, so this routine must not be called during
-  * autoconfig or dump.
-  */
  void
! wdcunwedge(wdc)
! 	struct wdc_softc *wdc;
! {
! 	int unit;
! 
! 	untimeout(wdctimeout, wdc);
! 	(void) wdcreset(wdc);
! 
! 	/* Schedule recalibrate for all drives on this controller. */
! 	for (unit = 0; unit < wd_cd.cd_ndevs; unit++) {
! 		struct wd_softc *wd = wd_cd.cd_devs[unit];
! 		if (!wd || (void *)wd->sc_dev.dv_parent != wdc)
! 			continue;
! 		if (wd->sc_state > RECAL)
! 			wd->sc_state = RECAL;
! 	}
! 
! 	wdc->sc_flags |= WDCF_ERROR;
! 	++wdc->sc_errors;
! 
! 	/* Wake up in a little bit and restart the operation. */
! 	timeout(wdcrestart, wdc, RECOVERYTIME);
! }
! 
! int
! wdcwait(wdc, mask)
! 	struct wdc_softc *wdc;
! 	int mask;
! {
! 	int iobase = wdc->sc_iobase;
! 	int timeout = 0;
! 	u_char status;
! #ifdef WDCNDELAY_DEBUG
! 	extern int cold;
! #endif
! 
! 	for (;;) {
! 		wdc->sc_status = status = inb(iobase+wd_status);
! 		if ((status & WDCS_BSY) == 0 && (status & mask) == mask)
! 			break;
! 		if (++timeout > WDCNDELAY)
! 			return -1;
! 		delay(WDCDELAY);
! 	}
! 	if (status & WDCS_ERR) {
! 		wdc->sc_error = inb(iobase+wd_error);
! 		return WDCS_ERR;
! 	}
! #ifdef WDCNDELAY_DEBUG
! 	/* After autoconfig, there should be no long delays. */
! 	if (!cold && timeout > WDCNDELAY_DEBUG)
! 		printf("%s: warning: busy-wait took %dus\n",
! 		    wdc->sc_dev.dv_xname, WDCDELAY * timeout);
! #endif
! 	return 0;
! }
! 
! void
! wdctimeout(arg)
! 	void *arg;
! {
! 	struct wdc_softc *wdc = (struct wdc_softc *)arg;
! 	int s;
! 
! 	s = splbio();
! 	if ((wdc->sc_flags & WDCF_ACTIVE) != 0) {
! 		struct wd_softc *wd = wdc->sc_drives.tqh_first;
! 		struct buf *bp = wd->sc_q.b_actf;
! 
! 		wdc->sc_flags &= ~WDCF_ACTIVE;
! 		wderror(wdc, NULL, "lost interrupt");
! 		printf("%s: lost interrupt: %sing %d@%s:%d (%d)\n",
! 		    wdc->sc_dev.dv_xname,
! 		    (bp->b_flags & B_READ) ? "read" : "writ",
! 		    wd->sc_nblks, wd->sc_dev.dv_xname, wd->sc_blkno, wd->sc_state);
! 		wdcunwedge(wdc);
! 	} else
! 		wderror(wdc, NULL, "missing untimeout");
! 	splx(s);
! }
! 
! void
! wderror(dev, bp, msg)
! 	void *dev;
  	struct buf *bp;
  	char *msg;
  {
! 	struct wd_softc *wd = dev;
! 	struct wdc_softc *wdc = dev;
  
  	if (bp) {
! 		diskerr(bp, "wd", msg, LOG_PRINTF, wd->sc_skip / DEV_BSIZE,
  		    wd->sc_dk.dk_label);
  		printf("\n");
  	} else
! 		printf("%s: %s: status %b error %b\n", wdc->sc_dev.dv_xname,
! 		    msg, wdc->sc_status, WDCS_BITS, wdc->sc_error, WDERR_BITS);
  }
--- 811,857 ----
  {
  	struct dkbad *bt = &wd->sc_dk.dk_cpulabel->bad;
  	struct disklabel *lp = wd->sc_dk.dk_label;
+ 	struct wd_link *d_link = wd->d_link;
  	int i = 0;
  
+ #ifdef WDDEBUG
+ 	printf("bad144intern\n");
+ #endif
+ 
  	for (; i < 126; i++) {
  		if (bt->bt_bad[i].bt_cyl == 0xffff)
  			break;
! 		d_link->sc_badsect[i] =
  		    bt->bt_bad[i].bt_cyl * lp->d_secpercyl +
  		    (bt->bt_bad[i].bt_trksec >> 8) * lp->d_nsectors +
  		    (bt->bt_bad[i].bt_trksec & 0xff);
  	}
  	for (; i < 127; i++)
! 		d_link->sc_badsect[i] = -1;
  }
  
  void
! wderror(d_link, bp, msg)
! 	struct wd_link *d_link;
  	struct buf *bp;
  	char *msg;
  {
! 	struct wd_softc *wd = (struct wd_softc *)d_link->wd_softc;
  
  	if (bp) {
! 		diskerr(bp, "wd", msg, LOG_PRINTF, bp->b_bcount ,
  		    wd->sc_dk.dk_label);
  		printf("\n");
  	} else
! 		printf("%s: %s\n", wd->sc_dev.dv_xname,
! 		    msg);
! }
! 
! void
! wddone(d_link, bp)
! struct wd_link *d_link;
! struct buf *bp;
! {
! 	struct wd_softc *wd = (void*)d_link->wd_softc;
! 	disk_unbusy(&wd->sc_dk, (bp->b_bcount - bp->b_resid));
  }
diff -c -r -N --exclude exp --exclude compile sys/arch/arm32.orig/mainbus/wdc.c sys/arch/arm32/mainbus/wdc.c
*** sys/arch/arm32.orig/mainbus/wdc.c	Thu Jan  1 01:00:00 1970
--- sys/arch/arm32/mainbus/wdc.c	Thu Jun 13 02:57:04 1996
***************
*** 0 ****
--- 1,1747 ----
+ /*	$NetBSD$	*/
+ 
+ /*
+  * Copyright (c) 1994, 1995 Charles M. Hannum.  All rights reserved.
+  *
+  * DMA and multi-sector PIO handling are derived from code contributed by
+  * Onno van der Linden.
+  *
+  * Atapi support added by Manuel Bouyer.
+  *
+  * 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, 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. All advertising materials mentioning features or use of this software
+  *    must display the following acknowledgement:
+  *	This product includes software developed by Charles M. Hannum.
+  * 4. The name of the author may not be used to endorse or promote products
+  *    derived from this software without specific prior written permission.
+  *
+  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+  * IN NO EVENT SHALL THE AUTHOR 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.
+  */
+ 
+ #undef ATAPI_DEBUG_WDC
+ 
+ #include <sys/param.h>
+ #include <sys/systm.h>
+ #include <sys/kernel.h>
+ #include <sys/conf.h>
+ #include <sys/file.h>
+ #include <sys/stat.h>
+ #include <sys/ioctl.h>
+ #include <sys/buf.h>
+ #include <sys/uio.h>
+ #include <sys/malloc.h>
+ #include <sys/device.h>
+ #include <sys/disklabel.h>
+ #include <sys/disk.h>
+ #include <sys/syslog.h>
+ #include <sys/proc.h>
+ 
+ #include <vm/vm.h>
+ 
+ #include <machine/cpu.h>
+ #include <machine/irqhandler.h>
+ #include <machine/io.h>
+ #include <machine/katelib.h>
+ 
+ #include <arm32/mainbus/mainbus.h>
+ #include <arm32/mainbus/wdreg.h>
+ #include <arm32/mainbus/wdlink.h>
+ #include <atapi/atapilink.h>
+ 
+ extern int wdresethack;
+ 
+ #define	WAITTIME	(10 * hz)	/* time to wait for a completion */
+     /* this is a lot for hard drives, but not for cdroms */
+ #define RECOVERYTIME hz/2
+ #define WDCDELAY	100
+ #define WDCNDELAY	100000		/* delay = 100us; so 10s for a controller state change */
+ #if 0
+ /* If you enable this, it will report any delays more than 100us * N long. */
+ #define WDCNDELAY_DEBUG	50
+ #endif
+ 
+ #define	WDIORETRIES	5		/* number of retries before giving up */
+ 
+ #define	WDPART(dev)			DISKPART(dev)
+ 
+ LIST_HEAD(xfer_free_list, wdc_xfer) xfer_free_list;
+ 
+ struct wdc_softc {
+ 	struct device sc_dev;
+ 	irqhandler_t sc_ih;
+ 	struct wd_link *d_link[2];
+ 	struct bus_link *ab_link;
+ 	struct wdc_link ctlr_link;
+ 	int sc_iobase;			/* I/O port base */
+ 	int sc_drq;			/* DMA channel */
+ 
+ 	TAILQ_HEAD(xferhead, wdc_xfer) sc_xfer;
+ 	int sc_flags;
+ #define	WDCF_ACTIVE		0x01	/* controller is active */
+ #define	WDCF_SINGLE		0x02	/* sector at a time mode */
+ #define	WDCF_ERROR		0x04	/* processing a disk error */
+ #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 */
+ 	int sc_errors;			/* errors during current transfer */
+ 	u_char sc_status;		/* copy of status register */
+ 	u_char sc_error;		/* copy of error register */
+ };
+ 
+ int wdcprobe __P((struct device *, void *, void *));
+ void wdcattach __P((struct device *, struct device *, void *));
+ 
+ struct cfattach wdc_ca = {
+ 	sizeof(struct wdc_softc), wdcprobe, wdcattach
+ };
+ 
+ struct cfdriver wdc_cd = {
+       NULL, "wdc", DV_DULL
+ };
+ 
+ 
+ int wdcintr __P((void *));
+ 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 *));
+ void wdc_atapi_start __P((struct wdc_softc *,struct wdc_xfer *));
+ int wdcreset __P((struct wdc_softc *));
+ void wdcrestart __P((void *arg));
+ void wdcunwedge __P((struct wdc_softc *));
+ void wdctimeout __P((void *arg));
+ int wdcwait __P((struct wdc_softc *, int));
+ int wdccontrol __P((struct wd_link *));
+ void wdc_ata_done __P((struct wdc_softc *, struct wdc_xfer *));
+ void wdc_free_xfer __P((struct wdc_xfer *));
+ void wdcerror __P((struct wdc_softc*, char *));
+ int wdccommandshort __P((struct wdc_softc *, int, int));
+ void wdcbit_bucket __P(( struct wdc_softc *, int));
+ int wdc_atapi_intr __P((struct wdc_softc *, struct wdc_xfer *));
+ void wdc_atapi_done __P((struct wdc_softc *, struct wdc_xfer *));
+ 
+ /* ST506 spec says that if READY or SEEKCMPLT go off, then the read or write
+    command is aborted. */
+ #define	wait_for_drq(d)		wdcwait(d, WDCS_DRDY | WDCS_DSC | WDCS_DRQ)
+ #define    wait_for_unbusy(d)      wdcwait(d, 0)
+ #define    wait_for_ready(d)       wdcwait(d, WDCS_DRDY | WDCS_DSC)
+ #define    atapi_ready(d)       wdcwait(d, WDCS_DRQ)
+ 
+ #ifdef ATAPI_DEBUG
+ static int wdc_nxfer;
+ #endif
+ 
+ int
+ wdcprobe(parent, match, aux)
+ 	struct device *parent;
+ 	void *match, *aux;
+ {
+ 	struct wdc_softc *wdc = match;
+ 	struct mainbus_attach_args *mb = aux;
+ 	int iobase;
+ 
+ 	wdc->sc_iobase = iobase = mb->mb_iobase;
+ 
+ 	/* Check if we have registers that work. */
+ 	outb(iobase+wd_error, 0x5a);	/* Error register not writable, */
+ 	outb(iobase+wd_cyl_lo, 0xa5);	/* but all of cyllo are. */
+ 	if (inb(iobase+wd_error) == 0x5a || inb(iobase+wd_cyl_lo) != 0xa5) {
+ 		/*
+ 		 * Test for a controller with no IDE master, just one
+ 		 * ATAPI device. Select drive 1, and try again.
+ 		 */
+ 		outb(iobase+wd_sdh, WDSD_IBM | 0x10);
+ 		outb(iobase+wd_error, 0x5a);
+ 		outb(iobase+wd_cyl_lo, 0xa5);
+ 		if (inb(iobase+wd_error) == 0x5a || inb(iobase+wd_cyl_lo)
+ 		    != 0xa5)
+ 			return 0;
+ 		wdc->sc_flags |= WDCF_ONESLAVE;
+ 	}
+ 
+ 	if (wdcreset(wdc) != 0) {
+ 		delay(500000);
+ 		if (wdcreset(wdc) != 0)
+ 			return 0;
+ 	}
+ 
+ 	/* Select drive 0 or ATAPI slave device */
+ 	if (wdc->sc_flags & WDCF_ONESLAVE)
+ 		outb(iobase+wd_sdh, WDSD_IBM | 0x10);
+ 	else
+ 		outb(iobase+wd_sdh, WDSD_IBM);
+ 
+ 	/* Wait for controller to become ready. */
+ 	if (wait_for_unbusy(wdc) < 0)
+ 		return 0;
+     
+ 	/* Start drive diagnostics. */
+ 	outb(iobase+wd_command, WDCC_DIAGNOSE);
+ 
+ 	/* Wait for command to complete. */
+ 	if (wait_for_unbusy(wdc) < 0)
+ 		return 0;
+ 
+ 	mb->mb_iosize = 32;
+ 	return 1;
+ }
+ 
+ int
+ wdprint(aux, wdc)
+ 	void *aux;
+ 	char *wdc;
+ {
+ 	struct wd_link *d_link = aux;
+ 
+ 	if (!wdc)
+ 		printf(" drive %d", d_link->sc_drive);
+ 	return QUIET;
+ }
+ 
+ void
+ wdcattach(parent, self, aux)
+ 	struct device *parent, *self;
+ 	void *aux;
+ {
+ 	struct wdc_softc *wdc = (void *)self;
+ 	struct mainbus_attach_args *mb = aux;
+ 	int drive;
+ 
+ 	TAILQ_INIT(&wdc->sc_xfer);
+ 	wdc->sc_drq = mb->mb_drq;
+ 
+ 	printf("\n");
+ 
+   	wdc->sc_ih.ih_func = wdcintr;
+    	wdc->sc_ih.ih_arg = wdc;
+    	wdc->sc_ih.ih_level = IPL_BIO;
+    	wdc->sc_ih.ih_name = "wdc";
+ 
+ 	if (irq_claim(mb->mb_irq, &wdc->sc_ih))
+ 		panic("Cannot claim IRQ %d for wdc%d\n", mb->mb_irq, parent->dv_unit);
+ 
+ 	wdc->ctlr_link.flags = 0;
+ #ifdef ATAPI_DEBUG
+ 	wdc_nxfer = 0;
+ #endif
+ 
+ 	for (drive = 0; drive < 2; drive++) {
+ 		wdc->sc_flags |= WDCF_ACTIVE; /* controller active while autoconf */
+ 		if (wdccommandshort(wdc, drive, WDCC_RECAL) != 0 ||
+             	    wait_for_ready(wdc) != 0) {
+ 			wdc->d_link[drive]=NULL;
+ 			wdc->sc_flags &= ~WDCF_ACTIVE;
+ 		}
+ 		else {
+ 			wdc->sc_flags &= ~WDCF_ACTIVE;
+ 			wdc->d_link[drive]=malloc(sizeof(struct wd_link), M_DEVBUF, M_NOWAIT);
+ 			bzero(wdc->d_link[drive],sizeof(struct wd_link));
+ 			wdc->d_link[drive]->type = DRIVE;
+ 			wdc->d_link[drive]->wdc_softc =(caddr_t) wdc;
+ 			wdc->d_link[drive]->ctlr_link = &(wdc->ctlr_link);
+ 			wdc->d_link[drive]->sc_drive = drive;
+ 			if (wdc->sc_drq != DRQUNK) 
+ 				wdc->d_link[drive]->sc_mode = WDM_DMA;
+ 			else wdc->d_link[drive]->sc_mode = 0;
+ 
+ 			(void)config_found(self, (void *)wdc->d_link[drive], wdprint);
+ 		}
+ 	}
+ 
+ 	wdc->ab_link = malloc(sizeof(struct bus_link), M_DEVBUF, M_NOWAIT);
+ 	bzero(wdc->ab_link,sizeof(struct bus_link));
+ 	wdc->ab_link->type = BUS;
+ 	wdc->ab_link->wdc_softc = (caddr_t) wdc;
+ 	wdc->ab_link->ctlr_link = &(wdc->ctlr_link);
+ 	wdc->ab_link->ctrl = self->dv_unit;
+ 	(void)config_found(self, (void *)wdc->ab_link, NULL);
+ }
+ 
+ /*
+  * Start I/O on a controller.  This does the calculation, and starts a read or
+  * write operation.  Called to from wdstart() to start a transfer, from
+  * wdcintr() to continue a multi-sector transfer or start the next transfer, or
+  * wdcrestart() after recovering from an error.
+  */
+ void
+ wdcstart(wdc)
+ 	struct wdc_softc *wdc;
+ {
+ 	struct wdc_xfer *xfer;
+ 
+ 
+ 	if ((wdc->sc_flags & WDCF_ACTIVE) != 0 ) {
+ #ifdef WDDEBUG
+ 		printf("wdcstart: already active\n");
+ #endif
+ 		return; /* controller aleady active */
+ 	}
+ #ifdef DIAGNOSTIC
+ 	if ((wdc->sc_flags & WDCF_IRQ_WAIT) != 0)
+ 		panic("wdcstart: controller waiting for irq\n");
+ #endif
+ 	/*
+ 	 * XXX
+ 	 * This is a kluge.  See comments in wd_get_parms().
+ 	 */
+ 	if ((wdc->sc_flags & WDCF_WANTED) != 0) {
+ #ifdef ATAPI_DEBUG_WDC
+ 		printf("WDCF_WANTED\n");
+ #endif
+ 		wdc->sc_flags &= ~WDCF_WANTED;
+ 		wakeup(wdc);
+ 		return;
+ 	}
+ 	/* is there a xfer ? */
+ 	xfer = wdc->sc_xfer.tqh_first;
+ 	if (xfer == NULL) {
+ #ifdef ATAPI_DEBUG2
+ 		printf("wdcstart: null xfer\n");
+ #endif
+ 		return;
+ 	}
+ 	wdc->sc_flags |= WDCF_ACTIVE;
+ 	if (xfer->c_flags & C_ATAPI) {
+ #ifdef ATAPI_DEBUG_WDC
+ 		printf("wdcstart: atapi\n");
+ #endif
+ 		wdc_atapi_start(wdc,xfer);
+ 	} else {
+ 		wdc_ata_start(wdc,xfer);
+ 	}
+ }
+ 
+ 
+ void wdc_ata_start(wdc, xfer)
+ 	struct wdc_softc *wdc;
+ 	struct wdc_xfer *xfer;
+ {
+ 	struct wd_link *d_link;
+ 	struct buf *bp = xfer->c_bp;
+ 	int nblks;
+ 
+ 	d_link=xfer->d_link;
+ 
+ /*loop:*/
+     
+ 	if (wdc->sc_errors >= WDIORETRIES) {
+ 		wderror(d_link, bp, "hard error");
+ 		xfer->c_flags |= C_ERROR;
+ 		wdc_ata_done(wdc, xfer);
+ 		return;
+ 	}
+ 
+ 	/* Do control operations specially. */
+ 	if (d_link->sc_state < OPEN) {
+ 		/*
+ 		 * Actually, we want to be careful not to mess with the control
+ 		 * state if the device is currently busy, but we can assume
+ 		 * that we never get to this point if that's the case.
+ 		 */
+ 		if (wdccontrol(d_link) == 0) {
+ 			/* The drive is busy.  Wait. */
+ 			return;
+ 		}
+ 	}
+ 
+ 	/*
+ 	 * WDCF_ERROR is set by wdcunwedge() and wdcintr() when an error is
+ 	 * encountered.  If we are in multi-sector mode, then we switch to
+ 	 * single-sector mode and retry the operation from the start.
+ 	 */
+ 	if (wdc->sc_flags & WDCF_ERROR) {
+ 		wdc->sc_flags &= ~WDCF_ERROR;
+ 		if ((wdc->sc_flags & WDCF_SINGLE) == 0) {
+ 			wdc->sc_flags |= WDCF_SINGLE;
+ 			xfer->c_skip = 0;
+ 		}
+ 	}
+ 
+ 
+ 	/* When starting a transfer... */
+ 	if (xfer->c_skip == 0) {
+ 		daddr_t blkno;
+ 
+ #ifdef WDDEBUG
+ 		printf("\n%s: wdc_ata_start %s %d@%d; map ", wdc->sc_dev.dv_xname,
+ 		    (xfer->c_flags & B_READ) ? "read" : "write", xfer->c_bcount,
+ 		    xfer->c_blkno);
+ #endif
+ 		blkno = xfer->c_blkno+xfer->c_p_offset;
+ 		xfer->c_blkno = blkno / (d_link->sc_lp->d_secsize / DEV_BSIZE);
+ 	} else {
+ #ifdef WDDEBUG
+ 		printf(" %d)%x", xfer->c_skip, inb(wdc->sc_iobase+wd_altsts));
+ #endif
+ 	}
+ 
+ 	/* When starting a multi-sector transfer, or doing single-sector
+ 	    transfers... */
+ 	if (xfer->c_skip == 0 || (wdc->sc_flags & WDCF_SINGLE) != 0 ||
+ 	    d_link->sc_mode == WDM_DMA) {
+ 		daddr_t blkno = xfer->c_blkno;
+ 		long cylin, head, sector;
+ 		int command;
+ 
+ 		if ((wdc->sc_flags & WDCF_SINGLE) != 0)
+ 			nblks = 1;
+ 		else if (d_link->sc_mode != WDM_DMA)
+ 			nblks = xfer->c_bcount / d_link->sc_lp->d_secsize;
+ 		else
+ 			nblks = min(xfer->c_bcount / d_link->sc_lp->d_secsize, 8);
+ 
+ 		/* Check for bad sectors and adjust transfer, if necessary. */
+ 		if ((d_link->sc_lp->d_flags & D_BADSECT) != 0
+ #ifdef B_FORMAT
+ 		    && (bp->b_flags & B_FORMAT) == 0
+ #endif
+ 		    ) {
+ 			long blkdiff;
+ 			int i;
+ 
+ 			for (i = 0; (blkdiff = d_link->sc_badsect[i]) != -1; i++) {
+ 				blkdiff -= blkno;
+ 				if (blkdiff < 0)
+ 					continue;
+ 				if (blkdiff == 0) {
+ 					/* Replace current block of transfer. */
+ 					blkno =
+ 					    d_link->sc_lp->d_secperunit -
+ 						d_link->sc_lp->d_nsectors - i - 1;
+ 				}
+ 				if (blkdiff < nblks) {
+ 					/* Bad block inside transfer. */
+ 					wdc->sc_flags |= WDCF_SINGLE;
+ 					nblks = 1;
+ 				}
+ 				break;
+ 			}
+ 			/* Tranfer is okay now. */
+ 		}
+ 
+ 		if ((d_link->sc_params.wdp_capabilities & WD_CAP_LBA) != 0) {
+ 			sector = (blkno >> 0) & 0xff;
+ 			cylin = (blkno >> 8) & 0xffff;
+ 			head = (blkno >> 24) & 0xf;
+ 			head |= WDSD_LBA;
+ 		} else {
+ 			sector = blkno % d_link->sc_lp->d_nsectors;
+ 			sector++;	/* Sectors begin with 1, not 0. */
+ 			blkno /= d_link->sc_lp->d_nsectors;
+ 			head = blkno % d_link->sc_lp->d_ntracks;
+ 			blkno /= d_link->sc_lp->d_ntracks;
+ 			cylin = blkno;
+ 			head |= WDSD_CHS;
+ 		}
+ 
+ 		if (d_link->sc_mode == WDM_PIOSINGLE ||
+ 		    (wdc->sc_flags & WDCF_SINGLE) != 0)
+ 			xfer->c_nblks = 1;
+ 		else if (d_link->sc_mode == WDM_PIOMULTI)
+ 			xfer->c_nblks = min(nblks, d_link->sc_multiple);
+ 		else
+ 			xfer->c_nblks = nblks;
+ 		xfer->c_nbytes = xfer->c_nblks * d_link->sc_lp->d_secsize;
+     
+ #ifdef B_FORMAT
+ 		if (bp->b_flags & B_FORMAT) {
+ 			sector = d_link->sc_lp->d_gap3;
+ 			nblks = d_link->sc_lp->d_nsectors;
+ 			command = WDCC_FORMAT;
+ 		} else
+ #endif
+ 		switch (d_link->sc_mode) {
+ 		case WDM_DMA:
+ 			panic("wdc: Cannot do DMA\n");
+ #if 0
+ 			command = (xfer->c_flags & B_READ) ?
+ 			    WDCC_READDMA : WDCC_WRITEDMA;
+ 			/* Start the DMA channel and bounce the buffer if
+ 			   necessary. */
+ 			isa_dmastart(xfer->c_flags & B_READ ? DMAMODE_READ : DMAMODE_WRITE,
+ 			    xfer->databuf + xfer->c_skip,
+ 			    xfer->c_nbytes, wdc->sc_drq);
+ 			break;
+ #endif
+ 		case WDM_PIOMULTI:
+ 			command = (xfer->c_flags & B_READ) ?
+ 			    WDCC_READMULTI : WDCC_WRITEMULTI;
+ 			break;
+ 		case WDM_PIOSINGLE:
+ 			command = (xfer->c_flags & B_READ) ?
+ 			    WDCC_READ : WDCC_WRITE;
+ 			break;
+                 default:
+ #ifdef DIAGNOSTIC
+                         panic("bad wd mode");
+ #endif
+                         return;
+ 		}
+ 	
+ 		/* Initiate command! */
+ 		if (wdccommand(d_link, command, d_link->sc_drive, cylin, head, sector, nblks) != 0) {
+ 			wderror(d_link, NULL,
+ 			    "wdc_ata_start: timeout waiting for unbusy");
+ 			wdcunwedge(wdc);
+ 			return;
+ 		}
+ 
+ #ifdef WDDEBUG
+ 		printf("sector %d cylin %d head %d addr %x sts %x\n", sector,
+ 		    cylin, head, xfer->databuf, 0/*inb(wdc->sc_iobase+wd_altsts)*/);
+ #endif
+ 	} else if (xfer->c_nblks > 1) {
+ 		/* The number of blocks in the last stretch may be smaller. */
+ 		nblks = xfer->c_bcount / d_link->sc_lp->d_secsize;
+ 		if (xfer->c_nblks > nblks) {
+ 			xfer->c_nblks = nblks;
+ 			xfer->c_nbytes = xfer->c_bcount;
+ 		}
+ 	}
+ 
+ 	/* If this was a write and not using DMA, push the data. */
+ 	if (d_link->sc_mode != WDM_DMA &&
+ 	    (xfer->c_flags & (B_READ|B_WRITE)) == B_WRITE) {
+ 		if (wait_for_drq(wdc) < 0) {
+ 			wderror(d_link, NULL, "wdc_ata_start: timeout waiting for drq");
+ 			wdcunwedge(wdc);
+ 			return;
+ 		}
+ 
+ 		/* Push out data. */
+ 		if ((d_link->sc_flags & WDF_32BIT) == 0)
+ 			outsw(wdc->sc_iobase+wd_data, xfer->databuf + xfer->c_skip,
+ 			    xfer->c_nbytes >> 1);
+ 		else
+ 			outsl(wdc->sc_iobase+wd_data, xfer->databuf + xfer->c_skip,
+ 			    xfer->c_nbytes >> 2);
+ 	}
+ 
+ 	wdc->sc_flags |= WDCF_IRQ_WAIT;
+ #ifdef WDDEBUG
+ 	printf("wdc_ata_start: timeout ");
+ #endif
+ 	timeout(wdctimeout, wdc, WAITTIME);
+ #ifdef WDDEBUG
+ 	printf("done\n");
+ #endif
+ }
+ 
+ void
+ wdc_atapi_start (wdc, xfer)
+ struct wdc_softc *wdc;
+ struct wdc_xfer *xfer;
+ {
+ 	struct atapi_command_packet *acp = xfer->atapi_cmd;
+ #ifdef ATAPI_DEBUG_WDC
+ 	printf("wdc_atapi_start, acp flags %lx\n",acp->flags);
+ #endif
+ 	if (wdc->sc_errors >= WDIORETRIES) {
+ 		acp->status |= ERROR;
+ 		acp->error = inb (wdc->sc_iobase + wd_error);
+ 		wdc_atapi_done(wdc, xfer);
+ 		return;
+ 	}
+ 	if (wait_for_unbusy (wdc) != 0)
+ 		if (!(wdc->sc_status & WDCS_ERR)) {
+ 			printf ("wdc_atapi_start: not ready, st = %02x\n",wdc->sc_status);
+ 			acp->status = ERROR;
+ 			return;
+ 		}
+ 
+ 	if (wdccommand ((struct wd_link*)xfer->d_link, ATAPI_PACKET_COMMAND,
+ 		acp->drive, acp->data_size, 0, 0, 0) != 0) {
+ 		printf("wdc_atapi_start: can't send atapi paket command\n");
+ 		acp->status = ERROR;
+ 		wdc->sc_flags |= WDCF_IRQ_WAIT;
+ 		return;
+ 	}
+ 	if ((acp->flags & 0x0300) != ACAP_DRQ_INTR) {
+ 		int i, phase;
+ 		for (i=20000; i>0; --i) {
+             phase = (inb(wdc->sc_iobase + wd_ireason) & (WDCI_CMD | WDCI_IN)) |
+                 (inb(wdc->sc_iobase + wd_status) & WDCS_DRQ);
+             if (phase == PHASE_CMDOUT)
+                 break;
+             delay(10);
+         }
+ 		if (phase != PHASE_CMDOUT ) {
+ 			printf("wdc_atapi_start: timout waiting PHASE_CMDOUT");
+ 			acp->status = ERROR;
+ 			wdc_atapi_done(wdc, xfer);
+ 			return;
+ 		}
+ 		outsw (wdc->sc_iobase + wd_data, acp->command,
+             acp->command_size/ sizeof (short));
+ 	}
+ 	wdc->sc_flags |= WDCF_IRQ_WAIT;
+ 
+ 	 
+ #ifdef ATAPI_DEBUG2
+ 	printf("wdc_atapi_start: timeout\n");
+ #endif
+ 	timeout(wdctimeout, wdc, WAITTIME);
+ 	return;
+ }
+ 
+ 
+ /*
+  * Interrupt routine for the controller.  Acknowledge the interrupt, check for
+  * errors on the current operation, mark it done if necessary, and start the
+  * next request.  Also check for a partially done transfer, and continue with
+  * the next chunk if so.
+  */
+ int
+ wdcintr(arg)
+ 	void *arg;
+ {
+ 	struct wdc_softc *wdc = arg;
+ 	struct wdc_xfer *xfer;
+ 
+ 	if ((wdc->sc_flags & WDCF_IRQ_WAIT) == 0) {
+ 		/* Clear the pending interrupt and abort. */
+ 		u_char s = inb(wdc->sc_iobase+wd_status);
+ 		u_char e = inb(wdc->sc_iobase+wd_error);
+ 		u_char i = inb(wdc->sc_iobase+wd_seccnt);
+ #ifdef ATAPI_DEBUG_WDC
+         printf ("wdcintr: inactive controller, punting st=%02x er=%02x irr=%02x\n", s, e, i);
+ #endif /* ATAPI_DEBUG */
+        if (s & WDCS_DRQ) {
+ 			int len = inb (wdc->sc_iobase + wd_cyl_lo) +
+ 			256 * inb (wdc->sc_iobase + wd_cyl_hi);
+ #ifdef ATAPI_DEBUG_WDC
+ 			printf ("wdcintr: clearing up %d bytes\n", len);
+ #endif /* ATAPI_DEBUG */
+ 			wdcbit_bucket (wdc, len);
+ 		}
+ 		return 0;
+ 	}
+ 
+ #ifdef WDDEBUG
+ 	printf("wdcintr\n");
+ #endif
+ 	wdc->sc_flags &= ~WDCF_IRQ_WAIT;
+ 	xfer = wdc->sc_xfer.tqh_first;
+ 	if (xfer->c_flags & C_ATAPI) {
+ 		(void) wdc_atapi_intr(wdc,xfer);
+ 		return 0;
+ 	} else {
+ 		return wdc_ata_intr(wdc,xfer);
+ 	}
+ }
+ 
+ 
+ int
+ wdc_ata_intr(wdc,xfer)
+ 	struct wdc_softc *wdc;
+ 	struct wdc_xfer *xfer;
+ {
+ 	struct wd_link *d_link;
+ 
+ 	d_link = xfer->d_link;
+ 
+ 	if (wait_for_unbusy(wdc) < 0) {
+ 		wdcerror(wdc, "wdcintr: timeout waiting for unbusy");
+ 		wdc->sc_status |= WDCS_ERR;	/* XXX */
+ 	}
+ 
+ 	untimeout(wdctimeout, wdc);
+ 
+ 	/* Is it not a transfer, but a control operation? */
+ 	if (d_link->sc_state < OPEN) {
+ 		if (wdccontrol(d_link) == 0) {
+ 			/* The drive is busy.  Wait. */
+ 			return 1;
+ 		}
+ #ifdef WDDEBUG
+ 		printf("wdc_ata_start from wdc_ata_intr(open) flags %d\n",
+ 			dc->sc_flags);
+ #endif
+ 		wdc_ata_start(wdc,xfer);
+ 		return 1;
+ 	}
+ 
+ 	/* Turn off the DMA channel and unbounce the buffer. */
+ 	if (d_link->sc_mode == WDM_DMA)
+ 		panic("wdc: Cannot do DMA\n");
+ #if 0
+ 		isa_dmadone(xfer->c_flags & B_READ ? DMAMODE_READ : DMAMODE_WRITE,
+ 			xfer->databuf + xfer->c_skip, xfer->c_nbytes, wdc->sc_drq);
+ #endif
+ 
+ 	/* Have we an error? */
+ 	if (wdc->sc_status & WDCS_ERR) {
+ #ifdef WDDEBUG
+ 		wderror(d_link, NULL, "wdc_ata_start");
+ #endif
+ 		if ((wdc->sc_flags & WDCF_SINGLE) == 0) {
+ 			wdc->sc_flags |= WDCF_ERROR;
+ 			goto restart;
+ 		}
+ 
+ #ifdef B_FORMAT
+ 		if (bp->b_flags & B_FORMAT)
+ 			goto bad;
+ #endif
+ 	
+ 		if (++wdc->sc_errors < WDIORETRIES)
+ 			goto restart;
+ 
+ 		wderror(d_link, xfer->c_bp, "hard error");
+ #ifdef B_FORMAT
+ 	bad:
+ #endif
+ 		xfer->c_flags |= C_ERROR;
+ 		goto done;
+ 	}
+ 
+ 	/* If this was a read and not using DMA, fetch the data. */
+ 	if (d_link->sc_mode != WDM_DMA &&
+ 	    (xfer->c_flags & (B_READ|B_WRITE)) == B_READ) {
+ 		if ((wdc->sc_status & (WDCS_DRDY | WDCS_DSC | WDCS_DRQ))
+ 		    != (WDCS_DRDY | WDCS_DSC | WDCS_DRQ)) {
+ 			wderror(d_link, NULL, "wdcintr: read intr before drq");
+ 			wdcunwedge(wdc);
+ 			return 1;
+ 		}
+ 
+ 		/* Pull in data. */
+ 		if ((d_link->sc_flags & WDF_32BIT) == 0)
+ 			insw(wdc->sc_iobase+wd_data, xfer->databuf + xfer->c_skip, 
+ 			    xfer->c_nbytes >> 1);
+ 		else
+ 			insl(wdc->sc_iobase+wd_data, xfer->databuf + xfer->c_skip, 
+ 			    xfer->c_nbytes >> 2);
+ 	}
+     
+ 	/* If we encountered any abnormalities, flag it as a soft error. */
+ 	if (wdc->sc_errors > 0 ||
+ 	    (wdc->sc_status & WDCS_CORR) != 0) {
+ 		wderror(d_link, xfer->c_bp, "soft error (corrected)");
+ 		wdc->sc_errors = 0;
+ 	}
+     
+ 	/* Adjust pointers for the next block, if any. */
+ 	xfer->c_blkno += xfer->c_nblks;
+ 	xfer->c_skip += xfer->c_nbytes;
+ 	xfer->c_bcount -= xfer->c_nbytes;
+ 
+ 	/* See if this transfer is complete. */
+ 	if (xfer->c_bcount > 0)
+ 		goto restart;
+ 
+ done:
+ 	/* Done with this transfer, with or without error. */
+ 	wdc_ata_done(wdc, xfer);
+ 	return 0;
+ 
+ restart:
+ 	/* Start the next operation */
+ #ifdef WDDEBUG
+ 	printf("wdc_ata_start from wdcintr flags %d\n",wdc->sc_flags);
+ #endif
+ 	wdc_ata_start(wdc, xfer);
+ 
+ 	return 1;
+ }
+ 
+ int
+ wdcreset(wdc)
+ 	struct wdc_softc *wdc;
+ {
+ 	int iobase = wdc->sc_iobase;
+ 
+ 	/* Reset the device. */
+ 	if (wdresethack) {
+ 		outb(iobase+wd_ctlr, WDCTL_RST | WDCTL_IDS);
+ 		delay(1000);
+ 		outb(iobase+wd_ctlr, WDCTL_IDS);
+ 		delay(1000);
+ 		(void) inb(iobase+wd_error);
+ 		outb(iobase+wd_ctlr, WDCTL_4BIT);
+ 	}
+ 
+ 	if (wait_for_unbusy(wdc) < 0) {
+ 		printf("%s: reset failed\n", wdc->sc_dev.dv_xname);
+ 		return 1;
+ 	}
+ 
+ 	return 0;
+ }
+ 
+ void
+ wdcrestart(arg)
+ 	void *arg;
+ {
+ 	struct wdc_softc *wdc = arg;
+ 	int s;
+ 
+ 	s = splbio();
+ 	wdcstart(wdc);
+ 	splx(s);
+ }
+ 
+ /*
+  * Unwedge the controller after an unexpected error.  We do this by resetting
+  * it, marking all drives for recalibration, and stalling the queue for a short
+  * period to give the reset time to finish.
+  * NOTE: We use a timeout here, so this routine must not be called during
+  * autoconfig or dump.
+  */
+ void
+ wdcunwedge(wdc)
+ 	struct wdc_softc *wdc;
+ {
+ 	int unit;
+ #ifdef ATAPI_DEBUG
+ 	printf("wdcunwedge\n");
+ #endif
+ 	untimeout(wdctimeout, wdc);
+ 	wdc->sc_flags &= ~WDCF_IRQ_WAIT;
+ 	(void) wdcreset(wdc);
+ 
+ 	/* Schedule recalibrate for all drives on this controller. */
+ 	for (unit = 0; unit < 2; unit++) {
+ 		if (!wdc->d_link[unit]) continue;
+ 		if (wdc->d_link[unit]->sc_state > RECAL)
+ 			wdc->d_link[unit]->sc_state = RECAL;
+ 	}
+ 
+ 	wdc->sc_flags |= WDCF_ERROR;
+ 	++wdc->sc_errors;
+ 
+ 	/* Wake up in a little bit and restart the operation. */
+ #ifdef WDDEBUG
+ 	printf("wdcrestart from wdcunwedge\n");
+ #endif
+ 	wdc->sc_flags &= ~WDCF_ACTIVE;
+ 	timeout(wdcrestart, wdc, RECOVERYTIME);
+ }
+ 
+ int
+ wdcwait(wdc, mask)
+ 	struct wdc_softc *wdc;
+ 	int mask;
+ {
+ 	int iobase = wdc->sc_iobase;
+ 	int timeout = 0;
+ 	u_char status;
+ #ifdef WDCNDELAY_DEBUG
+ 	extern int cold;
+ #endif
+ #ifdef WDDEBUG
+     printf("wdcwait\n");
+ #endif
+ 		
+ 	for (;;) {
+ 		wdc->sc_status = status = inb(iobase+wd_status);
+ 		/*
+ 		 * XXX
+ 		 * If a single slave ATAPI device is attached, it may
+ 		 * have released the bus. Select it and try again.
+ 		 */
+ 		if (status == 0xff && wdc->sc_flags & WDCF_ONESLAVE) {
+ 			outb(iobase+wd_sdh, WDSD_IBM | 0x10);
+ 			wdc->sc_status = status = inb(iobase+wd_status);
+ 		}
+ 		if ((status & WDCS_BSY) == 0 && (status & mask) == mask)
+ 			break;
+ 		if (++timeout > WDCNDELAY) {
+ #ifdef ATAPI_DEBUG2
+ 			printf("wdcwait: timeout, status %x\n", status);
+ #endif
+ 			return -1;
+ 		}
+ 		delay(WDCDELAY);
+ 	}
+ 	if (status & WDCS_ERR) {
+ 		wdc->sc_error = inb(iobase+wd_error);
+ 		return WDCS_ERR;
+ 	}
+ #ifdef WDCNDELAY_DEBUG
+ 	/* After autoconfig, there should be no long delays. */
+ 	if (!cold && timeout > WDCNDELAY_DEBUG) {
+ 		struct wdc_xfer *xfer = wdc->sc_xfer.tqh_first;
+ 		if (xfer == NULL)
+ 			printf("%s: warning: busy-wait took %dus\n",
+ 	    		wdc->sc_dev.dv_xname, WDCDELAY * timeout);
+ 		else 
+ 			printf("%s(%s): warning: busy-wait took %dus\n",
+ 				wdc->sc_dev.dv_xname,
+ 				((struct device*)xfer->d_link->wd_softc)->dv_xname,
+ 				WDCDELAY * timeout);
+ 	}
+ #endif
+ 	return 0;
+ }
+ 
+ void
+ wdctimeout(arg)
+ 	void *arg;
+ {
+ 	struct wdc_softc *wdc = (struct wdc_softc *)arg;
+ 	int s;
+ #ifdef WDDEBUG
+     printf("wdctimeout\n");
+ #endif
+ 
+ 	s = splbio();
+ 	if ((wdc->sc_flags & WDCF_IRQ_WAIT) != 0) {
+ 		wdc->sc_flags &= ~WDCF_IRQ_WAIT;
+ 		wdcerror(wdc, "lost interrupt");
+ 		wdcunwedge(wdc);
+ 	} else
+ 		wdcerror(wdc, "missing untimeout");
+ 	splx(s);
+ }
+ 
+ /*
+  * Wait for the drive to become ready and send a command.
+  * Return -1 if busy for too long or 0 otherwise.
+  * Assumes interrupts are blocked.
+  */
+ int
+ wdccommand(d_link, command, drive, cylin, head, sector, count)
+         struct wd_link *d_link;
+         int command;
+         int drive, cylin, head, sector, count;
+ {
+ 		struct wdc_softc *wdc = (void*)d_link->wdc_softc;
+         int iobase = wdc->sc_iobase;
+         int stat;
+ #ifdef WDDEBUG
+     printf("wdccommand drive %d\n",drive);
+ #endif
+ #if defined(DIAGNOSTIC) && defined(WDCDEBUG)
+ 	if ((wdc->sc_flags & WDCF_ACTIVE) == 0 )
+ 		printf("wdccommand: controler not active (drive %d)\n", drive);
+ #endif
+ 
+         /* Select drive, head, and addressing mode. */
+         outb(iobase+wd_sdh, WDSD_IBM | (drive << 4) | head);
+ 
+         /* Wait for it to become ready to accept a command. */
+         if (command == WDCC_IDP || d_link->type == BUS)
+                 stat = wait_for_unbusy(wdc);
+         else
+                 stat = wdcwait(wdc, WDCS_DRDY);
+         if (stat < 0) {
+ #ifdef ATAPI_DEBUG
+ 			    printf("wdcommand:xfer failed (wait_for_unbusy) status %d\n",stat);
+ #endif
+                 return -1;
+ 		 }
+ 
+         /* Load parameters. */
+         if (d_link->type == DRIVE && d_link->sc_lp->d_type == DTYPE_ST506)
+                 outb(iobase+wd_precomp, d_link->sc_lp->d_precompcyl / 4);
+         else
+                 outb(iobase+wd_features, 0);
+         outb(iobase+wd_cyl_lo, cylin);
+         outb(iobase+wd_cyl_hi, cylin >> 8);
+         outb(iobase+wd_sector, sector);
+         outb(iobase+wd_seccnt, count);
+ 
+         /* Send command. */
+         outb(iobase+wd_command, command);
+ 
+         return 0;
+ }
+ 
+ /*
+  * Simplified version of wdccommand().
+  */
+ int
+ wdccommandshort(wdc, drive, command)
+ 	    struct wdc_softc *wdc;
+         int drive;
+         int command;
+ {
+ 		int iobase = wdc->sc_iobase;
+ #ifdef WDDEBUG
+     printf("wdccommandshort\n");
+ #endif
+ #if defined(DIAGNOSTIC) && defined(WDCDEBUG)
+ 	if ((wdc->sc_flags & WDCF_ACTIVE) == 0 )
+ 		printf("wdccommandshort: controler not active (drive %d)\n", drive);
+ #endif
+ 
+         /* Select drive. */
+         outb(iobase+wd_sdh, WDSD_IBM | (drive << 4));
+ 
+         if (wdcwait(wdc, WDCS_DRDY) < 0)
+                 return -1;
+ 
+         outb(iobase+wd_command, command);
+ 
+         return 0;
+ }
+ 
+ #ifndef __BDEVSW_DUMP_OLD_TYPE
+ /* #define WD_DUMP_NOT_TRUSTED*/ /* if you just want to watch */
+ static int wddumprecalibrated;
+ 
+ int
+ wdcdump(d_link, blkno, nblks, va)
+ struct wd_link *d_link;
+ daddr_t blkno;
+ int nblks;
+ caddr_t va;
+ {
+ 	struct wdc_softc *wdc = (void*)d_link->wdc_softc;
+ 	struct disklabel *lp = d_link->sc_lp;
+     /* Recalibrate, if first dump transfer. */
+ 	wdc->sc_flags  |= WDCF_ACTIVE;
+     if (wddumprecalibrated == 0) {
+     	if (wdccommandshort(wdc, d_link->sc_drive, WDCC_RECAL) != 0 ||
+ 		wait_for_ready(wdc) != 0 ||
+ 		wdsetctlr(d_link) != 0 || wait_for_ready(wdc) != 0) {
+        		 wdcerror(wdc, "wdcdump: recal failed");
+ 			 return EIO;
+     	}
+     }
+     while (nblks > 0) {
+         daddr_t xlt_blkno = blkno;
+         long cylin, head, sector;
+     
+         if ((lp->d_flags & D_BADSECT) != 0) {
+             long blkdiff;
+             int i;
+ 
+             for (i = 0; (blkdiff = d_link->sc_badsect[i]) != -1; i++) {
+                 blkdiff -= xlt_blkno;
+                 if (blkdiff < 0)
+                     continue;
+                 if (blkdiff == 0) {
+                     /* Replace current block of transfer. */
+                     xlt_blkno = lp->d_secperunit -
+                         lp->d_nsectors - i - 1;
+                 }
+                 break;
+             }
+             /* Tranfer is okay now. */
+         }
+      
+         if ((d_link->sc_params.wdp_capabilities & WD_CAP_LBA) != 0) {
+             sector = (xlt_blkno >> 0) & 0xff;
+             cylin = (xlt_blkno >> 8) & 0xffff;
+             head = (xlt_blkno >> 24) & 0xf;
+             head |= WDSD_LBA;
+         } else {
+             sector = xlt_blkno % lp->d_nsectors;
+             sector++;   /* Sectors begin with 1, not 0. */
+             xlt_blkno /= lp->d_nsectors;
+             head = xlt_blkno % lp->d_ntracks;
+             xlt_blkno /= lp->d_ntracks;
+             cylin = xlt_blkno;
+             head |= WDSD_CHS;
+         }
+ #ifndef WD_DUMP_NOT_TRUSTED
+ 
+         if (wdccommand(d_link, WDCC_WRITE, d_link->sc_drive, cylin, head, sector, 1) != 0 ||
+             wait_for_drq(wdc) != 0) {
+             wdcerror(wdc, "wddump: write failed");
+             return EIO;
+         }
+    
+         outsw(wdc->sc_iobase+wd_data, va, lp->d_secsize >> 1);
+    
+         /* Check data request (should be done). */
+         if (wait_for_ready(wdc) != 0) {
+             wdcerror(wdc, "wddump: timeout waiting for ready");
+             return EIO;
+         }
+ #else   /* WD_DUMP_NOT_TRUSTED */
+         /* Let's just talk about this first... */
+         printf("wd%d: dump addr 0x%x, cylin %d, head %d, sector %d\n",
+             d_link->sc_drive, va, cylin, head, sector);
+         delay(500 * 1000);  /* half a second */
+ #endif
+         /* update block count */
+         nblks -= 1;
+         blkno += 1;
+         va += lp->d_secsize;
+     }
+ 	wdc->sc_flags  &= ~WDCF_ACTIVE;
+     return 0;
+ }
+ #endif
+ 
+ void wdc_ata_done(wdc, xfer)
+ struct wdc_softc *wdc;
+ struct wdc_xfer *xfer;
+ {
+ 	int s;
+ 	struct buf *bp = xfer->c_bp;
+ 	struct wd_link *d_link = xfer->d_link;
+ #ifdef WDDEBUG
+     printf("wdc_ata_done\n");
+ #endif
+ 	/* remove this command from xfer queue */
+ 	s = splbio();
+ 	TAILQ_REMOVE(&wdc->sc_xfer, xfer, c_xferchain);
+ 	wdc->sc_flags &= ~(WDCF_SINGLE | WDCF_ERROR | WDCF_ACTIVE);
+     wdc->sc_errors = 0;
+ 	if (bp) {
+ 		if (xfer->c_flags & C_ERROR) {
+ 			bp->b_flags |= B_ERROR;
+ 			bp->b_error = EIO;
+ 		}
+ 		bp->b_resid = xfer->c_bcount;
+ 		wddone(d_link, bp);
+ 		biodone(bp);
+ 	} else {
+ 		wakeup(xfer->databuf);
+ 	}
+ 	xfer->c_skip = 0;
+ 	wdc_free_xfer(xfer);
+ 	d_link->openings++;
+ 	wdstart((void*)d_link->wd_softc);
+ #ifdef WDDEBUG
+ 	printf("wdcstart from wdc_ata_done, flags %d\n",wdc->sc_flags);
+ #endif
+ 	wdcstart(wdc);
+ 	splx(s);
+ }
+ 
+ void wdc_exec_xfer(d_link, xfer)
+ struct wd_link *d_link;
+ struct wdc_xfer *xfer;
+ {
+    struct wdc_softc *wdc=(struct wdc_softc *)d_link->wdc_softc;
+    int s;
+   
+ #ifdef WDDEBUG
+     printf("wdc_exec_xfer\n");
+ #endif
+ 	s = splbio();
+    /* insert at the end of command list */
+    TAILQ_INSERT_TAIL(&wdc->sc_xfer,xfer , c_xferchain)
+ #ifdef WDDEBUG
+ 	printf("wdcstart from wdc_exec_xfer, flags %d\n",wdc->sc_flags);
+ #endif
+ 	wdcstart(wdc);
+ 	splx(s);
+ }   
+ 
+ struct wdc_xfer *
+ wdc_get_xfer(c_link,flags)
+ struct wdc_link *c_link;
+ int flags;
+ {
+ 	struct wdc_xfer *xfer;
+ 	int s;
+ 
+ 	s = splbio();
+ 	if (xfer = xfer_free_list.lh_first) {
+ 		LIST_REMOVE(xfer, free_list);
+ 		splx(s);
+ #ifdef DIAGNOSTIC
+ 		if ((xfer->c_flags & C_INUSE) != 0) panic("xfer already in use\n");
+ #endif
+ 	} else {
+ 		splx(s);
+ #ifdef ATAPI_DEBUG
+ 		printf("wdc:making xfer %d\n",wdc_nxfer);
+ #endif
+ 		xfer = malloc(sizeof(*xfer), M_DEVBUF,
+ 		((flags & IDE_NOSLEEP) != 0 ? M_NOWAIT : M_WAITOK));
+ 		if (!xfer) {
+ 			return 0;
+ 		}
+ #ifdef DIAGNOSTIC
+ 		xfer->c_flags &= ~C_INUSE;
+ #endif
+ #ifdef ATAPI_DEBUG
+ 		wdc_nxfer++;
+ #endif
+ 	}
+ #ifdef DIAGNOSTIC
+ 	if ((xfer->c_flags & C_INUSE) != 0) panic("xfer already in use\n");
+ #endif
+ 	bzero(xfer,sizeof(struct wdc_xfer));
+ 	xfer->c_flags = C_INUSE;
+ 	xfer->c_link = c_link;
+     return xfer;
+ }
+ 
+ void
+ wdc_free_xfer(xfer)
+     struct wdc_xfer *xfer;
+ {
+ 	int s;
+ 
+ 	s = splbio();
+     xfer->c_flags &= ~C_INUSE;
+     LIST_INSERT_HEAD(&xfer_free_list, xfer, free_list);
+ 	splx(s);
+ }
+ 
+ /*
+  * Implement operations needed before read/write.
+  * Returns 0 if operation still in progress, 1 if completed.
+  */
+ int
+ wdccontrol(d_link)
+     struct wd_link *d_link;
+ {
+     struct wdc_softc *wdc = (void *)d_link->wdc_softc;
+ #ifdef WDDEBUG
+     printf("wdccontrol\n");
+ #endif
+ 
+     switch (d_link->sc_state) {
+     case RECAL:         /* Set SDH, step rate, do recal. */
+         if (wdccommandshort(wdc, d_link->sc_drive, WDCC_RECAL) != 0) {
+             wderror(d_link, NULL, "wdccontrol: recal failed (1)");
+             goto bad;
+         }
+         d_link->sc_state = RECAL_WAIT;
+         break;
+ 
+ 
+     case RECAL_WAIT:
+         if (wdc->sc_status & WDCS_ERR) {
+             wderror(d_link, NULL, "wdccontrol: recal failed (2)");
+             goto bad;
+         }
+         /* fall through */
+     case GEOMETRY:
+         if ((d_link->sc_params.wdp_capabilities & WD_CAP_LBA) != 0)
+             goto multimode;
+         if (wdsetctlr(d_link) != 0) {
+             /* Already printed a message. */
+             goto bad;
+         }
+         d_link->sc_state = GEOMETRY_WAIT;
+         break;
+ 
+     case GEOMETRY_WAIT:
+         if (wdc->sc_status & WDCS_ERR) {
+             wderror(d_link, NULL, "wdccontrol: geometry failed");
+             goto bad;
+         }
+         /* fall through */
+     case MULTIMODE:
+     multimode:
+         if (d_link->sc_mode != WDM_PIOMULTI)
+             goto open;
+         outb(wdc->sc_iobase+wd_seccnt, d_link->sc_multiple);
+         if (wdccommandshort(wdc, d_link->sc_drive, WDCC_SETMULTI) != 0) {
+             wderror(d_link, NULL, "wdccontrol: setmulti failed (1)");
+             goto bad;
+         }
+         d_link->sc_state = MULTIMODE_WAIT;
+         break;
+ 
+     case MULTIMODE_WAIT:
+         if (wdc->sc_status & WDCS_ERR) {
+             wderror(d_link, NULL, "wdccontrol: setmulti failed (2)");
+             goto bad;
+         }
+         /* fall through */
+     case OPEN:
+     open:
+         wdc->sc_errors = 0;
+         d_link->sc_state = OPEN;
+         /*
+          * The rest of the initialization can be done by normal means.
+          */
+         return 1;
+ 
+     bad:
+         wdcunwedge(wdc);
+         return 0;
+     }
+ 
+     wdc->sc_flags |= WDCF_IRQ_WAIT;
+     timeout(wdctimeout, wdc, WAITTIME);
+     return 0;
+ }
+ 
+ /*
+  * Get the drive parameters, if ESDI or ATA, or create fake ones for ST506.
+  */
+ int
+ wdc_get_parms(d_link)
+     struct wd_link *d_link;
+ {
+     struct wdc_softc *wdc = (struct wdc_softc *)d_link->wdc_softc;
+     int i;
+     char tb[DEV_BSIZE];
+     int s, error;
+ 
+     /*
+      * XXX
+      * The locking done here, and the length of time this may keep the rest
+      * of the system suspended, is a kluge.  This should be rewritten to
+      * set up a transfer and queue it through wdstart(), but it's called
+      * infrequently enough that this isn't a pressing matter.
+      */
+ 
+     s = splbio();
+ 
+     while ((wdc->sc_flags & WDCF_ACTIVE) != 0) {
+         wdc->sc_flags |= WDCF_WANTED;
+         if ((error = tsleep(wdc, PRIBIO | PCATCH, "wdprm", 0)) != 0) {
+             splx(s);
+             return error;
+         }
+     }
+ 
+ 	wdc->sc_flags |= WDCF_ACTIVE;
+ 
+     if (wdccommandshort(wdc, d_link->sc_drive, WDCC_IDENTIFY) != 0 ||
+         wait_for_drq(wdc) != 0) {
+         /*
+          * We `know' there's a drive here; just assume it's old.
+          * This geometry is only used to read the MBR and print a
+          * (false) attach message.
+          */
+         strncpy(d_link->sc_lp->d_typename, "ST506",
+             sizeof d_link->sc_lp->d_typename);
+         d_link->sc_lp->d_type = DTYPE_ST506;
+ 
+         strncpy(d_link->sc_params.wdp_model, "unknown",
+             sizeof d_link->sc_params.wdp_model);
+         d_link->sc_params.wdp_config = WD_CFG_FIXED;
+         d_link->sc_params.wdp_cylinders = 1024;
+         d_link->sc_params.wdp_heads = 8;
+         d_link->sc_params.wdp_sectors = 17;
+         d_link->sc_params.wdp_maxmulti = 0;
+         d_link->sc_params.wdp_usedmovsd = 0;
+         d_link->sc_params.wdp_capabilities = 0;
+     } else {
+         strncpy(d_link->sc_lp->d_typename, "ESDI/IDE",
+             sizeof d_link->sc_lp->d_typename);
+         d_link->sc_lp->d_type = DTYPE_ESDI;
+ 
+         /* Read in parameter block. */
+         insw(wdc->sc_iobase+wd_data, tb, sizeof(tb) / sizeof(short));
+         bcopy(tb, &d_link->sc_params, sizeof(struct wdparams));
+ 
+         /* Shuffle string byte order. */
+         for (i = 0; i < sizeof(d_link->sc_params.wdp_model); i += 2) {
+             u_short *p;
+             p = (u_short *)(d_link->sc_params.wdp_model + i);
+             *p = ntohs(*p);
+         }
+     }
+ 
+     /* Clear any leftover interrupt. */
+     (void) inb(wdc->sc_iobase+wd_status);
+ 
+     /* Restart the queue. */
+ #ifdef WDDEBUG
+ 	printf("wdcstart from wdc_get_parms flags %d\n",wdc->sc_flags);
+ #endif
+ 	wdc->sc_flags &= ~WDCF_ACTIVE;
+     wdcstart(wdc);
+ 
+     splx(s);
+     return 0;
+ }
+ void
+ wdcerror(wdc, msg) 
+     struct wdc_softc *wdc;
+ 	char *msg;
+ {
+ 	struct wdc_xfer *xfer = wdc->sc_xfer.tqh_first;
+ 	if (xfer == NULL)
+ 		printf("%s: %s\n", wdc->sc_dev.dv_xname, msg);
+ 	else
+ 		printf("%s(%s): %s\n", wdc->sc_dev.dv_xname, 
+ 			((struct device*)xfer->d_link->wd_softc)->dv_xname, msg);
+  }
+ 
+ int wdc_atapi_get_params(ab_link, drive, id)
+ struct bus_link *ab_link;
+ u_int8_t drive;
+ struct atapi_identify *id;
+ {
+ 	struct wdc_softc *wdc = (void*)ab_link->wdc_softc;
+ 	int status, len, excess = 0;
+ 	int s, error;
+ 
+ 	if (wdc->d_link[drive] != 0) {
+ #ifdef ATAPI_DEBUG_PROBE
+ 		printf("wdc_atapi_get_params: WD drive %d\n", drive);
+ #endif
+ 		return 0;
+ 	}
+ 
+ 	/* If there is only one ATAPI slave ion the bus,don't probe
+ 	   drive 0 (master) */
+ 
+ 	if (wdc->sc_flags & WDCF_ONESLAVE && drive != 1)
+ 		return 0;
+ 
+ #ifdef ATAPI_DEBUG_PROBE
+ 	printf("wdc_atapi_get_params: probing drive %d\n", drive);
+ #endif
+ 
+     /*
+      * XXX
+      * The locking done here, and the length of time this may keep the rest
+      * of the system suspended, is a kluge.  This should be rewritten to
+      * set up a transfer and queue it through wdstart(), but it's called
+      * infrequently enough that this isn't a pressing matter.
+      */
+ 
+     s = splbio();
+ 
+     while ((wdc->sc_flags & WDCF_ACTIVE) != 0) {
+         wdc->sc_flags |= WDCF_WANTED;
+         if ((error = tsleep(wdc, PRIBIO | PCATCH, "atprm", 0)) != 0) {
+             splx(s);
+             return error;
+         }
+     }
+ 
+ 	wdc->sc_flags |= WDCF_ACTIVE;
+ 	error = 1;
+ 	(void)wdcreset(wdc);
+ 	if ((status = wdccommand((struct wd_link*)ab_link, ATAPI_SOFT_RESET, drive,
+ 		0, 0, 0, 0)) != 0) {
+ #ifdef ATAPI_DEBUG
+ 		printf("wdc_atapi_get_params: ATAPI_SOFT_RESET failed for drive %d: status %d error %d\n", drive, status, wdc->sc_error);
+ #endif
+ 		error = 0;
+ 		goto end;
+ 	} 
+ 	if ((status = wait_for_unbusy(wdc)) != 0 ) {
+ #ifdef ATAPI_DEBUG
+         printf("wdc_atapi_get_params: wait_for_unbusy failed for drive %d: status %d error %d\n", drive, status, wdc->sc_error);
+ #endif
+ 		error = 0;
+ 		goto end;
+ 	}
+ 
+ 	if (wdccommand((struct wd_link*)ab_link, ATAPI_IDENTIFY_DEVICE, drive, sizeof(struct atapi_identify), 0,
+ 	0, 0) != 0 || atapi_ready(wdc) != 0) {
+ #ifdef ATAPI_DEBUG_PROBE
+ 		printf("ATAPI_IDENTIFY_DEVICE failed for drive %d\n",drive);
+ #endif
+ 		error = 0;
+ 		goto end;
+ 	}
+ 	len = inb(wdc->sc_iobase + wd_cyl_lo) +
+ 		256 * inb(wdc->sc_iobase + wd_cyl_hi);
+ 	if (len != sizeof(struct atapi_identify)) {
+ 		printf("Warning drive %d returned %d/%d of indentify device data\n",
+ 			drive, len, sizeof(struct atapi_identify));
+ 		excess = len - sizeof(struct atapi_identify);
+ 		if (excess < 0) excess = 0;
+ 	}
+ 	insw(wdc->sc_iobase + wd_data, id,
+ 		sizeof(struct atapi_identify)/sizeof(short));
+ 	wdcbit_bucket(wdc, excess);
+ 
+ end: /* Restart the queue. */
+ #ifdef WDDEBUG
+ 	printf("wdcstart from wdc_atapi_get_parms flags %d\n",wdc->sc_flags);
+ #endif
+ 	wdc->sc_flags &= ~WDCF_ACTIVE;
+     wdcstart(wdc);
+ 	splx(s);
+ 	return error;
+ }
+ 	
+ 
+ void wdc_atapi_send_command_packet(ab_link, acp)
+ struct bus_link *ab_link;
+ struct atapi_command_packet *acp;
+ {
+ 	struct wdc_softc *wdc = (void*)ab_link->wdc_softc;
+ 	struct wdc_xfer *xfer;
+ 	int s;
+ 	u_int8_t flags = acp->flags & 0xff;
+ 	
+ 	if (flags & A_POLLED) {   /* Must use the queue and wdc_atapi_start */
+ 		struct wdc_xfer xfer_s;
+ 		int i;
+ #ifdef ATAPI_DEBUG_WDC
+ 		printf("wdc_atapi_send_cmd: flags %ld drive %d cmdlen %d datalen %d",
+ 		acp->flags, acp->drive, acp->command_size, acp->data_size);
+ #endif
+ 		xfer = &xfer_s;
+ 		bzero(xfer, sizeof(xfer_s));
+ 		xfer->c_flags = C_INUSE|C_ATAPI|acp->flags;
+ 		xfer->d_link = (struct wd_link*) ab_link;
+ 		xfer->c_link = ab_link->ctlr_link;
+ 		xfer->c_bp = acp->bp;
+ 		xfer->atapi_cmd = acp;
+ 		xfer->c_blkno = 0;
+ 		xfer->databuf = acp->databuf;
+ 		xfer->c_bcount = acp->data_size;
+ 		if (wait_for_unbusy (wdc) != 0) 
+ 			if (!(wdc->sc_status & WDCS_ERR)) {
+ 				printf ("wdc_atapi_send_command: not ready, st = %02x\n",wdc->sc_status);
+ 				acp->status = ERROR;
+ 				return;
+ 			}
+ 
+ 		if (wdccommand ((struct wd_link*)ab_link, ATAPI_PACKET_COMMAND,
+ 	acp->drive, acp->data_size, 0, 0, 0) != 0) {
+ 			printf("can't send atapi paket command\n");
+ 			acp->status = ERROR;
+ 			return;
+ 		}
+ 		/* Wait for cmd i/o phase. */
+ 		for (i=20000; i>0; --i) {
+ 			int phase;
+ 			phase = (inb(wdc->sc_iobase + wd_ireason) & (WDCI_CMD | WDCI_IN)) |
+ 				(inb(wdc->sc_iobase + 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
+ 
+ 		outsw (wdc->sc_iobase + wd_data, acp->command,
+ 			acp->command_size/ sizeof (short));
+ 		/* Wait for data i/o phase. */
+ 
+ 		for (i=20000; i>0; --i) {
+ 			int phase;
+ 			phase = (inb(wdc->sc_iobase + wd_ireason) & (WDCI_CMD | WDCI_IN)) |
+ 				(inb(wdc->sc_iobase + 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
+ 		while (wdc_atapi_intr(wdc, xfer)) {
+ 			for (i=2000; i>0; --i)
+ 				if (! (inb (wdc->sc_iobase + wd_status) & WDCS_DRQ))
+ 					break;
+ #ifdef ATAPI_DEBUG_WDC
+ 			printf("wdc_atapi_intr: i=%d\n", i);
+ #endif
+ 		}
+ 		wdc->sc_flags &= ~(WDCF_IRQ_WAIT | WDCF_SINGLE | WDCF_ERROR);
+ 		wdc->sc_errors = 0;
+ 		xfer->c_skip = 0;
+ 		return;
+ 	} else {   /* POLLED */
+ 		xfer = wdc_get_xfer(ab_link->ctlr_link, flags&A_NOSLEEP?IDE_NOSLEEP:0);
+ 		if (xfer == NULL) {
+ 			acp->status = ERROR;
+ 			return;
+ 		}
+ 		xfer->c_flags |= C_ATAPI|acp->flags;
+ 		xfer->d_link = (struct wd_link*) ab_link;
+ 		xfer->c_link = ab_link->ctlr_link;
+ 		xfer->c_bp = acp->bp;
+ 		xfer->atapi_cmd = acp;
+ 		xfer->c_blkno = 0;
+ 		xfer->databuf = acp->databuf;
+ 		xfer->c_bcount = acp->data_size;
+ 		wdc_exec_xfer((struct wd_link*)ab_link,xfer);
+ 		return;
+ 	}
+ }
+ 
+ 		
+ /* 
+    the bit bucket
+    */
+ void wdcbit_bucket (wdc, size)
+     struct wdc_softc *wdc; 
+     int size;
+ {
+     int iobase = wdc->sc_iobase; 
+     int i;
+  
+     for (i = 0 ; i < size / 2 ; i++) {
+     short null; 
+     (void) insw (iobase + wd_data, &null, 1);
+     } 
+  
+     if (size % 2)
+     (void) inb (iobase + wd_data);
+ 
+ }
+ 
+ int wdc_atapi_intr(wdc, xfer)
+ struct wdc_softc *wdc;
+ struct wdc_xfer *xfer;
+ {
+ 	int len, phase, i;
+ 	int err, st, ire;
+ 	struct atapi_command_packet *acp = xfer->atapi_cmd;
+ 	if (wait_for_unbusy(wdc)<0) {
+ 		printf("wdc_atapi_intr: controller busy\n");
+ 		acp->status = ERROR;
+ 		acp->error = inb (wdc->sc_iobase + wd_error);
+ 		return 0;
+ 	}
+ #ifdef ATAPI_DEBUG2
+      printf("wdc_atapi_intr: %s\n", wdc->sc_dev.dv_xname);
+ #endif
+ 
+ 	len = inb (wdc->sc_iobase + wd_cyl_lo) +
+ 	256 * inb (wdc->sc_iobase + wd_cyl_hi);
+ 
+ 	st = inb(wdc->sc_iobase + wd_status);
+ 	err = inb(wdc->sc_iobase + wd_error);
+ 	ire = inb(wdc->sc_iobase + wd_ireason);
+ 	
+ 	phase = (ire & (WDCI_CMD | WDCI_IN)) | (st & WDCS_DRQ);
+ #ifdef ATAPI_DEBUG_WDC
+ 	printf("wdc_atapi_intr: len %d st %d err %d ire %d :", len, st, err, ire);
+ #endif
+ 	switch (phase) {
+ 
+ 	case PHASE_CMDOUT:
+ 		/* send packet command */
+ #ifdef ATAPI_DEBUG_WDC
+ 		printf("PHASE_CMDOUT\n");
+ #endif
+ 
+ #ifdef ATAPI_DEBUG_WDC
+ 		{
+ 		int i;
+ 		char *c = (char*)acp->command;   
+ 		printf("wdc_atapi_intr: cmd ");
+ 		for(i=0;i<acp->command_size;i++) printf("%x ",c[i]);
+ 		printf("\n");
+ 		}
+ #endif
+ 
+ 		wdc->sc_flags |= WDCF_IRQ_WAIT;
+ 		outsw (wdc->sc_iobase + wd_data, acp->command,
+ 			acp->command_size/ sizeof (short));
+ 		return 1;
+ 
+ 	case PHASE_DATAOUT:
+ 		/* write data */
+ #ifdef ATAPI_DEBUG_WDC
+ 		printf("PHASE_DATAOUT\n");
+ #endif
+ 		if ((acp->flags & (B_READ|B_WRITE)) != B_WRITE) {
+ 			printf("wdc_atapi_intr: bad data phase\n");
+ 			acp->status = ERROR;
+ 			return 1;
+ 		}
+ 		wdc->sc_flags |= WDCF_IRQ_WAIT;
+ 		if (xfer->c_bcount < len) {
+ 			printf("wdc_atapi_intr: warning: write only %d of %d requested bytes\n",
+ 			xfer->c_bcount, len);
+ 			outsw (wdc->sc_iobase + wd_data, xfer->databuf+xfer->c_skip,
+ 						xfer->c_bcount/sizeof (short));
+ 			for(i = xfer->c_bcount; i<len; i+=sizeof(short))
+ 				outw(wdc->sc_iobase + wd_data, 0);
+ 			xfer->c_bcount = 0;
+ 			return 1;
+ 		} else {
+ 			outsw (wdc->sc_iobase + wd_data, xfer->databuf+xfer->c_skip,
+ 					len/sizeof (short));
+ 			xfer->c_skip += len;
+ 			xfer->c_bcount -= len;
+ 			return 1;
+ 		}
+ 	
+ 		case PHASE_DATAIN:
+ 			/* Read data */
+ #ifdef ATAPI_DEBUG_WDC
+ 		printf("PHASE_DATAIN\n");
+ #endif
+ 		if ((acp->flags & (B_READ|B_WRITE)) != B_READ) {
+ 			printf("wdc_atapi_intr: bad data phase\n");
+ 			acp->status = ERROR;
+ 			return 1;
+ 		}
+ 		wdc->sc_flags |= WDCF_IRQ_WAIT;
+ 		if (xfer->c_bcount < len) {
+ 			printf("wdc_atapi_intr: warning: reading only %d of %d bytes\n",
+ 				xfer->c_bcount, len);
+ 			insw(wdc->sc_iobase + wd_data, xfer->databuf+xfer->c_skip,
+ 				xfer->c_bcount/sizeof(short));
+ 			wdcbit_bucket(wdc, len - xfer->c_bcount);
+ 			xfer->c_bcount = 0;
+ 			return 1;
+ 		} else {
+ 			insw(wdc->sc_iobase + wd_data, xfer->databuf+xfer->c_skip,
+ 				len/sizeof(short));
+ 			xfer->c_skip += len;
+ 			xfer->c_bcount -=len;
+ 			return 1;
+ 		}
+ 		case PHASE_ABORTED:
+ 		case PHASE_COMPLETED:
+ #ifdef ATAPI_DEBUG_WDC
+ 		printf("PHASE_COMPLETED\n");
+ #endif
+ 		if (st & WDCS_ERR)  {
+ 			acp->error = inb (wdc->sc_iobase + wd_error);
+ 			acp->status = ERROR;
+ 		}
+ #ifdef ATAPI_DEBUG_WDC
+ 		if (xfer->c_bcount != 0) {
+ 			printf("wdc_atapi_intr warning: bcount value is %d after io\n",
+ 				xfer->c_bcount );
+ 		}
+ #endif
+ 		break;
+ 		default: 
+ 			printf("wdc_atapi_intr: unknown phase %d\n", phase);
+ 			acp->status = ERROR;
+ 	}
+ 	wdc_atapi_done(wdc, xfer);
+ 	return(0);
+ }
+ 
+ 
+ void
+ wdc_atapi_done(wdc, xfer)
+ struct wdc_softc *wdc;
+ struct wdc_xfer *xfer;
+ {
+ 	struct atapi_command_packet *acp = xfer->atapi_cmd;
+ 	int s;
+ 
+ 	acp->data_size = xfer->c_bcount;
+ 	s = splbio();
+ 	/* remove this command from xfer queue */
+ 	wdc->sc_errors = 0;
+ 	xfer->c_skip = 0;
+ 	if ((xfer->c_flags & A_POLLED) == 0) {
+ 		untimeout(wdctimeout, wdc);
+ 		TAILQ_REMOVE(&wdc->sc_xfer, xfer, c_xferchain);
+ 		wdc->sc_flags &= ~(WDCF_SINGLE | WDCF_ERROR | WDCF_ACTIVE);
+ 		wdc_free_xfer(xfer);
+ #ifdef ATAPI_DEBU
+ 		printf("wdc_atapi_done: atapi_done\n");
+ #endif
+ 		atapi_done(acp);
+ #ifdef WDDEBUG
+        	printf("wdcstart from wdc_atapi_intr, flags %d\n",wdc->sc_flags);
+ #endif
+ 		wdcstart(wdc);
+ 	} else {
+ 		wdc->sc_flags &= ~(WDCF_SINGLE | WDCF_ERROR | WDCF_ACTIVE);
+ 	}
+ 	splx(s);
+ }
diff -c -r -N --exclude exp --exclude compile sys/arch/arm32.orig/mainbus/wdlink.h sys/arch/arm32/mainbus/wdlink.h
*** sys/arch/arm32.orig/mainbus/wdlink.h	Thu Jan  1 01:00:00 1970
--- sys/arch/arm32/mainbus/wdlink.h	Thu Jun 13 02:57:04 1996
***************
*** 0 ****
--- 1,112 ----
+ /*
+  * Copyright (c) 1994, 1995 Charles M. Hannum.  All rights reserved.
+  *
+  * DMA and multi-sector PIO handling are derived from code contributed by
+  * Onno van der Linden.
+  *
+  * Atapi support added by Manuel Bouyer.
+  *
+  * 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, 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. All advertising materials mentioning features or use of this software
+  *    must display the following acknowledgement:
+  *  This product includes software developed by Charles M. Hannum.
+  * 4. The name of the author may not be used to endorse or promote products
+  *    derived from this software without specific prior written permission.
+  *
+  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+  * IN NO EVENT SHALL THE AUTHOR 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.
+  */
+ 
+ 
+ #undef WDDEBUG
+ /* #undef DIAGNOSTIC */
+ 
+ struct wdc_link {
+ 	int flags;
+ 	int openings;
+ };
+ 
+ struct wd_link {
+ 	u_char type;  
+ #define DRIVE 0
+ #define BUS 1
+ 	caddr_t wdc_softc;
+ 	caddr_t wd_softc;
+ 	struct wdc_link *ctlr_link;
+ 	struct wdparams sc_params;
+     /* Long-term state: */
+ 	u_int8_t openings;
+     int sc_drive;                   /* physical unit number */
+     int sc_state;                   /* control state */
+ #define RECAL           0               /* recalibrate */
+ #define RECAL_WAIT      1               /* done recalibrating */
+ #define GEOMETRY        2               /* upload geometry */
+ #define GEOMETRY_WAIT   3               /* done uploading geometry */
+ #define MULTIMODE       4               /* set multiple mode */
+ #define MULTIMODE_WAIT  5               /* done setting multiple mode */
+ #define OPEN            6               /* done with open */
+     int sc_mode;                    /* transfer mode */
+ #define WDM_PIOSINGLE   0               /* single-sector PIO */
+ #define WDM_PIOMULTI    1               /* multi-sector PIO */
+ #define WDM_DMA         2               /* DMA */
+     int sc_multiple;                /* multiple for WDM_PIOMULTI */
+     int sc_flags;                   /* drive characteistics found */
+ #define WDF_LOCKED      0x01
+ #define WDF_WANTED      0x02
+ #define WDF_WLABEL      0x04            /* label is writable */
+ #define WDF_LABELLING   0x08            /* writing label */
+ /* XXX Nothing resets this yet, but disk change sensing will when ATAPI is
+    implemented. */
+ #define WDF_LOADED      0x10            /* parameters loaded */
+ #define WDF_32BIT       0x20            /* can do 32-bit transfer */
+ #define WDF_WAIT 		0x40			/* waiting for resourses */
+     daddr_t sc_badsect[127];        /* 126 plus trailing -1 marker */
+ 	struct disklabel * sc_lp;	/* label info for this disk */
+ };
+ 
+ struct wdc_xfer {
+     struct wdc_link *c_link;   /* controller structure info */
+     struct wd_link *d_link;   /* drive/bus structure info */
+ 	volatile long c_flags; /* handle also B_READ and B_WRITE */
+ #define C_INUSE 0x01
+ #define C_ATAPI 0x02
+ #define C_ERROR 0x04
+ 	/* Information about the current transfer  */
+ 	struct buf *c_bp;
+ 	void *atapi_cmd;
+ 	void* databuf;
+ 	daddr_t c_blkno;       /* starting block number */
+ 	int c_bcount;          /* byte count left */
+ 	int c_skip;            /* bytes already transferred */
+ 	int c_nblks;           /* number of blocks currently transferring */
+ 	int c_nbytes;          /* number of bytes currently transferring */
+ 	u_long c_p_offset;  /* offset of the partition */
+ 	TAILQ_ENTRY(wdc_xfer) c_xferchain;
+ 	LIST_ENTRY(wdc_xfer) free_list;
+ };
+ 
+ 
+ void wdc_exec_xfer __P((struct wd_link *, struct wdc_xfer *));
+ struct wdc_xfer * wdc_get_xfer __P((struct wdc_link *, int));
+ int wdc_get_parms __P((struct wd_link *));
+ void wderror __P((struct wd_link* , struct buf *, char *));
+ void wddone __P((struct wd_link*, struct buf*));
+ int wdccommand __P((struct wd_link *, int, int, int, int, int, int));
+ int wdcdumpprecalibrated __P((struct wd_link *));
+ 
+ #define IDE_NOSLEEP 0x01
diff -c -r -N --exclude exp --exclude compile sys/arch/arm32.orig/mainbus/wdreg.h sys/arch/arm32/mainbus/wdreg.h
*** sys/arch/arm32.orig/mainbus/wdreg.h	Sun May 12 22:34:06 1996
--- sys/arch/arm32/mainbus/wdreg.h	Thu Jun 13 02:57:04 1996
***************
*** 47,52 ****
--- 47,53 ----
  #define	wd_precomp	0x004	/* write precompensation (W) */
  #define	wd_features	0x004	/* features (W) */
  #define	wd_seccnt	0x008	/* sector count (R/W) */
+ #define wd_ireason	0x008   /* interrupt reason (R/W) (for atapi) */
  #define	wd_sector	0x00c	/* first sector number (R/W) */
  #define	wd_cyl_lo	0x010	/* cylinder address, low byte (R/W) */
  #define	wd_cyl_hi	0x014	/* cylinder address, high byte (R/W) */
***************
*** 119,124 ****
--- 120,147 ----
  #define	WDSD_CHS	0x00	/* cylinder/head/sector addressing */
  #define	WDSD_LBA	0x40	/* logical block addressing */
  
+ /* Commands for ATAPI devices */
+ #define ATAPI_CHECK_POWER_MODE      0xe5
+ #define ATAPI_EXEC_DRIVE_DIAGS      0x90
+ #define ATAPI_IDLE_IMMEDIATE        0xe1
+ #define ATAPI_NOP           0x00
+ #define ATAPI_PACKET_COMMAND        0xa0
+ #define ATAPI_IDENTIFY_DEVICE       0xa1
+ #define ATAPI_SOFT_RESET        0x08
+ #define ATAPI_SET_FEATURES      0xef
+ #define ATAPI_SLEEP         0xe6
+ #define ATAPI_STANDBY_IMMEDIATE     0xe0
+ 
+ /* ireason */
+ #define WDCI_CMD         0x01    /* command(1) or data(0) */
+ #define WDCI_IN          0x02    /* transfer to(1) or from(0) the host */
+ #define WDCI_RELEASE     0x04    /* bus released until completion */
+ 
+ #define PHASE_CMDOUT    (WDCS_DRQ | WDCI_CMD)
+ #define PHASE_DATAIN    (WDCS_DRQ | WDCI_IN)
+ #define PHASE_DATAOUT   WDCS_DRQ
+ #define PHASE_COMPLETED (WDCI_IN | WDCI_CMD)
+ #define PHASE_ABORTED   0
  
  #ifdef _KERNEL
  /*
