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