xref: /csrg-svn/sys/i386/isa/wd.c (revision 43592)
141056Swilliam /*-
241056Swilliam  * Copyright (c) 1990 The Regents of the University of California.
341056Swilliam  * All rights reserved.
441056Swilliam  *
541056Swilliam  * This code is derived from software contributed to Berkeley by
641056Swilliam  * William Jolitz.
741056Swilliam  *
841056Swilliam  * %sccs.include.386.c%
941056Swilliam  *
10*43592Sdonahn  *	@(#)wd.c	5.2 (Berkeley) 06/23/90
1141056Swilliam  */
12*43592Sdonahn 
1341056Swilliam #include "wd.h"
1441056Swilliam #if	NWD > 0
1541056Swilliam 
1641056Swilliam #include "param.h"
1741056Swilliam #include "dkbad.h"
1841056Swilliam #include "systm.h"
1941056Swilliam #include "conf.h"
2041056Swilliam #include "file.h"
2141056Swilliam #include "dir.h"
2241056Swilliam #include "user.h"
2341056Swilliam #include "ioctl.h"
2441056Swilliam #include "disk.h"
2541056Swilliam #include "buf.h"
2641056Swilliam #include "vm.h"
2741056Swilliam #include "uio.h"
2841056Swilliam #include "machine/pte.h"
2941056Swilliam #include "machine/device.h"
3041056Swilliam #include "atio.h"
3141056Swilliam #include "icu.h"
3241056Swilliam #include "wdreg.h"
3341056Swilliam #include "syslog.h"
3441056Swilliam 
3541056Swilliam #define	RETRIES		5	/* number of retries before giving up */
3641056Swilliam #define	MAXTRANSFER	256	/* max size of transfer in page clusters */
3741056Swilliam 
3841056Swilliam #define WDUNIT(dev)	((minor(dev) & 070) >> 3)
3941056Swilliam 
4041056Swilliam #define b_cylin	b_resid		/* cylinder number for doing IO to */
4141056Swilliam 				/* shares an entry in the buf struct */
4241056Swilliam 
4341056Swilliam /*
4441056Swilliam  * Drive states.  Used for open and format operations.
4541056Swilliam  * States < OPEN (> 0) are transient, during an open operation.
4641056Swilliam  * OPENRAW is used for unlabeled disks, and for floppies, to inhibit
4741056Swilliam  * bad-sector forwarding.
4841056Swilliam  */
4941056Swilliam #define RAWDISK		8		/* raw disk operation, no translation*/
5041056Swilliam #define ISRAWSTATE(s)	(RAWDISK&(s))	/* are we in a raw state? */
5141056Swilliam #define DISKSTATE(s)	(~RAWDISK&(s))	/* are we in a given state regardless
5241056Swilliam 					   of raw or cooked mode? */
5341056Swilliam 
5441056Swilliam #define	CLOSED		0		/* disk is closed. */
5541056Swilliam 					/* "cooked" disk states */
5641056Swilliam #define	WANTOPEN	1		/* open requested, not started */
5741056Swilliam #define	RECAL		2		/* doing restore */
5841056Swilliam #define	RDLABEL		3		/* reading pack label */
5941056Swilliam #define	RDBADTBL	4		/* reading bad-sector table */
6041056Swilliam #define	OPEN		5		/* done with open */
6141056Swilliam 
6241056Swilliam #define	WANTOPENRAW	(WANTOPEN|RAWDISK)	/* raw WANTOPEN */
6341056Swilliam #define	RECALRAW	(RECAL|RAWDISK)	/* raw open, doing restore */
6441056Swilliam #define	OPENRAW		(OPEN|RAWDISK)	/* open, but unlabeled disk or floppy */
6541056Swilliam 
6641056Swilliam 
6741056Swilliam /*
6841056Swilliam  * The structure of a disk drive.
6941056Swilliam  */
7041056Swilliam struct	disk {
7141056Swilliam 	struct disklabel dk_dd;			/* device configuration data */
7241056Swilliam 	long	dk_bc;				/* byte count left */
7341056Swilliam 	short	dk_skip;			/* blocks already transferred */
7441056Swilliam 	char	dk_unit;			/* physical unit number */
7541056Swilliam 	char	dk_sdh;				/* sdh prototype */
7641056Swilliam 	char	dk_state;			/* control state */
7741056Swilliam 	u_char	dk_status;			/* copy of status reg. */
7841056Swilliam 	u_char	dk_error;			/* copy of error reg. */
7941056Swilliam 	short	dk_open;			/* open/closed refcnt */
8041056Swilliam };
8141056Swilliam 
8241056Swilliam /*
8341056Swilliam  * This label is used as a default when initializing a new or raw disk.
8441056Swilliam  * It really only lets us access the first track until we know more.
8541056Swilliam  */
8641056Swilliam struct disklabel dflt_sizes = {
8741056Swilliam 	DISKMAGIC, DTYPE_ST506,
8841056Swilliam 	{
8941056Swilliam 		512,		/* sector size */
9041056Swilliam 		17,		/* # of sectors per track */
9141056Swilliam 		15,		/* # of tracks per cylinder */
9241056Swilliam 		918,		/* # of cylinders per unit */
9341056Swilliam 		17*15,		/* # of sectors per cylinder */
9441056Swilliam 		918*15*17,	/* # of sectors per unit */
9541056Swilliam 		0		/* write precomp cylinder (none) */
9641056Swilliam 	},
9741056Swilliam 	7560,	0,	/* A=root filesystem */
9841056Swilliam 	7560,	56,
9941056Swilliam 	123930, 0,	/* C=whole disk */
10041056Swilliam 	0,	0,
10141056Swilliam 	7560,	861,
10241056Swilliam 	0,	0,
10341056Swilliam 	0,	0,
10441056Swilliam 	101115,	112
10541056Swilliam };
10641056Swilliam static	struct	dkbad	dkbad[NWD];
10741056Swilliam struct	disk	wddrives[NWD] = {0};	/* table of units */
10841056Swilliam struct	buf	wdtab = {0};
10941056Swilliam struct	buf	wdutab[NWD] = {0};	/* head of queue per drive */
11041056Swilliam struct	buf	rwdbuf[NWD] = {0};	/* buffers for raw IO */
11141056Swilliam long	wdxfer[NWD] = {0};		/* count of transfers */
11241056Swilliam int	writeprotected[NWD] = { 0 };
11341056Swilliam int	wdprobe(), wdattach(), wdintr();
11441056Swilliam struct	driver wddriver = {
11541056Swilliam 	wdprobe, wdattach, "wd",
11641056Swilliam };
11741056Swilliam #include "dbg.h"
11841056Swilliam 
11941056Swilliam /*
12041056Swilliam  * Probe routine
12141056Swilliam  */
12241056Swilliam wdprobe(dvp)
12341056Swilliam 	struct device *dvp;
12441056Swilliam {
12541056Swilliam 	register wdc = dvp->ioa;
12641056Swilliam 
12741056Swilliam #ifdef lint
12841056Swilliam 	wdintr(0);
12941056Swilliam #endif
13041056Swilliam 	outb(wdc+wd_error, 0x5a) ;	/* error register not writable */
13141056Swilliam 	/*wdp->wd_cyl_hi = 0xff ;/* only two bits of cylhi are implemented */
13241056Swilliam 	outb(wdc+wd_cyl_lo, 0xa5) ;	/* but all of cyllo are implemented */
13341056Swilliam 	if(inb(wdc+wd_error) != 0x5a /*&& wdp->wd_cyl_hi == 3*/
13441056Swilliam 	   && inb(wdc+wd_cyl_lo) == 0xa5)
13541056Swilliam 		return(1) ;
13641056Swilliam 	return (0);
13741056Swilliam }
13841056Swilliam 
13941056Swilliam /*
14041056Swilliam  * attach each drive if possible.
14141056Swilliam  */
14241056Swilliam wdattach(dvp)
14341056Swilliam 	struct device *dvp;
14441056Swilliam {
14541056Swilliam 	int unit = dvp->unit;
14641056Swilliam 
14741056Swilliam 	INTREN((IRQ14|4));
14841056Swilliam 	outb(0x3f6,0);
14941056Swilliam }
15041056Swilliam 
15141056Swilliam /* Read/write routine for a buffer.  Finds the proper unit, range checks
15241056Swilliam  * arguments, and schedules the transfer.  Does not wait for the transfer
15341056Swilliam  * to complete.  Multi-page transfers are supported.  All I/O requests must
15441056Swilliam  * be a multiple of a sector in length.
15541056Swilliam  */
15641056Swilliam wdstrategy(bp)
15741056Swilliam 	register struct buf *bp;	/* IO operation to perform */
15841056Swilliam {
15941056Swilliam 	register struct buf *dp;
16041056Swilliam 	register struct disk *du;	/* Disk unit to do the IO.	*/
16141056Swilliam 	long nblocks, cyloff, blknum;
16241056Swilliam 	int	unit = WDUNIT(bp->b_dev), xunit = minor(bp->b_dev) & 7;
16341056Swilliam 	int	s;
16441056Swilliam 
16541056Swilliam 	if ((unit >= NWD) || (bp->b_blkno < 0)) {
166*43592Sdonahn 		printf("wdstrat: unit = %d, blkno = %d, bcount = %d\n",
16741056Swilliam 			unit, bp->b_blkno, bp->b_bcount);
168*43592Sdonahn 		pg("wd:error in wdstrategy");
16941056Swilliam 		bp->b_flags |= B_ERROR;
17041056Swilliam 		goto bad;
17141056Swilliam 	}
17241056Swilliam 	if (writeprotected[unit] && (bp->b_flags & B_READ) == 0) {
17341056Swilliam 		printf("wd%d: write protected\n", unit);
17441056Swilliam 		goto bad;
17541056Swilliam 	}
17641056Swilliam 	du = &wddrives[unit];
17741056Swilliam 	if (DISKSTATE(du->dk_state) != OPEN)
17841056Swilliam 		goto q;
17941056Swilliam 	/*
18041056Swilliam 	 * Convert DEV_BSIZE "blocks" to sectors.
18141056Swilliam 	 * Note: doing the conversions this way limits the partition size
18241056Swilliam 	 * to about 8 million sectors (1-8 Gb).
18341056Swilliam 	 */
18441056Swilliam 	blknum = (unsigned long) bp->b_blkno * DEV_BSIZE / du->dk_dd.dk_secsize;
18541056Swilliam 	if (((u_long) bp->b_blkno * DEV_BSIZE % du->dk_dd.dk_secsize != 0) ||
186*43592Sdonahn 	    bp->b_bcount >= MAXTRANSFER * CLBYTES) {
18741056Swilliam 		bp->b_flags |= B_ERROR;
18841056Swilliam 		goto bad;
18941056Swilliam 	}
19041056Swilliam 	nblocks = du->dk_dd.dk_partition[xunit].nblocks;
19141056Swilliam 	cyloff = du->dk_dd.dk_partition[xunit].cyloff;
19241056Swilliam 	if (blknum + (bp->b_bcount / du->dk_dd.dk_secsize) > nblocks) {
19341056Swilliam 		if (blknum == nblocks)
19441056Swilliam 			bp->b_resid = bp->b_bcount;
19541056Swilliam 		else
19641056Swilliam 			bp->b_flags |= B_ERROR;
19741056Swilliam 		goto bad;
19841056Swilliam 	}
19941056Swilliam 	bp->b_cylin = blknum / du->dk_dd.dk_secpercyl + cyloff;
20041056Swilliam q:
20141056Swilliam 	dp = &wdutab[unit];
20241056Swilliam 	s = splbio();
20341056Swilliam 	disksort(dp, bp);
20441056Swilliam 	if (dp->b_active == 0)
20541056Swilliam 		wdustart(du);		/* start drive if idle */
20641056Swilliam 	if (wdtab.b_active == 0)
20741056Swilliam 		wdstart(s);		/* start IO if controller idle */
20841056Swilliam 	splx(s);
20941056Swilliam 	return;
21041056Swilliam 
21141056Swilliam bad:
21241056Swilliam 	bp->b_error = EINVAL;
21341056Swilliam 	biodone(bp);
21441056Swilliam }
21541056Swilliam 
21641056Swilliam /* Routine to queue a read or write command to the controller.  The request is
21741056Swilliam  * linked into the active list for the controller.  If the controller is idle,
21841056Swilliam  * the transfer is started.
21941056Swilliam  */
22041056Swilliam wdustart(du)
22141056Swilliam 	register struct disk *du;
22241056Swilliam {
22341056Swilliam 	register struct buf *bp, *dp;
22441056Swilliam 
22541056Swilliam 	dp = &wdutab[du->dk_unit];
22641056Swilliam 	if (dp->b_active)
22741056Swilliam 		return;
22841056Swilliam 	bp = dp->b_actf;
22941056Swilliam 	if (bp == NULL)
23041056Swilliam 		return;
23141056Swilliam 	dp->b_forw = NULL;
23241056Swilliam 	if (wdtab.b_actf  == NULL)		/* link unit into active list */
23341056Swilliam 		wdtab.b_actf = dp;
23441056Swilliam 	else
23541056Swilliam 		wdtab.b_actl->b_forw = dp;
23641056Swilliam 	wdtab.b_actl = dp;
23741056Swilliam 	dp->b_active = 1;		/* mark the drive as busy */
23841056Swilliam }
23941056Swilliam 
24041056Swilliam /*
24141056Swilliam  * Controller startup routine.  This does the calculation, and starts
24241056Swilliam  * a single-sector read or write operation.  Called to start a transfer,
24341056Swilliam  * or from the interrupt routine to continue a multi-sector transfer.
24441056Swilliam  * RESTRICTIONS:
24541056Swilliam  * 1.	The transfer length must be an exact multiple of the sector size.
24641056Swilliam  */
24741056Swilliam 
24841056Swilliam wdstart()
24941056Swilliam {
25041056Swilliam 	register struct disk *du;	/* disk unit for IO */
25141056Swilliam 	register wdc = IO_WD0; /*XXX*/
25241056Swilliam 	register struct buf *bp;
25341056Swilliam 	struct buf *dp;
25441056Swilliam 	register struct bt_bad *bt_ptr;
25541056Swilliam 	long	blknum, pagcnt, cylin, head, sector;
25641056Swilliam 	long	secpertrk, secpercyl, addr, i;
25741056Swilliam 	int	minor_dev, unit, s;
25841056Swilliam 
25941056Swilliam loop:
26041056Swilliam 	dp = wdtab.b_actf;
26141056Swilliam 	if (dp == NULL)
26241056Swilliam 		return;
26341056Swilliam 	bp = dp->b_actf;
26441056Swilliam 	if (bp == NULL) {
26541056Swilliam 		wdtab.b_actf = dp->b_forw;
26641056Swilliam 		goto loop;
26741056Swilliam 	}
26841056Swilliam 	unit = WDUNIT(bp->b_dev);
26941056Swilliam 	du = &wddrives[unit];
27041056Swilliam 	if (DISKSTATE(du->dk_state) <= RDLABEL) {
27141056Swilliam 		if (wdcontrol(bp)) {
27241056Swilliam 			dp->b_actf = bp->av_forw;
27341056Swilliam 			goto loop;	/* done */
27441056Swilliam 		}
27541056Swilliam 		return;
27641056Swilliam 	}
27741056Swilliam 	minor_dev = minor(bp->b_dev) & 7;
27841056Swilliam 	secpertrk = du->dk_dd.dk_nsectors;
27941056Swilliam 	secpercyl = du->dk_dd.dk_secpercyl;
28041056Swilliam 	/*
28141056Swilliam 	 * Convert DEV_BSIZE "blocks" to sectors.
28241056Swilliam 	 */
28341056Swilliam 	blknum = (unsigned long) bp->b_blkno * DEV_BSIZE / du->dk_dd.dk_secsize
28441056Swilliam 		+ du->dk_skip;
28541056Swilliam #ifdef	WDDEBUG
28641056Swilliam 	if (du->dk_skip == 0) {
28741056Swilliam 		dprintf(DDSK,"\nwdstart %d: %s %d@%d; map ", unit,
28841056Swilliam 			(bp->b_flags & B_READ) ? "read" : "write",
28941056Swilliam 			bp->b_bcount, blknum);
29041056Swilliam 	} else {
29141056Swilliam 		dprintf(DDSK," %d)", du->dk_skip);
29241056Swilliam 	}
29341056Swilliam #endif
29441056Swilliam 
29541056Swilliam 	addr = (int) bp->b_un.b_addr;
29641056Swilliam 	if(du->dk_skip==0) du->dk_bc = bp->b_bcount;
29741056Swilliam 	cylin = blknum / secpercyl;
29841056Swilliam 	head = (blknum % secpercyl) / secpertrk;
29941056Swilliam 	sector = blknum % secpertrk + 1;
30041056Swilliam 	if (DISKSTATE(du->dk_state) == OPEN)
30141056Swilliam 		cylin += du->dk_dd.dk_partition[minor_dev].cyloff;
30241056Swilliam 
30341056Swilliam 
30441056Swilliam 	/*
30541056Swilliam 	 * See if the current block is in the bad block list.
30641056Swilliam 	 * (If we have one, and not formatting.)
30741056Swilliam 	 */
30841056Swilliam #ifdef notyet
30941056Swilliam 	if (du->dk_state == OPEN)
31041056Swilliam 	    for (bt_ptr = dkbad[unit].bt_bad; bt_ptr->bt_cyl != -1; bt_ptr++) {
31141056Swilliam 		if (bt_ptr->bt_cyl > cylin)
31241056Swilliam 			/* Sorted list, and we passed our cylinder. quit. */
31341056Swilliam 			break;
31441056Swilliam 		if (bt_ptr->bt_cyl == cylin &&
31541056Swilliam 				bt_ptr->bt_trksec == (head << 8) + sector) {
31641056Swilliam 			/*
31741056Swilliam 			 * Found bad block.  Calculate new block addr.
31841056Swilliam 			 * This starts at the end of the disk (skip the
31941056Swilliam 			 * last track which is used for the bad block list),
32041056Swilliam 			 * and works backwards to the front of the disk.
32141056Swilliam 			 */
32241056Swilliam #ifdef	WDDEBUG
32341056Swilliam 			    dprintf(DDSK,"--- badblock code -> Old = %d; ",
32441056Swilliam 				blknum);
32541056Swilliam #endif
32641056Swilliam 			blknum = du->dk_dd.dk_secperunit - du->dk_dd.dk_nsectors
32741056Swilliam 				- (bt_ptr - dkbad[unit].bt_bad) - 1;
32841056Swilliam 			cylin = blknum / secpercyl;
32941056Swilliam 			head = (blknum % secpercyl) / secpertrk;
33041056Swilliam 			sector = blknum % secpertrk;
33141056Swilliam #ifdef	WDDEBUG
33241056Swilliam 			    dprintf(DDSK, "new = %d\n", blknum);
33341056Swilliam #endif
33441056Swilliam 			break;
33541056Swilliam 		}
33641056Swilliam 	}
33741056Swilliam #endif
33841056Swilliam 
33941056Swilliam 	wdtab.b_active = 1;		/* mark controller active */
34041056Swilliam 
34141056Swilliam 	outb(wdc+wd_precomp, 0xff);
34241056Swilliam 	/*wr(wdc+wd_precomp, du->dk_dd.dk_precompcyl / 4);*/
34341056Swilliam 	/*if (bp->b_flags & B_FORMAT) {
34441056Swilliam 		wr(wdc+wd_sector, du->dk_dd.dk_gap3);
34541056Swilliam 		wr(wdc+wd_seccnt, du->dk_dd.dk_nsectors);
34641056Swilliam 	} else {*/
34741056Swilliam 	outb(wdc+wd_seccnt, 1);
34841056Swilliam 	outb(wdc+wd_sector, sector);
34941056Swilliam 
35041056Swilliam 	outb(wdc+wd_cyl_lo, cylin);
35141056Swilliam 	outb(wdc+wd_cyl_hi, cylin >> 8);
35241056Swilliam 
35341056Swilliam 	/* Set up the SDH register (select drive).     */
35441056Swilliam 	outb(wdc+wd_sdh, WDSD_IBM | (unit<<4) | (head & 0xf));
35541056Swilliam 	while ((inb(wdc+wd_altsts) & WDCS_READY) == 0) ;
35641056Swilliam 
35741056Swilliam 	/*if (bp->b_flags & B_FORMAT)
35841056Swilliam 		wr(wdc+wd_command, WDCC_FORMAT);
35941056Swilliam 	else*/
36041056Swilliam 		outb(wdc+wd_command,
36141056Swilliam 			(bp->b_flags & B_READ)? WDCC_READ : WDCC_WRITE);
36241056Swilliam #ifdef	WDDEBUG
36341056Swilliam 	if(du->dk_skip == 0)
36441056Swilliam 	dprintf(DDSK,"sector %d cylin %d head %d addr %x\n",
36541056Swilliam 	    sector, cylin, head, addr);
36641056Swilliam #endif
36741056Swilliam 
36841056Swilliam 
36941056Swilliam 	/* If this is a read operation, just go away until it's done.	*/
37041056Swilliam 	if (bp->b_flags & B_READ) return;
37141056Swilliam 
37241056Swilliam 	/* Ready to send data?	*/
37341056Swilliam 	while ((inb(wdc+wd_altsts) & WDCS_DRQ) == 0)
37441056Swilliam 		nulldev();		/* So compiler won't optimize out */
37541056Swilliam 
37641056Swilliam 	/* ASSUMES CONTIGUOUS MEMORY */
37741056Swilliam 	{ register buff_addr;
37841056Swilliam 
37941056Swilliam 	buff_addr = addr;
38041056Swilliam 	buff_addr += (du->dk_skip * 512)/* & CLOFSET*/;
38141056Swilliam 	outsw (wdc+wd_data, buff_addr, 256);
38241056Swilliam 	}
38341056Swilliam 	du->dk_bc -= 512;
38441056Swilliam }
38541056Swilliam 
38641056Swilliam /*
38741056Swilliam  * these are globally defined so they can be found
38841056Swilliam  * by the debugger easily in the case of a system crash
38941056Swilliam  */
39041056Swilliam daddr_t wd_errsector;
39141056Swilliam daddr_t wd_errbn;
39241056Swilliam unsigned char wd_errstat;
39341056Swilliam 
39441056Swilliam /* Interrupt routine for the controller.  Acknowledge the interrupt, check for
39541056Swilliam  * errors on the current operation, mark it done if necessary, and start
39641056Swilliam  * the next request.  Also check for a partially done transfer, and
39741056Swilliam  * continue with the next chunk if so.
39841056Swilliam  */
39941056Swilliam wdintr()
40041056Swilliam {
40141056Swilliam 	register struct	disk *du;
40241056Swilliam 	register wdc = IO_WD0; /*XXX*/
40341056Swilliam 	register struct buf *bp, *dp;
40441056Swilliam 	int status;
40541056Swilliam 	char partch ;
40641056Swilliam 
40741056Swilliam 	/* Shouldn't need this, but it may be a slow controller.	*/
40841056Swilliam 	while ((status = inb(wdc+wd_altsts)) & WDCS_BUSY)
40941056Swilliam 		nulldev();
41041056Swilliam 	if (!wdtab.b_active) {
41141056Swilliam 		printf("wd: extra interrupt\n");
41241056Swilliam 		return;
41341056Swilliam 	}
41441056Swilliam 
41541056Swilliam #ifdef	WDDEBUGx
41641056Swilliam 	dprintf(DDSK,"I ");
41741056Swilliam #endif
41841056Swilliam 	dp = wdtab.b_actf;
41941056Swilliam 	bp = dp->b_actf;
42041056Swilliam 	du = &wddrives[WDUNIT(bp->b_dev)];
42141056Swilliam 	partch = "abcdefgh"[minor(bp->b_dev)&7] ;
42241056Swilliam 	if (DISKSTATE(du->dk_state) <= RDLABEL) {
42341056Swilliam 		if (wdcontrol(bp))
42441056Swilliam 			goto done;
42541056Swilliam 		return;
42641056Swilliam 	}
42741056Swilliam 	if (status & (WDCS_ERR | WDCS_ECCCOR)) {
42841056Swilliam #ifdef	WDDEBUG
429*43592Sdonahn 		printf("error %x\n", wd_errstat);
43041056Swilliam #endif
43141056Swilliam 		/*if (bp->b_flags & B_FORMAT) {
43241056Swilliam 			du->dk_status = status;
43341056Swilliam 			du->dk_error = wdp->wd_error;
43441056Swilliam 			bp->b_flags |= B_ERROR;
43541056Swilliam 			goto done;
43641056Swilliam 		}*/
43741056Swilliam 
43841056Swilliam 		wd_errstat = inb(wdc+wd_error);		/* save error status */
43941056Swilliam 		wd_errsector = (bp->b_cylin * du->dk_dd.dk_secpercyl) +
44041056Swilliam 			(((unsigned long) bp->b_blkno * DEV_BSIZE /
44141056Swilliam 			    du->dk_dd.dk_secsize) % du->dk_dd.dk_secpercyl) +
44241056Swilliam 			du->dk_skip;
44341056Swilliam 		wd_errbn = bp->b_blkno
44441056Swilliam 			+ du->dk_skip * du->dk_dd.dk_secsize / DEV_BSIZE ;
44541056Swilliam 		if (status & WDCS_ERR) {
44641056Swilliam 			if (++wdtab.b_errcnt < RETRIES)
44741056Swilliam 				wdtab.b_active = 0;
44841056Swilliam 			else {
44941056Swilliam 				printf("wd%d%c: ", du->dk_unit, partch);
45041056Swilliam 				printf(
45141056Swilliam 				"hard %s error, sn %d bn %d status %b error %b\n",
45241056Swilliam 					(bp->b_flags & B_READ)? "read":"write",
45341056Swilliam 					wd_errsector, wd_errbn, status, WDCS_BITS,
45441056Swilliam 					wd_errstat, WDERR_BITS);
45541056Swilliam 				bp->b_flags |= B_ERROR;	/* flag the error */
45641056Swilliam 			}
45741056Swilliam 		} else
45841056Swilliam 			log(LOG_WARNING,"wd%d%c: soft ecc sn %d bn %d\n",
45941056Swilliam 				du->dk_unit, partch, wd_errsector,
46041056Swilliam 				wd_errbn);
46141056Swilliam 	}
46241056Swilliam 
46341056Swilliam 	/*
46441056Swilliam 	 * If this was a successful read operation, fetch the data.
46541056Swilliam 	 */
46641056Swilliam 	if (((bp->b_flags & (B_READ | B_ERROR)) == B_READ) && wdtab.b_active) {
46741056Swilliam 		int chk, dummy;
46841056Swilliam 
46941056Swilliam 		chk = min(256,(du->dk_bc/2));
47041056Swilliam 		/* Ready to receive data?	*/
47141056Swilliam 		while ((inb(wdc+wd_status) & WDCS_DRQ) == 0)
47241056Swilliam 			nulldev();
47341056Swilliam 
47441056Swilliam /*dprintf(DDSK,"addr %x\n", (int)bp->b_un.b_addr + du->dk_skip * 512);*/
47541056Swilliam 		insw(wdc+wd_data,(int)bp->b_un.b_addr + du->dk_skip * 512 ,chk);
476*43592Sdonahn 		du->dk_bc -= 2*chk;
47741056Swilliam 		while(chk++ < 256) insw(wdc+wd_data,&dummy,1);
47841056Swilliam 	}
47941056Swilliam 
48041056Swilliam 	wdxfer[du->dk_unit]++;
48141056Swilliam 	if (wdtab.b_active) {
48241056Swilliam 		if ((bp->b_flags & B_ERROR) == 0) {
48341056Swilliam 			du->dk_skip++;		/* Add to successful sectors. */
48441056Swilliam 			if (wdtab.b_errcnt) {
48541056Swilliam 				log(LOG_WARNING, "wd%d%c: ",
48641056Swilliam 						du->dk_unit, partch);
48741056Swilliam 				log(LOG_WARNING,
48841056Swilliam 			"soft %s error, sn %d bn %d error %b retries %d\n",
48941056Swilliam 				    (bp->b_flags & B_READ) ? "read" : "write",
49041056Swilliam 				    wd_errsector, wd_errbn, wd_errstat,
49141056Swilliam 				    WDERR_BITS, wdtab.b_errcnt);
49241056Swilliam 			}
49341056Swilliam 			wdtab.b_errcnt = 0;
49441056Swilliam 
49541056Swilliam 			/* see if more to transfer */
496*43592Sdonahn 			/*if (du->dk_skip < (bp->b_bcount + 511) / 512) {*/
497*43592Sdonahn 			if (du->dk_bc > 0) {
49841056Swilliam 				wdstart();
49941056Swilliam 				return;		/* next chunk is started */
50041056Swilliam 			}
50141056Swilliam 		}
50241056Swilliam 
50341056Swilliam done:
50441056Swilliam 		/* done with this transfer, with or without error */
50541056Swilliam 		wdtab.b_actf = dp->b_forw;
50641056Swilliam 		wdtab.b_errcnt = 0;
50741056Swilliam 		du->dk_skip = 0;
50841056Swilliam 		dp->b_active = 0;
50941056Swilliam 		dp->b_actf = bp->av_forw;
51041056Swilliam 		dp->b_errcnt = 0;
51141056Swilliam 		bp->b_resid = 0;
51241056Swilliam 		biodone(bp);
51341056Swilliam 	}
51441056Swilliam 	wdtab.b_active = 0;
51541056Swilliam 	if (dp->b_actf)
51641056Swilliam 		wdustart(du);		/* requeue disk if more io to do */
51741056Swilliam 	if (wdtab.b_actf)
51841056Swilliam 		wdstart();		/* start IO on next drive */
51941056Swilliam }
52041056Swilliam 
52141056Swilliam /*
52241056Swilliam  * Initialize a drive.
52341056Swilliam  */
52441056Swilliam wdopen(dev, flags)
52541056Swilliam 	dev_t	dev;
52641056Swilliam 	int	flags;
52741056Swilliam {
52841056Swilliam 	register unsigned int unit;
52941056Swilliam 	register struct buf *bp;
53041056Swilliam 	register struct disk *du;
53141056Swilliam 	struct dkbad *db;
53241056Swilliam 	int i, error = 0;
53341056Swilliam 
53441056Swilliam 	unit = WDUNIT(dev);
535*43592Sdonahn /*dprintf(DDSK,"wdopen %x\n",unit);*/
53641056Swilliam 	if (unit >= NWD) return (ENXIO) ;
53741056Swilliam 	du = &wddrives[unit];
53841056Swilliam 	if (du->dk_open){
53941056Swilliam 		du->dk_open++ ;
54041056Swilliam 		return(0);	/* already is open, don't mess with it */
54141056Swilliam 	}
54241056Swilliam #ifdef THE_BUG
54341056Swilliam 	if (du->dk_state && DISKSTATE(du->dk_state) <= OPEN)
54441056Swilliam 		return(0);
54541056Swilliam #endif
54641056Swilliam 	du->dk_unit = unit;
54741056Swilliam 	wdutab[unit].b_actf = NULL;
54841056Swilliam 	/*if (flags & O_NDELAY)
54941056Swilliam 		du->dk_state = WANTOPENRAW;
55041056Swilliam 	else*/
55141056Swilliam 		du->dk_state = WANTOPEN;
55241056Swilliam 	/*
55341056Swilliam 	 * Use the default sizes until we've read the label,
55441056Swilliam 	 * or longer if there isn't one there.
55541056Swilliam 	 */
55641056Swilliam 	du->dk_dd = dflt_sizes;
55741056Swilliam 
55841056Swilliam 	/*
55941056Swilliam 	 * Recal, read of disk label will be done in wdcontrol
56041056Swilliam 	 * during first read operation.
56141056Swilliam 	 */
56241056Swilliam 	bp = geteblk(512);
56341056Swilliam 	bp->b_dev = dev;
56441056Swilliam 	bp->b_blkno = bp->b_bcount = 0;
56541056Swilliam 	bp->b_flags = B_READ;
56641056Swilliam 	wdstrategy(bp);
56741056Swilliam 	biowait(bp);
56841056Swilliam 	if (bp->b_flags & B_ERROR) {
56941056Swilliam 		u.u_error = 0; 	/* XXX */
57041056Swilliam 		error = ENXIO;
57141056Swilliam 		du->dk_state = CLOSED;
57241056Swilliam 		goto done;
57341056Swilliam 	}
57441056Swilliam 	if (du->dk_state == OPENRAW) {
57541056Swilliam 		du->dk_state = OPENRAW;
57641056Swilliam 		goto done;
57741056Swilliam 	}
57841056Swilliam #ifdef notyet
57941056Swilliam 	/*
58041056Swilliam 	 * Read bad sector table into memory.
58141056Swilliam 	 */
58241056Swilliam 	i = 0;
58341056Swilliam 	do {
58441056Swilliam 		u.u_error = 0;				/* XXX */
58541056Swilliam 		bp->b_flags = B_BUSY | B_READ;
58641056Swilliam 		bp->b_blkno = du->dk_dd.dk_secperunit - du->dk_dd.dk_nsectors
58741056Swilliam 			+ i;
58841056Swilliam 		if (du->dk_dd.dk_secsize > DEV_BSIZE)
58941056Swilliam 			bp->b_blkno *= du->dk_dd.dk_secsize / DEV_BSIZE;
59041056Swilliam 		else
59141056Swilliam 			bp->b_blkno /= DEV_BSIZE / du->dk_dd.dk_secsize;
59241056Swilliam 		bp->b_bcount = du->dk_dd.dk_secsize;
59341056Swilliam 		bp->b_cylin = du->dk_dd.dk_ncylinders - 1;
59441056Swilliam 		wdstrategy(bp);
59541056Swilliam 		biowait(bp);
59641056Swilliam 	} while ((bp->b_flags & B_ERROR) && (i += 2) < 10 &&
59741056Swilliam 		i < du->dk_dd.dk_nsectors);
59841056Swilliam 	db = (struct dkbad *)(bp->b_un.b_addr);
59941056Swilliam 	if ((bp->b_flags & B_ERROR) == 0 && db->bt_mbz == 0 &&
60041056Swilliam 	    db->bt_flag == DKBAD_MAGIC) {
60141056Swilliam 		dkbad[unit] = *db;
60241056Swilliam 		du->dk_state = OPEN;
60341056Swilliam 	} else {
60441056Swilliam 		printf("wd%d: %s bad-sector file\n", unit,
60541056Swilliam 		    (bp->b_flags & B_ERROR) ? "can't read" : "format error in");
60641056Swilliam 		u.u_error = 0;				/* XXX */
60741056Swilliam 		/*error = ENXIO ;*/
60841056Swilliam 		du->dk_state = OPENRAW;
60941056Swilliam 	}
61041056Swilliam #else
61141056Swilliam 	du->dk_state = OPEN;
61241056Swilliam #endif
61341056Swilliam done:
61441056Swilliam 	bp->b_flags = B_INVAL | B_AGE;
61541056Swilliam 	brelse(bp);
61641056Swilliam 	if (error == 0)
61741056Swilliam 		du->dk_open = 1;
61841056Swilliam 	return (error);
61941056Swilliam }
62041056Swilliam 
62141056Swilliam /*
62241056Swilliam  * Implement operations other than read/write.
62341056Swilliam  * Called from wdstart or wdintr during opens and formats.
62441056Swilliam  * Uses finite-state-machine to track progress of operation in progress.
62541056Swilliam  * Returns 0 if operation still in progress, 1 if completed.
62641056Swilliam  */
62741056Swilliam wdcontrol(bp)
62841056Swilliam 	register struct buf *bp;
62941056Swilliam {
63041056Swilliam 	register struct disk *du;
63141056Swilliam 	register wdc = IO_WD0; /*XXX*/
63241056Swilliam 	register unit;
63341056Swilliam 	unsigned char  stat;
63441056Swilliam 	int s, cnt;
63541056Swilliam 	extern int bootdev, cyloffset;
63641056Swilliam 
637*43592Sdonahn 	cyloffset=0;
63841056Swilliam 	du = &wddrives[WDUNIT(bp->b_dev)];
63941056Swilliam 	unit = du->dk_unit;
64041056Swilliam 	switch (DISKSTATE(du->dk_state)) {
64141056Swilliam 
64241056Swilliam 	tryagainrecal:
64341056Swilliam 	case WANTOPEN:			/* set SDH, step rate, do restore */
64441056Swilliam #ifdef	WDDEBUG
64541056Swilliam 		dprintf(DDSK,"wd%d: recal ", unit);
64641056Swilliam #endif
64741056Swilliam 		s = splbio();		/* not called from intr level ... */
64841056Swilliam 		outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));
64941056Swilliam 		wdtab.b_active = 1;
65041056Swilliam 		outb(wdc+wd_command, WDCC_RESTORE | WD_STEP);
65141056Swilliam 		du->dk_state++;
65241056Swilliam 		splx(s);
65341056Swilliam 		return(0);
65441056Swilliam 
65541056Swilliam 	case RECAL:
65641056Swilliam 		if ((stat = inb(wdc+wd_altsts)) & WDCS_ERR) {
65741056Swilliam 			printf("wd%d: recal", du->dk_unit);
65841056Swilliam 			if (unit == 0) {
65941056Swilliam 				printf(": status %b error %b\n",
66041056Swilliam 					stat, WDCS_BITS,
66141056Swilliam 					inb(wdc+wd_error), WDERR_BITS);
66241056Swilliam 				if (++wdtab.b_errcnt < RETRIES)
66341056Swilliam 					goto tryagainrecal;
66441056Swilliam 			}
66541056Swilliam 			goto badopen;
66641056Swilliam 		}
66741056Swilliam 		wdtab.b_errcnt = 0;
66841056Swilliam 		if (ISRAWSTATE(du->dk_state)) {
66941056Swilliam 			du->dk_state = OPENRAW;
67041056Swilliam 			return(1);
67141056Swilliam 		}
67241056Swilliam retry:
67341056Swilliam #ifdef	WDDEBUG
67441056Swilliam 		dprintf(DDSK,"rdlabel ");
67541056Swilliam #endif
67641056Swilliam 		/*
67741056Swilliam 		 * Read in sector 0 to get the pack label and geometry.
67841056Swilliam 		 */
67941056Swilliam 		outb(wdc+wd_precomp, 0xff);/* sometimes this is head bit 3 */
68041056Swilliam 		outb(wdc+wd_seccnt, 1);
68141056Swilliam 		outb(wdc+wd_sector, 1);
68241056Swilliam 		/*if (bp->b_dev == bootdev) {
68341056Swilliam 			(wdc+wd_cyl_lo = cyloffset & 0xff;
68441056Swilliam 			(wdc+wd_cyl_hi = cyloffset >> 8;
68541056Swilliam 		} else {
68641056Swilliam 			(wdc+wd_cyl_lo = 0;
68741056Swilliam 			(wdc+wd_cyl_hi = 0;
68841056Swilliam 		}*/
68941056Swilliam 		outb(wdc+wd_cyl_lo, (cyloffset & 0xff));
69041056Swilliam 		outb(wdc+wd_cyl_hi, (cyloffset >> 8));
69141056Swilliam 		outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));
69241056Swilliam 		outb(wdc+wd_command, WDCC_READ);
69341056Swilliam 		du->dk_state = RDLABEL;
69441056Swilliam 		return(0);
69541056Swilliam 
69641056Swilliam 	case RDLABEL:
69741056Swilliam 		if ((stat = inb(wdc+wd_status)) & WDCS_ERR) {
69841056Swilliam 			if (++wdtab.b_errcnt < RETRIES)
69941056Swilliam 				goto retry;
70041056Swilliam 			printf("wd%d: read label", unit);
70141056Swilliam 			goto badopen;
70241056Swilliam 		}
70341056Swilliam 
70441056Swilliam 		insw(wdc+wd_data, bp->b_un.b_addr, 256);
70541056Swilliam 
70641056Swilliam 		if (((struct disklabel *)
70741056Swilliam 		    (bp->b_un.b_addr + LABELOFFSET))->dk_magic == DISKMAGIC) {
70841056Swilliam 		       du->dk_dd =
70941056Swilliam 			 * (struct disklabel *) (bp->b_un.b_addr + LABELOFFSET);
71041056Swilliam 		} else {
71141056Swilliam 			printf("wd%d: bad disk label\n", du->dk_unit);
71241056Swilliam 			du->dk_state = OPENRAW;
71341056Swilliam 		}
71441056Swilliam 		if (du->dk_state == RDLABEL)
71541056Swilliam 			du->dk_state = RDBADTBL;
71641056Swilliam 		/*
71741056Swilliam 		 * The rest of the initialization can be done
71841056Swilliam 		 * by normal means.
71941056Swilliam 		 */
72041056Swilliam 		return(1);
72141056Swilliam 
72241056Swilliam 	default:
72341056Swilliam 		panic("wdcontrol %x", du->dk_state );
72441056Swilliam 	}
72541056Swilliam 	/* NOTREACHED */
72641056Swilliam 
72741056Swilliam badopen:
72841056Swilliam 	printf(": status %b error %b\n",
72941056Swilliam 		stat, WDCS_BITS, inb(wdc+wd_error), WDERR_BITS);
73041056Swilliam 	du->dk_state = OPENRAW;
73141056Swilliam 	return(1);
73241056Swilliam }
73341056Swilliam 
73441056Swilliam wdclose(dev)
73541056Swilliam 	dev_t dev;
73641056Swilliam {	struct disk *du;
73741056Swilliam 
73841056Swilliam 	du = &wddrives[WDUNIT(dev)];
73941056Swilliam 	du->dk_open-- ;
74041056Swilliam 	/*if (du->dk_open == 0) du->dk_state = CLOSED ; does not work */
74141056Swilliam }
74241056Swilliam 
74341056Swilliam wdioctl(dev,cmd,addr,flag)
74441056Swilliam 	dev_t dev;
74541056Swilliam 	caddr_t addr;
74641056Swilliam {
74741056Swilliam 	int unit = WDUNIT(dev);
74841056Swilliam 	register struct disk *du;
74941056Swilliam 	int error = 0;
75041056Swilliam 	struct uio auio;
75141056Swilliam 	struct iovec aiov;
75241056Swilliam 	/*int wdformat();*/
75341056Swilliam 
75441056Swilliam 	du = &wddrives[unit];
75541056Swilliam 
75641056Swilliam 	switch (cmd) {
75741056Swilliam 
75841056Swilliam 	case DIOCGDINFO:
75941056Swilliam 		*(struct disklabel *)addr = du->dk_dd;
76041056Swilliam 		break;
76141056Swilliam 
76241056Swilliam 	case DIOCGDINFOP:
76341056Swilliam 		*(struct disklabel **)addr = &(du->dk_dd);
76441056Swilliam 		break;
76541056Swilliam 
76641056Swilliam #ifdef notyet
76741056Swilliam 	case DIOCWFORMAT:
76841056Swilliam 		if ((flag & FWRITE) == 0)
76941056Swilliam 			error = EBADF;
77041056Swilliam 		else {
77141056Swilliam 			register struct format_op *fop;
77241056Swilliam 
77341056Swilliam 			fop = (struct format_op *)addr;
77441056Swilliam 			aiov.iov_base = fop->df_buf;
77541056Swilliam 			aiov.iov_len = fop->df_count;
77641056Swilliam 			auio.uio_iov = &aiov;
77741056Swilliam 			auio.uio_iovcnt = 1;
77841056Swilliam 			auio.uio_resid = fop->df_count;
77941056Swilliam 			auio.uio_segflg = 0;
78041056Swilliam 			auio.uio_offset =
78141056Swilliam 				fop->df_startblk * du->dk_dd.dk_secsize;
78241056Swilliam 			error = physio(wdformat, &rwdbuf[unit], dev, B_WRITE,
78341056Swilliam 				minphys, &auio);
78441056Swilliam 			fop->df_count -= auio.uio_resid;
78541056Swilliam 			fop->df_reg[0] = du->dk_status;
78641056Swilliam 			fop->df_reg[1] = du->dk_error;
78741056Swilliam 		}
78841056Swilliam 		break;
78941056Swilliam #endif
79041056Swilliam 
79141056Swilliam 	default:
79241056Swilliam 		error = ENOTTY;
79341056Swilliam 		break;
79441056Swilliam 	}
79541056Swilliam 	return (error);
79641056Swilliam }
79741056Swilliam 
79841056Swilliam /*wdformat(bp)
79941056Swilliam 	struct buf *bp;
80041056Swilliam {
80141056Swilliam 
80241056Swilliam 	bp->b_flags |= B_FORMAT;
80341056Swilliam 	return (wdstrategy(bp));
80441056Swilliam }*/
80541056Swilliam 
80641056Swilliam /*
80741056Swilliam  * Routines to do raw IO for a unit.
80841056Swilliam  */
80941056Swilliam wdread(dev, uio)			/* character read routine */
81041056Swilliam 	dev_t dev;
81141056Swilliam 	struct uio *uio;
81241056Swilliam {
81341056Swilliam 	int unit = WDUNIT(dev) ;
81441056Swilliam 
81541056Swilliam 	if (unit >= NWD) return(ENXIO);
81641056Swilliam 	return(physio(wdstrategy, &rwdbuf[unit], dev, B_READ, minphys, uio));
81741056Swilliam }
81841056Swilliam 
81941056Swilliam 
82041056Swilliam wdwrite(dev, uio)			/* character write routine */
82141056Swilliam 	dev_t dev;
82241056Swilliam 	struct uio *uio;
82341056Swilliam {
82441056Swilliam 	int unit = WDUNIT(dev) ;
82541056Swilliam 
82641056Swilliam 	if (unit >= NWD) return(ENXIO);
82741056Swilliam 	return(physio(wdstrategy, &rwdbuf[unit], dev, B_WRITE, minphys, uio));
82841056Swilliam }
82941056Swilliam 
83041056Swilliam wdsize(dev)
83141056Swilliam 	dev_t dev;
83241056Swilliam {
83341056Swilliam 	register unit = WDUNIT(dev) ;
83441056Swilliam 	register xunit = minor(dev) & 07;
83541056Swilliam 	register struct disk *du;
83641056Swilliam 	register val ;
83741056Swilliam 
838*43592Sdonahn 	return(12144);
83941056Swilliam #ifdef notdef
84041056Swilliam 	if (unit >= NWD) return(-1);
84141056Swilliam 	if (wddrives[unit].dk_state == 0) /*{
84241056Swilliam 		val = wdopen (dev, 0) ;
84341056Swilliam 		if (val < 0) return (val) ;
84441056Swilliam 	}*/	return (-1) ;
84541056Swilliam 	du = &wddrives[unit];
84641056Swilliam 	return((int)((u_long)du->dk_dd.dk_partition[xunit].nblocks *
84741056Swilliam 		du->dk_dd.dk_secsize / 512));
84841056Swilliam #endif
84941056Swilliam }
85041056Swilliam 
85141056Swilliam wddump(dev)			/* dump core after a system crash */
85241056Swilliam 	dev_t dev;
85341056Swilliam {
85441056Swilliam #ifdef notyet
85541056Swilliam 	register struct disk *du;	/* disk unit to do the IO */
85641056Swilliam 	register struct wd1010 *wdp = (struct wd1010 *) VA_WD;
85741056Swilliam 	register struct bt_bad *bt_ptr;
85841056Swilliam 	long	num;			/* number of sectors to write */
85941056Swilliam 	int	unit, xunit;
86041056Swilliam 	long	cyloff, blknum, blkcnt;
86141056Swilliam 	long	cylin, head, sector;
86241056Swilliam 	long	secpertrk, secpercyl, nblocks, i;
86341056Swilliam 	register char *addr;
86441056Swilliam 	char	*end;
86541056Swilliam 	extern	int dumplo, totalclusters;
86641056Swilliam 	static  wddoingadump = 0 ;
86741056Swilliam 
86841056Swilliam 	addr = (char *) PA_RAM;		/* starting address */
86941056Swilliam 	/* size of memory to dump */
87041056Swilliam 	num = totalclusters * CLSIZE - PA_RAM / PGSIZE;
87141056Swilliam 	unit = WDUNIT(dev) ;		/* eventually support floppies? */
87241056Swilliam 	xunit = minor(dev) & 7;		/* file system */
87341056Swilliam 	/* check for acceptable drive number */
87441056Swilliam 	if (unit >= NWD) return(ENXIO);
87541056Swilliam 
87641056Swilliam 	du = &wddrives[unit];
87741056Swilliam 	/* was it ever initialized ? */
87841056Swilliam 	if (du->dk_state < OPEN) return (ENXIO) ;
87941056Swilliam 
88041056Swilliam 	/* Convert to disk sectors */
88141056Swilliam 	num = (u_long) num * PGSIZE / du->dk_dd.dk_secsize;
88241056Swilliam 
88341056Swilliam 	/* check if controller active */
88441056Swilliam 	/*if (wdtab.b_active) return(EFAULT); */
88541056Swilliam 	if (wddoingadump) return(EFAULT);
88641056Swilliam 
88741056Swilliam 	secpertrk = du->dk_dd.dk_nsectors;
88841056Swilliam 	secpercyl = du->dk_dd.dk_secpercyl;
88941056Swilliam 	nblocks = du->dk_dd.dk_partition[xunit].nblocks;
89041056Swilliam 	cyloff = du->dk_dd.dk_partition[xunit].cyloff;
89141056Swilliam 
89241056Swilliam 	/* check transfer bounds against partition size */
89341056Swilliam 	if ((dumplo < 0) || ((dumplo + num) >= nblocks))
89441056Swilliam 		return(EINVAL);
89541056Swilliam 
89641056Swilliam 	/*wdtab.b_active = 1;		/* mark controller active for if we
89741056Swilliam 					   panic during the dump */
89841056Swilliam 	wddoingadump = 1  ;  i = 100000 ;
89941056Swilliam 	while ((wdp->wd_status & WDCS_BUSY) && (i-- > 0)) nulldev() ;
90041056Swilliam 	inb(wdc+wd_sdh = du->dk_sdh ;
90141056Swilliam 	inb(wdc+wd_command = WDCC_RESTORE | WD_STEP;
90241056Swilliam 	while (inb(wdc+wd_status & WDCS_BUSY) nulldev() ;
90341056Swilliam 
90441056Swilliam 	blknum = dumplo;
90541056Swilliam 	while (num > 0) {
90641056Swilliam #ifdef notdef
90741056Swilliam 		if (blkcnt > MAXTRANSFER) blkcnt = MAXTRANSFER;
90841056Swilliam 		if ((blknum + blkcnt - 1) / secpercyl != blknum / secpercyl)
90941056Swilliam 			blkcnt = secpercyl - (blknum % secpercyl);
91041056Swilliam 			    /* keep transfer within current cylinder */
91141056Swilliam #endif
91241056Swilliam 
91341056Swilliam 		/* compute disk address */
91441056Swilliam 		cylin = blknum / secpercyl;
91541056Swilliam 		head = (blknum % secpercyl) / secpertrk;
91641056Swilliam 		sector = blknum % secpertrk;
91741056Swilliam 		sector++;		/* origin 1 */
918*43592Sdonahn 		cylin += cyloff;
91941056Swilliam 
92041056Swilliam 		/*
92141056Swilliam 		 * See if the current block is in the bad block list.
92241056Swilliam 		 * (If we have one.)
92341056Swilliam 		 */
92441056Swilliam 	    		for (bt_ptr = dkbad[unit].bt_bad;
92541056Swilliam 				bt_ptr->bt_cyl != -1; bt_ptr++) {
92641056Swilliam 			if (bt_ptr->bt_cyl > cylin)
92741056Swilliam 				/* Sorted list, and we passed our cylinder.
92841056Swilliam 					quit. */
92941056Swilliam 				break;
93041056Swilliam 			if (bt_ptr->bt_cyl == cylin &&
93141056Swilliam 				bt_ptr->bt_trksec == (head << 8) + sector) {
93241056Swilliam 			/*
93341056Swilliam 			 * Found bad block.  Calculate new block addr.
93441056Swilliam 			 * This starts at the end of the disk (skip the
93541056Swilliam 			 * last track which is used for the bad block list),
93641056Swilliam 			 * and works backwards to the front of the disk.
93741056Swilliam 			 */
93841056Swilliam 				blknum = (du->dk_dd.dk_secperunit)
93941056Swilliam 					- du->dk_dd.dk_nsectors
94041056Swilliam 					- (bt_ptr - dkbad[unit].bt_bad) - 1;
94141056Swilliam 				cylin = blknum / secpercyl;
94241056Swilliam 				head = (blknum % secpercyl) / secpertrk;
94341056Swilliam 				sector = blknum % secpertrk;
94441056Swilliam 				break;
94541056Swilliam 			}
94641056Swilliam 
94741056Swilliam 		/* select drive.     */
94841056Swilliam 		inb(wdc+wd_sdh = du->dk_sdh | (head&07);
94941056Swilliam 		while ((inb(wdc+wd_status & WDCS_READY) == 0) nulldev();
95041056Swilliam 
95141056Swilliam 		/* transfer some blocks */
95241056Swilliam 		inb(wdc+wd_sector = sector;
95341056Swilliam 		inb(wdc+wd_seccnt = 1;
95441056Swilliam 		inb(wdc+wd_cyl_lo = cylin;
95541056Swilliam 		if (du->dk_dd.dk_ntracks > 8) {
95641056Swilliam 			if (head > 7)
95741056Swilliam 				inb(wdc+wd_precomp = 0;	/* set 3rd head bit */
95841056Swilliam 			else
95941056Swilliam 				inb(wdc+wd_precomp = 0xff;	/* set 3rd head bit */
96041056Swilliam 		}
96141056Swilliam 		inb(wdc+wd_cyl_hi = cylin >> 8;
96241056Swilliam #ifdef notdef
96341056Swilliam 		/* lets just talk about this first...*/
96441056Swilliam 		printf ("sdh 0%o sector %d cyl %d addr 0x%x\n",
96541056Swilliam 			wdp->wd_sdh, wdp->wd_sector,
96641056Swilliam 			wdp->wd_cyl_hi*256+wdp->wd_cyl_lo, addr) ;
96741056Swilliam 		for (i=10000; i > 0 ; i--)
96841056Swilliam 			;
96941056Swilliam 		continue;
97041056Swilliam #endif
97141056Swilliam 		inb(wdc+wd_command = WDCC_WRITE;
97241056Swilliam 
97341056Swilliam 		/* Ready to send data?	*/
97441056Swilliam 		while ((inb(wdc+wd_status & WDCS_DRQ) == 0) nulldev();
97541056Swilliam 		if (inb(wdc+wd_status & WDCS_ERR) return(EIO) ;
97641056Swilliam 
97741056Swilliam 		end = (char *)addr + du->dk_dd.dk_secsize;
97841056Swilliam 		for (; addr < end; addr += 8) {
97941056Swilliam 			wdp->wd_data = addr[0];
98041056Swilliam 			wdp->wd_data = addr[1];
98141056Swilliam 			wdp->wd_data = addr[2];
98241056Swilliam 			wdp->wd_data = addr[3];
98341056Swilliam 			wdp->wd_data = addr[4];
98441056Swilliam 			wdp->wd_data = addr[5];
98541056Swilliam 			wdp->wd_data = addr[6];
98641056Swilliam 			wdp->wd_data = addr[7];
98741056Swilliam 		}
98841056Swilliam 		if (inb(wdc+wd_status & WDCS_ERR) return(EIO) ;
98941056Swilliam 		/* Check data request (should be done).         */
99041056Swilliam 		if (inb(wdc+wd_status & WDCS_DRQ) return(EIO) ;
99141056Swilliam 
99241056Swilliam 		/* wait for completion */
99341056Swilliam 		for ( i = 1000000 ; inb(wdc+wd_status & WDCS_BUSY ; i--) {
99441056Swilliam 				if (i < 0) return (EIO) ;
99541056Swilliam 				nulldev () ;
99641056Swilliam 		}
99741056Swilliam 		/* error check the xfer */
99841056Swilliam 		if (inb(wdc+wd_status & WDCS_ERR) return(EIO) ;
99941056Swilliam 		/* update block count */
100041056Swilliam 		num--;
100141056Swilliam 		blknum++ ;
100241056Swilliam #ifdef	WDDEBUG
100341056Swilliam if (num % 100 == 0) printf(".") ;
100441056Swilliam #endif
100541056Swilliam 	}
100641056Swilliam 	return(0);
100741056Swilliam #endif
100841056Swilliam }
100941056Swilliam #endif
1010