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