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