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