xref: /csrg-svn/sys/i386/isa/wd.c (revision 45552)
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*45552Sbill  *	@(#)wd.c	5.6 (Berkeley) 11/08/90
1141056Swilliam  */
1243592Sdonahn 
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"
29*45552Sbill #include "machine/isa/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 */
9045550Sbill 		36,		/* # of sectors per track */
9141056Swilliam 		15,		/* # of tracks per cylinder */
9245550Sbill 		1224,		/* # of cylinders per unit */
9345550Sbill 		36*15,		/* # of sectors per cylinder */
9445550Sbill 		1224*15*36,	/* # of sectors per unit */
9541056Swilliam 		0		/* write precomp cylinder (none) */
9641056Swilliam 	},
9745550Sbill 	21600,	0,	/* A=root filesystem */
9845550Sbill 	21600,	40,
9945550Sbill 	660890, 0,	/* C=whole disk */
10045550Sbill 	216000,	80,
10141056Swilliam 	0,	0,
10241056Swilliam 	0,	0,
10341056Swilliam 	0,	0,
10445550Sbill 	399600,	480
10541056Swilliam };
10645550Sbill 
10741056Swilliam static	struct	dkbad	dkbad[NWD];
10841056Swilliam struct	disk	wddrives[NWD] = {0};	/* table of units */
10941056Swilliam struct	buf	wdtab = {0};
11041056Swilliam struct	buf	wdutab[NWD] = {0};	/* head of queue per drive */
11141056Swilliam struct	buf	rwdbuf[NWD] = {0};	/* buffers for raw IO */
11241056Swilliam long	wdxfer[NWD] = {0};		/* count of transfers */
11341056Swilliam int	writeprotected[NWD] = { 0 };
11441056Swilliam int	wdprobe(), wdattach(), wdintr();
115*45552Sbill struct	isa_driver wddriver = {
11641056Swilliam 	wdprobe, wdattach, "wd",
11741056Swilliam };
11841056Swilliam #include "dbg.h"
11941056Swilliam 
120*45552Sbill static wdc;
12141056Swilliam /*
12241056Swilliam  * Probe routine
12341056Swilliam  */
12441056Swilliam wdprobe(dvp)
125*45552Sbill 	struct isa_device *dvp;
12641056Swilliam {
127*45552Sbill wdc = dvp->id_iobase;
12841056Swilliam 
12941056Swilliam #ifdef lint
13041056Swilliam 	wdintr(0);
13141056Swilliam #endif
13241056Swilliam 	outb(wdc+wd_error, 0x5a) ;	/* error register not writable */
13341056Swilliam 	/*wdp->wd_cyl_hi = 0xff ;/* only two bits of cylhi are implemented */
13441056Swilliam 	outb(wdc+wd_cyl_lo, 0xa5) ;	/* but all of cyllo are implemented */
13541056Swilliam 	if(inb(wdc+wd_error) != 0x5a /*&& wdp->wd_cyl_hi == 3*/
13641056Swilliam 	   && inb(wdc+wd_cyl_lo) == 0xa5)
13741056Swilliam 		return(1) ;
13841056Swilliam 	return (0);
13941056Swilliam }
14041056Swilliam 
14141056Swilliam /*
14241056Swilliam  * attach each drive if possible.
14341056Swilliam  */
14441056Swilliam wdattach(dvp)
145*45552Sbill 	struct isa_device *dvp;
14641056Swilliam {
147*45552Sbill 	int unit = dvp->id_unit;
14841056Swilliam 
149*45552Sbill 	outb(wdc+wd_ctlr,12);
150*45552Sbill 	DELAY(1000);
151*45552Sbill 	outb(wdc+wd_ctlr,8);
15241056Swilliam }
15341056Swilliam 
15441056Swilliam /* Read/write routine for a buffer.  Finds the proper unit, range checks
15541056Swilliam  * arguments, and schedules the transfer.  Does not wait for the transfer
15641056Swilliam  * to complete.  Multi-page transfers are supported.  All I/O requests must
15741056Swilliam  * be a multiple of a sector in length.
15841056Swilliam  */
15941056Swilliam wdstrategy(bp)
16041056Swilliam 	register struct buf *bp;	/* IO operation to perform */
16141056Swilliam {
16241056Swilliam 	register struct buf *dp;
16341056Swilliam 	register struct disk *du;	/* Disk unit to do the IO.	*/
16441056Swilliam 	long nblocks, cyloff, blknum;
16541056Swilliam 	int	unit = WDUNIT(bp->b_dev), xunit = minor(bp->b_dev) & 7;
16641056Swilliam 	int	s;
16741056Swilliam 
16841056Swilliam 	if ((unit >= NWD) || (bp->b_blkno < 0)) {
16943592Sdonahn 		printf("wdstrat: unit = %d, blkno = %d, bcount = %d\n",
17041056Swilliam 			unit, bp->b_blkno, bp->b_bcount);
17143592Sdonahn 		pg("wd:error in wdstrategy");
17241056Swilliam 		bp->b_flags |= B_ERROR;
17341056Swilliam 		goto bad;
17441056Swilliam 	}
17541056Swilliam 	if (writeprotected[unit] && (bp->b_flags & B_READ) == 0) {
17641056Swilliam 		printf("wd%d: write protected\n", unit);
17741056Swilliam 		goto bad;
17841056Swilliam 	}
17941056Swilliam 	du = &wddrives[unit];
18041056Swilliam 	if (DISKSTATE(du->dk_state) != OPEN)
18141056Swilliam 		goto q;
18241056Swilliam 	/*
18341056Swilliam 	 * Convert DEV_BSIZE "blocks" to sectors.
18441056Swilliam 	 * Note: doing the conversions this way limits the partition size
18541056Swilliam 	 * to about 8 million sectors (1-8 Gb).
18641056Swilliam 	 */
18741056Swilliam 	blknum = (unsigned long) bp->b_blkno * DEV_BSIZE / du->dk_dd.dk_secsize;
18841056Swilliam 	if (((u_long) bp->b_blkno * DEV_BSIZE % du->dk_dd.dk_secsize != 0) ||
18943592Sdonahn 	    bp->b_bcount >= MAXTRANSFER * CLBYTES) {
19041056Swilliam 		bp->b_flags |= B_ERROR;
19141056Swilliam 		goto bad;
19241056Swilliam 	}
19341056Swilliam 	nblocks = du->dk_dd.dk_partition[xunit].nblocks;
19441056Swilliam 	cyloff = du->dk_dd.dk_partition[xunit].cyloff;
19541056Swilliam 	if (blknum + (bp->b_bcount / du->dk_dd.dk_secsize) > nblocks) {
19641056Swilliam 		if (blknum == nblocks)
19741056Swilliam 			bp->b_resid = bp->b_bcount;
19841056Swilliam 		else
19941056Swilliam 			bp->b_flags |= B_ERROR;
20041056Swilliam 		goto bad;
20141056Swilliam 	}
20241056Swilliam 	bp->b_cylin = blknum / du->dk_dd.dk_secpercyl + cyloff;
20341056Swilliam q:
20441056Swilliam 	dp = &wdutab[unit];
20545550Sbill 	s = splhigh();
20641056Swilliam 	disksort(dp, bp);
20741056Swilliam 	if (dp->b_active == 0)
20841056Swilliam 		wdustart(du);		/* start drive if idle */
20941056Swilliam 	if (wdtab.b_active == 0)
21041056Swilliam 		wdstart(s);		/* start IO if controller idle */
21141056Swilliam 	splx(s);
21241056Swilliam 	return;
21341056Swilliam 
21441056Swilliam bad:
21541056Swilliam 	bp->b_error = EINVAL;
21641056Swilliam 	biodone(bp);
21741056Swilliam }
21841056Swilliam 
21941056Swilliam /* Routine to queue a read or write command to the controller.  The request is
22041056Swilliam  * linked into the active list for the controller.  If the controller is idle,
22141056Swilliam  * the transfer is started.
22241056Swilliam  */
22341056Swilliam wdustart(du)
22441056Swilliam 	register struct disk *du;
22541056Swilliam {
22641056Swilliam 	register struct buf *bp, *dp;
22741056Swilliam 
22841056Swilliam 	dp = &wdutab[du->dk_unit];
22941056Swilliam 	if (dp->b_active)
23041056Swilliam 		return;
23141056Swilliam 	bp = dp->b_actf;
23241056Swilliam 	if (bp == NULL)
23341056Swilliam 		return;
23441056Swilliam 	dp->b_forw = NULL;
23541056Swilliam 	if (wdtab.b_actf  == NULL)		/* link unit into active list */
23641056Swilliam 		wdtab.b_actf = dp;
23741056Swilliam 	else
23841056Swilliam 		wdtab.b_actl->b_forw = dp;
23941056Swilliam 	wdtab.b_actl = dp;
24041056Swilliam 	dp->b_active = 1;		/* mark the drive as busy */
24141056Swilliam }
24241056Swilliam 
24341056Swilliam /*
24441056Swilliam  * Controller startup routine.  This does the calculation, and starts
24541056Swilliam  * a single-sector read or write operation.  Called to start a transfer,
24641056Swilliam  * or from the interrupt routine to continue a multi-sector transfer.
24741056Swilliam  * RESTRICTIONS:
24841056Swilliam  * 1.	The transfer length must be an exact multiple of the sector size.
24941056Swilliam  */
25041056Swilliam 
25145550Sbill static wd_sebyse;
25245550Sbill 
25341056Swilliam wdstart()
25441056Swilliam {
25541056Swilliam 	register struct disk *du;	/* disk unit for IO */
25641056Swilliam 	register struct buf *bp;
25741056Swilliam 	struct buf *dp;
25841056Swilliam 	register struct bt_bad *bt_ptr;
25941056Swilliam 	long	blknum, pagcnt, cylin, head, sector;
26041056Swilliam 	long	secpertrk, secpercyl, addr, i;
26141056Swilliam 	int	minor_dev, unit, s;
26241056Swilliam 
26341056Swilliam loop:
26441056Swilliam 	dp = wdtab.b_actf;
26541056Swilliam 	if (dp == NULL)
26641056Swilliam 		return;
26741056Swilliam 	bp = dp->b_actf;
26841056Swilliam 	if (bp == NULL) {
26941056Swilliam 		wdtab.b_actf = dp->b_forw;
27041056Swilliam 		goto loop;
27141056Swilliam 	}
27241056Swilliam 	unit = WDUNIT(bp->b_dev);
27341056Swilliam 	du = &wddrives[unit];
27441056Swilliam 	if (DISKSTATE(du->dk_state) <= RDLABEL) {
27541056Swilliam 		if (wdcontrol(bp)) {
27641056Swilliam 			dp->b_actf = bp->av_forw;
27741056Swilliam 			goto loop;	/* done */
27841056Swilliam 		}
27941056Swilliam 		return;
28041056Swilliam 	}
28141056Swilliam 	minor_dev = minor(bp->b_dev) & 7;
28241056Swilliam 	secpertrk = du->dk_dd.dk_nsectors;
28341056Swilliam 	secpercyl = du->dk_dd.dk_secpercyl;
28441056Swilliam 	/*
28541056Swilliam 	 * Convert DEV_BSIZE "blocks" to sectors.
28641056Swilliam 	 */
28741056Swilliam 	blknum = (unsigned long) bp->b_blkno * DEV_BSIZE / du->dk_dd.dk_secsize
28841056Swilliam 		+ du->dk_skip;
28941056Swilliam #ifdef	WDDEBUG
29041056Swilliam 	if (du->dk_skip == 0) {
29141056Swilliam 		dprintf(DDSK,"\nwdstart %d: %s %d@%d; map ", unit,
29241056Swilliam 			(bp->b_flags & B_READ) ? "read" : "write",
29341056Swilliam 			bp->b_bcount, blknum);
29441056Swilliam 	} else {
29545550Sbill 		dprintf(DDSK," %d)%x", du->dk_skip, inb(wdc+wd_altsts));
29641056Swilliam 	}
29741056Swilliam #endif
29841056Swilliam 
29941056Swilliam 	addr = (int) bp->b_un.b_addr;
30041056Swilliam 	if(du->dk_skip==0) du->dk_bc = bp->b_bcount;
30141056Swilliam 	cylin = blknum / secpercyl;
30241056Swilliam 	head = (blknum % secpercyl) / secpertrk;
30345550Sbill 	sector = blknum % secpertrk;
30441056Swilliam 	if (DISKSTATE(du->dk_state) == OPEN)
30541056Swilliam 		cylin += du->dk_dd.dk_partition[minor_dev].cyloff;
30641056Swilliam 
30741056Swilliam 	/*
30841056Swilliam 	 * See if the current block is in the bad block list.
30941056Swilliam 	 * (If we have one, and not formatting.)
31041056Swilliam 	 */
31145550Sbill 	if (DISKSTATE(du->dk_state) == OPEN && wd_sebyse)
31241056Swilliam 	    for (bt_ptr = dkbad[unit].bt_bad; bt_ptr->bt_cyl != -1; bt_ptr++) {
31341056Swilliam 		if (bt_ptr->bt_cyl > cylin)
31441056Swilliam 			/* Sorted list, and we passed our cylinder. quit. */
31541056Swilliam 			break;
31641056Swilliam 		if (bt_ptr->bt_cyl == cylin &&
31741056Swilliam 				bt_ptr->bt_trksec == (head << 8) + sector) {
31841056Swilliam 			/*
31941056Swilliam 			 * Found bad block.  Calculate new block addr.
32041056Swilliam 			 * This starts at the end of the disk (skip the
32141056Swilliam 			 * last track which is used for the bad block list),
32241056Swilliam 			 * and works backwards to the front of the disk.
32341056Swilliam 			 */
32441056Swilliam #ifdef	WDDEBUG
32541056Swilliam 			    dprintf(DDSK,"--- badblock code -> Old = %d; ",
32641056Swilliam 				blknum);
32741056Swilliam #endif
32841056Swilliam 			blknum = du->dk_dd.dk_secperunit - du->dk_dd.dk_nsectors
32941056Swilliam 				- (bt_ptr - dkbad[unit].bt_bad) - 1;
33041056Swilliam 			cylin = blknum / secpercyl;
33141056Swilliam 			head = (blknum % secpercyl) / secpertrk;
33241056Swilliam 			sector = blknum % secpertrk;
33341056Swilliam #ifdef	WDDEBUG
33441056Swilliam 			    dprintf(DDSK, "new = %d\n", blknum);
33541056Swilliam #endif
33641056Swilliam 			break;
33741056Swilliam 		}
33841056Swilliam 	}
33945550Sbill 	sector += 1;	/* sectors begin with 1, not 0 */
34041056Swilliam 
34141056Swilliam 	wdtab.b_active = 1;		/* mark controller active */
34241056Swilliam 
34345550Sbill 	if(du->dk_skip==0 || wd_sebyse) {
34445550Sbill 	if(wdtab.b_errcnt && (bp->b_flags & B_READ) == 0) du->dk_bc += 512;
34545550Sbill 	while ((inb(wdc+wd_status) & WDCS_BUSY) != 0) ;
34645550Sbill 	/*while ((inb(wdc+wd_status) & WDCS_DRQ)) inb(wdc+wd_data);*/
34741056Swilliam 	outb(wdc+wd_precomp, 0xff);
34841056Swilliam 	/*wr(wdc+wd_precomp, du->dk_dd.dk_precompcyl / 4);*/
34941056Swilliam 	/*if (bp->b_flags & B_FORMAT) {
35041056Swilliam 		wr(wdc+wd_sector, du->dk_dd.dk_gap3);
35141056Swilliam 		wr(wdc+wd_seccnt, du->dk_dd.dk_nsectors);
35241056Swilliam 	} else {*/
35345550Sbill 	if(wd_sebyse)
35445550Sbill 		outb(wdc+wd_seccnt, 1);
35545550Sbill 	else
35645550Sbill 		outb(wdc+wd_seccnt, ((du->dk_bc +511) / 512));
35741056Swilliam 	outb(wdc+wd_sector, sector);
35841056Swilliam 
35941056Swilliam 	outb(wdc+wd_cyl_lo, cylin);
36041056Swilliam 	outb(wdc+wd_cyl_hi, cylin >> 8);
36141056Swilliam 
36241056Swilliam 	/* Set up the SDH register (select drive).     */
36341056Swilliam 	outb(wdc+wd_sdh, WDSD_IBM | (unit<<4) | (head & 0xf));
36445551Sbill 	while ((inb(wdc+wd_status) & WDCS_READY) == 0) ;
36541056Swilliam 
36641056Swilliam 	/*if (bp->b_flags & B_FORMAT)
36741056Swilliam 		wr(wdc+wd_command, WDCC_FORMAT);
36841056Swilliam 	else*/
36941056Swilliam 		outb(wdc+wd_command,
37041056Swilliam 			(bp->b_flags & B_READ)? WDCC_READ : WDCC_WRITE);
37141056Swilliam #ifdef	WDDEBUG
37245550Sbill 	dprintf(DDSK,"sector %d cylin %d head %d addr %x sts %x\n",
37345550Sbill 	    sector, cylin, head, addr, inb(wdc+wd_altsts));
37441056Swilliam #endif
37545550Sbill }
37641056Swilliam 
37741056Swilliam 	/* If this is a read operation, just go away until it's done.	*/
37841056Swilliam 	if (bp->b_flags & B_READ) return;
37941056Swilliam 
38041056Swilliam 	/* Ready to send data?	*/
38145551Sbill 	while ((inb(wdc+wd_status) & WDCS_DRQ) == 0)
38241056Swilliam 		nulldev();		/* So compiler won't optimize out */
38341056Swilliam 
38441056Swilliam 	/* ASSUMES CONTIGUOUS MEMORY */
38545550Sbill 	outsw (wdc+wd_data, addr+du->dk_skip*512, 256);
38641056Swilliam 	du->dk_bc -= 512;
38741056Swilliam }
38841056Swilliam 
38941056Swilliam /*
39041056Swilliam  * these are globally defined so they can be found
39141056Swilliam  * by the debugger easily in the case of a system crash
39241056Swilliam  */
39341056Swilliam daddr_t wd_errsector;
39441056Swilliam daddr_t wd_errbn;
39541056Swilliam unsigned char wd_errstat;
39641056Swilliam 
39741056Swilliam /* Interrupt routine for the controller.  Acknowledge the interrupt, check for
39841056Swilliam  * errors on the current operation, mark it done if necessary, and start
39941056Swilliam  * the next request.  Also check for a partially done transfer, and
40041056Swilliam  * continue with the next chunk if so.
40141056Swilliam  */
40241056Swilliam wdintr()
40341056Swilliam {
40441056Swilliam 	register struct	disk *du;
40541056Swilliam 	register struct buf *bp, *dp;
40641056Swilliam 	int status;
40741056Swilliam 	char partch ;
40845550Sbill static shit[32];
40945550Sbill static wd_haderror;
41041056Swilliam 
41141056Swilliam 	/* Shouldn't need this, but it may be a slow controller.	*/
41245550Sbill 	while ((status = inb(wdc+wd_status)) & WDCS_BUSY)
41341056Swilliam 		nulldev();
41441056Swilliam 	if (!wdtab.b_active) {
41541056Swilliam 		printf("wd: extra interrupt\n");
41641056Swilliam 		return;
41741056Swilliam 	}
41841056Swilliam 
41945549Sbill #ifdef	WDDEBUG
42041056Swilliam 	dprintf(DDSK,"I ");
42141056Swilliam #endif
42241056Swilliam 	dp = wdtab.b_actf;
42341056Swilliam 	bp = dp->b_actf;
42441056Swilliam 	du = &wddrives[WDUNIT(bp->b_dev)];
42541056Swilliam 	partch = "abcdefgh"[minor(bp->b_dev)&7] ;
42641056Swilliam 	if (DISKSTATE(du->dk_state) <= RDLABEL) {
42741056Swilliam 		if (wdcontrol(bp))
42841056Swilliam 			goto done;
42941056Swilliam 		return;
43041056Swilliam 	}
43141056Swilliam 	if (status & (WDCS_ERR | WDCS_ECCCOR)) {
43245550Sbill 		wd_errstat = inb(wdc+wd_error);		/* save error status */
43341056Swilliam #ifdef	WDDEBUG
43445550Sbill 		printf("status %x error %x\n", status, wd_errstat);
43541056Swilliam #endif
43645550Sbill 		if(wd_sebyse == 0) {
43745550Sbill 			wd_haderror = 1;
43845550Sbill 			goto outt;
43945550Sbill 		}
44041056Swilliam 		/*if (bp->b_flags & B_FORMAT) {
44141056Swilliam 			du->dk_status = status;
44241056Swilliam 			du->dk_error = wdp->wd_error;
44341056Swilliam 			bp->b_flags |= B_ERROR;
44441056Swilliam 			goto done;
44541056Swilliam 		}*/
44641056Swilliam 
44741056Swilliam 		wd_errsector = (bp->b_cylin * du->dk_dd.dk_secpercyl) +
44841056Swilliam 			(((unsigned long) bp->b_blkno * DEV_BSIZE /
44941056Swilliam 			    du->dk_dd.dk_secsize) % du->dk_dd.dk_secpercyl) +
45041056Swilliam 			du->dk_skip;
45141056Swilliam 		wd_errbn = bp->b_blkno
45241056Swilliam 			+ du->dk_skip * du->dk_dd.dk_secsize / DEV_BSIZE ;
45341056Swilliam 		if (status & WDCS_ERR) {
45445550Sbill 			if (++wdtab.b_errcnt < RETRIES) {
45541056Swilliam 				wdtab.b_active = 0;
45645550Sbill 				/*while ((inb(wdc+wd_status) & WDCS_DRQ))
45745550Sbill 				insw(wdc+wd_data, &shit, sizeof(shit)/2);*/
45845550Sbill 			} else {
45941056Swilliam 				printf("wd%d%c: ", du->dk_unit, partch);
46041056Swilliam 				printf(
46141056Swilliam 				"hard %s error, sn %d bn %d status %b error %b\n",
46241056Swilliam 					(bp->b_flags & B_READ)? "read":"write",
46341056Swilliam 					wd_errsector, wd_errbn, status, WDCS_BITS,
46441056Swilliam 					wd_errstat, WDERR_BITS);
46541056Swilliam 				bp->b_flags |= B_ERROR;	/* flag the error */
46641056Swilliam 			}
46741056Swilliam 		} else
46841056Swilliam 			log(LOG_WARNING,"wd%d%c: soft ecc sn %d bn %d\n",
46941056Swilliam 				du->dk_unit, partch, wd_errsector,
47041056Swilliam 				wd_errbn);
47141056Swilliam 	}
47245550Sbill outt:
47341056Swilliam 
47441056Swilliam 	/*
47541056Swilliam 	 * If this was a successful read operation, fetch the data.
47641056Swilliam 	 */
47741056Swilliam 	if (((bp->b_flags & (B_READ | B_ERROR)) == B_READ) && wdtab.b_active) {
47841056Swilliam 		int chk, dummy;
47941056Swilliam 
48045550Sbill 		chk = min(256,du->dk_bc/2);
48141056Swilliam 		/* Ready to receive data?	*/
48241056Swilliam 		while ((inb(wdc+wd_status) & WDCS_DRQ) == 0)
48341056Swilliam 			nulldev();
48441056Swilliam 
48541056Swilliam /*dprintf(DDSK,"addr %x\n", (int)bp->b_un.b_addr + du->dk_skip * 512);*/
48641056Swilliam 		insw(wdc+wd_data,(int)bp->b_un.b_addr + du->dk_skip * 512 ,chk);
48743592Sdonahn 		du->dk_bc -= 2*chk;
48845550Sbill 		while (chk++ < 256) insw (wdc+wd_data,&dummy,1);
48941056Swilliam 	}
49041056Swilliam 
49141056Swilliam 	wdxfer[du->dk_unit]++;
49241056Swilliam 	if (wdtab.b_active) {
49341056Swilliam 		if ((bp->b_flags & B_ERROR) == 0) {
49441056Swilliam 			du->dk_skip++;		/* Add to successful sectors. */
49541056Swilliam 			if (wdtab.b_errcnt) {
49641056Swilliam 				log(LOG_WARNING, "wd%d%c: ",
49741056Swilliam 						du->dk_unit, partch);
49841056Swilliam 				log(LOG_WARNING,
49941056Swilliam 			"soft %s error, sn %d bn %d error %b retries %d\n",
50041056Swilliam 				    (bp->b_flags & B_READ) ? "read" : "write",
50141056Swilliam 				    wd_errsector, wd_errbn, wd_errstat,
50241056Swilliam 				    WDERR_BITS, wdtab.b_errcnt);
50341056Swilliam 			}
50441056Swilliam 			wdtab.b_errcnt = 0;
50541056Swilliam 
50641056Swilliam 			/* see if more to transfer */
50743592Sdonahn 			/*if (du->dk_skip < (bp->b_bcount + 511) / 512) {*/
50845550Sbill 			if (du->dk_bc > 0 && wd_haderror == 0) {
50941056Swilliam 				wdstart();
51041056Swilliam 				return;		/* next chunk is started */
51145550Sbill 			} else if (wd_haderror && wd_sebyse == 0) {
51245550Sbill 				du->dk_skip = 0;
51345550Sbill 				wd_haderror = 0;
51445550Sbill 				wd_sebyse = 1;
51545550Sbill 				wdstart();
51645550Sbill 				return;		/* redo xfer sector by sector */
51741056Swilliam 			}
51841056Swilliam 		}
51941056Swilliam 
52041056Swilliam done:
52145550Sbill 		wd_sebyse = 0;
52241056Swilliam 		/* done with this transfer, with or without error */
52341056Swilliam 		wdtab.b_actf = dp->b_forw;
52441056Swilliam 		wdtab.b_errcnt = 0;
52541056Swilliam 		du->dk_skip = 0;
52641056Swilliam 		dp->b_active = 0;
52741056Swilliam 		dp->b_actf = bp->av_forw;
52841056Swilliam 		dp->b_errcnt = 0;
52941056Swilliam 		bp->b_resid = 0;
53041056Swilliam 		biodone(bp);
53141056Swilliam 	}
53241056Swilliam 	wdtab.b_active = 0;
53341056Swilliam 	if (dp->b_actf)
53441056Swilliam 		wdustart(du);		/* requeue disk if more io to do */
53541056Swilliam 	if (wdtab.b_actf)
53641056Swilliam 		wdstart();		/* start IO on next drive */
53741056Swilliam }
53841056Swilliam 
53941056Swilliam /*
54041056Swilliam  * Initialize a drive.
54141056Swilliam  */
54241056Swilliam wdopen(dev, flags)
54341056Swilliam 	dev_t	dev;
54441056Swilliam 	int	flags;
54541056Swilliam {
54641056Swilliam 	register unsigned int unit;
54741056Swilliam 	register struct buf *bp;
54841056Swilliam 	register struct disk *du;
54941056Swilliam 	struct dkbad *db;
55041056Swilliam 	int i, error = 0;
55141056Swilliam 
55241056Swilliam 	unit = WDUNIT(dev);
55341056Swilliam 	if (unit >= NWD) return (ENXIO) ;
55441056Swilliam 	du = &wddrives[unit];
55541056Swilliam 	if (du->dk_open){
55641056Swilliam 		du->dk_open++ ;
55741056Swilliam 		return(0);	/* already is open, don't mess with it */
55841056Swilliam 	}
55941056Swilliam #ifdef THE_BUG
56041056Swilliam 	if (du->dk_state && DISKSTATE(du->dk_state) <= OPEN)
56141056Swilliam 		return(0);
56241056Swilliam #endif
56341056Swilliam 	du->dk_unit = unit;
56441056Swilliam 	wdutab[unit].b_actf = NULL;
56541056Swilliam 	/*if (flags & O_NDELAY)
56641056Swilliam 		du->dk_state = WANTOPENRAW;
56741056Swilliam 	else*/
56841056Swilliam 		du->dk_state = WANTOPEN;
56941056Swilliam 	/*
57041056Swilliam 	 * Use the default sizes until we've read the label,
57141056Swilliam 	 * or longer if there isn't one there.
57241056Swilliam 	 */
57341056Swilliam 	du->dk_dd = dflt_sizes;
57441056Swilliam 
57541056Swilliam 	/*
57641056Swilliam 	 * Recal, read of disk label will be done in wdcontrol
57741056Swilliam 	 * during first read operation.
57841056Swilliam 	 */
57941056Swilliam 	bp = geteblk(512);
58045549Sbill 	bp->b_dev = dev & 0xff00;
58141056Swilliam 	bp->b_blkno = bp->b_bcount = 0;
58241056Swilliam 	bp->b_flags = B_READ;
58341056Swilliam 	wdstrategy(bp);
58441056Swilliam 	biowait(bp);
58541056Swilliam 	if (bp->b_flags & B_ERROR) {
58641056Swilliam 		u.u_error = 0; 	/* XXX */
58741056Swilliam 		error = ENXIO;
58841056Swilliam 		du->dk_state = CLOSED;
58941056Swilliam 		goto done;
59041056Swilliam 	}
59141056Swilliam 	if (du->dk_state == OPENRAW) {
59241056Swilliam 		du->dk_state = OPENRAW;
59341056Swilliam 		goto done;
59441056Swilliam 	}
59541056Swilliam 	/*
59641056Swilliam 	 * Read bad sector table into memory.
59741056Swilliam 	 */
59841056Swilliam 	i = 0;
59941056Swilliam 	do {
60041056Swilliam 		u.u_error = 0;				/* XXX */
60141056Swilliam 		bp->b_flags = B_BUSY | B_READ;
60241056Swilliam 		bp->b_blkno = du->dk_dd.dk_secperunit - du->dk_dd.dk_nsectors
60341056Swilliam 			+ i;
60441056Swilliam 		if (du->dk_dd.dk_secsize > DEV_BSIZE)
60541056Swilliam 			bp->b_blkno *= du->dk_dd.dk_secsize / DEV_BSIZE;
60641056Swilliam 		else
60741056Swilliam 			bp->b_blkno /= DEV_BSIZE / du->dk_dd.dk_secsize;
60841056Swilliam 		bp->b_bcount = du->dk_dd.dk_secsize;
60941056Swilliam 		bp->b_cylin = du->dk_dd.dk_ncylinders - 1;
61041056Swilliam 		wdstrategy(bp);
61141056Swilliam 		biowait(bp);
61241056Swilliam 	} while ((bp->b_flags & B_ERROR) && (i += 2) < 10 &&
61341056Swilliam 		i < du->dk_dd.dk_nsectors);
61441056Swilliam 	db = (struct dkbad *)(bp->b_un.b_addr);
61545550Sbill #define DKBAD_MAGIC 0x4321
61641056Swilliam 	if ((bp->b_flags & B_ERROR) == 0 && db->bt_mbz == 0 &&
61741056Swilliam 	    db->bt_flag == DKBAD_MAGIC) {
61841056Swilliam 		dkbad[unit] = *db;
61941056Swilliam 		du->dk_state = OPEN;
62041056Swilliam 	} else {
62141056Swilliam 		printf("wd%d: %s bad-sector file\n", unit,
62241056Swilliam 		    (bp->b_flags & B_ERROR) ? "can't read" : "format error in");
62341056Swilliam 		u.u_error = 0;				/* XXX */
62441056Swilliam 		/*error = ENXIO ;*/
62541056Swilliam 		du->dk_state = OPENRAW;
62641056Swilliam 	}
62741056Swilliam done:
62841056Swilliam 	bp->b_flags = B_INVAL | B_AGE;
62941056Swilliam 	brelse(bp);
63041056Swilliam 	if (error == 0)
63141056Swilliam 		du->dk_open = 1;
63241056Swilliam 	return (error);
63341056Swilliam }
63441056Swilliam 
63541056Swilliam /*
63641056Swilliam  * Implement operations other than read/write.
63741056Swilliam  * Called from wdstart or wdintr during opens and formats.
63841056Swilliam  * Uses finite-state-machine to track progress of operation in progress.
63941056Swilliam  * Returns 0 if operation still in progress, 1 if completed.
64041056Swilliam  */
64141056Swilliam wdcontrol(bp)
64241056Swilliam 	register struct buf *bp;
64341056Swilliam {
64441056Swilliam 	register struct disk *du;
64541056Swilliam 	register unit;
64641056Swilliam 	unsigned char  stat;
64741056Swilliam 	int s, cnt;
64841056Swilliam 	extern int bootdev, cyloffset;
64941056Swilliam 
65041056Swilliam 	du = &wddrives[WDUNIT(bp->b_dev)];
65141056Swilliam 	unit = du->dk_unit;
65241056Swilliam 	switch (DISKSTATE(du->dk_state)) {
65341056Swilliam 
65441056Swilliam 	tryagainrecal:
65541056Swilliam 	case WANTOPEN:			/* set SDH, step rate, do restore */
65641056Swilliam #ifdef	WDDEBUG
65741056Swilliam 		dprintf(DDSK,"wd%d: recal ", unit);
65841056Swilliam #endif
65941056Swilliam 		s = splbio();		/* not called from intr level ... */
660*45552Sbill 
661*45552Sbill #ifdef notdef
662*45552Sbill 		/* some compaq controllers require this ... */
663*45552Sbill 		outb(wdc+wd_sdh, WDSD_IBM | (unit << 4)
664*45552Sbill 			+ du->dk_dd.dk_ntracks-1);
665*45552Sbill 		outb(wdc+wd_seccnt, du->dk_dd.dk_nsectors);
666*45552Sbill 		outb(wdc+wd_command, 0x91);
667*45552Sbill 		while ((stat = inb(wdc+wd_status)) & WDCS_BUSY) nulldev();
668*45552Sbill #endif
669*45552Sbill 
67041056Swilliam 		outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));
67141056Swilliam 		wdtab.b_active = 1;
67241056Swilliam 		outb(wdc+wd_command, WDCC_RESTORE | WD_STEP);
67341056Swilliam 		du->dk_state++;
67441056Swilliam 		splx(s);
67541056Swilliam 		return(0);
67641056Swilliam 
67741056Swilliam 	case RECAL:
67845551Sbill 		if ((stat = inb(wdc+wd_status)) & WDCS_ERR) {
67941056Swilliam 			printf("wd%d: recal", du->dk_unit);
68041056Swilliam 			if (unit == 0) {
68141056Swilliam 				printf(": status %b error %b\n",
68241056Swilliam 					stat, WDCS_BITS,
68341056Swilliam 					inb(wdc+wd_error), WDERR_BITS);
68441056Swilliam 				if (++wdtab.b_errcnt < RETRIES)
68541056Swilliam 					goto tryagainrecal;
68641056Swilliam 			}
68741056Swilliam 			goto badopen;
68841056Swilliam 		}
68941056Swilliam 		wdtab.b_errcnt = 0;
69041056Swilliam 		if (ISRAWSTATE(du->dk_state)) {
69141056Swilliam 			du->dk_state = OPENRAW;
69241056Swilliam 			return(1);
69341056Swilliam 		}
69441056Swilliam retry:
69541056Swilliam #ifdef	WDDEBUG
69641056Swilliam 		dprintf(DDSK,"rdlabel ");
69741056Swilliam #endif
698*45552Sbill if( cyloffset < 0 || cyloffset > 2048) cyloffset=0;
69941056Swilliam 		/*
70041056Swilliam 		 * Read in sector 0 to get the pack label and geometry.
70141056Swilliam 		 */
70241056Swilliam 		outb(wdc+wd_precomp, 0xff);/* sometimes this is head bit 3 */
70341056Swilliam 		outb(wdc+wd_seccnt, 1);
70441056Swilliam 		outb(wdc+wd_sector, 1);
70541056Swilliam 		/*if (bp->b_dev == bootdev) {
70641056Swilliam 			(wdc+wd_cyl_lo = cyloffset & 0xff;
70741056Swilliam 			(wdc+wd_cyl_hi = cyloffset >> 8;
70841056Swilliam 		} else {
70941056Swilliam 			(wdc+wd_cyl_lo = 0;
71041056Swilliam 			(wdc+wd_cyl_hi = 0;
71141056Swilliam 		}*/
71241056Swilliam 		outb(wdc+wd_cyl_lo, (cyloffset & 0xff));
71341056Swilliam 		outb(wdc+wd_cyl_hi, (cyloffset >> 8));
71441056Swilliam 		outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));
71541056Swilliam 		outb(wdc+wd_command, WDCC_READ);
71641056Swilliam 		du->dk_state = RDLABEL;
71741056Swilliam 		return(0);
71841056Swilliam 
71941056Swilliam 	case RDLABEL:
72041056Swilliam 		if ((stat = inb(wdc+wd_status)) & WDCS_ERR) {
72141056Swilliam 			if (++wdtab.b_errcnt < RETRIES)
72241056Swilliam 				goto retry;
72341056Swilliam 			printf("wd%d: read label", unit);
72441056Swilliam 			goto badopen;
72541056Swilliam 		}
72641056Swilliam 
72741056Swilliam 		insw(wdc+wd_data, bp->b_un.b_addr, 256);
72841056Swilliam 
72941056Swilliam 		if (((struct disklabel *)
73041056Swilliam 		    (bp->b_un.b_addr + LABELOFFSET))->dk_magic == DISKMAGIC) {
73141056Swilliam 		       du->dk_dd =
73241056Swilliam 			 * (struct disklabel *) (bp->b_un.b_addr + LABELOFFSET);
73341056Swilliam 		} else {
73441056Swilliam 			printf("wd%d: bad disk label\n", du->dk_unit);
73541056Swilliam 			du->dk_state = OPENRAW;
73641056Swilliam 		}
737*45552Sbill 
738*45552Sbill 		s = splbio();		/* not called from intr level ... */
739*45552Sbill 		while ((stat = inb(wdc+wd_status)) & WDCS_BUSY) nulldev();
740*45552Sbill 		outb(wdc+wd_sdh, WDSD_IBM | (unit << 4)
741*45552Sbill 			+ du->dk_dd.dk_ntracks-1);
742*45552Sbill 		outb(wdc+wd_cyl_lo, du->dk_dd.dk_ncylinders);
743*45552Sbill 		outb(wdc+wd_cyl_hi, du->dk_dd.dk_ncylinders>>8);
744*45552Sbill 		outb(wdc+wd_seccnt, du->dk_dd.dk_nsectors);
745*45552Sbill 		outb(wdc+wd_command, 0x91);
746*45552Sbill 		while ((stat = inb(wdc+wd_status)) & WDCS_BUSY) nulldev();
747*45552Sbill 		outb(wdc+wd_seccnt, 0);
748*45552Sbill 		splx(s);
749*45552Sbill 
75041056Swilliam 		if (du->dk_state == RDLABEL)
75141056Swilliam 			du->dk_state = RDBADTBL;
75241056Swilliam 		/*
75341056Swilliam 		 * The rest of the initialization can be done
75441056Swilliam 		 * by normal means.
75541056Swilliam 		 */
75641056Swilliam 		return(1);
75741056Swilliam 
75841056Swilliam 	default:
75941056Swilliam 		panic("wdcontrol %x", du->dk_state );
76041056Swilliam 	}
76141056Swilliam 	/* NOTREACHED */
76241056Swilliam 
76341056Swilliam badopen:
76441056Swilliam 	printf(": status %b error %b\n",
76541056Swilliam 		stat, WDCS_BITS, inb(wdc+wd_error), WDERR_BITS);
76641056Swilliam 	du->dk_state = OPENRAW;
76741056Swilliam 	return(1);
76841056Swilliam }
76941056Swilliam 
77041056Swilliam wdclose(dev)
77141056Swilliam 	dev_t dev;
77241056Swilliam {	struct disk *du;
77341056Swilliam 
77441056Swilliam 	du = &wddrives[WDUNIT(dev)];
77541056Swilliam 	du->dk_open-- ;
77641056Swilliam 	/*if (du->dk_open == 0) du->dk_state = CLOSED ; does not work */
77741056Swilliam }
77841056Swilliam 
77941056Swilliam wdioctl(dev,cmd,addr,flag)
78041056Swilliam 	dev_t dev;
78141056Swilliam 	caddr_t addr;
78241056Swilliam {
78341056Swilliam 	int unit = WDUNIT(dev);
78441056Swilliam 	register struct disk *du;
78541056Swilliam 	int error = 0;
78641056Swilliam 	struct uio auio;
78741056Swilliam 	struct iovec aiov;
78841056Swilliam 	/*int wdformat();*/
78941056Swilliam 
79041056Swilliam 	du = &wddrives[unit];
79141056Swilliam 
79241056Swilliam 	switch (cmd) {
79341056Swilliam 
79441056Swilliam 	case DIOCGDINFO:
79541056Swilliam 		*(struct disklabel *)addr = du->dk_dd;
79641056Swilliam 		break;
79741056Swilliam 
79841056Swilliam 	case DIOCGDINFOP:
79941056Swilliam 		*(struct disklabel **)addr = &(du->dk_dd);
80041056Swilliam 		break;
80141056Swilliam 
80241056Swilliam #ifdef notyet
80341056Swilliam 	case DIOCWFORMAT:
80441056Swilliam 		if ((flag & FWRITE) == 0)
80541056Swilliam 			error = EBADF;
80641056Swilliam 		else {
80741056Swilliam 			register struct format_op *fop;
80841056Swilliam 
80941056Swilliam 			fop = (struct format_op *)addr;
81041056Swilliam 			aiov.iov_base = fop->df_buf;
81141056Swilliam 			aiov.iov_len = fop->df_count;
81241056Swilliam 			auio.uio_iov = &aiov;
81341056Swilliam 			auio.uio_iovcnt = 1;
81441056Swilliam 			auio.uio_resid = fop->df_count;
81541056Swilliam 			auio.uio_segflg = 0;
81641056Swilliam 			auio.uio_offset =
81741056Swilliam 				fop->df_startblk * du->dk_dd.dk_secsize;
81841056Swilliam 			error = physio(wdformat, &rwdbuf[unit], dev, B_WRITE,
81941056Swilliam 				minphys, &auio);
82041056Swilliam 			fop->df_count -= auio.uio_resid;
82141056Swilliam 			fop->df_reg[0] = du->dk_status;
82241056Swilliam 			fop->df_reg[1] = du->dk_error;
82341056Swilliam 		}
82441056Swilliam 		break;
82541056Swilliam #endif
82641056Swilliam 
82741056Swilliam 	default:
82841056Swilliam 		error = ENOTTY;
82941056Swilliam 		break;
83041056Swilliam 	}
83141056Swilliam 	return (error);
83241056Swilliam }
83341056Swilliam 
83441056Swilliam /*wdformat(bp)
83541056Swilliam 	struct buf *bp;
83641056Swilliam {
83741056Swilliam 
83841056Swilliam 	bp->b_flags |= B_FORMAT;
83941056Swilliam 	return (wdstrategy(bp));
84041056Swilliam }*/
84141056Swilliam 
84241056Swilliam /*
84341056Swilliam  * Routines to do raw IO for a unit.
84441056Swilliam  */
84541056Swilliam wdread(dev, uio)			/* character read routine */
84641056Swilliam 	dev_t dev;
84741056Swilliam 	struct uio *uio;
84841056Swilliam {
84941056Swilliam 	int unit = WDUNIT(dev) ;
85041056Swilliam 
85141056Swilliam 	if (unit >= NWD) return(ENXIO);
85241056Swilliam 	return(physio(wdstrategy, &rwdbuf[unit], dev, B_READ, minphys, uio));
85341056Swilliam }
85441056Swilliam 
85541056Swilliam 
85641056Swilliam wdwrite(dev, uio)			/* character write routine */
85741056Swilliam 	dev_t dev;
85841056Swilliam 	struct uio *uio;
85941056Swilliam {
86041056Swilliam 	int unit = WDUNIT(dev) ;
86141056Swilliam 
86241056Swilliam 	if (unit >= NWD) return(ENXIO);
86341056Swilliam 	return(physio(wdstrategy, &rwdbuf[unit], dev, B_WRITE, minphys, uio));
86441056Swilliam }
86541056Swilliam 
86641056Swilliam wdsize(dev)
86741056Swilliam 	dev_t dev;
86841056Swilliam {
86941056Swilliam 	register unit = WDUNIT(dev) ;
87041056Swilliam 	register xunit = minor(dev) & 07;
87141056Swilliam 	register struct disk *du;
87241056Swilliam 	register val ;
87341056Swilliam 
87445550Sbill 	return(21600);
87541056Swilliam #ifdef notdef
87641056Swilliam 	if (unit >= NWD) return(-1);
87741056Swilliam 	if (wddrives[unit].dk_state == 0) /*{
87841056Swilliam 		val = wdopen (dev, 0) ;
87941056Swilliam 		if (val < 0) return (val) ;
88041056Swilliam 	}*/	return (-1) ;
88141056Swilliam 	du = &wddrives[unit];
88241056Swilliam 	return((int)((u_long)du->dk_dd.dk_partition[xunit].nblocks *
88341056Swilliam 		du->dk_dd.dk_secsize / 512));
88441056Swilliam #endif
88541056Swilliam }
88641056Swilliam 
88741056Swilliam wddump(dev)			/* dump core after a system crash */
88841056Swilliam 	dev_t dev;
88941056Swilliam {
89041056Swilliam #ifdef notyet
89141056Swilliam 	register struct disk *du;	/* disk unit to do the IO */
89241056Swilliam 	register struct wd1010 *wdp = (struct wd1010 *) VA_WD;
89341056Swilliam 	register struct bt_bad *bt_ptr;
89441056Swilliam 	long	num;			/* number of sectors to write */
89541056Swilliam 	int	unit, xunit;
89641056Swilliam 	long	cyloff, blknum, blkcnt;
89741056Swilliam 	long	cylin, head, sector;
89841056Swilliam 	long	secpertrk, secpercyl, nblocks, i;
89941056Swilliam 	register char *addr;
90041056Swilliam 	char	*end;
90141056Swilliam 	extern	int dumplo, totalclusters;
90241056Swilliam 	static  wddoingadump = 0 ;
90341056Swilliam 
90441056Swilliam 	addr = (char *) PA_RAM;		/* starting address */
90541056Swilliam 	/* size of memory to dump */
90641056Swilliam 	num = totalclusters * CLSIZE - PA_RAM / PGSIZE;
90741056Swilliam 	unit = WDUNIT(dev) ;		/* eventually support floppies? */
90841056Swilliam 	xunit = minor(dev) & 7;		/* file system */
90941056Swilliam 	/* check for acceptable drive number */
91041056Swilliam 	if (unit >= NWD) return(ENXIO);
91141056Swilliam 
91241056Swilliam 	du = &wddrives[unit];
91341056Swilliam 	/* was it ever initialized ? */
91441056Swilliam 	if (du->dk_state < OPEN) return (ENXIO) ;
91541056Swilliam 
91641056Swilliam 	/* Convert to disk sectors */
91741056Swilliam 	num = (u_long) num * PGSIZE / du->dk_dd.dk_secsize;
91841056Swilliam 
91941056Swilliam 	/* check if controller active */
92041056Swilliam 	/*if (wdtab.b_active) return(EFAULT); */
92141056Swilliam 	if (wddoingadump) return(EFAULT);
92241056Swilliam 
92341056Swilliam 	secpertrk = du->dk_dd.dk_nsectors;
92441056Swilliam 	secpercyl = du->dk_dd.dk_secpercyl;
92541056Swilliam 	nblocks = du->dk_dd.dk_partition[xunit].nblocks;
92641056Swilliam 	cyloff = du->dk_dd.dk_partition[xunit].cyloff;
92741056Swilliam 
92841056Swilliam 	/* check transfer bounds against partition size */
92941056Swilliam 	if ((dumplo < 0) || ((dumplo + num) >= nblocks))
93041056Swilliam 		return(EINVAL);
93141056Swilliam 
93241056Swilliam 	/*wdtab.b_active = 1;		/* mark controller active for if we
93341056Swilliam 					   panic during the dump */
93441056Swilliam 	wddoingadump = 1  ;  i = 100000 ;
93541056Swilliam 	while ((wdp->wd_status & WDCS_BUSY) && (i-- > 0)) nulldev() ;
93641056Swilliam 	inb(wdc+wd_sdh = du->dk_sdh ;
93741056Swilliam 	inb(wdc+wd_command = WDCC_RESTORE | WD_STEP;
93841056Swilliam 	while (inb(wdc+wd_status & WDCS_BUSY) nulldev() ;
93941056Swilliam 
94041056Swilliam 	blknum = dumplo;
94141056Swilliam 	while (num > 0) {
94241056Swilliam #ifdef notdef
94341056Swilliam 		if (blkcnt > MAXTRANSFER) blkcnt = MAXTRANSFER;
94441056Swilliam 		if ((blknum + blkcnt - 1) / secpercyl != blknum / secpercyl)
94541056Swilliam 			blkcnt = secpercyl - (blknum % secpercyl);
94641056Swilliam 			    /* keep transfer within current cylinder */
94741056Swilliam #endif
94841056Swilliam 
94941056Swilliam 		/* compute disk address */
95041056Swilliam 		cylin = blknum / secpercyl;
95141056Swilliam 		head = (blknum % secpercyl) / secpertrk;
95241056Swilliam 		sector = blknum % secpertrk;
95341056Swilliam 		sector++;		/* origin 1 */
95443592Sdonahn 		cylin += cyloff;
95541056Swilliam 
95641056Swilliam 		/*
95741056Swilliam 		 * See if the current block is in the bad block list.
95841056Swilliam 		 * (If we have one.)
95941056Swilliam 		 */
96041056Swilliam 	    		for (bt_ptr = dkbad[unit].bt_bad;
96141056Swilliam 				bt_ptr->bt_cyl != -1; bt_ptr++) {
96241056Swilliam 			if (bt_ptr->bt_cyl > cylin)
96341056Swilliam 				/* Sorted list, and we passed our cylinder.
96441056Swilliam 					quit. */
96541056Swilliam 				break;
96641056Swilliam 			if (bt_ptr->bt_cyl == cylin &&
96741056Swilliam 				bt_ptr->bt_trksec == (head << 8) + sector) {
96841056Swilliam 			/*
96941056Swilliam 			 * Found bad block.  Calculate new block addr.
97041056Swilliam 			 * This starts at the end of the disk (skip the
97141056Swilliam 			 * last track which is used for the bad block list),
97241056Swilliam 			 * and works backwards to the front of the disk.
97341056Swilliam 			 */
97441056Swilliam 				blknum = (du->dk_dd.dk_secperunit)
97541056Swilliam 					- du->dk_dd.dk_nsectors
97641056Swilliam 					- (bt_ptr - dkbad[unit].bt_bad) - 1;
97741056Swilliam 				cylin = blknum / secpercyl;
97841056Swilliam 				head = (blknum % secpercyl) / secpertrk;
97941056Swilliam 				sector = blknum % secpertrk;
98041056Swilliam 				break;
98141056Swilliam 			}
98241056Swilliam 
98341056Swilliam 		/* select drive.     */
98441056Swilliam 		inb(wdc+wd_sdh = du->dk_sdh | (head&07);
98541056Swilliam 		while ((inb(wdc+wd_status & WDCS_READY) == 0) nulldev();
98641056Swilliam 
98741056Swilliam 		/* transfer some blocks */
98841056Swilliam 		inb(wdc+wd_sector = sector;
98941056Swilliam 		inb(wdc+wd_seccnt = 1;
99041056Swilliam 		inb(wdc+wd_cyl_lo = cylin;
99141056Swilliam 		if (du->dk_dd.dk_ntracks > 8) {
99241056Swilliam 			if (head > 7)
99341056Swilliam 				inb(wdc+wd_precomp = 0;	/* set 3rd head bit */
99441056Swilliam 			else
99541056Swilliam 				inb(wdc+wd_precomp = 0xff;	/* set 3rd head bit */
99641056Swilliam 		}
99741056Swilliam 		inb(wdc+wd_cyl_hi = cylin >> 8;
99841056Swilliam #ifdef notdef
99941056Swilliam 		/* lets just talk about this first...*/
100041056Swilliam 		printf ("sdh 0%o sector %d cyl %d addr 0x%x\n",
100141056Swilliam 			wdp->wd_sdh, wdp->wd_sector,
100241056Swilliam 			wdp->wd_cyl_hi*256+wdp->wd_cyl_lo, addr) ;
100341056Swilliam 		for (i=10000; i > 0 ; i--)
100441056Swilliam 			;
100541056Swilliam 		continue;
100641056Swilliam #endif
100741056Swilliam 		inb(wdc+wd_command = WDCC_WRITE;
100841056Swilliam 
100941056Swilliam 		/* Ready to send data?	*/
101041056Swilliam 		while ((inb(wdc+wd_status & WDCS_DRQ) == 0) nulldev();
101141056Swilliam 		if (inb(wdc+wd_status & WDCS_ERR) return(EIO) ;
101241056Swilliam 
101341056Swilliam 		end = (char *)addr + du->dk_dd.dk_secsize;
101441056Swilliam 		for (; addr < end; addr += 8) {
101541056Swilliam 			wdp->wd_data = addr[0];
101641056Swilliam 			wdp->wd_data = addr[1];
101741056Swilliam 			wdp->wd_data = addr[2];
101841056Swilliam 			wdp->wd_data = addr[3];
101941056Swilliam 			wdp->wd_data = addr[4];
102041056Swilliam 			wdp->wd_data = addr[5];
102141056Swilliam 			wdp->wd_data = addr[6];
102241056Swilliam 			wdp->wd_data = addr[7];
102341056Swilliam 		}
102441056Swilliam 		if (inb(wdc+wd_status & WDCS_ERR) return(EIO) ;
102541056Swilliam 		/* Check data request (should be done).         */
102641056Swilliam 		if (inb(wdc+wd_status & WDCS_DRQ) return(EIO) ;
102741056Swilliam 
102841056Swilliam 		/* wait for completion */
102941056Swilliam 		for ( i = 1000000 ; inb(wdc+wd_status & WDCS_BUSY ; i--) {
103041056Swilliam 				if (i < 0) return (EIO) ;
103141056Swilliam 				nulldev () ;
103241056Swilliam 		}
103341056Swilliam 		/* error check the xfer */
103441056Swilliam 		if (inb(wdc+wd_status & WDCS_ERR) return(EIO) ;
103541056Swilliam 		/* update block count */
103641056Swilliam 		num--;
103741056Swilliam 		blknum++ ;
103841056Swilliam #ifdef	WDDEBUG
103941056Swilliam if (num % 100 == 0) printf(".") ;
104041056Swilliam #endif
104141056Swilliam 	}
104241056Swilliam 	return(0);
104341056Swilliam #endif
104441056Swilliam }
104541056Swilliam #endif
1046