xref: /netbsd-src/sys/arch/x68k/dev/fd.c (revision 481fca6e59249d8ffcf24fef7cfbe7b131bfb080)
1 /*	$NetBSD: fd.c,v 1.35 2000/06/29 07:07:52 mrg Exp $	*/
2 
3 /*-
4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Charles M. Hannum and Minoura Makoto.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *        This product includes software developed by the NetBSD
21  *        Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 /*-
40  * Copyright (c) 1990 The Regents of the University of California.
41  * All rights reserved.
42  *
43  * This code is derived from software contributed to Berkeley by
44  * Don Ahn.
45  *
46  * Redistribution and use in source and binary forms, with or without
47  * modification, are permitted provided that the following conditions
48  * are met:
49  * 1. Redistributions of source code must retain the above copyright
50  *    notice, this list of conditions and the following disclaimer.
51  * 2. Redistributions in binary form must reproduce the above copyright
52  *    notice, this list of conditions and the following disclaimer in the
53  *    documentation and/or other materials provided with the distribution.
54  * 3. All advertising materials mentioning features or use of this software
55  *    must display the following acknowledgement:
56  *	This product includes software developed by the University of
57  *	California, Berkeley and its contributors.
58  * 4. Neither the name of the University nor the names of its contributors
59  *    may be used to endorse or promote products derived from this software
60  *    without specific prior written permission.
61  *
62  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
63  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
64  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
65  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
66  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
67  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
68  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
69  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
70  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
71  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
72  * SUCH DAMAGE.
73  *
74  *	@(#)fd.c	7.4 (Berkeley) 5/25/91
75  */
76 
77 #include "rnd.h"
78 #include "opt_ddb.h"
79 #include "opt_m680x0.h"
80 
81 #include <sys/param.h>
82 #include <sys/systm.h>
83 #include <sys/callout.h>
84 #include <sys/kernel.h>
85 #include <sys/conf.h>
86 #include <sys/file.h>
87 #include <sys/stat.h>
88 #include <sys/ioctl.h>
89 #include <sys/malloc.h>
90 #include <sys/device.h>
91 #include <sys/disklabel.h>
92 #include <sys/dkstat.h>
93 #include <sys/disk.h>
94 #include <sys/buf.h>
95 #include <sys/uio.h>
96 #include <sys/syslog.h>
97 #include <sys/queue.h>
98 #include <sys/fdio.h>
99 #if NRND > 0
100 #include <sys/rnd.h>
101 #endif
102 
103 #include <uvm/uvm_extern.h>
104 
105 #include <machine/bus.h>
106 #include <machine/cpu.h>
107 
108 #include <arch/x68k/dev/intiovar.h>
109 #include <arch/x68k/dev/dmacvar.h>
110 #include <arch/x68k/dev/fdreg.h>
111 #include <arch/x68k/dev/opmreg.h> /* for CT1 access */
112 
113 #include "locators.h"
114 
115 #ifdef FDDEBUG
116 #define DPRINTF(x)      if (fddebug) printf x
117 int     fddebug = 0;
118 #else
119 #define DPRINTF(x)
120 #endif
121 
122 #define FDUNIT(dev)	(minor(dev) / 8)
123 #define FDTYPE(dev)	(minor(dev) % 8)
124 
125 enum fdc_state {
126 	DEVIDLE = 0,
127 	MOTORWAIT,
128 	DOSEEK,
129 	SEEKWAIT,
130 	SEEKTIMEDOUT,
131 	SEEKCOMPLETE,
132 	DOIO,
133 	IOCOMPLETE,
134 	IOTIMEDOUT,
135 	DORESET,
136 	RESETCOMPLETE,
137 	RESETTIMEDOUT,
138 	DORECAL,
139 	RECALWAIT,
140 	RECALTIMEDOUT,
141 	RECALCOMPLETE,
142 	DOCOPY,
143 	DOIOHALF,
144 	COPYCOMPLETE,
145 };
146 
147 /* software state, per controller */
148 struct fdc_softc {
149 	struct device sc_dev;		/* boilerplate */
150 
151 	bus_space_tag_t sc_iot;		/* intio i/o space identifier */
152 	bus_space_handle_t sc_ioh;	/* intio io handle */
153 
154 	struct callout sc_timo_ch;	/* timeout callout */
155 	struct callout sc_intr_ch;	/* pseudo-intr callout */
156 
157 	bus_dma_tag_t sc_dmat;		/* intio dma tag */
158 	bus_dmamap_t sc_dmamap;		/* dma map */
159 	u_int8_t *sc_addr;			/* physical address */
160 	struct dmac_channel_stat *sc_dmachan; /* intio dma channel */
161 	struct dmac_dma_xfer *sc_xfer;	/* dma transfer */
162 
163 	struct fd_softc *sc_fd[4];	/* pointers to children */
164 	TAILQ_HEAD(drivehead, fd_softc) sc_drives;
165 	enum fdc_state sc_state;
166 	int sc_errors;			/* number of retries so far */
167 	u_char sc_status[7];		/* copy of registers */
168 } fdc_softc;
169 
170 bdev_decl(fd);
171 cdev_decl(fd);
172 
173 int fdcintr __P((void*));
174 void fdcreset __P((struct fdc_softc *));
175 
176 /* controller driver configuration */
177 int fdcprobe __P((struct device *, struct cfdata *, void *));
178 void fdcattach __P((struct device *, struct device *, void *));
179 int fdprint __P((void *, const char *));
180 
181 struct cfattach fdc_ca = {
182 	sizeof(struct fdc_softc), fdcprobe, fdcattach
183 };
184 
185 extern struct cfdriver fdc_cd;
186 
187 /*
188  * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how
189  * we tell them apart.
190  */
191 struct fd_type {
192 	int	sectrac;	/* sectors per track */
193 	int	heads;		/* number of heads */
194 	int	seccyl;		/* sectors per cylinder */
195 	int	secsize;	/* size code for sectors */
196 	int	datalen;	/* data len when secsize = 0 */
197 	int	steprate;	/* step rate and head unload time */
198 	int	gap1;		/* gap len between sectors */
199 	int	gap2;		/* formatting gap */
200 	int	cyls;		/* total num of cylinders */
201 	int	size;		/* size of disk in sectors */
202 	int	step;		/* steps per cylinder */
203 	int	rate;		/* transfer speed code */
204 	char	*name;
205 };
206 
207 /* The order of entries in the following table is important -- BEWARE! */
208 struct fd_type fd_types[] = {
209         {  8,2,16,3,0xff,0xdf,0x35,0x74,77,1232,1,FDC_500KBPS, "1.2MB/[1024bytes/sector]"    }, /* 1.2 MB japanese format */
210         { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS,"1.44MB"    }, /* 1.44MB diskette */
211         { 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS, "1.2MB"    }, /* 1.2 MB AT-diskettes */
212         {  9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS, "360KB/AT" }, /* 360kB in 1.2MB drive */
213         {  9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS, "360KB/PC" }, /* 360kB PC diskettes */
214         {  9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS, "720KB"    }, /* 3.5" 720kB diskette */
215         {  9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS, "720KB/x"  }, /* 720kB in 1.2MB drive */
216         {  9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS, "360KB/x"  }, /* 360kB in 720kB drive */
217 };
218 
219 /* software state, per disk (with up to 4 disks per ctlr) */
220 struct fd_softc {
221 	struct device sc_dev;
222 	struct disk sc_dk;
223 
224 	struct fd_type *sc_deftype;	/* default type descriptor */
225 	struct fd_type *sc_type;	/* current type descriptor */
226 
227 	struct callout sc_motoron_ch;
228 	struct callout sc_motoroff_ch;
229 
230 	daddr_t	sc_blkno;	/* starting block number */
231 	int sc_bcount;		/* byte count left */
232  	int sc_opts;			/* user-set options */
233 	int sc_skip;		/* bytes already transferred */
234 	int sc_nblks;		/* number of blocks currently tranferring */
235 	int sc_nbytes;		/* number of bytes currently tranferring */
236 
237 	int sc_drive;		/* physical unit number */
238 	int sc_flags;
239 #define	FD_BOPEN	0x01		/* it's open */
240 #define	FD_COPEN	0x02		/* it's open */
241 #define	FD_OPEN		(FD_BOPEN|FD_COPEN)	/* it's open */
242 #define	FD_MOTOR	0x04		/* motor should be on */
243 #define	FD_MOTOR_WAIT	0x08		/* motor coming up */
244 #define	FD_ALIVE	0x10		/* alive */
245 	int sc_cylin;		/* where we think the head is */
246 
247 	TAILQ_ENTRY(fd_softc) sc_drivechain;
248 	int sc_ops;		/* I/O ops since last switch */
249 	struct buf_queue sc_q;	/* pending I/O requests */
250 	int sc_active;		/* number of active I/O operations */
251 	u_char *sc_copybuf;	/* for secsize >=3 */
252 	u_char sc_part;		/* for secsize >=3 */
253 #define	SEC_P10	0x02		/* first part */
254 #define	SEC_P01	0x01		/* second part */
255 #define	SEC_P11	0x03		/* both part */
256 
257 #if NRND > 0
258 	rndsource_element_t	rnd_source;
259 #endif
260 };
261 
262 /* floppy driver configuration */
263 int fdprobe __P((struct device *, struct cfdata *, void *));
264 void fdattach __P((struct device *, struct device *, void *));
265 
266 struct cfattach fd_ca = {
267 	sizeof(struct fd_softc), fdprobe, fdattach
268 };
269 
270 extern struct cfdriver fd_cd;
271 
272 void fdstrategy __P((struct buf *));
273 void fdstart __P((struct fd_softc *fd));
274 
275 struct dkdriver fddkdriver = { fdstrategy };
276 
277 void fd_set_motor __P((struct fdc_softc *fdc, int reset));
278 void fd_motor_off __P((void *arg));
279 void fd_motor_on __P((void *arg));
280 int fdcresult __P((struct fdc_softc *fdc));
281 int out_fdc __P((bus_space_tag_t, bus_space_handle_t, u_char x));
282 void fdcstart __P((struct fdc_softc *fdc));
283 void fdcstatus __P((struct device *dv, int n, char *s));
284 void fdctimeout __P((void *arg));
285 void fdcpseudointr __P((void *arg));
286 void fdcretry __P((struct fdc_softc *fdc));
287 void fdfinish __P((struct fd_softc *fd, struct buf *bp));
288 __inline struct fd_type *fd_dev_to_type __P((struct fd_softc *, dev_t));
289 static int fdcpoll __P((struct fdc_softc *));
290 static int fdgetdisklabel __P((struct fd_softc *, dev_t));
291 static void fd_do_eject __P((struct fdc_softc *, int));
292 
293 void fd_mountroot_hook __P((struct device *));
294 
295 /* dma transfer routines */
296 __inline static void fdc_dmastart __P((struct fdc_softc*, int,
297 				       caddr_t, vsize_t));
298 static int fdcdmaintr __P((void*));
299 static int fdcdmaerrintr __P((void*));
300 
301 __inline static void
302 fdc_dmastart(fdc, read, addr, count)
303 	struct fdc_softc *fdc;
304 	int read;
305 	caddr_t addr;
306 	vsize_t count;
307 {
308 	int error;
309 
310 	DPRINTF(("fdc_dmastart: (%s, addr = %p, count = %d\n",
311 		 read ? "read" : "write", (caddr_t) addr, count));
312 
313 	error = bus_dmamap_load(fdc->sc_dmat, fdc->sc_dmamap, addr, count,
314 				0, BUS_DMA_NOWAIT);
315 	if (error) {
316 		panic ("fdc_dmastart: cannot load dmamap");
317 	}
318 
319 	bus_dmamap_sync(fdc->sc_dmat, fdc->sc_dmamap, 0, count,
320 			read?BUS_DMASYNC_PREREAD:BUS_DMASYNC_PREWRITE);
321 
322 	fdc->sc_xfer = dmac_prepare_xfer(fdc->sc_dmachan, fdc->sc_dmat,
323 					 fdc->sc_dmamap,
324 					 (read?
325 					  DMAC_OCR_DIR_DTM:DMAC_OCR_DIR_MTD),
326 					 (DMAC_SCR_MAC_COUNT_UP|
327 					  DMAC_SCR_DAC_NO_COUNT),
328 					 (u_int8_t*) (fdc->sc_addr +
329 						      fddata));	/* XXX */
330 #if defined(M68040) || defined(M68060)
331 	if (mmutype == MMU_68040)
332 		dma_cachectl(addr, count);
333 #endif
334 
335 	dmac_start_xfer(fdc->sc_dmachan->ch_softc, fdc->sc_xfer);
336 }
337 
338 static int
339 fdcdmaintr(arg)
340 	void *arg;
341 {
342 	struct fdc_softc *fdc = arg;
343 
344 	bus_dmamap_unload(fdc->sc_dmat, fdc->sc_dmamap);
345 
346 	return 0;
347 }
348 
349 static int
350 fdcdmaerrintr(dummy)
351 	void *dummy;
352 {
353 	DPRINTF(("fdcdmaerrintr\n"));
354 
355 	return 0;
356 }
357 
358 /* ARGSUSED */
359 int
360 fdcprobe(parent, cf, aux)
361 	struct device *parent;
362 	struct cfdata *cf;
363 	void *aux;
364 {
365 	struct intio_attach_args *ia = aux;
366 
367 	if (strcmp(ia->ia_name, "fdc") != 0)
368 		return 0;
369 
370 	if (ia->ia_addr == INTIOCF_ADDR_DEFAULT)
371 		ia->ia_addr = FDC_ADDR;
372 	if (ia->ia_intr == INTIOCF_INTR_DEFAULT)
373 		ia->ia_intr = FDC_INTR;
374 	if (ia->ia_dma == INTIOCF_DMA_DEFAULT)
375 		ia->ia_dma = FDC_DMA;
376 	if (ia->ia_dmaintr == INTIOCF_DMAINTR_DEFAULT)
377 		ia->ia_dmaintr = FDC_DMAINTR;
378 
379 	if ((ia->ia_intr & 0x03) != 0)
380 		return 0;
381 
382 	ia->ia_size = 0x2000;
383 	if (intio_map_allocate_region (parent, ia, INTIO_MAP_TESTONLY))
384 		return 0;
385 
386 	/* builtin device; always there */
387 	return 1;
388 }
389 
390 /*
391  * Arguments passed between fdcattach and fdprobe.
392  */
393 struct fdc_attach_args {
394 	int fa_drive;
395 	struct fd_type *fa_deftype;
396 };
397 
398 /*
399  * Print the location of a disk drive (called just before attaching the
400  * the drive).  If `fdc' is not NULL, the drive was found but was not
401  * in the system config file; print the drive name as well.
402  * Return QUIET (config_find ignores this if the device was configured) to
403  * avoid printing `fdN not configured' messages.
404  */
405 int
406 fdprint(aux, fdc)
407 	void *aux;
408 	const char *fdc;
409 {
410 	register struct fdc_attach_args *fa = aux;
411 
412 	if (!fdc)
413 		printf(" drive %d", fa->fa_drive);
414 	return QUIET;
415 }
416 
417 void
418 fdcattach(parent, self, aux)
419 	struct device *parent, *self;
420 	void *aux;
421 {
422 	struct fdc_softc *fdc = (void *)self;
423 	bus_space_tag_t iot;
424 	bus_space_handle_t ioh;
425 	struct intio_attach_args *ia = aux;
426 	struct fdc_attach_args fa;
427 
428 	iot = ia->ia_bst;
429 
430 	printf("\n");
431 
432 	callout_init(&fdc->sc_timo_ch);
433 	callout_init(&fdc->sc_intr_ch);
434 
435 	/* Re-map the I/O space. */
436 	bus_space_map(iot, ia->ia_addr, 0x2000, BUS_SPACE_MAP_SHIFTED, &ioh);
437 
438 	fdc->sc_iot = iot;
439 	fdc->sc_ioh = ioh;
440 	fdc->sc_addr = (void*) ia->ia_addr;
441 
442 	fdc->sc_dmat = ia->ia_dmat;
443 	fdc->sc_state = DEVIDLE;
444 	TAILQ_INIT(&fdc->sc_drives);
445 
446 	/* Initialize DMAC channel */
447 	fdc->sc_dmachan = dmac_alloc_channel(parent, ia->ia_dma, "fdc",
448 					     ia->ia_dmaintr, fdcdmaintr, fdc,
449 					     ia->ia_dmaintr+1, fdcdmaerrintr,
450 					     fdc);
451 	if (bus_dmamap_create(fdc->sc_dmat, FDC_MAXIOSIZE, 16, 0xf000, 0,
452 			      BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW,
453 			      &fdc->sc_dmamap)) {
454 		printf("%s: can't set up intio DMA map\n",
455 		    fdc->sc_dev.dv_xname);
456 		return;
457 	}
458 
459 	if (intio_intr_establish(ia->ia_intr, "fdc", fdcintr, fdc))
460 		panic ("Could not establish interrupt (duplicated vector?).");
461 	intio_set_ivec(ia->ia_intr);
462 
463 	/* reset */
464 	intio_disable_intr(SICILIAN_INTR_FDD);
465 	intio_enable_intr(SICILIAN_INTR_FDC);
466 	fdcresult(fdc);
467 	fdcreset(fdc);
468 
469 	printf("%s: uPD72065 FDC\n", fdc->sc_dev.dv_xname);
470 	out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
471 	out_fdc(iot, ioh, 0xd0);
472 	out_fdc(iot, ioh, 0x10);
473 
474 	/* physical limit: four drives per controller. */
475 	for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) {
476 		(void)config_found(self, (void *)&fa, fdprint);
477 	}
478 
479 	intio_enable_intr(SICILIAN_INTR_FDC);
480 }
481 
482 void
483 fdcreset(fdc)
484 	struct fdc_softc *fdc;
485 {
486 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdsts, NE7CMD_RESET);
487 }
488 
489 static int
490 fdcpoll(fdc)
491 	struct fdc_softc *fdc;
492 {
493 	int i = 25000, n;
494 	while (--i > 0) {
495 		if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC)) {
496 			out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
497 			n = fdcresult(fdc);
498 			break;
499 		}
500 		DELAY(100);
501 	}
502 	return i;
503 }
504 
505 int
506 fdprobe(parent, cf, aux)
507 	struct device *parent;
508 	struct cfdata *cf;
509 	void *aux;
510 {
511 	struct fdc_softc *fdc = (void *)parent;
512 	struct fd_type *type;
513 	struct fdc_attach_args *fa = aux;
514 	int drive = fa->fa_drive;
515 	bus_space_tag_t iot = fdc->sc_iot;
516 	bus_space_handle_t ioh = fdc->sc_ioh;
517 	int n;
518 	int found = 0;
519 	int i;
520 
521 	if (cf->cf_loc[FDCCF_UNIT] != FDCCF_UNIT_DEFAULT &&
522 	    cf->cf_loc[FDCCF_UNIT] != drive)
523 		return 0;
524 
525 	type = &fd_types[0];	/* XXX 1.2MB */
526 
527 	intio_disable_intr(SICILIAN_INTR_FDC);
528 
529 	/* select drive and turn on motor */
530 	bus_space_write_1(iot, ioh, fdctl, 0x80 | (type->rate << 4)| drive);
531 	fdc_force_ready(FDCRDY);
532 	fdcpoll(fdc);
533 
534 retry:
535 	out_fdc(iot, ioh, NE7CMD_RECAL);
536 	out_fdc(iot, ioh, drive);
537 
538 	i = 25000;
539 	while (--i > 0) {
540 		if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC)) {
541 			out_fdc(iot, ioh, NE7CMD_SENSEI);
542 			n = fdcresult(fdc);
543 			break;
544 		}
545 		DELAY(100);
546 	}
547 
548 #ifdef FDDEBUG
549 	{
550 		int i;
551 		DPRINTF(("fdprobe: status"));
552 		for (i = 0; i < n; i++)
553 			DPRINTF((" %x", fdc->sc_status[i]));
554 		DPRINTF(("\n"));
555 	}
556 #endif
557 
558 	if (n == 2) {
559 		if ((fdc->sc_status[0] & 0xf0) == 0x20) {
560 			found = 1;
561 		} else if ((fdc->sc_status[0] & 0xf0) == 0xc0) {
562 			goto retry;
563 		}
564 	}
565 
566 	/* turn off motor */
567 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh,
568 			  fdctl, (type->rate << 4)| drive);
569 	fdc_force_ready(FDCSTBY);
570 	if (!found) {
571 		intio_enable_intr(SICILIAN_INTR_FDC);
572 		return 0;
573 	}
574 
575 	return 1;
576 }
577 
578 /*
579  * Controller is working, and drive responded.  Attach it.
580  */
581 void
582 fdattach(parent, self, aux)
583 	struct device *parent, *self;
584 	void *aux;
585 {
586 	struct fdc_softc *fdc = (void *)parent;
587 	struct fd_softc *fd = (void *)self;
588 	struct fdc_attach_args *fa = aux;
589 	struct fd_type *type = &fd_types[0];	/* XXX 1.2MB */
590 	int drive = fa->fa_drive;
591 
592 	callout_init(&fd->sc_motoron_ch);
593 	callout_init(&fd->sc_motoroff_ch);
594 
595 	fd->sc_flags = 0;
596 
597 	if (type)
598 		printf(": %s, %d cyl, %d head, %d sec\n", type->name,
599 		       type->cyls, type->heads, type->sectrac);
600 	else
601 		printf(": density unknown\n");
602 
603 	BUFQ_INIT(&fd->sc_q);
604 	fd->sc_cylin = -1;
605 	fd->sc_drive = drive;
606 	fd->sc_deftype = type;
607 	fdc->sc_fd[drive] = fd;
608 
609 	fd->sc_copybuf = (u_char *)malloc(NBPG, M_DEVBUF, M_WAITOK);
610 	if (fd->sc_copybuf == 0)
611 		printf("fdprobe: WARNING!! malloc() failed.\n");
612 	fd->sc_flags |= FD_ALIVE;
613 
614 	/*
615 	 * Initialize and attach the disk structure.
616 	 */
617 	fd->sc_dk.dk_name = fd->sc_dev.dv_xname;
618 	fd->sc_dk.dk_driver = &fddkdriver;
619 	disk_attach(&fd->sc_dk);
620 
621 	/*
622 	 * Establish a mountroot_hook anyway in case we booted
623 	 * with RB_ASKNAME and get selected as the boot device.
624 	 */
625 	mountroothook_establish(fd_mountroot_hook, &fd->sc_dev);
626 
627 #if NRND > 0
628 	rnd_attach_source(&fd->rnd_source, fd->sc_dev.dv_xname,
629 			  RND_TYPE_DISK, 0);
630 #endif
631 }
632 
633 __inline struct fd_type *
634 fd_dev_to_type(fd, dev)
635 	struct fd_softc *fd;
636 	dev_t dev;
637 {
638 	int type = FDTYPE(dev);
639 
640 	if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
641 		return NULL;
642 	return &fd_types[type];
643 }
644 
645 void
646 fdstrategy(bp)
647 	register struct buf *bp;	/* IO operation to perform */
648 {
649 	struct fd_softc *fd;
650 	int unit = FDUNIT(bp->b_dev);
651 	int sz;
652  	int s;
653 
654 	if (unit >= fd_cd.cd_ndevs ||
655 	    (fd = fd_cd.cd_devs[unit]) == 0 ||
656 	    bp->b_blkno < 0 ||
657 	    (bp->b_bcount % FDC_BSIZE) != 0) {
658 		DPRINTF(("fdstrategy: unit=%d, blkno=%d, bcount=%d\n", unit,
659 			 bp->b_blkno, bp->b_bcount));
660 		bp->b_error = EINVAL;
661 		goto bad;
662 	}
663 
664 	/* If it's a null transfer, return immediately. */
665 	if (bp->b_bcount == 0)
666 		goto done;
667 
668 	sz = howmany(bp->b_bcount, FDC_BSIZE);
669 
670 	if (bp->b_blkno + sz > (fd->sc_type->size << (fd->sc_type->secsize - 2))) {
671 		sz = (fd->sc_type->size << (fd->sc_type->secsize - 2)) - bp->b_blkno;
672 		if (sz == 0) {
673 			/* If exactly at end of disk, return EOF. */
674 			bp->b_resid = bp->b_bcount;
675 			goto done;
676 		}
677 		if (sz < 0) {
678 			/* If past end of disk, return EINVAL. */
679 			bp->b_error = EINVAL;
680 			goto bad;
681 		}
682 		/* Otherwise, truncate request. */
683 		bp->b_bcount = sz << DEV_BSHIFT;
684 	}
685 
686 	bp->b_rawblkno = bp->b_blkno;
687  	bp->b_cylinder = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE)
688 		/ (fd->sc_type->seccyl * (1 << (fd->sc_type->secsize - 2)));
689 
690 	DPRINTF(("fdstrategy: %s b_blkno %d b_bcount %ld cylin %ld\n",
691 		 bp->b_flags & B_READ ? "read" : "write",
692 		 bp->b_blkno, bp->b_bcount, bp->b_cylinder));
693 	/* Queue transfer on drive, activate drive and controller if idle. */
694 	s = splbio();
695 	disksort_cylinder(&fd->sc_q, bp);
696 	callout_stop(&fd->sc_motoroff_ch);		/* a good idea */
697 	if (fd->sc_active == 0)
698 		fdstart(fd);
699 #ifdef DIAGNOSTIC
700 	else {
701 		struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
702 		if (fdc->sc_state == DEVIDLE) {
703 			printf("fdstrategy: controller inactive\n");
704 			fdcstart(fdc);
705 		}
706 	}
707 #endif
708 	splx(s);
709 	return;
710 
711 bad:
712 	bp->b_flags |= B_ERROR;
713 done:
714 	/* Toss transfer; we're done early. */
715 	biodone(bp);
716 }
717 
718 void
719 fdstart(fd)
720 	struct fd_softc *fd;
721 {
722 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
723 	int active = fdc->sc_drives.tqh_first != 0;
724 
725 	/* Link into controller queue. */
726 	fd->sc_active = 1;
727 	TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
728 
729 	/* If controller not already active, start it. */
730 	if (!active)
731 		fdcstart(fdc);
732 }
733 
734 void
735 fdfinish(fd, bp)
736 	struct fd_softc *fd;
737 	struct buf *bp;
738 {
739 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
740 
741 	/*
742 	 * Move this drive to the end of the queue to give others a `fair'
743 	 * chance.  We only force a switch if N operations are completed while
744 	 * another drive is waiting to be serviced, since there is a long motor
745 	 * startup delay whenever we switch.
746 	 */
747 	if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) {
748 		fd->sc_ops = 0;
749 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
750 		if (BUFQ_NEXT(bp) != NULL) {
751 			TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
752 		} else
753 			fd->sc_active = 0;
754 	}
755 	bp->b_resid = fd->sc_bcount;
756 	fd->sc_skip = 0;
757 	BUFQ_REMOVE(&fd->sc_q, bp);
758 
759 #if NRND > 0
760 	rnd_add_uint32(&fd->rnd_source, bp->b_blkno);
761 #endif
762 
763 	biodone(bp);
764 	/* turn off motor 5s from now */
765 	callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd);
766 	fdc->sc_state = DEVIDLE;
767 }
768 
769 int
770 fdread(dev, uio, flags)
771 	dev_t dev;
772 	struct uio *uio;
773 	int flags;
774 {
775 
776 	return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
777 }
778 
779 int
780 fdwrite(dev, uio, flags)
781 	dev_t dev;
782 	struct uio *uio;
783 	int flags;
784 {
785 
786 	return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
787 }
788 
789 void
790 fd_set_motor(fdc, reset)
791 	struct fdc_softc *fdc;
792 	int reset;
793 {
794 	struct fd_softc *fd;
795 	int n;
796 
797 	DPRINTF(("fd_set_motor:\n"));
798 	for (n = 0; n < 4; n++)
799 		if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR)) {
800 			bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdctl,
801 					  0x80 | (fd->sc_type->rate << 4)| n);
802 		}
803 }
804 
805 void
806 fd_motor_off(arg)
807 	void *arg;
808 {
809 	struct fd_softc *fd = arg;
810 	struct fdc_softc *fdc = (struct fdc_softc*) fd->sc_dev.dv_parent;
811 	int s;
812 
813 	DPRINTF(("fd_motor_off:\n"));
814 
815 	s = splbio();
816 	fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
817 	bus_space_write_1 (fdc->sc_iot, fdc->sc_ioh, fdctl,
818 			   (fd->sc_type->rate << 4) | fd->sc_drive);
819 #if 0
820 	fd_set_motor(fdc, 0); /* XXX */
821 #endif
822 	splx(s);
823 }
824 
825 void
826 fd_motor_on(arg)
827 	void *arg;
828 {
829 	struct fd_softc *fd = arg;
830 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
831 	int s;
832 
833 	DPRINTF(("fd_motor_on:\n"));
834 
835 	s = splbio();
836 	fd->sc_flags &= ~FD_MOTOR_WAIT;
837 	if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT))
838 		(void) fdcintr(fdc);
839 	splx(s);
840 }
841 
842 int
843 fdcresult(fdc)
844 	struct fdc_softc *fdc;
845 {
846 	bus_space_tag_t iot = fdc->sc_iot;
847 	bus_space_handle_t ioh = fdc->sc_ioh;
848 	u_char i;
849 	int j = 100000,
850 	    n = 0;
851 
852 	for (; j; j--) {
853 		i = bus_space_read_1(iot, ioh, fdsts) &
854 		  (NE7_DIO | NE7_RQM | NE7_CB);
855 
856 		if (i == NE7_RQM)
857 			return n;
858 		if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
859 			if (n >= sizeof(fdc->sc_status)) {
860 				log(LOG_ERR, "fdcresult: overrun\n");
861 				return -1;
862 			}
863 			fdc->sc_status[n++] =
864 			  bus_space_read_1(iot, ioh, fddata);
865 		}
866 		delay(10);
867 	}
868 	log(LOG_ERR, "fdcresult: timeout\n");
869 	return -1;
870 }
871 
872 int
873 out_fdc(iot, ioh, x)
874 	bus_space_tag_t iot;
875 	bus_space_handle_t ioh;
876 	u_char x;
877 {
878 	int i = 100000;
879 
880 	while ((bus_space_read_1(iot, ioh, fdsts) & NE7_DIO) && i-- > 0);
881 	if (i <= 0)
882 		return -1;
883 	while ((bus_space_read_1(iot, ioh, fdsts) & NE7_RQM) == 0 && i-- > 0);
884 	if (i <= 0)
885 		return -1;
886 	bus_space_write_1(iot, ioh, fddata, x);
887 	return 0;
888 }
889 
890 int
891 fdopen(dev, flags, mode, p)
892 	dev_t dev;
893 	int flags, mode;
894 	struct proc *p;
895 {
896  	int unit;
897 	struct fd_softc *fd;
898 	struct fd_type *type;
899 	struct fdc_softc *fdc;
900 
901 	unit = FDUNIT(dev);
902 	if (unit >= fd_cd.cd_ndevs)
903 		return ENXIO;
904 	fd = fd_cd.cd_devs[unit];
905 	if (fd == 0)
906 		return ENXIO;
907 	type = fd_dev_to_type(fd, dev);
908 	if (type == NULL)
909 		return ENXIO;
910 
911 	if ((fd->sc_flags & FD_OPEN) != 0 &&
912 	    fd->sc_type != type)
913 		return EBUSY;
914 
915 	fdc = (void *)fd->sc_dev.dv_parent;
916 	if ((fd->sc_flags & FD_OPEN) == 0) {
917 		/* Lock eject button */
918 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
919 				  0x40 | ( 1 << unit));
920 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0x40);
921 	}
922 
923 	fd->sc_type = type;
924 	fd->sc_cylin = -1;
925 
926 	switch (mode) {
927 	case S_IFCHR:
928 		fd->sc_flags |= FD_COPEN;
929 		break;
930 	case S_IFBLK:
931 		fd->sc_flags |= FD_BOPEN;
932 		break;
933 	}
934 
935 	fdgetdisklabel(fd, dev);
936 
937 	return 0;
938 }
939 
940 int
941 fdclose(dev, flags, mode, p)
942 	dev_t dev;
943 	int flags, mode;
944 	struct proc *p;
945 {
946  	int unit = FDUNIT(dev);
947 	struct fd_softc *fd = fd_cd.cd_devs[unit];
948 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
949 
950 	DPRINTF(("fdclose %d\n", unit));
951 
952 	switch (mode) {
953 	case S_IFCHR:
954 		fd->sc_flags &= ~FD_COPEN;
955 		break;
956 	case S_IFBLK:
957 		fd->sc_flags &= ~FD_BOPEN;
958 		break;
959 	}
960 
961 	if ((fd->sc_flags & FD_OPEN) == 0) {
962 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
963 				  ( 1 << unit));
964 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0);
965 	}
966 	return 0;
967 }
968 
969 void
970 fdcstart(fdc)
971 	struct fdc_softc *fdc;
972 {
973 
974 #ifdef DIAGNOSTIC
975 	/* only got here if controller's drive queue was inactive; should
976 	   be in idle state */
977 	if (fdc->sc_state != DEVIDLE) {
978 		printf("fdcstart: not idle\n");
979 		return;
980 	}
981 #endif
982 	(void) fdcintr(fdc);
983 }
984 
985 void
986 fdcstatus(dv, n, s)
987 	struct device *dv;
988 	int n;
989 	char *s;
990 {
991 	struct fdc_softc *fdc = (void *)dv->dv_parent;
992 	char bits[64];
993 
994 	if (n == 0) {
995 		out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
996 		(void) fdcresult(fdc);
997 		n = 2;
998 	}
999 
1000 	printf("%s: %s: state %d", dv->dv_xname, s, fdc->sc_state);
1001 
1002 	switch (n) {
1003 	case 0:
1004 		printf("\n");
1005 		break;
1006 	case 2:
1007 		printf(" (st0 %s cyl %d)\n",
1008 		    bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS,
1009 		    bits, sizeof(bits)), fdc->sc_status[1]);
1010 		break;
1011 	case 7:
1012 		printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
1013 		    NE7_ST0BITS, bits, sizeof(bits)));
1014 		printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
1015 		    NE7_ST1BITS, bits, sizeof(bits)));
1016 		printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
1017 		    NE7_ST2BITS, bits, sizeof(bits)));
1018 		printf(" cyl %d head %d sec %d)\n",
1019 		    fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
1020 		break;
1021 #ifdef DIAGNOSTIC
1022 	default:
1023 		printf(" fdcstatus: weird size: %d\n", n);
1024 		break;
1025 #endif
1026 	}
1027 }
1028 
1029 void
1030 fdctimeout(arg)
1031 	void *arg;
1032 {
1033 	struct fdc_softc *fdc = arg;
1034 	struct fd_softc *fd = fdc->sc_drives.tqh_first;
1035 	int s;
1036 
1037 	s = splbio();
1038 	fdcstatus(&fd->sc_dev, 0, "timeout");
1039 
1040 	if (BUFQ_FIRST(&fd->sc_q) != NULL)
1041 		fdc->sc_state++;
1042 	else
1043 		fdc->sc_state = DEVIDLE;
1044 
1045 	(void) fdcintr(fdc);
1046 	splx(s);
1047 }
1048 
1049 #if 0
1050 void
1051 fdcpseudointr(arg)
1052 	void *arg;
1053 {
1054 	int s;
1055 	struct fdc_softc *fdc = arg;
1056 
1057 	/* just ensure it has the right spl */
1058 	s = splbio();
1059 	(void) fdcintr(fdc);
1060 	splx(s);
1061 }
1062 #endif
1063 
1064 int
1065 fdcintr(arg)
1066 	void *arg;
1067 {
1068 	struct fdc_softc *fdc = arg;
1069 #define	st0	fdc->sc_status[0]
1070 #define	cyl	fdc->sc_status[1]
1071 	struct fd_softc *fd;
1072 	struct buf *bp;
1073 	bus_space_tag_t iot = fdc->sc_iot;
1074 	bus_space_handle_t ioh = fdc->sc_ioh;
1075 	int read, head, sec, pos, i, sectrac, nblks;
1076 	int	tmp;
1077 	struct fd_type *type;
1078 
1079 loop:
1080 	fd = fdc->sc_drives.tqh_first;
1081 	if (fd == NULL) {
1082 		DPRINTF(("fdcintr: set DEVIDLE\n"));
1083 		if (fdc->sc_state == DEVIDLE) {
1084 			if (intio_get_sicilian_intr() & SICILIAN_STAT_FDC) {
1085 				out_fdc(iot, ioh, NE7CMD_SENSEI);
1086 				if ((tmp = fdcresult(fdc)) != 2 ||
1087 				    (st0 & 0xf8) != 0x20) {
1088 					goto loop;
1089 				}
1090 			}
1091 		}
1092 		/* no drives waiting; end */
1093 		fdc->sc_state = DEVIDLE;
1094  		return 1;
1095 	}
1096 
1097 	/* Is there a transfer to this drive?  If not, deactivate drive. */
1098 	bp = BUFQ_FIRST(&fd->sc_q);
1099 	if (bp == NULL) {
1100 		fd->sc_ops = 0;
1101 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
1102 		fd->sc_active = 0;
1103 		goto loop;
1104 	}
1105 
1106 	switch (fdc->sc_state) {
1107 	case DEVIDLE:
1108 		DPRINTF(("fdcintr: in DEVIDLE\n"));
1109 		fdc->sc_errors = 0;
1110 		fd->sc_skip = 0;
1111 		fd->sc_bcount = bp->b_bcount;
1112 		fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
1113 		callout_stop(&fd->sc_motoroff_ch);
1114 		if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
1115 			fdc->sc_state = MOTORWAIT;
1116 			return 1;
1117 		}
1118 		if ((fd->sc_flags & FD_MOTOR) == 0) {
1119 			/* Turn on the motor */
1120 			/* being careful about other drives. */
1121 			for (i = 0; i < 4; i++) {
1122 				struct fd_softc *ofd = fdc->sc_fd[i];
1123 				if (ofd && ofd->sc_flags & FD_MOTOR) {
1124 					callout_stop(&ofd->sc_motoroff_ch);
1125 					ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
1126 					break;
1127 				}
1128 			}
1129 			fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
1130 			fd_set_motor(fdc, 0);
1131 			fdc->sc_state = MOTORWAIT;
1132 			/* allow .5s for motor to stabilize */
1133 			callout_reset(&fd->sc_motoron_ch, hz / 2,
1134 			    fd_motor_on, fd);
1135 			return 1;
1136 		}
1137 		/* Make sure the right drive is selected. */
1138 		fd_set_motor(fdc, 0);
1139 
1140 		/* fall through */
1141 	case DOSEEK:
1142 	doseek:
1143 		DPRINTF(("fdcintr: in DOSEEK\n"));
1144 		if (fd->sc_cylin == bp->b_cylinder)
1145 			goto doio;
1146 
1147 		out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
1148 		out_fdc(iot, ioh, 0xd0);	/* XXX const */
1149 		out_fdc(iot, ioh, 0x10);
1150 
1151 		out_fdc(iot, ioh, NE7CMD_SEEK);	/* seek function */
1152 		out_fdc(iot, ioh, fd->sc_drive);	/* drive number */
1153 		out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step);
1154 
1155 		fd->sc_cylin = -1;
1156 		fdc->sc_state = SEEKWAIT;
1157 
1158 		fd->sc_dk.dk_seek++;
1159 		disk_busy(&fd->sc_dk);
1160 
1161 		callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
1162 		return 1;
1163 
1164 	case DOIO:
1165 	doio:
1166 		DPRINTF(("fdcintr: DOIO: "));
1167 		type = fd->sc_type;
1168 		sectrac = type->sectrac;
1169 		pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
1170 		sec = pos / (1 << (type->secsize - 2));
1171 		if (type->secsize == 2) {
1172 			fd->sc_part = SEC_P11;
1173 			nblks = (sectrac - sec) << (type->secsize - 2);
1174 			nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
1175 			DPRINTF(("nblks(0)"));
1176 		} else if ((fd->sc_blkno % 2) == 0) {
1177 			if (fd->sc_bcount & 0x00000200) {
1178 				if (fd->sc_bcount == FDC_BSIZE) {
1179 					fd->sc_part = SEC_P10;
1180 					nblks = 1;
1181 					DPRINTF(("nblks(1)"));
1182 				} else {
1183 					fd->sc_part = SEC_P11;
1184 					nblks = (sectrac - sec) * 2;
1185 					nblks = min(nblks, fd->sc_bcount
1186 						    / FDC_BSIZE - 1);
1187 					DPRINTF(("nblks(2)"));
1188 				}
1189 			} else {
1190 				fd->sc_part = SEC_P11;
1191 				nblks = (sectrac - sec)
1192 					<< (type->secsize - 2);
1193 				nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
1194 				DPRINTF(("nblks(3)"));
1195 			}
1196 		} else {
1197 			fd->sc_part = SEC_P01;
1198 			nblks = 1;
1199 			DPRINTF(("nblks(4)"));
1200 		}
1201 		nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
1202 		DPRINTF((" %d\n", nblks));
1203 		fd->sc_nblks = nblks;
1204 		fd->sc_nbytes = nblks * FDC_BSIZE;
1205 		head = (fd->sc_blkno
1206 			% (type->seccyl * (1 << (type->secsize - 2))))
1207 			 / (type->sectrac * (1 << (type->secsize - 2)));
1208 
1209 #ifdef DIAGNOSTIC
1210 		{int block;
1211 		 block = ((fd->sc_cylin * type->heads + head) * type->sectrac
1212 			  + sec) * (1 << (type->secsize - 2));
1213 		 block += (fd->sc_part == SEC_P01) ? 1 : 0;
1214 		 if (block != fd->sc_blkno) {
1215 			 printf("C H R N: %d %d %d %d\n", fd->sc_cylin, head, sec, type->secsize);
1216 			 printf("fdcintr: doio: block %d != blkno %d\n", block, fd->sc_blkno);
1217 #ifdef DDB
1218 			 Debugger();
1219 #endif
1220 		 }}
1221 #endif
1222 		read = bp->b_flags & B_READ;
1223 		DPRINTF(("fdcintr: %s drive %d track %d head %d sec %d nblks %d, skip %d\n",
1224 			 read ? "read" : "write", fd->sc_drive, fd->sc_cylin,
1225 			 head, sec, nblks, fd->sc_skip));
1226 		DPRINTF(("C H R N: %d %d %d %d\n", fd->sc_cylin, head, sec,
1227 			 type->secsize));
1228 
1229 		if (fd->sc_part != SEC_P11)
1230 			goto docopy;
1231 
1232 		fdc_dmastart(fdc,
1233 			     read, bp->b_data + fd->sc_skip, fd->sc_nbytes);
1234 		if (read)
1235 			out_fdc(iot, ioh, NE7CMD_READ);	/* READ */
1236 		else
1237 			out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
1238 		out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1239 		out_fdc(iot, ioh, bp->b_cylinder);	/* cylinder */
1240 		out_fdc(iot, ioh, head);
1241 		out_fdc(iot, ioh, sec + 1);		/* sector +1 */
1242 		out_fdc(iot, ioh, type->secsize);	/* sector size */
1243 		out_fdc(iot, ioh, type->sectrac);	/* sectors/track */
1244 		out_fdc(iot, ioh, type->gap1);		/* gap1 size */
1245 		out_fdc(iot, ioh, type->datalen);	/* data length */
1246 		fdc->sc_state = IOCOMPLETE;
1247 
1248 		disk_busy(&fd->sc_dk);
1249 
1250 		/* allow 2 seconds for operation */
1251 		callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1252 		return 1;				/* will return later */
1253 
1254 	case DOCOPY:
1255 	docopy:
1256 		DPRINTF(("fdcintr: DOCOPY:\n"));
1257 		fdc_dmastart(fdc, B_READ, fd->sc_copybuf, 1024);
1258 		out_fdc(iot, ioh, NE7CMD_READ);		/* READ */
1259 		out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1260 		out_fdc(iot, ioh, bp->b_cylinder);	/* cylinder */
1261 		out_fdc(iot, ioh, head);
1262 		out_fdc(iot, ioh, sec + 1);		/* sector +1 */
1263 		out_fdc(iot, ioh, type->secsize);	/* sector size */
1264 		out_fdc(iot, ioh, type->sectrac);	/* sectors/track */
1265 		out_fdc(iot, ioh, type->gap1);		/* gap1 size */
1266 		out_fdc(iot, ioh, type->datalen);	/* data length */
1267 		fdc->sc_state = COPYCOMPLETE;
1268 		/* allow 2 seconds for operation */
1269 		callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1270 		return 1;				/* will return later */
1271 
1272 	case DOIOHALF:
1273 	doiohalf:
1274 		DPRINTF((" DOIOHALF:\n"));
1275 
1276 #ifdef DIAGNOSTIC
1277 		type = fd->sc_type;
1278 		sectrac = type->sectrac;
1279 		pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
1280 		sec = pos / (1 << (type->secsize - 2));
1281 		head = (fd->sc_blkno
1282 			% (type->seccyl * (1 << (type->secsize - 2))))
1283 			 / (type->sectrac * (1 << (type->secsize - 2)));
1284 		{int block;
1285 		 block = ((fd->sc_cylin * type->heads + head) * type->sectrac + sec)
1286 			 * (1 << (type->secsize - 2));
1287 		 block += (fd->sc_part == SEC_P01) ? 1 : 0;
1288 		 if (block != fd->sc_blkno) {
1289 			 printf("fdcintr: block %d != blkno %d\n", block, fd->sc_blkno);
1290 #ifdef DDB
1291 			 Debugger();
1292 #endif
1293 		 }}
1294 #endif
1295 		if ((read = bp->b_flags & B_READ)) {
1296 			bcopy(fd->sc_copybuf
1297 			      + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0),
1298 			      bp->b_data + fd->sc_skip,
1299 			      FDC_BSIZE);
1300 			fdc->sc_state = IOCOMPLETE;
1301 			goto iocomplete2;
1302 		} else {
1303 			bcopy(bp->b_data + fd->sc_skip,
1304 			      fd->sc_copybuf
1305 			      + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0),
1306 			      FDC_BSIZE);
1307 			fdc_dmastart(fdc, read, fd->sc_copybuf, 1024);
1308 		}
1309 		out_fdc(iot, ioh, NE7CMD_WRITE);	/* WRITE */
1310 		out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1311 		out_fdc(iot, ioh, bp->b_cylinder);	/* cylinder */
1312 		out_fdc(iot, ioh, head);
1313 		out_fdc(iot, ioh, sec + 1);		/* sector +1 */
1314 		out_fdc(iot, ioh, fd->sc_type->secsize); /* sector size */
1315 		out_fdc(iot, ioh, sectrac);		/* sectors/track */
1316 		out_fdc(iot, ioh, fd->sc_type->gap1);	/* gap1 size */
1317 		out_fdc(iot, ioh, fd->sc_type->datalen); /* data length */
1318 		fdc->sc_state = IOCOMPLETE;
1319 		/* allow 2 seconds for operation */
1320 		callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1321 		return 1;				/* will return later */
1322 
1323 	case SEEKWAIT:
1324 		callout_stop(&fdc->sc_timo_ch);
1325 		fdc->sc_state = SEEKCOMPLETE;
1326 		/* allow 1/50 second for heads to settle */
1327 #if 0
1328 		callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc);
1329 #endif
1330 		return 1;
1331 
1332 	case SEEKCOMPLETE:
1333 		/* Make sure seek really happened */
1334 		DPRINTF(("fdcintr: SEEKCOMPLETE: FDC status = %x\n",
1335 			 bus_space_read_1(fdc->sc_iot, fdc->sc_ioh, fdsts)));
1336 		out_fdc(iot, ioh, NE7CMD_SENSEI);
1337 		tmp = fdcresult(fdc);
1338 		if ((st0 & 0xf8) == 0xc0) {
1339 			DPRINTF(("fdcintr: first seek!\n"));
1340 			fdc->sc_state = DORECAL;
1341 			goto loop;
1342 		} else if (tmp != 2 ||
1343 			   (st0 & 0xf8) != 0x20 ||
1344 			   cyl != bp->b_cylinder) {
1345 #ifdef FDDEBUG
1346 			fdcstatus(&fd->sc_dev, 2, "seek failed");
1347 #endif
1348 			fdcretry(fdc);
1349 			goto loop;
1350 		}
1351 		fd->sc_cylin = bp->b_cylinder;
1352 		goto doio;
1353 
1354 	case IOTIMEDOUT:
1355 #if 0
1356 		isa_dmaabort(fdc->sc_drq);
1357 #endif
1358 	case SEEKTIMEDOUT:
1359 	case RECALTIMEDOUT:
1360 	case RESETTIMEDOUT:
1361 		fdcretry(fdc);
1362 		goto loop;
1363 
1364 	case IOCOMPLETE: /* IO DONE, post-analyze */
1365 		callout_stop(&fdc->sc_timo_ch);
1366 		DPRINTF(("fdcintr: in IOCOMPLETE\n"));
1367 		if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
1368 			printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0);
1369 #if 0
1370 			isa_dmaabort(fdc->sc_drq);
1371 #endif
1372 			fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
1373 				  "read failed" : "write failed");
1374 			printf("blkno %d nblks %d\n",
1375 			    fd->sc_blkno, fd->sc_nblks);
1376 			fdcretry(fdc);
1377 			goto loop;
1378 		}
1379 #if 0
1380 		isa_dmadone(bp->b_flags & B_READ, bp->b_data + fd->sc_skip,
1381 		    nblks * FDC_BSIZE, fdc->sc_drq);
1382 #endif
1383 	iocomplete2:
1384 		if (fdc->sc_errors) {
1385 			diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF,
1386 			    fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
1387 			printf("\n");
1388 			fdc->sc_errors = 0;
1389 		}
1390 		fd->sc_blkno += fd->sc_nblks;
1391 		fd->sc_skip += fd->sc_nbytes;
1392 		fd->sc_bcount -= fd->sc_nbytes;
1393 		DPRINTF(("fd->sc_bcount = %d\n", fd->sc_bcount));
1394 		if (fd->sc_bcount > 0) {
1395 			bp->b_cylinder = fd->sc_blkno
1396 				/ (fd->sc_type->seccyl
1397 				   * (1 << (fd->sc_type->secsize - 2)));
1398 			goto doseek;
1399 		}
1400 		fdfinish(fd, bp);
1401 		goto loop;
1402 
1403 	case COPYCOMPLETE: /* IO DONE, post-analyze */
1404 		DPRINTF(("fdcintr: COPYCOMPLETE:"));
1405 		callout_stop(&fdc->sc_timo_ch);
1406 		if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
1407 			printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0);
1408 #if 0
1409 			isa_dmaabort(fdc->sc_drq);
1410 #endif
1411 			fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
1412 				  "read failed" : "write failed");
1413 			printf("blkno %d nblks %d\n",
1414 			    fd->sc_blkno, fd->sc_nblks);
1415 			fdcretry(fdc);
1416 			goto loop;
1417 		}
1418 		goto doiohalf;
1419 
1420 	case DORESET:
1421 		DPRINTF(("fdcintr: in DORESET\n"));
1422 		/* try a reset, keep motor on */
1423 		fd_set_motor(fdc, 1);
1424 		DELAY(100);
1425 		fd_set_motor(fdc, 0);
1426 		fdc->sc_state = RESETCOMPLETE;
1427 		callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc);
1428 		return 1;			/* will return later */
1429 
1430 	case RESETCOMPLETE:
1431 		DPRINTF(("fdcintr: in RESETCOMPLETE\n"));
1432 		callout_stop(&fdc->sc_timo_ch);
1433 		/* clear the controller output buffer */
1434 		for (i = 0; i < 4; i++) {
1435 			out_fdc(iot, ioh, NE7CMD_SENSEI);
1436 			(void) fdcresult(fdc);
1437 		}
1438 
1439 		/* fall through */
1440 	case DORECAL:
1441 		DPRINTF(("fdcintr: in DORECAL\n"));
1442 		out_fdc(iot, ioh, NE7CMD_RECAL);	/* recalibrate function */
1443 		out_fdc(iot, ioh, fd->sc_drive);
1444 		fdc->sc_state = RECALWAIT;
1445 		callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc);
1446 		return 1;			/* will return later */
1447 
1448 	case RECALWAIT:
1449 		DPRINTF(("fdcintr: in RECALWAIT\n"));
1450 		callout_stop(&fdc->sc_timo_ch);
1451 		fdc->sc_state = RECALCOMPLETE;
1452 		/* allow 1/30 second for heads to settle */
1453 #if 0
1454 		callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc);
1455 #endif
1456 		return 1;			/* will return later */
1457 
1458 	case RECALCOMPLETE:
1459 		DPRINTF(("fdcintr: in RECALCOMPLETE\n"));
1460 		out_fdc(iot, ioh, NE7CMD_SENSEI);
1461 		tmp = fdcresult(fdc);
1462 		if ((st0 & 0xf8) == 0xc0) {
1463 			DPRINTF(("fdcintr: first seek!\n"));
1464 			fdc->sc_state = DORECAL;
1465 			goto loop;
1466 		} else if (tmp != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
1467 #ifdef FDDEBUG
1468 			fdcstatus(&fd->sc_dev, 2, "recalibrate failed");
1469 #endif
1470 			fdcretry(fdc);
1471 			goto loop;
1472 		}
1473 		fd->sc_cylin = 0;
1474 		goto doseek;
1475 
1476 	case MOTORWAIT:
1477 		if (fd->sc_flags & FD_MOTOR_WAIT)
1478 			return 1;		/* time's not up yet */
1479 		goto doseek;
1480 
1481 	default:
1482 		fdcstatus(&fd->sc_dev, 0, "stray interrupt");
1483 		return 1;
1484 	}
1485 #ifdef DIAGNOSTIC
1486 	panic("fdcintr: impossible");
1487 #endif
1488 #undef	st0
1489 #undef	cyl
1490 }
1491 
1492 void
1493 fdcretry(fdc)
1494 	struct fdc_softc *fdc;
1495 {
1496 	struct fd_softc *fd;
1497 	struct buf *bp;
1498 	char bits[64];
1499 
1500 	DPRINTF(("fdcretry:\n"));
1501 	fd = fdc->sc_drives.tqh_first;
1502 	bp = BUFQ_FIRST(&fd->sc_q);
1503 
1504 	switch (fdc->sc_errors) {
1505 	case 0:
1506 		/* try again */
1507 		fdc->sc_state = SEEKCOMPLETE;
1508 		break;
1509 
1510 	case 1: case 2: case 3:
1511 		/* didn't work; try recalibrating */
1512 		fdc->sc_state = DORECAL;
1513 		break;
1514 
1515 	case 4:
1516 		/* still no go; reset the bastard */
1517 		fdc->sc_state = DORESET;
1518 		break;
1519 
1520 	default:
1521 		diskerr(bp, "fd", "hard error", LOG_PRINTF,
1522 			fd->sc_skip, (struct disklabel *)NULL);
1523 		printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
1524 						    NE7_ST0BITS, bits,
1525 						    sizeof(bits)));
1526 		printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
1527 						   NE7_ST1BITS, bits,
1528 						   sizeof(bits)));
1529 		printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
1530 						   NE7_ST2BITS, bits,
1531 						   sizeof(bits)));
1532 		printf(" cyl %d head %d sec %d)\n",
1533 		       fdc->sc_status[3],
1534 		       fdc->sc_status[4],
1535 		       fdc->sc_status[5]);
1536 
1537 		bp->b_flags |= B_ERROR;
1538 		bp->b_error = EIO;
1539 		fdfinish(fd, bp);
1540 	}
1541 	fdc->sc_errors++;
1542 }
1543 
1544 int
1545 fdsize(dev)
1546 	dev_t dev;
1547 {
1548 
1549 	/* Swapping to floppies would not make sense. */
1550 	return -1;
1551 }
1552 
1553 int
1554 fddump(dev, blkno, va, size)
1555 	dev_t dev;
1556 	daddr_t blkno;
1557 	caddr_t va;
1558 	size_t size;
1559 {
1560 
1561 	/* Not implemented. */
1562 	return ENXIO;
1563 }
1564 
1565 int
1566 fdioctl(dev, cmd, addr, flag, p)
1567 	dev_t dev;
1568 	u_long cmd;
1569 	caddr_t addr;
1570 	int flag;
1571 	struct proc *p;
1572 {
1573 	struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
1574 	struct fdc_softc *fdc = (void*) fd->sc_dev.dv_parent;
1575 	int unit = FDUNIT(dev);
1576 	int part = DISKPART(dev);
1577 	struct disklabel buffer;
1578 	int error;
1579 
1580 	DPRINTF(("fdioctl:\n"));
1581 	switch (cmd) {
1582 	case DIOCGDINFO:
1583 #if 1
1584 		*(struct disklabel *)addr = *(fd->sc_dk.dk_label);
1585 		return(0);
1586 #else
1587 		memset(&buffer, 0, sizeof(buffer));
1588 
1589 		buffer.d_secpercyl = fd->sc_type->seccyl;
1590 		buffer.d_type = DTYPE_FLOPPY;
1591 		buffer.d_secsize = 128 << fd->sc_type->secsize;
1592 
1593 		if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL)
1594 			return EINVAL;
1595 
1596 		*(struct disklabel *)addr = buffer;
1597 		return 0;
1598 #endif
1599 
1600 	case DIOCGPART:
1601 		((struct partinfo *)addr)->disklab = fd->sc_dk.dk_label;
1602 		((struct partinfo *)addr)->part =
1603 		    &fd->sc_dk.dk_label->d_partitions[part];
1604 		return(0);
1605 
1606 	case DIOCWLABEL:
1607 		if ((flag & FWRITE) == 0)
1608 			return EBADF;
1609 		/* XXX do something */
1610 		return 0;
1611 
1612 	case DIOCWDINFO:
1613 		if ((flag & FWRITE) == 0)
1614 			return EBADF;
1615 
1616 		error = setdisklabel(&buffer, (struct disklabel *)addr, 0, NULL);
1617 		if (error)
1618 			return error;
1619 
1620 		error = writedisklabel(dev, fdstrategy, &buffer, NULL);
1621 		return error;
1622 
1623 	case DIOCLOCK:
1624 		/*
1625 		 * Nothing to do here, really.
1626 		 */
1627 		return 0; /* XXX */
1628 
1629 	case DIOCEJECT:
1630 		if (*(int *)addr == 0) {
1631 			/*
1632 			 * Don't force eject: check that we are the only
1633 			 * partition open. If so, unlock it.
1634 			 */
1635 			if ((fd->sc_dk.dk_openmask & ~(1 << part)) != 0 ||
1636 			    fd->sc_dk.dk_bopenmask + fd->sc_dk.dk_copenmask !=
1637 			    fd->sc_dk.dk_openmask) {
1638 				return (EBUSY);
1639 			}
1640 		}
1641 		/* FALLTHROUGH */
1642 	case ODIOCEJECT:
1643 		fd_do_eject(fdc, unit);
1644 		return 0;
1645 
1646 	default:
1647 		return ENOTTY;
1648 	}
1649 
1650 #ifdef DIAGNOSTIC
1651 	panic("fdioctl: impossible");
1652 #endif
1653 }
1654 
1655 void
1656 fd_do_eject(fdc, unit)
1657 	struct fdc_softc *fdc;
1658 	int unit;
1659 {
1660 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
1661 			  0x20 | ( 1 << unit));
1662 	DELAY(1); /* XXX */
1663 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0x20);
1664 }
1665 
1666 /*
1667  * Build disk label. For now we only create a label from what we know
1668  * from 'sc'.
1669  */
1670 static int
1671 fdgetdisklabel(sc, dev)
1672 	struct fd_softc *sc;
1673 	dev_t dev;
1674 {
1675 	struct disklabel *lp;
1676 	int part;
1677 
1678 	DPRINTF(("fdgetdisklabel()\n"));
1679 
1680 	part = DISKPART(dev);
1681 	lp = sc->sc_dk.dk_label;
1682 	bzero(lp, sizeof(struct disklabel));
1683 
1684 	lp->d_secsize     = 128 << sc->sc_type->secsize;
1685 	lp->d_ntracks     = sc->sc_type->heads;
1686 	lp->d_nsectors    = sc->sc_type->sectrac;
1687 	lp->d_secpercyl   = lp->d_ntracks * lp->d_nsectors;
1688 	lp->d_ncylinders  = sc->sc_type->size / lp->d_secpercyl;
1689 	lp->d_secperunit  = sc->sc_type->size;
1690 
1691 	lp->d_type        = DTYPE_FLOPPY;
1692 	lp->d_rpm         = 300; 	/* XXX */
1693 	lp->d_interleave  = 1;		/* FIXME: is this OK?		*/
1694 	lp->d_bbsize      = 0;
1695 	lp->d_sbsize      = 0;
1696 	lp->d_npartitions = part + 1;
1697 #define STEP_DELAY	6000	/* 6ms (6000us) delay after stepping	*/
1698 	lp->d_trkseek     = STEP_DELAY; /* XXX */
1699 	lp->d_magic       = DISKMAGIC;
1700 	lp->d_magic2      = DISKMAGIC;
1701 	lp->d_checksum    = dkcksum(lp);
1702 	lp->d_partitions[part].p_size   = lp->d_secperunit;
1703 	lp->d_partitions[part].p_fstype = FS_UNUSED;
1704 	lp->d_partitions[part].p_fsize  = 1024;
1705 	lp->d_partitions[part].p_frag   = 8;
1706 
1707 	return(0);
1708 }
1709 
1710 #include <dev/cons.h>
1711 
1712 /*
1713  * Mountroot hook: prompt the user to enter the root file system
1714  * floppy.
1715  */
1716 void
1717 fd_mountroot_hook(dev)
1718 	struct device *dev;
1719 {
1720 	struct fd_softc *fd = (void*) dev;
1721 	struct fdc_softc *fdc = (void*) fd->sc_dev.dv_parent;
1722 	int c;
1723 
1724 	fd_do_eject(fdc, dev->dv_unit);
1725 	printf("Insert filesystem floppy and press return.");
1726 	for (;;) {
1727 		c = cngetc();
1728 		if ((c == '\r') || (c == '\n')) {
1729 			printf("\n");
1730 			break;
1731 		}
1732 	}
1733 }
1734