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