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