xref: /netbsd/sys/arch/x68k/dev/fd.c (revision bf9ec67e)
1 /*	$NetBSD: fd.c,v 1.40 2001/12/27 02:23:24 wiz 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 transferring */
235 	int sc_nbytes;		/* number of bytes currently transferring */
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 
331 	dmac_start_xfer(fdc->sc_dmachan->ch_softc, fdc->sc_xfer);
332 }
333 
334 static int
335 fdcdmaintr(arg)
336 	void *arg;
337 {
338 	struct fdc_softc *fdc = arg;
339 
340 	bus_dmamap_unload(fdc->sc_dmat, fdc->sc_dmamap);
341 
342 	return 0;
343 }
344 
345 static int
346 fdcdmaerrintr(dummy)
347 	void *dummy;
348 {
349 	DPRINTF(("fdcdmaerrintr\n"));
350 
351 	return 0;
352 }
353 
354 /* ARGSUSED */
355 int
356 fdcprobe(parent, cf, aux)
357 	struct device *parent;
358 	struct cfdata *cf;
359 	void *aux;
360 {
361 	struct intio_attach_args *ia = aux;
362 
363 	if (strcmp(ia->ia_name, "fdc") != 0)
364 		return 0;
365 
366 	if (ia->ia_addr == INTIOCF_ADDR_DEFAULT)
367 		ia->ia_addr = FDC_ADDR;
368 	if (ia->ia_intr == INTIOCF_INTR_DEFAULT)
369 		ia->ia_intr = FDC_INTR;
370 	if (ia->ia_dma == INTIOCF_DMA_DEFAULT)
371 		ia->ia_dma = FDC_DMA;
372 	if (ia->ia_dmaintr == INTIOCF_DMAINTR_DEFAULT)
373 		ia->ia_dmaintr = FDC_DMAINTR;
374 
375 	if ((ia->ia_intr & 0x03) != 0)
376 		return 0;
377 
378 	ia->ia_size = 0x2000;
379 	if (intio_map_allocate_region (parent, ia, INTIO_MAP_TESTONLY))
380 		return 0;
381 
382 	/* builtin device; always there */
383 	return 1;
384 }
385 
386 /*
387  * Arguments passed between fdcattach and fdprobe.
388  */
389 struct fdc_attach_args {
390 	int fa_drive;
391 	struct fd_type *fa_deftype;
392 };
393 
394 /*
395  * Print the location of a disk drive (called just before attaching the
396  * the drive).  If `fdc' is not NULL, the drive was found but was not
397  * in the system config file; print the drive name as well.
398  * Return QUIET (config_find ignores this if the device was configured) to
399  * avoid printing `fdN not configured' messages.
400  */
401 int
402 fdprint(aux, fdc)
403 	void *aux;
404 	const char *fdc;
405 {
406 	register struct fdc_attach_args *fa = aux;
407 
408 	if (!fdc)
409 		printf(" drive %d", fa->fa_drive);
410 	return QUIET;
411 }
412 
413 void
414 fdcattach(parent, self, aux)
415 	struct device *parent, *self;
416 	void *aux;
417 {
418 	struct fdc_softc *fdc = (void *)self;
419 	bus_space_tag_t iot;
420 	bus_space_handle_t ioh;
421 	struct intio_attach_args *ia = aux;
422 	struct fdc_attach_args fa;
423 
424 	iot = ia->ia_bst;
425 
426 	printf("\n");
427 
428 	callout_init(&fdc->sc_timo_ch);
429 	callout_init(&fdc->sc_intr_ch);
430 
431 	/* Re-map the I/O space. */
432 	bus_space_map(iot, ia->ia_addr, 0x2000, BUS_SPACE_MAP_SHIFTED, &ioh);
433 
434 	fdc->sc_iot = iot;
435 	fdc->sc_ioh = ioh;
436 	fdc->sc_addr = (void*) ia->ia_addr;
437 
438 	fdc->sc_dmat = ia->ia_dmat;
439 	fdc->sc_state = DEVIDLE;
440 	TAILQ_INIT(&fdc->sc_drives);
441 
442 	/* Initialize DMAC channel */
443 	fdc->sc_dmachan = dmac_alloc_channel(parent, ia->ia_dma, "fdc",
444 					     ia->ia_dmaintr, fdcdmaintr, fdc,
445 					     ia->ia_dmaintr+1, fdcdmaerrintr,
446 					     fdc);
447 	if (bus_dmamap_create(fdc->sc_dmat, FDC_MAXIOSIZE, 1, DMAC_MAXSEGSZ,
448 			      0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW,
449 			      &fdc->sc_dmamap)) {
450 		printf("%s: can't set up intio DMA map\n",
451 		    fdc->sc_dev.dv_xname);
452 		return;
453 	}
454 
455 	if (intio_intr_establish(ia->ia_intr, "fdc", fdcintr, fdc))
456 		panic ("Could not establish interrupt (duplicated vector?).");
457 	intio_set_ivec(ia->ia_intr);
458 
459 	/* reset */
460 	intio_disable_intr(SICILIAN_INTR_FDD);
461 	intio_enable_intr(SICILIAN_INTR_FDC);
462 	fdcresult(fdc);
463 	fdcreset(fdc);
464 
465 	printf("%s: uPD72065 FDC\n", fdc->sc_dev.dv_xname);
466 	out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
467 	out_fdc(iot, ioh, 0xd0);
468 	out_fdc(iot, ioh, 0x10);
469 
470 	/* physical limit: four drives per controller. */
471 	for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) {
472 		(void)config_found(self, (void *)&fa, fdprint);
473 	}
474 
475 	intio_enable_intr(SICILIAN_INTR_FDC);
476 }
477 
478 void
479 fdcreset(fdc)
480 	struct fdc_softc *fdc;
481 {
482 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdsts, NE7CMD_RESET);
483 }
484 
485 static int
486 fdcpoll(fdc)
487 	struct fdc_softc *fdc;
488 {
489 	int i = 25000, n;
490 	while (--i > 0) {
491 		if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC)) {
492 			out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
493 			n = fdcresult(fdc);
494 			break;
495 		}
496 		DELAY(100);
497 	}
498 	return i;
499 }
500 
501 int
502 fdprobe(parent, cf, aux)
503 	struct device *parent;
504 	struct cfdata *cf;
505 	void *aux;
506 {
507 	struct fdc_softc *fdc = (void *)parent;
508 	struct fd_type *type;
509 	struct fdc_attach_args *fa = aux;
510 	int drive = fa->fa_drive;
511 	bus_space_tag_t iot = fdc->sc_iot;
512 	bus_space_handle_t ioh = fdc->sc_ioh;
513 	int n;
514 	int found = 0;
515 	int i;
516 
517 	if (cf->cf_loc[FDCCF_UNIT] != FDCCF_UNIT_DEFAULT &&
518 	    cf->cf_loc[FDCCF_UNIT] != drive)
519 		return 0;
520 
521 	type = &fd_types[0];	/* XXX 1.2MB */
522 
523 	intio_disable_intr(SICILIAN_INTR_FDC);
524 
525 	/* select drive and turn on motor */
526 	bus_space_write_1(iot, ioh, fdctl, 0x80 | (type->rate << 4)| drive);
527 	fdc_force_ready(FDCRDY);
528 	fdcpoll(fdc);
529 
530 retry:
531 	out_fdc(iot, ioh, NE7CMD_RECAL);
532 	out_fdc(iot, ioh, drive);
533 
534 	i = 25000;
535 	while (--i > 0) {
536 		if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC)) {
537 			out_fdc(iot, ioh, NE7CMD_SENSEI);
538 			n = fdcresult(fdc);
539 			break;
540 		}
541 		DELAY(100);
542 	}
543 
544 #ifdef FDDEBUG
545 	{
546 		int i;
547 		DPRINTF(("fdprobe: status"));
548 		for (i = 0; i < n; i++)
549 			DPRINTF((" %x", fdc->sc_status[i]));
550 		DPRINTF(("\n"));
551 	}
552 #endif
553 
554 	if (n == 2) {
555 		if ((fdc->sc_status[0] & 0xf0) == 0x20) {
556 			found = 1;
557 		} else if ((fdc->sc_status[0] & 0xf0) == 0xc0) {
558 			goto retry;
559 		}
560 	}
561 
562 	/* turn off motor */
563 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh,
564 			  fdctl, (type->rate << 4)| drive);
565 	fdc_force_ready(FDCSTBY);
566 	if (!found) {
567 		intio_enable_intr(SICILIAN_INTR_FDC);
568 		return 0;
569 	}
570 
571 	return 1;
572 }
573 
574 /*
575  * Controller is working, and drive responded.  Attach it.
576  */
577 void
578 fdattach(parent, self, aux)
579 	struct device *parent, *self;
580 	void *aux;
581 {
582 	struct fdc_softc *fdc = (void *)parent;
583 	struct fd_softc *fd = (void *)self;
584 	struct fdc_attach_args *fa = aux;
585 	struct fd_type *type = &fd_types[0];	/* XXX 1.2MB */
586 	int drive = fa->fa_drive;
587 
588 	callout_init(&fd->sc_motoron_ch);
589 	callout_init(&fd->sc_motoroff_ch);
590 
591 	fd->sc_flags = 0;
592 
593 	if (type)
594 		printf(": %s, %d cyl, %d head, %d sec\n", type->name,
595 		       type->cyls, type->heads, type->sectrac);
596 	else
597 		printf(": density unknown\n");
598 
599 	BUFQ_INIT(&fd->sc_q);
600 	fd->sc_cylin = -1;
601 	fd->sc_drive = drive;
602 	fd->sc_deftype = type;
603 	fdc->sc_fd[drive] = fd;
604 
605 	fd->sc_copybuf = (u_char *)malloc(NBPG, M_DEVBUF, M_WAITOK);
606 	if (fd->sc_copybuf == 0)
607 		printf("fdprobe: WARNING!! malloc() failed.\n");
608 	fd->sc_flags |= FD_ALIVE;
609 
610 	/*
611 	 * Initialize and attach the disk structure.
612 	 */
613 	fd->sc_dk.dk_name = fd->sc_dev.dv_xname;
614 	fd->sc_dk.dk_driver = &fddkdriver;
615 	disk_attach(&fd->sc_dk);
616 
617 	/*
618 	 * Establish a mountroot_hook anyway in case we booted
619 	 * with RB_ASKNAME and get selected as the boot device.
620 	 */
621 	mountroothook_establish(fd_mountroot_hook, &fd->sc_dev);
622 
623 #if NRND > 0
624 	rnd_attach_source(&fd->rnd_source, fd->sc_dev.dv_xname,
625 			  RND_TYPE_DISK, 0);
626 #endif
627 }
628 
629 __inline struct fd_type *
630 fd_dev_to_type(fd, dev)
631 	struct fd_softc *fd;
632 	dev_t dev;
633 {
634 	int type = FDTYPE(dev);
635 
636 	if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
637 		return NULL;
638 	return &fd_types[type];
639 }
640 
641 void
642 fdstrategy(bp)
643 	register struct buf *bp;	/* IO operation to perform */
644 {
645 	struct fd_softc *fd;
646 	int unit = FDUNIT(bp->b_dev);
647 	int sz;
648  	int s;
649 
650 	if (unit >= fd_cd.cd_ndevs ||
651 	    (fd = fd_cd.cd_devs[unit]) == 0 ||
652 	    bp->b_blkno < 0 ||
653 	    (bp->b_bcount % FDC_BSIZE) != 0) {
654 		DPRINTF(("fdstrategy: unit=%d, blkno=%d, bcount=%d\n", unit,
655 			 bp->b_blkno, bp->b_bcount));
656 		bp->b_error = EINVAL;
657 		goto bad;
658 	}
659 
660 	/* If it's a null transfer, return immediately. */
661 	if (bp->b_bcount == 0)
662 		goto done;
663 
664 	sz = howmany(bp->b_bcount, FDC_BSIZE);
665 
666 	if (bp->b_blkno + sz > (fd->sc_type->size << (fd->sc_type->secsize - 2))) {
667 		sz = (fd->sc_type->size << (fd->sc_type->secsize - 2)) - bp->b_blkno;
668 		if (sz == 0) {
669 			/* If exactly at end of disk, return EOF. */
670 			bp->b_resid = bp->b_bcount;
671 			goto done;
672 		}
673 		if (sz < 0) {
674 			/* If past end of disk, return EINVAL. */
675 			bp->b_error = EINVAL;
676 			goto bad;
677 		}
678 		/* Otherwise, truncate request. */
679 		bp->b_bcount = sz << DEV_BSHIFT;
680 	}
681 
682 	bp->b_rawblkno = bp->b_blkno;
683  	bp->b_cylinder = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE)
684 		/ (fd->sc_type->seccyl * (1 << (fd->sc_type->secsize - 2)));
685 
686 	DPRINTF(("fdstrategy: %s b_blkno %d b_bcount %ld cylin %ld\n",
687 		 bp->b_flags & B_READ ? "read" : "write",
688 		 bp->b_blkno, bp->b_bcount, bp->b_cylinder));
689 	/* Queue transfer on drive, activate drive and controller if idle. */
690 	s = splbio();
691 	disksort_cylinder(&fd->sc_q, bp);
692 	callout_stop(&fd->sc_motoroff_ch);		/* a good idea */
693 	if (fd->sc_active == 0)
694 		fdstart(fd);
695 #ifdef DIAGNOSTIC
696 	else {
697 		struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
698 		if (fdc->sc_state == DEVIDLE) {
699 			printf("fdstrategy: controller inactive\n");
700 			fdcstart(fdc);
701 		}
702 	}
703 #endif
704 	splx(s);
705 	return;
706 
707 bad:
708 	bp->b_flags |= B_ERROR;
709 done:
710 	/* Toss transfer; we're done early. */
711 	biodone(bp);
712 }
713 
714 void
715 fdstart(fd)
716 	struct fd_softc *fd;
717 {
718 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
719 	int active = fdc->sc_drives.tqh_first != 0;
720 
721 	/* Link into controller queue. */
722 	fd->sc_active = 1;
723 	TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
724 
725 	/* If controller not already active, start it. */
726 	if (!active)
727 		fdcstart(fdc);
728 }
729 
730 void
731 fdfinish(fd, bp)
732 	struct fd_softc *fd;
733 	struct buf *bp;
734 {
735 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
736 
737 	/*
738 	 * Move this drive to the end of the queue to give others a `fair'
739 	 * chance.  We only force a switch if N operations are completed while
740 	 * another drive is waiting to be serviced, since there is a long motor
741 	 * startup delay whenever we switch.
742 	 */
743 	if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) {
744 		fd->sc_ops = 0;
745 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
746 		if (BUFQ_NEXT(bp) != NULL) {
747 			TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
748 		} else
749 			fd->sc_active = 0;
750 	}
751 	bp->b_resid = fd->sc_bcount;
752 	fd->sc_skip = 0;
753 	BUFQ_REMOVE(&fd->sc_q, bp);
754 
755 #if NRND > 0
756 	rnd_add_uint32(&fd->rnd_source, bp->b_blkno);
757 #endif
758 
759 	biodone(bp);
760 	/* turn off motor 5s from now */
761 	callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd);
762 	fdc->sc_state = DEVIDLE;
763 }
764 
765 int
766 fdread(dev, uio, flags)
767 	dev_t dev;
768 	struct uio *uio;
769 	int flags;
770 {
771 
772 	return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
773 }
774 
775 int
776 fdwrite(dev, uio, flags)
777 	dev_t dev;
778 	struct uio *uio;
779 	int flags;
780 {
781 
782 	return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
783 }
784 
785 void
786 fd_set_motor(fdc, reset)
787 	struct fdc_softc *fdc;
788 	int reset;
789 {
790 	struct fd_softc *fd;
791 	int n;
792 
793 	DPRINTF(("fd_set_motor:\n"));
794 	for (n = 0; n < 4; n++)
795 		if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR)) {
796 			bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdctl,
797 					  0x80 | (fd->sc_type->rate << 4)| n);
798 		}
799 }
800 
801 void
802 fd_motor_off(arg)
803 	void *arg;
804 {
805 	struct fd_softc *fd = arg;
806 	struct fdc_softc *fdc = (struct fdc_softc*) fd->sc_dev.dv_parent;
807 	int s;
808 
809 	DPRINTF(("fd_motor_off:\n"));
810 
811 	s = splbio();
812 	fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
813 	bus_space_write_1 (fdc->sc_iot, fdc->sc_ioh, fdctl,
814 			   (fd->sc_type->rate << 4) | fd->sc_drive);
815 #if 0
816 	fd_set_motor(fdc, 0); /* XXX */
817 #endif
818 	splx(s);
819 }
820 
821 void
822 fd_motor_on(arg)
823 	void *arg;
824 {
825 	struct fd_softc *fd = arg;
826 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
827 	int s;
828 
829 	DPRINTF(("fd_motor_on:\n"));
830 
831 	s = splbio();
832 	fd->sc_flags &= ~FD_MOTOR_WAIT;
833 	if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT))
834 		(void) fdcintr(fdc);
835 	splx(s);
836 }
837 
838 int
839 fdcresult(fdc)
840 	struct fdc_softc *fdc;
841 {
842 	bus_space_tag_t iot = fdc->sc_iot;
843 	bus_space_handle_t ioh = fdc->sc_ioh;
844 	u_char i;
845 	int j = 100000,
846 	    n = 0;
847 
848 	for (; j; j--) {
849 		i = bus_space_read_1(iot, ioh, fdsts) &
850 		  (NE7_DIO | NE7_RQM | NE7_CB);
851 
852 		if (i == NE7_RQM)
853 			return n;
854 		if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
855 			if (n >= sizeof(fdc->sc_status)) {
856 				log(LOG_ERR, "fdcresult: overrun\n");
857 				return -1;
858 			}
859 			fdc->sc_status[n++] =
860 			  bus_space_read_1(iot, ioh, fddata);
861 		}
862 		delay(10);
863 	}
864 	log(LOG_ERR, "fdcresult: timeout\n");
865 	return -1;
866 }
867 
868 int
869 out_fdc(iot, ioh, x)
870 	bus_space_tag_t iot;
871 	bus_space_handle_t ioh;
872 	u_char x;
873 {
874 	int i = 100000;
875 
876 	while ((bus_space_read_1(iot, ioh, fdsts) & NE7_DIO) && i-- > 0);
877 	if (i <= 0)
878 		return -1;
879 	while ((bus_space_read_1(iot, ioh, fdsts) & NE7_RQM) == 0 && i-- > 0);
880 	if (i <= 0)
881 		return -1;
882 	bus_space_write_1(iot, ioh, fddata, x);
883 	return 0;
884 }
885 
886 int
887 fdopen(dev, flags, mode, p)
888 	dev_t dev;
889 	int flags, mode;
890 	struct proc *p;
891 {
892  	int unit;
893 	struct fd_softc *fd;
894 	struct fd_type *type;
895 	struct fdc_softc *fdc;
896 
897 	unit = FDUNIT(dev);
898 	if (unit >= fd_cd.cd_ndevs)
899 		return ENXIO;
900 	fd = fd_cd.cd_devs[unit];
901 	if (fd == 0)
902 		return ENXIO;
903 	type = fd_dev_to_type(fd, dev);
904 	if (type == NULL)
905 		return ENXIO;
906 
907 	if ((fd->sc_flags & FD_OPEN) != 0 &&
908 	    fd->sc_type != type)
909 		return EBUSY;
910 
911 	fdc = (void *)fd->sc_dev.dv_parent;
912 	if ((fd->sc_flags & FD_OPEN) == 0) {
913 		/* Lock eject button */
914 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
915 				  0x40 | ( 1 << unit));
916 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0x40);
917 	}
918 
919 	fd->sc_type = type;
920 	fd->sc_cylin = -1;
921 
922 	switch (mode) {
923 	case S_IFCHR:
924 		fd->sc_flags |= FD_COPEN;
925 		break;
926 	case S_IFBLK:
927 		fd->sc_flags |= FD_BOPEN;
928 		break;
929 	}
930 
931 	fdgetdisklabel(fd, dev);
932 
933 	return 0;
934 }
935 
936 int
937 fdclose(dev, flags, mode, p)
938 	dev_t dev;
939 	int flags, mode;
940 	struct proc *p;
941 {
942  	int unit = FDUNIT(dev);
943 	struct fd_softc *fd = fd_cd.cd_devs[unit];
944 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
945 
946 	DPRINTF(("fdclose %d\n", unit));
947 
948 	switch (mode) {
949 	case S_IFCHR:
950 		fd->sc_flags &= ~FD_COPEN;
951 		break;
952 	case S_IFBLK:
953 		fd->sc_flags &= ~FD_BOPEN;
954 		break;
955 	}
956 
957 	if ((fd->sc_flags & FD_OPEN) == 0) {
958 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
959 				  ( 1 << unit));
960 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0);
961 	}
962 	return 0;
963 }
964 
965 void
966 fdcstart(fdc)
967 	struct fdc_softc *fdc;
968 {
969 
970 #ifdef DIAGNOSTIC
971 	/* only got here if controller's drive queue was inactive; should
972 	   be in idle state */
973 	if (fdc->sc_state != DEVIDLE) {
974 		printf("fdcstart: not idle\n");
975 		return;
976 	}
977 #endif
978 	(void) fdcintr(fdc);
979 }
980 
981 void
982 fdcstatus(dv, n, s)
983 	struct device *dv;
984 	int n;
985 	char *s;
986 {
987 	struct fdc_softc *fdc = (void *)dv->dv_parent;
988 	char bits[64];
989 
990 	if (n == 0) {
991 		out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
992 		(void) fdcresult(fdc);
993 		n = 2;
994 	}
995 
996 	printf("%s: %s: state %d", dv->dv_xname, s, fdc->sc_state);
997 
998 	switch (n) {
999 	case 0:
1000 		printf("\n");
1001 		break;
1002 	case 2:
1003 		printf(" (st0 %s cyl %d)\n",
1004 		    bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS,
1005 		    bits, sizeof(bits)), fdc->sc_status[1]);
1006 		break;
1007 	case 7:
1008 		printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
1009 		    NE7_ST0BITS, bits, sizeof(bits)));
1010 		printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
1011 		    NE7_ST1BITS, bits, sizeof(bits)));
1012 		printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
1013 		    NE7_ST2BITS, bits, sizeof(bits)));
1014 		printf(" cyl %d head %d sec %d)\n",
1015 		    fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
1016 		break;
1017 #ifdef DIAGNOSTIC
1018 	default:
1019 		printf(" fdcstatus: weird size: %d\n", n);
1020 		break;
1021 #endif
1022 	}
1023 }
1024 
1025 void
1026 fdctimeout(arg)
1027 	void *arg;
1028 {
1029 	struct fdc_softc *fdc = arg;
1030 	struct fd_softc *fd = fdc->sc_drives.tqh_first;
1031 	int s;
1032 
1033 	s = splbio();
1034 	fdcstatus(&fd->sc_dev, 0, "timeout");
1035 
1036 	if (BUFQ_FIRST(&fd->sc_q) != NULL)
1037 		fdc->sc_state++;
1038 	else
1039 		fdc->sc_state = DEVIDLE;
1040 
1041 	(void) fdcintr(fdc);
1042 	splx(s);
1043 }
1044 
1045 #if 0
1046 void
1047 fdcpseudointr(arg)
1048 	void *arg;
1049 {
1050 	int s;
1051 	struct fdc_softc *fdc = arg;
1052 
1053 	/* just ensure it has the right spl */
1054 	s = splbio();
1055 	(void) fdcintr(fdc);
1056 	splx(s);
1057 }
1058 #endif
1059 
1060 int
1061 fdcintr(arg)
1062 	void *arg;
1063 {
1064 	struct fdc_softc *fdc = arg;
1065 #define	st0	fdc->sc_status[0]
1066 #define	cyl	fdc->sc_status[1]
1067 	struct fd_softc *fd;
1068 	struct buf *bp;
1069 	bus_space_tag_t iot = fdc->sc_iot;
1070 	bus_space_handle_t ioh = fdc->sc_ioh;
1071 	int read, head, sec, pos, i, sectrac, nblks;
1072 	int	tmp;
1073 	struct fd_type *type;
1074 
1075 loop:
1076 	fd = fdc->sc_drives.tqh_first;
1077 	if (fd == NULL) {
1078 		DPRINTF(("fdcintr: set DEVIDLE\n"));
1079 		if (fdc->sc_state == DEVIDLE) {
1080 			if (intio_get_sicilian_intr() & SICILIAN_STAT_FDC) {
1081 				out_fdc(iot, ioh, NE7CMD_SENSEI);
1082 				if ((tmp = fdcresult(fdc)) != 2 ||
1083 				    (st0 & 0xf8) != 0x20) {
1084 					goto loop;
1085 				}
1086 			}
1087 		}
1088 		/* no drives waiting; end */
1089 		fdc->sc_state = DEVIDLE;
1090  		return 1;
1091 	}
1092 
1093 	/* Is there a transfer to this drive?  If not, deactivate drive. */
1094 	bp = BUFQ_FIRST(&fd->sc_q);
1095 	if (bp == NULL) {
1096 		fd->sc_ops = 0;
1097 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
1098 		fd->sc_active = 0;
1099 		goto loop;
1100 	}
1101 
1102 	switch (fdc->sc_state) {
1103 	case DEVIDLE:
1104 		DPRINTF(("fdcintr: in DEVIDLE\n"));
1105 		fdc->sc_errors = 0;
1106 		fd->sc_skip = 0;
1107 		fd->sc_bcount = bp->b_bcount;
1108 		fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
1109 		callout_stop(&fd->sc_motoroff_ch);
1110 		if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
1111 			fdc->sc_state = MOTORWAIT;
1112 			return 1;
1113 		}
1114 		if ((fd->sc_flags & FD_MOTOR) == 0) {
1115 			/* Turn on the motor */
1116 			/* being careful about other drives. */
1117 			for (i = 0; i < 4; i++) {
1118 				struct fd_softc *ofd = fdc->sc_fd[i];
1119 				if (ofd && ofd->sc_flags & FD_MOTOR) {
1120 					callout_stop(&ofd->sc_motoroff_ch);
1121 					ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
1122 					break;
1123 				}
1124 			}
1125 			fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
1126 			fd_set_motor(fdc, 0);
1127 			fdc->sc_state = MOTORWAIT;
1128 			/* allow .5s for motor to stabilize */
1129 			callout_reset(&fd->sc_motoron_ch, hz / 2,
1130 			    fd_motor_on, fd);
1131 			return 1;
1132 		}
1133 		/* Make sure the right drive is selected. */
1134 		fd_set_motor(fdc, 0);
1135 
1136 		/* fall through */
1137 	case DOSEEK:
1138 	doseek:
1139 		DPRINTF(("fdcintr: in DOSEEK\n"));
1140 		if (fd->sc_cylin == bp->b_cylinder)
1141 			goto doio;
1142 
1143 		out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
1144 		out_fdc(iot, ioh, 0xd0);	/* XXX const */
1145 		out_fdc(iot, ioh, 0x10);
1146 
1147 		out_fdc(iot, ioh, NE7CMD_SEEK);	/* seek function */
1148 		out_fdc(iot, ioh, fd->sc_drive);	/* drive number */
1149 		out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step);
1150 
1151 		fd->sc_cylin = -1;
1152 		fdc->sc_state = SEEKWAIT;
1153 
1154 		fd->sc_dk.dk_seek++;
1155 		disk_busy(&fd->sc_dk);
1156 
1157 		callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
1158 		return 1;
1159 
1160 	case DOIO:
1161 	doio:
1162 		DPRINTF(("fdcintr: DOIO: "));
1163 		type = fd->sc_type;
1164 		sectrac = type->sectrac;
1165 		pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
1166 		sec = pos / (1 << (type->secsize - 2));
1167 		if (type->secsize == 2) {
1168 			fd->sc_part = SEC_P11;
1169 			nblks = (sectrac - sec) << (type->secsize - 2);
1170 			nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
1171 			DPRINTF(("nblks(0)"));
1172 		} else if ((fd->sc_blkno % 2) == 0) {
1173 			if (fd->sc_bcount & 0x00000200) {
1174 				if (fd->sc_bcount == FDC_BSIZE) {
1175 					fd->sc_part = SEC_P10;
1176 					nblks = 1;
1177 					DPRINTF(("nblks(1)"));
1178 				} else {
1179 					fd->sc_part = SEC_P11;
1180 					nblks = (sectrac - sec) * 2;
1181 					nblks = min(nblks, fd->sc_bcount
1182 						    / FDC_BSIZE - 1);
1183 					DPRINTF(("nblks(2)"));
1184 				}
1185 			} else {
1186 				fd->sc_part = SEC_P11;
1187 				nblks = (sectrac - sec)
1188 					<< (type->secsize - 2);
1189 				nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
1190 				DPRINTF(("nblks(3)"));
1191 			}
1192 		} else {
1193 			fd->sc_part = SEC_P01;
1194 			nblks = 1;
1195 			DPRINTF(("nblks(4)"));
1196 		}
1197 		nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
1198 		DPRINTF((" %d\n", nblks));
1199 		fd->sc_nblks = nblks;
1200 		fd->sc_nbytes = nblks * FDC_BSIZE;
1201 		head = (fd->sc_blkno
1202 			% (type->seccyl * (1 << (type->secsize - 2))))
1203 			 / (type->sectrac * (1 << (type->secsize - 2)));
1204 
1205 #ifdef DIAGNOSTIC
1206 		{int block;
1207 		 block = ((fd->sc_cylin * type->heads + head) * type->sectrac
1208 			  + sec) * (1 << (type->secsize - 2));
1209 		 block += (fd->sc_part == SEC_P01) ? 1 : 0;
1210 		 if (block != fd->sc_blkno) {
1211 			 printf("C H R N: %d %d %d %d\n", fd->sc_cylin, head, sec, type->secsize);
1212 			 printf("fdcintr: doio: block %d != blkno %d\n", block, fd->sc_blkno);
1213 #ifdef DDB
1214 			 Debugger();
1215 #endif
1216 		 }}
1217 #endif
1218 		read = bp->b_flags & B_READ;
1219 		DPRINTF(("fdcintr: %s drive %d track %d head %d sec %d nblks %d, skip %d\n",
1220 			 read ? "read" : "write", fd->sc_drive, fd->sc_cylin,
1221 			 head, sec, nblks, fd->sc_skip));
1222 		DPRINTF(("C H R N: %d %d %d %d\n", fd->sc_cylin, head, sec,
1223 			 type->secsize));
1224 
1225 		if (fd->sc_part != SEC_P11)
1226 			goto docopy;
1227 
1228 		fdc_dmastart(fdc,
1229 			     read, bp->b_data + fd->sc_skip, fd->sc_nbytes);
1230 		if (read)
1231 			out_fdc(iot, ioh, NE7CMD_READ);	/* READ */
1232 		else
1233 			out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
1234 		out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1235 		out_fdc(iot, ioh, bp->b_cylinder);	/* cylinder */
1236 		out_fdc(iot, ioh, head);
1237 		out_fdc(iot, ioh, sec + 1);		/* sector +1 */
1238 		out_fdc(iot, ioh, type->secsize);	/* sector size */
1239 		out_fdc(iot, ioh, type->sectrac);	/* sectors/track */
1240 		out_fdc(iot, ioh, type->gap1);		/* gap1 size */
1241 		out_fdc(iot, ioh, type->datalen);	/* data length */
1242 		fdc->sc_state = IOCOMPLETE;
1243 
1244 		disk_busy(&fd->sc_dk);
1245 
1246 		/* allow 2 seconds for operation */
1247 		callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1248 		return 1;				/* will return later */
1249 
1250 	case DOCOPY:
1251 	docopy:
1252 		DPRINTF(("fdcintr: DOCOPY:\n"));
1253 		fdc_dmastart(fdc, B_READ, fd->sc_copybuf, 1024);
1254 		out_fdc(iot, ioh, NE7CMD_READ);		/* READ */
1255 		out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1256 		out_fdc(iot, ioh, bp->b_cylinder);	/* cylinder */
1257 		out_fdc(iot, ioh, head);
1258 		out_fdc(iot, ioh, sec + 1);		/* sector +1 */
1259 		out_fdc(iot, ioh, type->secsize);	/* sector size */
1260 		out_fdc(iot, ioh, type->sectrac);	/* sectors/track */
1261 		out_fdc(iot, ioh, type->gap1);		/* gap1 size */
1262 		out_fdc(iot, ioh, type->datalen);	/* data length */
1263 		fdc->sc_state = COPYCOMPLETE;
1264 		/* allow 2 seconds for operation */
1265 		callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1266 		return 1;				/* will return later */
1267 
1268 	case DOIOHALF:
1269 	doiohalf:
1270 		DPRINTF((" DOIOHALF:\n"));
1271 
1272 #ifdef DIAGNOSTIC
1273 		type = fd->sc_type;
1274 		sectrac = type->sectrac;
1275 		pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
1276 		sec = pos / (1 << (type->secsize - 2));
1277 		head = (fd->sc_blkno
1278 			% (type->seccyl * (1 << (type->secsize - 2))))
1279 			 / (type->sectrac * (1 << (type->secsize - 2)));
1280 		{int block;
1281 		 block = ((fd->sc_cylin * type->heads + head) * type->sectrac + sec)
1282 			 * (1 << (type->secsize - 2));
1283 		 block += (fd->sc_part == SEC_P01) ? 1 : 0;
1284 		 if (block != fd->sc_blkno) {
1285 			 printf("fdcintr: block %d != blkno %d\n", block, fd->sc_blkno);
1286 #ifdef DDB
1287 			 Debugger();
1288 #endif
1289 		 }}
1290 #endif
1291 		if ((read = bp->b_flags & B_READ)) {
1292 			memcpy(bp->b_data + fd->sc_skip, fd->sc_copybuf
1293 			    + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0),
1294 			    FDC_BSIZE);
1295 			fdc->sc_state = IOCOMPLETE;
1296 			goto iocomplete2;
1297 		} else {
1298 			memcpy(fd->sc_copybuf
1299 			    + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0),
1300 			    bp->b_data + fd->sc_skip, FDC_BSIZE);
1301 			fdc_dmastart(fdc, read, fd->sc_copybuf, 1024);
1302 		}
1303 		out_fdc(iot, ioh, NE7CMD_WRITE);	/* WRITE */
1304 		out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1305 		out_fdc(iot, ioh, bp->b_cylinder);	/* cylinder */
1306 		out_fdc(iot, ioh, head);
1307 		out_fdc(iot, ioh, sec + 1);		/* sector +1 */
1308 		out_fdc(iot, ioh, fd->sc_type->secsize); /* sector size */
1309 		out_fdc(iot, ioh, sectrac);		/* sectors/track */
1310 		out_fdc(iot, ioh, fd->sc_type->gap1);	/* gap1 size */
1311 		out_fdc(iot, ioh, fd->sc_type->datalen); /* data length */
1312 		fdc->sc_state = IOCOMPLETE;
1313 		/* allow 2 seconds for operation */
1314 		callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1315 		return 1;				/* will return later */
1316 
1317 	case SEEKWAIT:
1318 		callout_stop(&fdc->sc_timo_ch);
1319 		fdc->sc_state = SEEKCOMPLETE;
1320 		/* allow 1/50 second for heads to settle */
1321 #if 0
1322 		callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc);
1323 #endif
1324 		return 1;
1325 
1326 	case SEEKCOMPLETE:
1327 		/* Make sure seek really happened */
1328 		DPRINTF(("fdcintr: SEEKCOMPLETE: FDC status = %x\n",
1329 			 bus_space_read_1(fdc->sc_iot, fdc->sc_ioh, fdsts)));
1330 		out_fdc(iot, ioh, NE7CMD_SENSEI);
1331 		tmp = fdcresult(fdc);
1332 		if ((st0 & 0xf8) == 0xc0) {
1333 			DPRINTF(("fdcintr: first seek!\n"));
1334 			fdc->sc_state = DORECAL;
1335 			goto loop;
1336 		} else if (tmp != 2 ||
1337 			   (st0 & 0xf8) != 0x20 ||
1338 			   cyl != bp->b_cylinder) {
1339 #ifdef FDDEBUG
1340 			fdcstatus(&fd->sc_dev, 2, "seek failed");
1341 #endif
1342 			fdcretry(fdc);
1343 			goto loop;
1344 		}
1345 		fd->sc_cylin = bp->b_cylinder;
1346 		goto doio;
1347 
1348 	case IOTIMEDOUT:
1349 #if 0
1350 		isa_dmaabort(fdc->sc_drq);
1351 #endif
1352 	case SEEKTIMEDOUT:
1353 	case RECALTIMEDOUT:
1354 	case RESETTIMEDOUT:
1355 		fdcretry(fdc);
1356 		goto loop;
1357 
1358 	case IOCOMPLETE: /* IO DONE, post-analyze */
1359 		callout_stop(&fdc->sc_timo_ch);
1360 		DPRINTF(("fdcintr: in IOCOMPLETE\n"));
1361 		if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
1362 			printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0);
1363 #if 0
1364 			isa_dmaabort(fdc->sc_drq);
1365 #endif
1366 			fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
1367 				  "read failed" : "write failed");
1368 			printf("blkno %d nblks %d\n",
1369 			    fd->sc_blkno, fd->sc_nblks);
1370 			fdcretry(fdc);
1371 			goto loop;
1372 		}
1373 #if 0
1374 		isa_dmadone(bp->b_flags & B_READ, bp->b_data + fd->sc_skip,
1375 		    nblks * FDC_BSIZE, fdc->sc_drq);
1376 #endif
1377 	iocomplete2:
1378 		if (fdc->sc_errors) {
1379 			diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF,
1380 			    fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
1381 			printf("\n");
1382 			fdc->sc_errors = 0;
1383 		}
1384 		fd->sc_blkno += fd->sc_nblks;
1385 		fd->sc_skip += fd->sc_nbytes;
1386 		fd->sc_bcount -= fd->sc_nbytes;
1387 		DPRINTF(("fd->sc_bcount = %d\n", fd->sc_bcount));
1388 		if (fd->sc_bcount > 0) {
1389 			bp->b_cylinder = fd->sc_blkno
1390 				/ (fd->sc_type->seccyl
1391 				   * (1 << (fd->sc_type->secsize - 2)));
1392 			goto doseek;
1393 		}
1394 		fdfinish(fd, bp);
1395 		goto loop;
1396 
1397 	case COPYCOMPLETE: /* IO DONE, post-analyze */
1398 		DPRINTF(("fdcintr: COPYCOMPLETE:"));
1399 		callout_stop(&fdc->sc_timo_ch);
1400 		if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
1401 			printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0);
1402 #if 0
1403 			isa_dmaabort(fdc->sc_drq);
1404 #endif
1405 			fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
1406 				  "read failed" : "write failed");
1407 			printf("blkno %d nblks %d\n",
1408 			    fd->sc_blkno, fd->sc_nblks);
1409 			fdcretry(fdc);
1410 			goto loop;
1411 		}
1412 		goto doiohalf;
1413 
1414 	case DORESET:
1415 		DPRINTF(("fdcintr: in DORESET\n"));
1416 		/* try a reset, keep motor on */
1417 		fd_set_motor(fdc, 1);
1418 		DELAY(100);
1419 		fd_set_motor(fdc, 0);
1420 		fdc->sc_state = RESETCOMPLETE;
1421 		callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc);
1422 		return 1;			/* will return later */
1423 
1424 	case RESETCOMPLETE:
1425 		DPRINTF(("fdcintr: in RESETCOMPLETE\n"));
1426 		callout_stop(&fdc->sc_timo_ch);
1427 		/* clear the controller output buffer */
1428 		for (i = 0; i < 4; i++) {
1429 			out_fdc(iot, ioh, NE7CMD_SENSEI);
1430 			(void) fdcresult(fdc);
1431 		}
1432 
1433 		/* fall through */
1434 	case DORECAL:
1435 		DPRINTF(("fdcintr: in DORECAL\n"));
1436 		out_fdc(iot, ioh, NE7CMD_RECAL);	/* recalibrate function */
1437 		out_fdc(iot, ioh, fd->sc_drive);
1438 		fdc->sc_state = RECALWAIT;
1439 		callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc);
1440 		return 1;			/* will return later */
1441 
1442 	case RECALWAIT:
1443 		DPRINTF(("fdcintr: in RECALWAIT\n"));
1444 		callout_stop(&fdc->sc_timo_ch);
1445 		fdc->sc_state = RECALCOMPLETE;
1446 		/* allow 1/30 second for heads to settle */
1447 #if 0
1448 		callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc);
1449 #endif
1450 		return 1;			/* will return later */
1451 
1452 	case RECALCOMPLETE:
1453 		DPRINTF(("fdcintr: in RECALCOMPLETE\n"));
1454 		out_fdc(iot, ioh, NE7CMD_SENSEI);
1455 		tmp = fdcresult(fdc);
1456 		if ((st0 & 0xf8) == 0xc0) {
1457 			DPRINTF(("fdcintr: first seek!\n"));
1458 			fdc->sc_state = DORECAL;
1459 			goto loop;
1460 		} else if (tmp != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
1461 #ifdef FDDEBUG
1462 			fdcstatus(&fd->sc_dev, 2, "recalibrate failed");
1463 #endif
1464 			fdcretry(fdc);
1465 			goto loop;
1466 		}
1467 		fd->sc_cylin = 0;
1468 		goto doseek;
1469 
1470 	case MOTORWAIT:
1471 		if (fd->sc_flags & FD_MOTOR_WAIT)
1472 			return 1;		/* time's not up yet */
1473 		goto doseek;
1474 
1475 	default:
1476 		fdcstatus(&fd->sc_dev, 0, "stray interrupt");
1477 		return 1;
1478 	}
1479 #ifdef DIAGNOSTIC
1480 	panic("fdcintr: impossible");
1481 #endif
1482 #undef	st0
1483 #undef	cyl
1484 }
1485 
1486 void
1487 fdcretry(fdc)
1488 	struct fdc_softc *fdc;
1489 {
1490 	struct fd_softc *fd;
1491 	struct buf *bp;
1492 	char bits[64];
1493 
1494 	DPRINTF(("fdcretry:\n"));
1495 	fd = fdc->sc_drives.tqh_first;
1496 	bp = BUFQ_FIRST(&fd->sc_q);
1497 
1498 	switch (fdc->sc_errors) {
1499 	case 0:
1500 		/* try again */
1501 		fdc->sc_state = SEEKCOMPLETE;
1502 		break;
1503 
1504 	case 1: case 2: case 3:
1505 		/* didn't work; try recalibrating */
1506 		fdc->sc_state = DORECAL;
1507 		break;
1508 
1509 	case 4:
1510 		/* still no go; reset the bastard */
1511 		fdc->sc_state = DORESET;
1512 		break;
1513 
1514 	default:
1515 		diskerr(bp, "fd", "hard error", LOG_PRINTF,
1516 			fd->sc_skip, (struct disklabel *)NULL);
1517 		printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
1518 						    NE7_ST0BITS, bits,
1519 						    sizeof(bits)));
1520 		printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
1521 						   NE7_ST1BITS, bits,
1522 						   sizeof(bits)));
1523 		printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
1524 						   NE7_ST2BITS, bits,
1525 						   sizeof(bits)));
1526 		printf(" cyl %d head %d sec %d)\n",
1527 		       fdc->sc_status[3],
1528 		       fdc->sc_status[4],
1529 		       fdc->sc_status[5]);
1530 
1531 		bp->b_flags |= B_ERROR;
1532 		bp->b_error = EIO;
1533 		fdfinish(fd, bp);
1534 	}
1535 	fdc->sc_errors++;
1536 }
1537 
1538 int
1539 fdsize(dev)
1540 	dev_t dev;
1541 {
1542 
1543 	/* Swapping to floppies would not make sense. */
1544 	return -1;
1545 }
1546 
1547 int
1548 fddump(dev, blkno, va, size)
1549 	dev_t dev;
1550 	daddr_t blkno;
1551 	caddr_t va;
1552 	size_t size;
1553 {
1554 
1555 	/* Not implemented. */
1556 	return ENXIO;
1557 }
1558 
1559 int
1560 fdioctl(dev, cmd, addr, flag, p)
1561 	dev_t dev;
1562 	u_long cmd;
1563 	caddr_t addr;
1564 	int flag;
1565 	struct proc *p;
1566 {
1567 	struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
1568 	struct fdc_softc *fdc = (void*) fd->sc_dev.dv_parent;
1569 	int unit = FDUNIT(dev);
1570 	int part = DISKPART(dev);
1571 	struct disklabel buffer;
1572 	int error;
1573 
1574 	DPRINTF(("fdioctl:\n"));
1575 	switch (cmd) {
1576 	case DIOCGDINFO:
1577 #if 1
1578 		*(struct disklabel *)addr = *(fd->sc_dk.dk_label);
1579 		return(0);
1580 #else
1581 		memset(&buffer, 0, sizeof(buffer));
1582 
1583 		buffer.d_secpercyl = fd->sc_type->seccyl;
1584 		buffer.d_type = DTYPE_FLOPPY;
1585 		buffer.d_secsize = 128 << fd->sc_type->secsize;
1586 
1587 		if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL)
1588 			return EINVAL;
1589 
1590 		*(struct disklabel *)addr = buffer;
1591 		return 0;
1592 #endif
1593 
1594 	case DIOCGPART:
1595 		((struct partinfo *)addr)->disklab = fd->sc_dk.dk_label;
1596 		((struct partinfo *)addr)->part =
1597 		    &fd->sc_dk.dk_label->d_partitions[part];
1598 		return(0);
1599 
1600 	case DIOCWLABEL:
1601 		if ((flag & FWRITE) == 0)
1602 			return EBADF;
1603 		/* XXX do something */
1604 		return 0;
1605 
1606 	case DIOCWDINFO:
1607 		if ((flag & FWRITE) == 0)
1608 			return EBADF;
1609 
1610 		error = setdisklabel(&buffer, (struct disklabel *)addr, 0, NULL);
1611 		if (error)
1612 			return error;
1613 
1614 		error = writedisklabel(dev, fdstrategy, &buffer, NULL);
1615 		return error;
1616 
1617 	case DIOCLOCK:
1618 		/*
1619 		 * Nothing to do here, really.
1620 		 */
1621 		return 0; /* XXX */
1622 
1623 	case DIOCEJECT:
1624 		if (*(int *)addr == 0) {
1625 			/*
1626 			 * Don't force eject: check that we are the only
1627 			 * partition open. If so, unlock it.
1628 			 */
1629 			if ((fd->sc_dk.dk_openmask & ~(1 << part)) != 0 ||
1630 			    fd->sc_dk.dk_bopenmask + fd->sc_dk.dk_copenmask !=
1631 			    fd->sc_dk.dk_openmask) {
1632 				return (EBUSY);
1633 			}
1634 		}
1635 		/* FALLTHROUGH */
1636 	case ODIOCEJECT:
1637 		fd_do_eject(fdc, unit);
1638 		return 0;
1639 
1640 	default:
1641 		return ENOTTY;
1642 	}
1643 
1644 #ifdef DIAGNOSTIC
1645 	panic("fdioctl: impossible");
1646 #endif
1647 }
1648 
1649 void
1650 fd_do_eject(fdc, unit)
1651 	struct fdc_softc *fdc;
1652 	int unit;
1653 {
1654 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
1655 			  0x20 | ( 1 << unit));
1656 	DELAY(1); /* XXX */
1657 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0x20);
1658 }
1659 
1660 /*
1661  * Build disk label. For now we only create a label from what we know
1662  * from 'sc'.
1663  */
1664 static int
1665 fdgetdisklabel(sc, dev)
1666 	struct fd_softc *sc;
1667 	dev_t dev;
1668 {
1669 	struct disklabel *lp;
1670 	int part;
1671 
1672 	DPRINTF(("fdgetdisklabel()\n"));
1673 
1674 	part = DISKPART(dev);
1675 	lp = sc->sc_dk.dk_label;
1676 	memset(lp, 0, sizeof(struct disklabel));
1677 
1678 	lp->d_secsize     = 128 << sc->sc_type->secsize;
1679 	lp->d_ntracks     = sc->sc_type->heads;
1680 	lp->d_nsectors    = sc->sc_type->sectrac;
1681 	lp->d_secpercyl   = lp->d_ntracks * lp->d_nsectors;
1682 	lp->d_ncylinders  = sc->sc_type->size / lp->d_secpercyl;
1683 	lp->d_secperunit  = sc->sc_type->size;
1684 
1685 	lp->d_type        = DTYPE_FLOPPY;
1686 	lp->d_rpm         = 300; 	/* XXX */
1687 	lp->d_interleave  = 1;		/* FIXME: is this OK?		*/
1688 	lp->d_bbsize      = 0;
1689 	lp->d_sbsize      = 0;
1690 	lp->d_npartitions = part + 1;
1691 #define STEP_DELAY	6000	/* 6ms (6000us) delay after stepping	*/
1692 	lp->d_trkseek     = STEP_DELAY; /* XXX */
1693 	lp->d_magic       = DISKMAGIC;
1694 	lp->d_magic2      = DISKMAGIC;
1695 	lp->d_checksum    = dkcksum(lp);
1696 	lp->d_partitions[part].p_size   = lp->d_secperunit;
1697 	lp->d_partitions[part].p_fstype = FS_UNUSED;
1698 	lp->d_partitions[part].p_fsize  = 1024;
1699 	lp->d_partitions[part].p_frag   = 8;
1700 
1701 	return(0);
1702 }
1703 
1704 #include <dev/cons.h>
1705 
1706 /*
1707  * Mountroot hook: prompt the user to enter the root file system
1708  * floppy.
1709  */
1710 void
1711 fd_mountroot_hook(dev)
1712 	struct device *dev;
1713 {
1714 	struct fd_softc *fd = (void*) dev;
1715 	struct fdc_softc *fdc = (void*) fd->sc_dev.dv_parent;
1716 	int c;
1717 
1718 	fd_do_eject(fdc, dev->dv_unit);
1719 	printf("Insert filesystem floppy and press return.");
1720 	for (;;) {
1721 		c = cngetc();
1722 		if ((c == '\r') || (c == '\n')) {
1723 			printf("\n");
1724 			break;
1725 		}
1726 	}
1727 }
1728