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