xref: /netbsd-src/sys/dev/ata/wd.c (revision ae9172d6cd9432a6a1a56760d86b32c57a66c39c)
1 /*	$NetBSD: wd.c,v 1.122 1994/12/14 15:23:49 mycroft Exp $	*/
2 
3 /*
4  * Copyright (c) 1994 Charles Hannum.  All rights reserved.
5  *
6  * DMA and multi-sector PIO handling are derived from code contributed by
7  * Onno van der Linden.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *	This product includes software developed by Charles Hannum.
20  * 4. The name of the author may not be used to endorse or promote products
21  *    derived from this software without specific prior written permission.
22  *
23  * Copyright (c) 1990 The Regents of the University of California.
24  * All rights reserved.
25  *
26  * This code is derived from software contributed to Berkeley by
27  * William Jolitz.
28  *
29  * Redistribution and use in source and binary forms, with or without
30  * modification, are permitted provided that the following conditions
31  * are met:
32  * 1. Redistributions of source code must retain the above copyright
33  *    notice, this list of conditions and the following disclaimer.
34  * 2. Redistributions in binary form must reproduce the above copyright
35  *    notice, this list of conditions and the following disclaimer in the
36  *    documentation and/or other materials provided with the distribution.
37  * 3. All advertising materials mentioning features or use of this software
38  *    must display the following acknowledgement:
39  *	This product includes software developed by the University of
40  *	California, Berkeley and its contributors.
41  * 4. Neither the name of the University nor the names of its contributors
42  *    may be used to endorse or promote products derived from this software
43  *    without specific prior written permission.
44  *
45  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
46  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
49  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55  * SUCH DAMAGE.
56  *
57  *	@(#)wd.c	7.2 (Berkeley) 5/9/91
58  */
59 
60 #define	INSTRUMENT	/* instrumentation stuff by Brad Parker */
61 
62 #include <sys/param.h>
63 #include <sys/systm.h>
64 #include <sys/kernel.h>
65 #include <sys/conf.h>
66 #include <sys/file.h>
67 #include <sys/stat.h>
68 #include <sys/ioctl.h>
69 #include <sys/buf.h>
70 #include <sys/uio.h>
71 #include <sys/malloc.h>
72 #include <sys/device.h>
73 #include <sys/disklabel.h>
74 #include <sys/disk.h>
75 #include <sys/syslog.h>
76 #ifdef INSTRUMENT
77 #include <sys/dkstat.h>
78 #endif
79 
80 #include <vm/vm.h>
81 
82 #include <machine/cpu.h>
83 #include <machine/pio.h>
84 
85 #include <i386/isa/isavar.h>
86 #include <i386/isa/wdreg.h>
87 
88 #define WDCNDELAY	100000	/* delay = 100us; so 10s for a controller state change */
89 #define WDCDELAY	100
90 
91 #define	WAITTIME	(4 * hz)	/* time to wait for a completion */
92 #define	RECOVERYTIME	(hz / 2)	/* time to recover from an error */
93 
94 #if 0
95 /* If you enable this, it will report any delays more than 100us * N long. */
96 #define WDCNDELAY_DEBUG	10
97 #endif
98 
99 #define	WDIORETRIES	5	/* number of retries before giving up */
100 
101 #define	WDUNIT(dev)			DISKUNIT(dev)
102 #define	WDPART(dev)			DISKPART(dev)
103 #define	MAKEWDDEV(maj, unit, part)	MAKEDISKDEV(maj, unit, part)
104 
105 #define	WDLABELDEV(dev)	(MAKEWDDEV(major(dev), WDUNIT(dev), RAW_PART))
106 
107 #define b_cylin	b_resid		/* cylinder number for doing IO to */
108 				/* shares an entry in the buf struct */
109 
110 /*
111  * Drive status.
112  */
113 struct wd_softc {
114 	struct device sc_dev;
115 	struct dkdevice sc_dk;
116 
117 	long	sc_bcount;	/* byte count left */
118 	short	sc_skip;	/* blocks already transferred */
119 	char	sc_drive;	/* physical unit number */
120 	char	sc_state;	/* control state */
121 #define	RECAL		0		/* recalibrate */
122 #define	RECAL_WAIT	1		/* done recalibrating */
123 #define	GEOMETRY	2		/* upload geometry */
124 #define	GEOMETRY_WAIT	3		/* done uploading geometry */
125 #define	MULTIMODE	4		/* set multiple mode */
126 #define	MULTIMODE_WAIT	5		/* done setting multiple mode */
127 #define	OPEN		6		/* done with open */
128 	char	sc_mode;	/* transfer mode */
129 #define	WDM_PIOSINGLE	0		/* single-sector PIO */
130 #define	WDM_PIOMULTI	1		/* multi-sector PIO */
131 #define	WDM_DMA		2		/* DMA */
132 	u_char	sc_multiple;	/* multiple for WDM_PIOMULTI */
133 	u_char	sc_flags;	/* drive characteistics found */
134 #define	WDF_LOCKED	0x01
135 #define	WDF_WANTED	0x02
136 #define	WDF_LOADED	0x04
137 #define	WDF_BSDLABEL	0x08		/* has a BSD disk label */
138 #define	WDF_WLABEL	0x10		/* label is writable */
139 #define	WDF_32BIT	0x20		/* can do 32-bit transfer */
140 	TAILQ_ENTRY(wd_softc) sc_drivechain;
141 	struct buf sc_q;
142 	struct wdparams sc_params; /* ESDI/IDE drive/controller parameters */
143 	long	sc_badsect[127];	/* 126 plus trailing -1 marker */
144 };
145 
146 struct wdc_softc {
147 	struct device sc_dev;
148 	struct intrhand sc_ih;
149 
150 	u_char	sc_flags;
151 #define	WDCF_ACTIVE	0x01	/* controller is active */
152 #define	WDCF_SINGLE	0x02	/* sector at a time mode */
153 #define	WDCF_ERROR	0x04	/* processing a disk error */
154 	u_char	sc_status;	/* copy of status register */
155 	u_char	sc_error;	/* copy of error register */
156 	int	sc_iobase;	/* I/O port base */
157 	int	sc_drq;		/* DMA channel */
158 	int	sc_errors;	/* count of errors during current transfer */
159 	int	sc_nblks;	/* number of blocks currently transferring */
160 	TAILQ_HEAD(drivehead, wd_softc) sc_drives;
161 };
162 
163 int wdcprobe __P((struct device *, void *, void *));
164 void wdcattach __P((struct device *, struct device *, void *));
165 
166 struct cfdriver wdccd = {
167 	NULL, "wdc", wdcprobe, wdcattach, DV_DULL, sizeof(struct wd_softc)
168 };
169 
170 int wdprobe __P((struct device *, void *, void *));
171 void wdattach __P((struct device *, struct device *, void *));
172 
173 struct cfdriver wdcd = {
174 	NULL, "wd", wdprobe, wdattach, DV_DISK, sizeof(struct wd_softc)
175 };
176 
177 void wdgetdisklabel __P((struct wd_softc *));
178 int wd_get_parms __P((struct wd_softc *));
179 void wdstrategy __P((struct buf *));
180 void wdstart __P((struct wd_softc *));
181 
182 struct dkdriver wddkdriver = { wdstrategy };
183 
184 void wdfinish __P((struct wd_softc *, struct buf *));
185 int wdcintr __P((struct wdc_softc *));
186 static void wdcstart __P((struct wdc_softc *));
187 static int wdcommand __P((struct wd_softc *, int, int, int, int, int));
188 static int wdcommandshort __P((struct wdc_softc *, int, int));
189 static int wdcontrol __P((struct wd_softc *));
190 static int wdsetctlr __P((struct wd_softc *));
191 static void bad144intern __P((struct wd_softc *));
192 static int wdcreset __P((struct wdc_softc *));
193 static void wdcrestart __P((void *arg));
194 static void wdcunwedge __P((struct wdc_softc *));
195 static void wdctimeout __P((void *arg));
196 static void wderror __P((void *, struct buf *, char *));
197 int wdcwait __P((struct wdc_softc *, int));
198 /* ST506 spec says that if READY or SEEKCMPLT go off, then the read or write
199    command is aborted. */
200 #define	wait_for_drq(d)		wdcwait(d, WDCS_DRDY | WDCS_DSC | WDCS_DRQ)
201 #define	wait_for_ready(d)	wdcwait(d, WDCS_DRDY | WDCS_DSC)
202 #define	wait_for_unbusy(d)	wdcwait(d, 0)
203 
204 /*
205  * Probe for controller.
206  */
207 int
208 wdcprobe(parent, match, aux)
209 	struct device *parent;
210 	void *match, *aux;
211 {
212 	struct wdc_softc *wdc = match;
213 	struct isa_attach_args *ia = aux;
214 	int iobase;
215 
216 	wdc->sc_iobase = iobase = ia->ia_iobase;
217 
218 	/* Check if we have registers that work. */
219 	outb(iobase+wd_error, 0x5a);	/* Error register not writable. */
220 	outb(iobase+wd_cyl_lo, 0xa5);	/* But all of cyllo are implemented. */
221 	if (inb(iobase+wd_error) == 0x5a || inb(iobase+wd_cyl_lo) != 0xa5)
222 		return 0;
223 
224 	if (wdcreset(wdc) != 0) {
225 		delay(500000);
226 		if (wdcreset(wdc) != 0)
227 			return 0;
228 	}
229 
230 	outb(iobase+wd_sdh, WDSD_IBM | 0);
231 
232 	/* Wait for controller to become ready. */
233 	if (wait_for_unbusy(wdc) < 0)
234 		return 0;
235 
236 	/* Send command. */
237 	outb(iobase+wd_command, WDCC_DIAGNOSE);
238 
239 	/* Wait for command to complete. */
240 	if (wait_for_unbusy(wdc) < 0)
241 		return 0;
242 
243 	ia->ia_iosize = 8;
244 	ia->ia_msize = 0;
245 	return 1;
246 }
247 
248 struct wdc_attach_args {
249 	int wa_drive;
250 };
251 
252 int
253 wdprint(aux, wdc)
254 	void *aux;
255 	char *wdc;
256 {
257 	struct wdc_attach_args *wa = aux;
258 
259 	if (!wdc)
260 		printf(" drive %d", wa->wa_drive);
261 	return QUIET;
262 }
263 
264 void
265 wdcattach(parent, self, aux)
266 	struct device *parent, *self;
267 	void *aux;
268 {
269 	struct wdc_softc *wdc = (void *)self;
270 	struct isa_attach_args *ia = aux;
271 	struct wdc_attach_args wa;
272 
273 	TAILQ_INIT(&wdc->sc_drives);
274 	wdc->sc_drq = ia->ia_drq;
275 
276 	printf("\n");
277 
278 	wdc->sc_ih.ih_fun = wdcintr;
279 	wdc->sc_ih.ih_arg = wdc;
280 	wdc->sc_ih.ih_level = IPL_BIO;
281 	intr_establish(ia->ia_irq, &wdc->sc_ih);
282 
283 	for (wa.wa_drive = 0; wa.wa_drive < 2; wa.wa_drive++)
284 		(void)config_found(self, (void *)&wa, wdprint);
285 }
286 
287 int
288 wdprobe(parent, match, aux)
289 	struct device *parent;
290 	void *match, *aux;
291 {
292 	struct wdc_softc *wdc = (void *)parent;
293 	struct cfdata *cf = match;
294 	struct wdc_attach_args *wa = aux;
295 	int drive = wa->wa_drive;
296 
297 	if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != drive)
298 		return 0;
299 
300 	if (wdcommandshort(wdc, drive, WDCC_RECAL) != 0 ||
301 	    wait_for_ready(wdc) != 0)
302 		return 0;
303 
304 	return 1;
305 }
306 
307 void
308 wdattach(parent, self, aux)
309 	struct device *parent, *self;
310 	void *aux;
311 {
312 	struct wd_softc *wd = (void *)self;
313 	struct wdc_softc *wdc = (void *)parent;
314 	struct wdc_attach_args *wa = aux;
315 	int i, blank;
316 
317 	wd->sc_drive = wa->wa_drive;
318 
319 	wd_get_parms(wd);
320 	printf(": %dMB, %d cyl, %d head, %d sec, %d bytes/sec <",
321 	    wd->sc_params.wdp_cylinders *
322 	    (wd->sc_params.wdp_heads * wd->sc_params.wdp_sectors) /
323 	    (1048576 / DEV_BSIZE),
324 	    wd->sc_params.wdp_cylinders,
325 	    wd->sc_params.wdp_heads,
326 	    wd->sc_params.wdp_sectors,
327 	    DEV_BSIZE);
328 	for (i = blank = 0; i < sizeof(wd->sc_params.wdp_model); i++) {
329 		char c = wd->sc_params.wdp_model[i];
330 		if (c == '\0')
331 			break;
332 		if (c != ' ') {
333 			if (blank)
334 				printf(" %c", c);
335 			else
336 				printf("%c", c);
337 			blank = 0;
338 		} else
339 			blank = 1;
340 	}
341 	printf(">\n");
342 
343 	if ((wd->sc_params.wdp_capabilities & WD_CAP_DMA) != 0 &&
344 	    wdc->sc_drq != DRQUNK) {
345 		wd->sc_mode = WDM_DMA;
346 	} else if (wd->sc_params.wdp_maxmulti > 1) {
347 		wd->sc_mode = WDM_PIOMULTI;
348 		wd->sc_multiple = min(wd->sc_params.wdp_maxmulti, 16);
349 	} else {
350 		wd->sc_mode = WDM_PIOSINGLE;
351 		wd->sc_multiple = 1;
352 	}
353 
354 	printf("%s: using", wd->sc_dev.dv_xname);
355 	if (wd->sc_mode == WDM_DMA)
356 		printf(" dma transfers,");
357 	else
358 		printf(" %d-sector %d-bit pio transfers,",
359 		    wd->sc_multiple, (wd->sc_flags & WDF_32BIT) == 0 ? 16 : 32);
360 	if ((wd->sc_params.wdp_capabilities & WD_CAP_LBA) != 0)
361 		printf(" lba addressing\n");
362 	else
363 		printf(" chs addressing\n");
364 
365 	wd->sc_dk.dk_driver = &wddkdriver;
366 }
367 
368 /*
369  * Read/write routine for a buffer.  Finds the proper unit, range checks
370  * arguments, and schedules the transfer.  Does not wait for the transfer to
371  * complete.  Multi-page transfers are supported.  All I/O requests must be a
372  * multiple of a sector in length.
373  */
374 void
375 wdstrategy(bp)
376 	struct buf *bp;
377 {
378 	struct wd_softc *wd;	/* disk unit to do the IO */
379 	int unit = WDUNIT(bp->b_dev);
380 	int s;
381 
382 	/* Valid unit, controller, and request?  */
383 	if (unit >= wdcd.cd_ndevs ||
384 	    (wd = wdcd.cd_devs[unit]) == 0 ||
385 	    bp->b_blkno < 0 ||
386 	    (bp->b_bcount % DEV_BSIZE) != 0 ||
387 	    (bp->b_bcount / DEV_BSIZE) >= (1 << NBBY)) {
388 		bp->b_error = EINVAL;
389 		goto bad;
390 	}
391 
392 #if 0
393 	/* "Soft" write protect check. */
394 	if ((wd->sc_flags & WDF_WRITEPROT) && (bp->b_flags & B_READ) == 0) {
395 		bp->b_error = EROFS;
396 		goto bad;
397 	}
398 #endif
399 
400 	/* If it's a null transfer, return immediately. */
401 	if (bp->b_bcount == 0)
402 		goto done;
403 
404 	/* Have partitions and want to use them? */
405 	if (WDPART(bp->b_dev) != RAW_PART) {
406 		if ((wd->sc_flags & WDF_BSDLABEL) == 0) {
407 			bp->b_error = EIO;
408 			goto bad;
409 		}
410 		/*
411 		 * Do bounds checking, adjust transfer. if error, process.
412 		 * If end of partition, just return.
413 		 */
414 		if (bounds_check_with_label(bp, &wd->sc_dk.dk_label,
415 		    (wd->sc_flags & WDF_WLABEL) != 0) <= 0)
416 			goto done;
417 		/* Otherwise, process transfer request. */
418 	}
419 
420 	/* Don't bother doing rotational optimization. */
421 	bp->b_cylin = 0;
422 
423 	/* Queue transfer on drive, activate drive and controller if idle. */
424 	s = splbio();
425 	disksort(&wd->sc_q, bp);
426 	if (!wd->sc_q.b_active)
427 		wdstart(wd);		/* Start drive. */
428 #if 0
429 	else {
430 		struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
431 		if ((wdc->sc_flags & (WDCF_ACTIVE|WDCF_ERROR)) == 0) {
432 			printf("wdstrategy: controller inactive\n");
433 			wdcstart(wdc);
434 		}
435 	}
436 #endif
437 	splx(s);
438 	return;
439 
440 bad:
441 	bp->b_flags |= B_ERROR;
442 done:
443 	/* Toss transfer; we're done early. */
444 	biodone(bp);
445 }
446 
447 /*
448  * Routine to queue a command to the controller.  The unit's request is linked
449  * into the active list for the controller.  If the controller is idle, the
450  * transfer is started.
451  */
452 void
453 wdstart(wd)
454 	struct wd_softc *wd;
455 {
456 	struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
457 	int active = wdc->sc_drives.tqh_first != 0;
458 
459 	/* Link onto controller queue. */
460 	wd->sc_q.b_active = 1;
461 	TAILQ_INSERT_TAIL(&wdc->sc_drives, wd, sc_drivechain);
462 
463 	/* If controller not already active, start it. */
464 	if (!active)
465 		wdcstart(wdc);
466 }
467 
468 void
469 wdfinish(wd, bp)
470 	struct wd_softc *wd;
471 	struct buf *bp;
472 {
473 	struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
474 
475 #ifdef INSTRUMENT
476 	dk_busy &= ~(1 << wd->sc_dev.dv_unit);
477 #endif
478 	wdc->sc_flags &= ~(WDCF_SINGLE | WDCF_ERROR);
479 	wdc->sc_errors = 0;
480 	/*
481 	 * Move this drive to the end of the queue to give others a `fair'
482 	 * chance.
483 	 */
484 	if (wd->sc_drivechain.tqe_next) {
485 		TAILQ_REMOVE(&wdc->sc_drives, wd, sc_drivechain);
486 		if (bp->b_actf) {
487 			TAILQ_INSERT_TAIL(&wdc->sc_drives, wd,
488 			    sc_drivechain);
489 		} else
490 			wd->sc_q.b_active = 0;
491 	}
492 	bp->b_resid = wd->sc_bcount;
493 	wd->sc_skip = 0;
494 	wd->sc_q.b_actf = bp->b_actf;
495 	biodone(bp);
496 }
497 
498 /*
499  * Controller startup routine.  This does the calculation, and starts a
500  * single-sector read or write operation.  Called to start a transfer, or from
501  * the interrupt routine to continue a multi-sector transfer.
502  * RESTRICTIONS:
503  * 1.	The transfer length must be an exact multiple of the sector size.
504  */
505 static void
506 wdcstart(wdc)
507 	struct wdc_softc *wdc;
508 {
509 	struct wd_softc *wd;	/* disk unit for IO */
510 	struct buf *bp;
511 	int nblks;
512 
513 loop:
514 	/* Is there a drive for the controller to do a transfer with? */
515 	wd = wdc->sc_drives.tqh_first;
516 	if (wd == NULL)
517 		return;
518 
519 	/* Is there a transfer to this drive?  If not, deactivate drive. */
520 	bp = wd->sc_q.b_actf;
521 	if (bp == NULL) {
522 		TAILQ_REMOVE(&wdc->sc_drives, wd, sc_drivechain);
523 		wd->sc_q.b_active = 0;
524 		goto loop;
525 	}
526 
527 	if (wdc->sc_errors >= WDIORETRIES) {
528 		wderror(wd, bp, "hard error");
529 		bp->b_error = EIO;
530 		bp->b_flags |= B_ERROR;
531 		wdfinish(wd, bp);
532 		goto loop;
533 	}
534 
535 	/* Do control operations specially. */
536 	if (wd->sc_state < OPEN) {
537 		/*
538 		 * Actually, we want to be careful not to mess with the control
539 		 * state if the device is currently busy, but we can assume
540 		 * that we never get to this point if that's the case.
541 		 */
542 		if (wdcontrol(wd) == 0) {
543 			/* The drive is busy.  Wait. */
544 			return;
545 		}
546 	}
547 
548 	/*
549 	 * WDCF_ERROR is set by wdcunwedge() and wdcintr() when an error is
550 	 * encountered.  If we are in multi-sector mode, then we switch to
551 	 * single-sector mode and retry the operation from the start.
552 	 */
553 	if (wdc->sc_flags & WDCF_ERROR) {
554 		wdc->sc_flags &= ~WDCF_ERROR;
555 		if ((wdc->sc_flags & WDCF_SINGLE) == 0) {
556 			wdc->sc_flags |= WDCF_SINGLE;
557 			wd->sc_skip = 0;
558 		}
559 	}
560 
561 	if (wd->sc_skip == 0) {
562 #ifdef WDDEBUG
563 		printf("\n%s: wdcstart %s %d@%d; map ", wd->sc_dev.dv_xname,
564 		    (bp->b_flags & B_READ) ? "read" : "write", bp->b_bcount,
565 		    bp->b_blkno);
566 #endif
567 		wd->sc_bcount = bp->b_bcount;
568 #ifdef INSTRUMENT
569 		dk_busy |= (1 << wd->sc_dev.dv_unit);
570 		dk_wds[wd->sc_dev.dv_unit] += bp->b_bcount >> 6;
571 #endif
572 	} else {
573 #ifdef WDDEBUG
574 		printf(" %d)%x", wd->sc_skip, inb(wd->sc_iobase+wd_altsts));
575 #endif
576 	}
577 
578 	/* If starting a multisector transfer, or doing single transfers. */
579 	if (wd->sc_skip == 0 || (wdc->sc_flags & WDCF_SINGLE) != 0) {
580 		struct disklabel *lp;
581 		long blkno;
582 		long cylin, head, sector;
583 		int command;
584 
585 		lp = &wd->sc_dk.dk_label;
586 		blkno = bp->b_blkno / (lp->d_secsize / DEV_BSIZE) + wd->sc_skip;
587 		if (WDPART(bp->b_dev) != RAW_PART)
588 			blkno += lp->d_partitions[WDPART(bp->b_dev)].p_offset;
589 		if ((wdc->sc_flags & WDCF_SINGLE) != 0)
590 			nblks = 1;
591 		else if (wd->sc_mode != WDM_DMA)
592 			nblks = wd->sc_bcount / DEV_BSIZE;
593 		else
594 			nblks = min(wd->sc_bcount / DEV_BSIZE, 8);
595 
596 		/* Check for bad sectors and adjust transfer, if necessary. */
597 		if ((lp->d_flags & D_BADSECT) != 0
598 #ifdef B_FORMAT
599 		    && (bp->b_flags & B_FORMAT) == 0
600 #endif
601 		    ) {
602 			long blkdiff;
603 			int i;
604 
605 			for (i = 0; (blkdiff = wd->sc_badsect[i]) != -1; i++) {
606 				blkdiff -= blkno;
607 				if (blkdiff < 0)
608 					continue;
609 				if (blkdiff == 0) {
610 					/* Replace current block of transfer. */
611 					blkno =
612 					    lp->d_secperunit - lp->d_nsectors - i - 1;
613 				}
614 				if (blkdiff < nblks) {
615 					/* Bad block inside transfer. */
616 					wdc->sc_flags |= WDCF_SINGLE;
617 					nblks = 1;
618 				}
619 				break;
620 			}
621 			/* Tranfer is okay now. */
622 		}
623 
624 		if ((wd->sc_params.wdp_capabilities & WD_CAP_LBA) != 0) {
625 			sector = (blkno >> 0) & 0xff;
626 			cylin = (blkno >> 8) & 0xffff;
627 			head = (blkno >> 24) & 0xf;
628 			head |= WDSD_LBA;
629 		} else {
630 			sector = blkno % lp->d_nsectors;
631 			sector++;	/* Sectors begin with 1, not 0. */
632 			blkno /= lp->d_nsectors;
633 			head = blkno % lp->d_ntracks;
634 			blkno /= lp->d_ntracks;
635 			cylin = blkno;
636 			head |= WDSD_CHS;
637 		}
638 
639 #ifdef INSTRUMENT
640 		++dk_seek[wd->sc_dev.dv_unit];
641 		++dk_xfer[wd->sc_dev.dv_unit];
642 #endif
643 
644 #ifdef B_FORMAT
645 		if (bp->b_flags & B_FORMAT) {
646 			sector = lp->d_gap3;
647 			nblks = lp->d_nsectors;
648 			command = WDCC_FORMAT;
649 		} else
650 #endif
651 		switch (wd->sc_mode) {
652 		case WDM_DMA:
653 			command = (bp->b_flags & B_READ) ?
654 			    WDCC_READDMA : WDCC_WRITEDMA;
655 			isa_dmastart(bp->b_flags & B_READ, bp->b_data,
656 			    nblks * DEV_BSIZE, wdc->sc_drq);
657 			break;
658 		case WDM_PIOMULTI:
659 			command = (bp->b_flags & B_READ) ?
660 			    WDCC_READMULTI : WDCC_WRITEMULTI;
661 			break;
662 		case WDM_PIOSINGLE:
663 			command = (bp->b_flags & B_READ) ?
664 			    WDCC_READ : WDCC_WRITE;
665 			break;
666 		}
667 
668 		/* Initiate command! */
669 		if (wdcommand(wd, command, cylin, head, sector, nblks) != 0) {
670 			wderror(wd, NULL,
671 			    "wdcstart: timeout waiting for unbusy");
672 			wdcunwedge(wdc);
673 			return;
674 		}
675 #ifdef WDDEBUG
676 		printf("sector %d cylin %d head %d addr %x sts %x\n", sector,
677 		    cylin, head, bp->b_data, inb(wd->sc_iobase+wd_altsts));
678 #endif
679 	}
680 
681 	if (wd->sc_mode == WDM_PIOSINGLE ||
682 	    (wdc->sc_flags & WDCF_SINGLE) != 0)
683 		nblks = 1;
684 	else if (wd->sc_mode != WDM_DMA)
685 		nblks = min(wd->sc_bcount / DEV_BSIZE, wd->sc_multiple);
686 	else
687 		nblks = min(wd->sc_bcount / DEV_BSIZE, 8);
688 	wdc->sc_nblks = nblks;
689 
690 	/* If this was a write and not using DMA, push the data. */
691 	if (wd->sc_mode != WDM_DMA &&
692 	    (bp->b_flags & B_READ) == 0) {
693 		if (wait_for_drq(wdc) < 0) {
694 			wderror(wd, NULL, "wdcstart: timeout waiting for drq");
695 			wdcunwedge(wdc);
696 			return;
697 		}
698 
699 		/* Then send it! */
700 		if ((wd->sc_flags & WDF_32BIT) == 0)
701 			outsw(wdc->sc_iobase+wd_data,
702 			    bp->b_data + wd->sc_skip * DEV_BSIZE,
703 			    nblks * DEV_BSIZE / sizeof(short));
704 		else
705 			outsl(wdc->sc_iobase+wd_data,
706 			    bp->b_data + wd->sc_skip * DEV_BSIZE,
707 			    nblks * DEV_BSIZE / sizeof(long));
708 	}
709 
710 	wdc->sc_flags |= WDCF_ACTIVE;
711 	timeout(wdctimeout, wdc, WAITTIME);
712 }
713 
714 /*
715  * Interrupt routine for the controller.  Acknowledge the interrupt, check for
716  * errors on the current operation, mark it done if necessary, and start the
717  * next request.  Also check for a partially done transfer, and continue with
718  * the next chunk if so.
719  */
720 int
721 wdcintr(wdc)
722 	struct wdc_softc *wdc;
723 {
724 	struct wd_softc *wd;
725 	struct buf *bp;
726 	int nblks;
727 
728 	if ((wdc->sc_flags & WDCF_ACTIVE) == 0) {
729 		/* Clear the pending interrupt. */
730 		(void) inb(wdc->sc_iobase+wd_status);
731 		return 0;
732 	}
733 
734 	wdc->sc_flags &= ~WDCF_ACTIVE;
735 	untimeout(wdctimeout, wdc);
736 
737 	wd = wdc->sc_drives.tqh_first;
738 	bp = wd->sc_q.b_actf;
739 
740 #ifdef WDDEBUG
741 	printf("I%d ", ctrlr);
742 #endif
743 
744 	if (wait_for_unbusy(wdc) < 0) {
745 		wderror(wd, NULL, "wdcintr: timeout waiting for unbusy");
746 		wdc->sc_status |= WDCS_ERR;	/* XXX */
747 	}
748 
749 	/* Is it not a transfer, but a control operation? */
750 	if (wd->sc_state < OPEN) {
751 		if (wdcontrol(wd) == 0) {
752 			/* The drive is busy.  Wait. */
753 			return 1;
754 		}
755 		wdcstart(wdc);
756 		return 1;
757 	}
758 
759 	nblks = wdc->sc_nblks;
760 
761 	if (wd->sc_mode == WDM_DMA)
762 		isa_dmadone(bp->b_flags & B_READ, bp->b_data,
763 		    nblks * DEV_BSIZE, wdc->sc_drq);
764 
765 	/* Have we an error? */
766 	if (wdc->sc_status & WDCS_ERR) {
767 	lose:
768 #ifdef WDDEBUG
769 		wderror(wd, NULL, "wdcintr");
770 #endif
771 		if ((wdc->sc_flags & WDCF_SINGLE) == 0) {
772 			wdc->sc_flags |= WDCF_ERROR;
773 			goto restart;
774 		}
775 
776 #ifdef B_FORMAT
777 		if (bp->b_flags & B_FORMAT)
778 			goto bad;
779 #endif
780 
781 		if (++wdc->sc_errors < WDIORETRIES)
782 			goto restart;
783 		wderror(wd, bp, "hard error");
784 
785 	bad:
786 		bp->b_error = EIO;
787 		bp->b_flags |= B_ERROR;
788 		goto done;
789 	}
790 
791 	if (wdc->sc_status & WDCS_CORR)
792 		wderror(wd, bp, "soft ecc");
793 
794 	/* If this was a read and not using DMA, fetch the data. */
795 	if (wd->sc_mode != WDM_DMA &&
796 	    (bp->b_flags & B_READ) != 0) {
797 		if ((wdc->sc_status & (WDCS_DRDY | WDCS_DSC | WDCS_DRQ))
798 		    != (WDCS_DRDY | WDCS_DSC | WDCS_DRQ)) {
799 			wderror(wd, NULL, "wdcintr: read intr before drq");
800 			wdcunwedge(wdc);
801 			return 1;
802 		}
803 
804 		/* Suck in data. */
805 		if ((wd->sc_flags & WDF_32BIT) == 0)
806 			insw(wdc->sc_iobase+wd_data,
807 			    bp->b_data + wd->sc_skip * DEV_BSIZE,
808 			    nblks * DEV_BSIZE / sizeof(short));
809 		else
810 			insl(wdc->sc_iobase+wd_data,
811 			    bp->b_data + wd->sc_skip * DEV_BSIZE,
812 			    nblks * DEV_BSIZE / sizeof(long));
813 	}
814 
815 	/* If we encountered any abnormalities, flag it as a soft error. */
816 	if (wdc->sc_errors) {
817 		wderror(wd, bp, "soft error");
818 		wdc->sc_errors = 0;
819 	}
820 
821 	/* Ready for the next block, if any. */
822 	wd->sc_skip += nblks;
823 	wd->sc_bcount -= nblks * DEV_BSIZE;
824 
825 	/* See if more to transfer. */
826 	if (wd->sc_bcount > 0)
827 		goto restart;
828 
829 done:
830 	/* Done with this transfer, with or without error. */
831 	wdfinish(wd, bp);
832 
833 restart:
834 	/* Start the next transfer, if any. */
835 	wdcstart(wdc);
836 
837 	return 1;
838 }
839 
840 /*
841  * Initialize a drive.
842  */
843 int
844 wdopen(dev, flag, fmt)
845 	dev_t dev;
846 	int flag, fmt;
847 {
848 	int error;
849 	int unit, part;
850 	struct wd_softc *wd;
851 
852 	unit = WDUNIT(dev);
853 	if (unit >= wdcd.cd_ndevs)
854 		return ENXIO;
855 	wd = wdcd.cd_devs[unit];
856 	if (wd == 0)
857 		return ENXIO;
858 
859 	part = WDPART(dev);
860 
861 	while ((wd->sc_flags & WDF_LOCKED) != 0) {
862 		wd->sc_flags |= WDF_WANTED;
863 		if ((error = tsleep(wd, PRIBIO | PCATCH, "wdopn", 0)) != 0)
864 			return error;
865 	}
866 
867 	if (wd->sc_dk.dk_openmask != 0) {
868 		/*
869 		 * If any partition is open, but the disk has been invalidated,
870 		 * disallow further opens.
871 		 */
872 		if ((wd->sc_flags & WDF_LOADED) == 0)
873 			return ENXIO;
874 	} else {
875 		wd->sc_flags |= WDF_LOCKED;
876 
877 		if ((wd->sc_flags & WDF_LOADED) == 0) {
878 			wd->sc_flags &= ~WDF_BSDLABEL;
879 			wd->sc_flags |= WDF_LOADED;
880 
881 			/* Load the physical device parameters. */
882 			if (wd_get_parms(wd) != 0) {
883 				error = ENXIO;
884 				goto bad2;
885 			}
886 
887 			/* Load the partition info if not already loaded. */
888 			wdgetdisklabel(wd);
889 		}
890 
891 		wd->sc_flags &= ~WDF_LOCKED;
892 		if ((wd->sc_flags & WDF_WANTED) != 0) {
893 			wd->sc_flags &= ~WDF_WANTED;
894 			wakeup(wd);
895 		}
896 	}
897 
898 	/* Check that the partition exists. */
899 	if (part != RAW_PART &&
900 	    (part >= wd->sc_dk.dk_label.d_npartitions ||
901 	     wd->sc_dk.dk_label.d_partitions[part].p_fstype == FS_UNUSED)) {
902 		error = ENXIO;
903 		goto bad;
904 	}
905 
906 	/* Insure only one open at a time. */
907 	switch (fmt) {
908 	case S_IFCHR:
909 		wd->sc_dk.dk_copenmask |= (1 << part);
910 		break;
911 	case S_IFBLK:
912 		wd->sc_dk.dk_bopenmask |= (1 << part);
913 		break;
914 	}
915 	wd->sc_dk.dk_openmask = wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask;
916 
917 	return 0;
918 
919 bad2:
920 	wd->sc_flags &= ~WDF_LOADED;
921 
922 bad:
923 	if (wd->sc_dk.dk_openmask == 0) {
924 		wd->sc_flags &= ~WDF_LOCKED;
925 		if ((wd->sc_flags & WDF_WANTED) != 0) {
926 			wd->sc_flags &= ~WDF_WANTED;
927 			wakeup(wd);
928 		}
929 	}
930 
931 	return error;
932 }
933 
934 void
935 wdgetdisklabel(wd)
936 	struct wd_softc *wd;
937 {
938 	char *errstring;
939 
940 	if ((wd->sc_flags & WDF_BSDLABEL) != 0)
941 		return;
942 
943 	bzero(&wd->sc_dk.dk_label, sizeof(struct disklabel));
944 	bzero(&wd->sc_dk.dk_cpulabel, sizeof(struct cpu_disklabel));
945 
946 	wd->sc_dk.dk_label.d_secsize = DEV_BSIZE;
947 	wd->sc_dk.dk_label.d_ntracks = wd->sc_params.wdp_heads;
948 	wd->sc_dk.dk_label.d_nsectors = wd->sc_params.wdp_sectors;
949 	wd->sc_dk.dk_label.d_ncylinders = wd->sc_params.wdp_cylinders;
950 	wd->sc_dk.dk_label.d_secpercyl =
951 	    wd->sc_dk.dk_label.d_ntracks * wd->sc_dk.dk_label.d_nsectors;
952 
953 #if 0
954 	strncpy(wd->sc_dk.dk_label.d_typename, "ST506 disk", 16);
955 	wd->sc_dk.dk_label.d_type = DTYPE_ST506;
956 #endif
957 	strncpy(wd->sc_dk.dk_label.d_packname, wd->sc_params.wdp_model, 16);
958 	wd->sc_dk.dk_label.d_secperunit =
959 	    wd->sc_dk.dk_label.d_secpercyl * wd->sc_dk.dk_label.d_ncylinders;
960 	wd->sc_dk.dk_label.d_rpm = 3600;
961 	wd->sc_dk.dk_label.d_interleave = 1;
962 	wd->sc_dk.dk_label.d_flags = 0;
963 
964 	wd->sc_dk.dk_label.d_partitions[RAW_PART].p_offset = 0;
965 	wd->sc_dk.dk_label.d_partitions[RAW_PART].p_size =
966 	    wd->sc_dk.dk_label.d_secperunit *
967 	    (wd->sc_dk.dk_label.d_secsize / DEV_BSIZE);
968 	wd->sc_dk.dk_label.d_partitions[RAW_PART].p_fstype = FS_UNUSED;
969 	wd->sc_dk.dk_label.d_npartitions = RAW_PART + 1;
970 
971 	wd->sc_dk.dk_label.d_magic = DISKMAGIC;
972 	wd->sc_dk.dk_label.d_magic2 = DISKMAGIC;
973 	wd->sc_dk.dk_label.d_checksum = dkcksum(&wd->sc_dk.dk_label);
974 
975 	wd->sc_badsect[0] = -1;
976 
977 	if (wd->sc_state > RECAL)
978 		wd->sc_state = RECAL;
979 	errstring = readdisklabel(MAKEWDDEV(0, wd->sc_dev.dv_unit, RAW_PART),
980 	    wdstrategy, &wd->sc_dk.dk_label, &wd->sc_dk.dk_cpulabel);
981 	if (errstring) {
982 		/*
983 		 * This probably happened because the drive's default
984 		 * geometry doesn't match the DOS geometry.  We
985 		 * assume the DOS geometry is now in the label and try
986 		 * again.  XXX This is a kluge.
987 		 */
988 		if (wd->sc_state > GEOMETRY)
989 			wd->sc_state = GEOMETRY;
990 		errstring = readdisklabel(MAKEWDDEV(0, wd->sc_dev.dv_unit, RAW_PART),
991 		    wdstrategy, &wd->sc_dk.dk_label, &wd->sc_dk.dk_cpulabel);
992 	}
993 	if (errstring) {
994 		printf("%s: %s\n", wd->sc_dev.dv_xname, errstring);
995 		return;
996 	}
997 
998 	if (wd->sc_state > GEOMETRY)
999 		wd->sc_state = GEOMETRY;
1000 	if ((wd->sc_dk.dk_label.d_flags & D_BADSECT) != 0)
1001 		bad144intern(wd);
1002 
1003 	wd->sc_flags |= WDF_BSDLABEL;
1004 }
1005 
1006 /*
1007  * Implement operations other than read/write.
1008  * Called from wdcstart or wdcintr during opens and formats.
1009  * Uses finite-state-machine to track progress of operation in progress.
1010  * Returns 0 if operation still in progress, 1 if completed.
1011  */
1012 static int
1013 wdcontrol(wd)
1014 	struct wd_softc *wd;
1015 {
1016 	struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
1017 
1018 	switch (wd->sc_state) {
1019 	case RECAL:			/* Set SDH, step rate, do recal. */
1020 		if (wdcommandshort(wdc, wd->sc_drive, WDCC_RECAL) != 0) {
1021 			wderror(wd, NULL, "wdcontrol: recal failed (1)");
1022 			goto bad;
1023 		}
1024 		wd->sc_state = RECAL_WAIT;
1025 		break;
1026 
1027 	case RECAL_WAIT:
1028 		if (wdc->sc_status & WDCS_ERR) {
1029 			wderror(wd, NULL, "wdcontrol: recal failed (2)");
1030 			goto bad;
1031 		}
1032 		/* fall through */
1033 	case GEOMETRY:
1034 		if ((wd->sc_params.wdp_capabilities & WD_CAP_LBA) != 0)
1035 			goto multimode;
1036 		if (wdsetctlr(wd) != 0) {
1037 			/* Already printed a message. */
1038 			goto bad;
1039 		}
1040 		wd->sc_state = GEOMETRY_WAIT;
1041 		break;
1042 
1043 	case GEOMETRY_WAIT:
1044 		if (wdc->sc_status & WDCS_ERR) {
1045 			wderror(wd, NULL, "wdcontrol: geometry failed");
1046 			goto bad;
1047 		}
1048 		/* fall through */
1049 	case MULTIMODE:
1050 	multimode:
1051 		if (wd->sc_mode != WDM_PIOMULTI)
1052 			goto open;
1053 		outb(wdc->sc_iobase+wd_seccnt, wd->sc_multiple);
1054 		if (wdcommandshort(wdc, wd->sc_drive, WDCC_SETMULTI) != 0) {
1055 			wderror(wd, NULL, "wdcontrol: setmulti failed (1)");
1056 			goto bad;
1057 		}
1058 		wd->sc_state = MULTIMODE_WAIT;
1059 		break;
1060 
1061 	case MULTIMODE_WAIT:
1062 		if (wdc->sc_status & WDCS_ERR) {
1063 			wderror(wd, NULL, "wdcontrol: setmulti failed (2)");
1064 			goto bad;
1065 		}
1066 		/* fall through */
1067 	case OPEN:
1068 	open:
1069 		wdc->sc_errors = 0;
1070 		wd->sc_state = OPEN;
1071 		/*
1072 		 * The rest of the initialization can be done by normal means.
1073 		 */
1074 		return 1;
1075 
1076 	bad:
1077 		wdcunwedge(wdc);
1078 		return 0;
1079 	}
1080 
1081 	wdc->sc_flags |= WDCF_ACTIVE;
1082 	timeout(wdctimeout, wdc, WAITTIME);
1083 	return 0;
1084 }
1085 
1086 /*
1087  * Send a command and wait uninterruptibly until controller is finished.
1088  * Return -1 if controller busy for too long, otherwise return non-zero if
1089  * error.  Intended for brief controller commands at critical points.
1090  * Assumes interrupts are blocked.
1091  */
1092 static int
1093 wdcommand(wd, command, cylin, head, sector, count)
1094 	struct wd_softc *wd;
1095 	int command;
1096 	int cylin, head, sector, count;
1097 {
1098 	struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
1099 	int iobase = wdc->sc_iobase;
1100 	int stat;
1101 
1102 	/* Select drive, head, and addressing mode. */
1103 	outb(iobase+wd_sdh, WDSD_IBM | (wd->sc_drive << 4) | head);
1104 
1105 	/* Wait for it to become ready to accept a command. */
1106 	if (command == WDCC_IDP)
1107 		stat = wait_for_unbusy(wdc);
1108 	else
1109 		stat = wdcwait(wdc, WDCS_DRDY);
1110 	if (stat < 0)
1111 		return -1;
1112 
1113 	/* Load parameters. */
1114 	if (wd->sc_dk.dk_label.d_type == DTYPE_ST506)
1115 		outb(iobase+wd_precomp, wd->sc_dk.dk_label.d_precompcyl / 4);
1116 	else
1117 		outb(iobase+wd_features, 0);
1118 	outb(iobase+wd_cyl_lo, cylin);
1119 	outb(iobase+wd_cyl_hi, cylin >> 8);
1120 	outb(iobase+wd_sector, sector);
1121 	outb(iobase+wd_seccnt, count);
1122 
1123 	/* Send command. */
1124 	outb(iobase+wd_command, command);
1125 
1126 	return 0;
1127 }
1128 
1129 int
1130 wdcommandshort(wdc, drive, command)
1131 	struct wdc_softc *wdc;
1132 	int drive;
1133 	int command;
1134 {
1135 	int iobase = wdc->sc_iobase;
1136 
1137 	/* Select drive. */
1138 	outb(iobase+wd_sdh, WDSD_IBM | (drive << 4));
1139 
1140 	if (wdcwait(wdc, WDCS_DRDY) < 0)
1141 		return -1;
1142 
1143 	outb(iobase+wd_command, command);
1144 
1145 	return 0;
1146 }
1147 
1148 /*
1149  * Issue IDP to drive to tell it just what geometry it is to be.
1150  */
1151 static int
1152 wdsetctlr(wd)
1153 	struct wd_softc *wd;
1154 {
1155 	struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
1156 
1157 #ifdef WDDEBUG
1158 	printf("wd(%d,%d) C%dH%dS%d\n", wd->sc_dev.dv_unit, wd->sc_drive,
1159 	    wd->sc_dk.dk_label.d_ncylinders, wd->sc_dk.dk_label.d_ntracks,
1160 	    wd->sc_dk.dk_label.d_nsectors);
1161 #endif
1162 
1163 	if (wdcommand(wd, WDCC_IDP, wd->sc_dk.dk_label.d_ncylinders,
1164 	    wd->sc_dk.dk_label.d_ntracks - 1, 0, wd->sc_dk.dk_label.d_nsectors)
1165 	    != 0) {
1166 		wderror(wd, NULL, "wdsetctlr: geometry upload failed");
1167 		return -1;
1168 	}
1169 
1170 	return 0;
1171 }
1172 
1173 /*
1174  * Issue IDENTIFY to drive to ask it what it is.
1175  */
1176 int
1177 wd_get_parms(wd)
1178 	struct wd_softc *wd;
1179 {
1180 	struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
1181 	int i;
1182 	char tb[DEV_BSIZE];
1183 
1184 	if (wdcommandshort(wdc, wd->sc_drive, WDCC_IDENTIFY) != 0 ||
1185 	    wait_for_drq(wdc) != 0) {
1186 		/*
1187 		 * We `know' there's a drive here; just assume it's old.
1188 		 */
1189 		strncpy(wd->sc_dk.dk_label.d_typename, "ST506",
1190 		    sizeof wd->sc_dk.dk_label.d_typename);
1191 		wd->sc_dk.dk_label.d_type = DTYPE_ST506;
1192 
1193 		strncpy(wd->sc_params.wdp_model, "unknown",
1194 		    sizeof wd->sc_params.wdp_model);
1195 		wd->sc_params.wdp_config = WD_CFG_FIXED;
1196 		wd->sc_params.wdp_cylinders = 1024;
1197 		wd->sc_params.wdp_heads = 8;
1198 		wd->sc_params.wdp_sectors = 17;
1199 		wd->sc_params.wdp_maxmulti = 0;
1200 		wd->sc_params.wdp_usedmovsd = 0;
1201 		wd->sc_params.wdp_capabilities = 0;
1202 	} else {
1203 		/* Obtain parameters. */
1204 		insw(wdc->sc_iobase+wd_data, tb, sizeof(tb) / sizeof(short));
1205 		bcopy(tb, &wd->sc_params, sizeof(struct wdparams));
1206 
1207 		/* Shuffle string byte order. */
1208 		for (i = 0; i < sizeof(wd->sc_params.wdp_model); i += 2) {
1209 			u_short *p;
1210 			p = (u_short *)(wd->sc_params.wdp_model + i);
1211 			*p = ntohs(*p);
1212 		}
1213 
1214 		strncpy(wd->sc_dk.dk_label.d_typename, "ESDI/IDE",
1215 		    sizeof wd->sc_dk.dk_label.d_typename);
1216 		wd->sc_dk.dk_label.d_type = DTYPE_ESDI;
1217 	}
1218 
1219 #if 0
1220 	printf("gc %x cyl %d trk %d sec %d type %d sz %d model %s\n",
1221 	    wp->wdp_config, wp->wdp_cylinders, wp->wdp_heads, wp->wdp_sectors,
1222 	    wp->wdp_buftype, wp->wdp_bufsize, wp->wdp_model);
1223 #endif
1224 
1225 	/* XXX sometimes possibly needed */
1226 	(void) inb(wdc->sc_iobase+wd_status);
1227 
1228 	return 0;
1229 }
1230 
1231 int
1232 wdclose(dev, flag, fmt)
1233 	dev_t dev;
1234 	int flag, fmt;
1235 {
1236 	struct wd_softc *wd = wdcd.cd_devs[WDUNIT(dev)];
1237 	int part = WDPART(dev);
1238 	int s;
1239 
1240 	switch (fmt) {
1241 	case S_IFCHR:
1242 		wd->sc_dk.dk_copenmask &= ~(1 << part);
1243 		break;
1244 	case S_IFBLK:
1245 		wd->sc_dk.dk_bopenmask &= ~(1 << part);
1246 		break;
1247 	}
1248 	wd->sc_dk.dk_openmask = wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask;
1249 
1250 	if (wd->sc_dk.dk_openmask == 0) {
1251 		wd->sc_flags |= WDF_LOCKED;
1252 
1253 #if 0
1254 		s = splbio();
1255 		while (...) {
1256 			wd->sc_flags |= WDF_WAITING;
1257 			if ((error = tsleep(wd, PRIBIO | PCATCH, "wdcls", 0)) != 0)
1258 				return error;
1259 		}
1260 		splx(s);
1261 #endif
1262 
1263 		wd->sc_flags &= ~WDF_LOCKED;
1264 		if ((wd->sc_flags & WDF_WANTED) != 0) {
1265 			wd->sc_flags &= WDF_WANTED;
1266 			wakeup(wd);
1267 		}
1268 	}
1269 
1270 	return 0;
1271 }
1272 
1273 int
1274 wdioctl(dev, command, addr, flag, p)
1275 	dev_t dev;
1276 	u_long command;
1277 	caddr_t addr;
1278 	int flag;
1279 	struct proc *p;
1280 {
1281 	struct wd_softc *wd = wdcd.cd_devs[WDUNIT(dev)];
1282 	int error;
1283 
1284 	if ((wd->sc_flags & WDF_LOADED) == 0)
1285 		return EIO;
1286 
1287 	switch (command) {
1288 	case DIOCSBAD:
1289 		if ((flag & FWRITE) == 0)
1290 			return EBADF;
1291 		wd->sc_dk.dk_cpulabel.bad = *(struct dkbad *)addr;
1292 		wd->sc_dk.dk_label.d_flags |= D_BADSECT;
1293 		bad144intern(wd);
1294 		return 0;
1295 
1296 	case DIOCGDINFO:
1297 		*(struct disklabel *)addr = wd->sc_dk.dk_label;
1298 		return 0;
1299 
1300 	case DIOCGPART:
1301 		((struct partinfo *)addr)->disklab = &wd->sc_dk.dk_label;
1302 		((struct partinfo *)addr)->part =
1303 		    &wd->sc_dk.dk_label.d_partitions[WDPART(dev)];
1304 		return 0;
1305 
1306 	case DIOCSDINFO:
1307 		if ((flag & FWRITE) == 0)
1308 			return EBADF;
1309 		error = setdisklabel(&wd->sc_dk.dk_label,
1310 		    (struct disklabel *)addr,
1311 		    /*(wd->sc_flags & WDF_BSDLABEL) ? wd->sc_dk.dk_openmask : */0,
1312 		    &wd->sc_dk.dk_cpulabel);
1313 		if (error == 0) {
1314 			wd->sc_flags |= WDF_BSDLABEL;
1315 			if (wd->sc_state > GEOMETRY)
1316 				wd->sc_state = GEOMETRY;
1317 		}
1318 		return error;
1319 
1320 	case DIOCWLABEL:
1321 		if ((flag & FWRITE) == 0)
1322 			return EBADF;
1323 		if (*(int *)addr)
1324 			wd->sc_flags |= WDF_WLABEL;
1325 		else
1326 			wd->sc_flags &= ~WDF_WLABEL;
1327 		return 0;
1328 
1329 	case DIOCWDINFO:
1330 		if ((flag & FWRITE) == 0)
1331 			return EBADF;
1332 		error = setdisklabel(&wd->sc_dk.dk_label,
1333 		    (struct disklabel *)addr,
1334 		    /*(wd->sc_flags & WDF_BSDLABEL) ? wd->sc_dk.dk_openmask : */0,
1335 		    &wd->sc_dk.dk_cpulabel);
1336 		if (error == 0) {
1337 			wd->sc_flags |= WDF_BSDLABEL;
1338 			if (wd->sc_state > GEOMETRY)
1339 				wd->sc_state = GEOMETRY;
1340 
1341 			/* Simulate opening partition 0 so write succeeds. */
1342 			wd->sc_dk.dk_openmask |= (1 << 0);	/* XXX */
1343 			error = writedisklabel(WDLABELDEV(dev), wdstrategy,
1344 			    &wd->sc_dk.dk_label, &wd->sc_dk.dk_cpulabel);
1345 			wd->sc_dk.dk_openmask =
1346 			    wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask;
1347 		}
1348 		return error;
1349 
1350 #ifdef notyet
1351 	case DIOCGDINFOP:
1352 		*(struct disklabel **)addr = &wd->sc_dk.dk_label;
1353 		return 0;
1354 
1355 	case DIOCWFORMAT:
1356 		if ((flag & FWRITE) == 0)
1357 			return EBADF;
1358 	{
1359 		register struct format_op *fop;
1360 		struct iovec aiov;
1361 		struct uio auio;
1362 
1363 		fop = (struct format_op *)addr;
1364 		aiov.iov_base = fop->df_buf;
1365 		aiov.iov_len = fop->df_count;
1366 		auio.uio_iov = &aiov;
1367 		auio.uio_iovcnt = 1;
1368 		auio.uio_resid = fop->df_count;
1369 		auio.uio_segflg = 0;
1370 		auio.uio_offset =
1371 		    fop->df_startblk * wd->sc_dk.dk_label.d_secsize;
1372 		auio.uio_procp = p;
1373 		error = physio(wdformat, NULL, dev, B_WRITE, minphys,
1374 		    &auio);
1375 		fop->df_count -= auio.uio_resid;
1376 		fop->df_reg[0] = wdc->sc_status;
1377 		fop->df_reg[1] = wdc->sc_error;
1378 		return error;
1379 	}
1380 #endif
1381 
1382 	default:
1383 		return ENOTTY;
1384 	}
1385 
1386 #ifdef DIAGNOSTIC
1387 	panic("wdioctl: impossible");
1388 #endif
1389 }
1390 
1391 #ifdef B_FORMAT
1392 int
1393 wdformat(struct buf *bp)
1394 {
1395 
1396 	bp->b_flags |= B_FORMAT;
1397 	return wdstrategy(bp);
1398 }
1399 #endif
1400 
1401 int
1402 wdsize(dev)
1403 	dev_t dev;
1404 {
1405 	struct wd_softc *wd;
1406 	int part;
1407 	int size;
1408 
1409 	if (wdopen(dev, 0, S_IFBLK) != 0)
1410 		return -1;
1411 	wd = wdcd.cd_devs[WDUNIT(dev)];
1412 	part = WDPART(dev);
1413 	if ((wd->sc_flags & WDF_BSDLABEL) == 0 ||
1414 	    wd->sc_dk.dk_label.d_partitions[part].p_fstype != FS_SWAP)
1415 		size = -1;
1416 	else
1417 		size = wd->sc_dk.dk_label.d_partitions[part].p_size;
1418 	if (wdclose(dev, 0, S_IFBLK) != 0)
1419 		return -1;
1420 	return size;
1421 }
1422 
1423 /*
1424  * Dump core after a system crash.
1425  */
1426 int
1427 wddump(dev)
1428 	dev_t dev;
1429 {
1430 	struct wd_softc *wd;	/* disk unit to do the IO */
1431 	struct wdc_softc *wdc;
1432 	struct disklabel *lp;
1433 	int unit, part;
1434 	long rblkno, nblks;
1435 	char *addr;
1436 	static wddoingadump = 0;
1437 	extern caddr_t CADDR1;
1438 	extern pt_entry_t *CMAP1;
1439 
1440 	if (wddoingadump)
1441 		return EFAULT;
1442 	wddoingadump = 1;
1443 
1444 	unit = WDUNIT(dev);
1445 	/* Check for acceptable drive number. */
1446 	if (unit >= wdcd.cd_ndevs)
1447 		return ENXIO;
1448 	wd = wdcd.cd_devs[unit];
1449 	/* Was it ever initialized? */
1450 	if (wd == 0 || wd->sc_state < OPEN)
1451 		return ENXIO;
1452 
1453 	wdc = (void *)wd->sc_dev.dv_parent;
1454 	addr = (char *)0;	/* starting address */
1455 	lp = &wd->sc_dk.dk_label;
1456 	part = WDPART(dev);
1457 
1458 	/* Convert to disk sectors. */
1459 	rblkno = lp->d_partitions[part].p_offset + dumplo;
1460 	nblks = min(ctob(physmem) / lp->d_secsize,
1461 		    lp->d_partitions[part].p_size - dumplo);
1462 
1463 	/* Check transfer bounds against partition size. */
1464 	if (dumplo < 0 || nblks <= 0)
1465 		return EINVAL;
1466 
1467 	/* Recalibrate. */
1468 	if (wdcommandshort(wdc, wd->sc_drive, WDCC_RECAL) != 0 ||
1469 	    wait_for_ready(wdc) != 0 || wdsetctlr(wd) != 0 ||
1470 	    wait_for_ready(wdc) != 0) {
1471 		wderror(wd, NULL, "wddump: recal failed");
1472 		return EIO;
1473 	}
1474 
1475 	while (nblks > 0) {
1476 		long blkno;
1477 		long cylin, head, sector;
1478 
1479 		blkno = rblkno;
1480 
1481 		if ((lp->d_flags & D_BADSECT) != 0) {
1482 			long blkdiff;
1483 			int i;
1484 
1485 			for (i = 0; (blkdiff = wd->sc_badsect[i]) != -1; i++) {
1486 				blkdiff -= blkno;
1487 				if (blkdiff < 0)
1488 					continue;
1489 				if (blkdiff == 0) {
1490 					/* Replace current block of transfer. */
1491 					blkno =
1492 					    lp->d_secperunit - lp->d_nsectors - i - 1;
1493 				}
1494 				break;
1495 			}
1496 			/* Tranfer is okay now. */
1497 		}
1498 
1499 		if ((wd->sc_params.wdp_capabilities & WD_CAP_LBA) != 0) {
1500 			sector = (blkno >> 0) & 0xff;
1501 			cylin = (blkno >> 8) & 0xffff;
1502 			head = (blkno >> 24) & 0xf;
1503 			head |= WDSD_LBA;
1504 		} else {
1505 			sector = blkno % lp->d_nsectors;
1506 			sector++;	/* Sectors begin with 1, not 0. */
1507 			blkno /= lp->d_nsectors;
1508 			head = blkno % lp->d_ntracks;
1509 			blkno /= lp->d_ntracks;
1510 			cylin = blkno;
1511 			head |= WDSD_CHS;
1512 		}
1513 
1514 #ifdef notdef
1515 		/* Let's just talk about this first. */
1516 		printf("cylin %d, head %d, sector %d, addr 0x%x", cylin, head,
1517 		    sector, addr);
1518 #endif
1519 		if (wdcommand(wd, WDCC_WRITE, cylin, head, sector, 1) != 0 ||
1520 		    wait_for_drq(wdc) != 0) {
1521 			wderror(wd, NULL, "wddump: write failed");
1522 			return EIO;
1523 		}
1524 
1525 #ifdef notdef	/* Cannot use this since this address was mapped differently. */
1526 		pmap_enter(kernel_pmap, CADDR1, trunc_page(addr), VM_PROT_READ, TRUE);
1527 #else
1528 		*CMAP1 = PG_V | PG_KW | ctob((long)addr);
1529 		tlbflush();
1530 #endif
1531 
1532 		outsw(wdc->sc_iobase+wd_data, CADDR1 + ((int)addr & PGOFSET),
1533 		    DEV_BSIZE / sizeof(short));
1534 
1535 		/* Check data request (should be done). */
1536 		if (wait_for_ready(wdc) != 0) {
1537 			wderror(wd, NULL, "wddump: timeout waiting for ready");
1538 			return EIO;
1539 		}
1540 		if (wdc->sc_status & WDCS_DRQ) {
1541 			wderror(wd, NULL, "wddump: extra drq");
1542 			return EIO;
1543 		}
1544 
1545 		if ((unsigned)addr % 1048576 == 0)
1546 			printf("%d ", nblks / (1048576 / DEV_BSIZE));
1547 
1548 		/* Update block count. */
1549 		nblks--;
1550 		rblkno++;
1551 		(int)addr += DEV_BSIZE;
1552 	}
1553 
1554 	return 0;
1555 }
1556 
1557 /*
1558  * Internalize the bad sector table.
1559  */
1560 void
1561 bad144intern(wd)
1562 	struct wd_softc *wd;
1563 {
1564 	struct dkbad *bt = &wd->sc_dk.dk_cpulabel.bad;
1565 	struct disklabel *lp = &wd->sc_dk.dk_label;
1566 	int i = 0;
1567 
1568 	for (; i < 126; i++) {
1569 		if (bt->bt_bad[i].bt_cyl == 0xffff)
1570 			break;
1571 		wd->sc_badsect[i] =
1572 		    bt->bt_bad[i].bt_cyl * lp->d_secpercyl +
1573 		    (bt->bt_bad[i].bt_trksec >> 8) * lp->d_nsectors +
1574 		    (bt->bt_bad[i].bt_trksec & 0xff);
1575 	}
1576 	for (; i < 127; i++)
1577 		wd->sc_badsect[i] = -1;
1578 }
1579 
1580 static int
1581 wdcreset(wdc)
1582 	struct wdc_softc *wdc;
1583 {
1584 	int iobase = wdc->sc_iobase;
1585 
1586 	/* Reset the device. */
1587 	outb(iobase+wd_ctlr, WDCTL_RST | WDCTL_IDS);
1588 	delay(1000);
1589 	outb(iobase+wd_ctlr, WDCTL_IDS);
1590 	delay(1000);
1591 	(void) inb(iobase+wd_error);
1592 	outb(iobase+wd_ctlr, WDCTL_4BIT);
1593 
1594 	if (wait_for_unbusy(wdc) < 0) {
1595 		printf("%s: reset failed\n", wdc->sc_dev.dv_xname);
1596 		return 1;
1597 	}
1598 
1599 	return 0;
1600 }
1601 
1602 static void
1603 wdcrestart(arg)
1604 	void *arg;
1605 {
1606 	struct wdc_softc *wdc = (struct wdc_softc *)arg;
1607 	int s;
1608 
1609 	s = splbio();
1610 	wdcstart(wdc);
1611 	splx(s);
1612 }
1613 
1614 /*
1615  * Unwedge the controller after an unexpected error.  We do this by resetting
1616  * it, marking all drives for recalibration, and stalling the queue for a short
1617  * period to give the reset time to finish.
1618  * NOTE: We use a timeout here, so this routine must not be called during
1619  * autoconfig or dump.
1620  */
1621 static void
1622 wdcunwedge(wdc)
1623 	struct wdc_softc *wdc;
1624 {
1625 	int unit;
1626 
1627 	untimeout(wdctimeout, wdc);
1628 	(void) wdcreset(wdc);
1629 
1630 	/* Schedule recalibrate for all drives on this controller. */
1631 	for (unit = 0; unit < wdcd.cd_ndevs; unit++) {
1632 		struct wd_softc *wd = wdcd.cd_devs[unit];
1633 		if (!wd || (void *)wd->sc_dev.dv_parent != wdc)
1634 			continue;
1635 		if (wd->sc_state > RECAL)
1636 			wd->sc_state = RECAL;
1637 	}
1638 
1639 	wdc->sc_flags |= WDCF_ERROR;
1640 	++wdc->sc_errors;
1641 
1642 	/* Wake up in a little bit and restart the operation. */
1643 	timeout(wdcrestart, wdc, RECOVERYTIME);
1644 }
1645 
1646 int
1647 wdcwait(wdc, mask)
1648 	struct wdc_softc *wdc;
1649 	int mask;
1650 {
1651 	int iobase = wdc->sc_iobase;
1652 	int timeout = 0;
1653 	u_char status;
1654 	extern int cold;
1655 
1656 	for (;;) {
1657 		wdc->sc_status = status = inb(iobase+wd_status);
1658 		if ((status & WDCS_BSY) == 0 && (status & mask) == mask)
1659 			break;
1660 		if (++timeout > WDCNDELAY)
1661 			return -1;
1662 		delay(WDCDELAY);
1663 	}
1664 	if (status & WDCS_ERR) {
1665 		wdc->sc_error = inb(iobase+wd_error);
1666 		return WDCS_ERR;
1667 	}
1668 #ifdef WDCNDELAY_DEBUG
1669 	/* After autoconfig, there should be no long delays. */
1670 	if (!cold && timeout > WDCNDELAY_DEBUG)
1671 		printf("%s: warning: busy-wait took %dus\n",
1672 		    wdc->sc_dev.dv_xname, WDCDELAY * timeout);
1673 #endif
1674 	return 0;
1675 }
1676 
1677 static void
1678 wdctimeout(arg)
1679 	void *arg;
1680 {
1681 	struct wdc_softc *wdc = (struct wdc_softc *)arg;
1682 	int s;
1683 
1684 	s = splbio();
1685 	if ((wdc->sc_flags & WDCF_ACTIVE) != 0) {
1686 		wdc->sc_flags &= ~WDCF_ACTIVE;
1687 		wderror(wdc, NULL, "lost interrupt");
1688 		wdcunwedge(wdc);
1689 	} else
1690 		wderror(wdc, NULL, "missing untimeout");
1691 	splx(s);
1692 }
1693 
1694 static void
1695 wderror(dev, bp, msg)
1696 	void *dev;
1697 	struct buf *bp;
1698 	char *msg;
1699 {
1700 	struct wd_softc *wd = dev;
1701 	struct wdc_softc *wdc = dev;
1702 
1703 	if (bp) {
1704 		diskerr(bp, "wd", msg, LOG_PRINTF, wd->sc_skip,
1705 		    &wd->sc_dk.dk_label);
1706 		printf("\n");
1707 	} else
1708 		printf("%s: %s: status %b error %b\n", wdc->sc_dev.dv_xname,
1709 		    msg, wdc->sc_status, WDCS_BITS, wdc->sc_error, WDERR_BITS);
1710 }
1711