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