xref: /netbsd-src/sys/arch/x68k/dev/fd.c (revision 8b0f9554ff8762542c4defc4f70e1eb76fb508fa)
1 /*	$NetBSD: fd.c,v 1.79 2007/10/17 19:58:01 garbled 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.79 2007/10/17 19:58:01 garbled 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, void *, 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, void *addr, vsize_t count)
311 {
312 	int error;
313 
314 	DPRINTF(("fdc_dmastart: %s, addr = %p, count = %ld\n",
315 		 read ? "read" : "write", (void *) 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, 0);
424 	callout_init(&fdc->sc_intr_ch, 0);
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, 0);
576 	callout_init(&fd->sc_motoroff_ch, 0);
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 	disk_init(&fd->sc_dk, fd->sc_dev.dv_xname, &fddkdriver);
601 	disk_attach(&fd->sc_dk);
602 
603 	/*
604 	 * Establish a mountroot_hook anyway in case we booted
605 	 * with RB_ASKNAME and get selected as the boot device.
606 	 */
607 	mountroothook_establish(fd_mountroot_hook, &fd->sc_dev);
608 
609 #if NRND > 0
610 	rnd_attach_source(&fd->rnd_source, fd->sc_dev.dv_xname,
611 			  RND_TYPE_DISK, 0);
612 #endif
613 }
614 
615 inline struct fd_type *
616 fd_dev_to_type(struct fd_softc *fd, dev_t dev)
617 {
618 	int type = FDTYPE(dev);
619 
620 	if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
621 		return NULL;
622 	return &fd_types[type];
623 }
624 
625 void
626 fdstrategy(struct buf *bp)
627 {
628 	struct fd_softc *fd;
629 	int unit = FDUNIT(bp->b_dev);
630 	int sz;
631 	int s;
632 
633 	if (unit >= fd_cd.cd_ndevs ||
634 	    (fd = fd_cd.cd_devs[unit]) == 0 ||
635 	    bp->b_blkno < 0 ||
636 	    (bp->b_bcount % FDC_BSIZE) != 0) {
637 		DPRINTF(("fdstrategy: unit=%d, blkno=%" PRId64 ", "
638 			 "bcount=%d\n", unit,
639 			 bp->b_blkno, bp->b_bcount));
640 		bp->b_error = EINVAL;
641 		goto done;
642 	}
643 
644 	/* If it's a null transfer, return immediately. */
645 	if (bp->b_bcount == 0)
646 		goto done;
647 
648 	sz = howmany(bp->b_bcount, FDC_BSIZE);
649 
650 	if (bp->b_blkno + sz >
651 	    (fd->sc_type->size << (fd->sc_type->secsize - 2))) {
652 		sz = (fd->sc_type->size << (fd->sc_type->secsize - 2))
653 		     - bp->b_blkno;
654 		if (sz == 0) {
655 			/* If exactly at end of disk, return EOF. */
656 			bp->b_resid = bp->b_bcount;
657 			goto done;
658 		}
659 		if (sz < 0) {
660 			/* If past end of disk, return EINVAL. */
661 			bp->b_error = EINVAL;
662 			goto done;
663 		}
664 		/* Otherwise, truncate request. */
665 		bp->b_bcount = sz << DEV_BSHIFT;
666 	}
667 
668 	bp->b_rawblkno = bp->b_blkno;
669 	bp->b_cylinder = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE)
670 		/ (fd->sc_type->seccyl * (1 << (fd->sc_type->secsize - 2)));
671 
672 	DPRINTF(("fdstrategy: %s b_blkno %" PRId64 " b_bcount %d cylin %d\n",
673 		 bp->b_flags & B_READ ? "read" : "write",
674 		 bp->b_blkno, bp->b_bcount, bp->b_cylinder));
675 	/* Queue transfer on drive, activate drive and controller if idle. */
676 	s = splbio();
677 	BUFQ_PUT(fd->sc_q, bp);
678 	callout_stop(&fd->sc_motoroff_ch);		/* a good idea */
679 	if (fd->sc_active == 0)
680 		fdstart(fd);
681 #ifdef DIAGNOSTIC
682 	else {
683 		struct fdc_softc *fdc = (void *)device_parent(&fd->sc_dev);
684 		if (fdc->sc_state == DEVIDLE) {
685 			printf("fdstrategy: controller inactive\n");
686 			fdcstart(fdc);
687 		}
688 	}
689 #endif
690 	splx(s);
691 	return;
692 
693 done:
694 	/* Toss transfer; we're done early. */
695 	biodone(bp);
696 }
697 
698 void
699 fdstart(struct fd_softc *fd)
700 {
701 	struct fdc_softc *fdc = (void *)device_parent(&fd->sc_dev);
702 	int active = fdc->sc_drives.tqh_first != 0;
703 
704 	/* Link into controller queue. */
705 	fd->sc_active = 1;
706 	TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
707 
708 	/* If controller not already active, start it. */
709 	if (!active)
710 		fdcstart(fdc);
711 }
712 
713 void
714 fdfinish(struct fd_softc *fd, struct buf *bp)
715 {
716 	struct fdc_softc *fdc = (void *)device_parent(&fd->sc_dev);
717 
718 	/*
719 	 * Move this drive to the end of the queue to give others a `fair'
720 	 * chance.  We only force a switch if N operations are completed while
721 	 * another drive is waiting to be serviced, since there is a long motor
722 	 * startup delay whenever we switch.
723 	 */
724 	(void)BUFQ_GET(fd->sc_q);
725 	if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) {
726 		fd->sc_ops = 0;
727 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
728 		if (BUFQ_PEEK(fd->sc_q) != NULL) {
729 			TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
730 		} else
731 			fd->sc_active = 0;
732 	}
733 	bp->b_resid = fd->sc_bcount;
734 	fd->sc_skip = 0;
735 
736 #if NRND > 0
737 	rnd_add_uint32(&fd->rnd_source, bp->b_blkno);
738 #endif
739 
740 	biodone(bp);
741 	/* turn off motor 5s from now */
742 	callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd);
743 	fdc->sc_state = DEVIDLE;
744 }
745 
746 int
747 fdread(dev_t dev, struct uio *uio, int flags)
748 {
749 
750 	return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
751 }
752 
753 int
754 fdwrite(dev_t dev, struct uio *uio, int flags)
755 {
756 
757 	return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
758 }
759 
760 void
761 fd_set_motor(struct fdc_softc *fdc, int reset)
762 {
763 	struct fd_softc *fd;
764 	int n;
765 
766 	DPRINTF(("fd_set_motor:\n"));
767 	for (n = 0; n < 4; n++)
768 		if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR)) {
769 			bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdctl,
770 					  0x80 | (fd->sc_type->rate << 4)| n);
771 		}
772 }
773 
774 void
775 fd_motor_off(void *arg)
776 {
777 	struct fd_softc *fd = arg;
778 	struct fdc_softc *fdc = (struct fdc_softc*) device_parent(&fd->sc_dev);
779 	int s;
780 
781 	DPRINTF(("fd_motor_off:\n"));
782 
783 	s = splbio();
784 	fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
785 	bus_space_write_1 (fdc->sc_iot, fdc->sc_ioh, fdctl,
786 			   (fd->sc_type->rate << 4) | fd->sc_drive);
787 #if 0
788 	fd_set_motor(fdc, 0); /* XXX */
789 #endif
790 	splx(s);
791 }
792 
793 void
794 fd_motor_on(void *arg)
795 {
796 	struct fd_softc *fd = arg;
797 	struct fdc_softc *fdc = (void *)device_parent(&fd->sc_dev);
798 	int s;
799 
800 	DPRINTF(("fd_motor_on:\n"));
801 
802 	s = splbio();
803 	fd->sc_flags &= ~FD_MOTOR_WAIT;
804 	if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT))
805 		(void) fdcintr(fdc);
806 	splx(s);
807 }
808 
809 int
810 fdcresult(struct fdc_softc *fdc)
811 {
812 	bus_space_tag_t iot = fdc->sc_iot;
813 	bus_space_handle_t ioh = fdc->sc_ioh;
814 	u_char i;
815 	int j = 100000,
816 	    n = 0;
817 
818 	for (; j; j--) {
819 		i = bus_space_read_1(iot, ioh, fdsts) &
820 		  (NE7_DIO | NE7_RQM | NE7_CB);
821 
822 		if (i == NE7_RQM)
823 			return n;
824 		if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
825 			if (n >= sizeof(fdc->sc_status)) {
826 				log(LOG_ERR, "fdcresult: overrun\n");
827 				return -1;
828 			}
829 			fdc->sc_status[n++] =
830 			  bus_space_read_1(iot, ioh, fddata);
831 		}
832 		delay(10);
833 	}
834 	log(LOG_ERR, "fdcresult: timeout\n");
835 	return -1;
836 }
837 
838 int
839 out_fdc(bus_space_tag_t iot, bus_space_handle_t ioh, u_char x)
840 {
841 	int i = 100000;
842 
843 	while ((bus_space_read_1(iot, ioh, fdsts) & NE7_DIO) && i-- > 0);
844 	if (i <= 0)
845 		return -1;
846 	while ((bus_space_read_1(iot, ioh, fdsts) & NE7_RQM) == 0 && i-- > 0);
847 	if (i <= 0)
848 		return -1;
849 	bus_space_write_1(iot, ioh, fddata, x);
850 	return 0;
851 }
852 
853 int
854 fdopen(dev_t dev, int flags, int mode, struct lwp *l)
855 {
856 	int unit;
857 	struct fd_softc *fd;
858 	struct fd_type *type;
859 	struct fdc_softc *fdc;
860 
861 	unit = FDUNIT(dev);
862 	if (unit >= fd_cd.cd_ndevs)
863 		return ENXIO;
864 	fd = fd_cd.cd_devs[unit];
865 	if (fd == 0)
866 		return ENXIO;
867 	type = fd_dev_to_type(fd, dev);
868 	if (type == NULL)
869 		return ENXIO;
870 
871 	if ((fd->sc_flags & FD_OPEN) != 0 &&
872 	    fd->sc_type != type)
873 		return EBUSY;
874 
875 	fdc = (void *)device_parent(&fd->sc_dev);
876 	if ((fd->sc_flags & FD_OPEN) == 0) {
877 		/* Lock eject button */
878 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
879 				  0x40 | ( 1 << unit));
880 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0x40);
881 	}
882 
883 	fd->sc_type = type;
884 	fd->sc_cylin = -1;
885 
886 	switch (mode) {
887 	case S_IFCHR:
888 		fd->sc_flags |= FD_COPEN;
889 		break;
890 	case S_IFBLK:
891 		fd->sc_flags |= FD_BOPEN;
892 		break;
893 	}
894 
895 	fdgetdisklabel(fd, dev);
896 
897 	return 0;
898 }
899 
900 int
901 fdclose(dev_t dev, int flags, int mode, struct lwp *l)
902 {
903 	int unit = FDUNIT(dev);
904 	struct fd_softc *fd = fd_cd.cd_devs[unit];
905 	struct fdc_softc *fdc = (void *)device_parent(&fd->sc_dev);
906 
907 	DPRINTF(("fdclose %d\n", unit));
908 
909 	switch (mode) {
910 	case S_IFCHR:
911 		fd->sc_flags &= ~FD_COPEN;
912 		break;
913 	case S_IFBLK:
914 		fd->sc_flags &= ~FD_BOPEN;
915 		break;
916 	}
917 
918 	if ((fd->sc_flags & FD_OPEN) == 0) {
919 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
920 				  ( 1 << unit));
921 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0);
922 	}
923 	return 0;
924 }
925 
926 void
927 fdcstart(struct fdc_softc *fdc)
928 {
929 
930 #ifdef DIAGNOSTIC
931 	/* only got here if controller's drive queue was inactive; should
932 	   be in idle state */
933 	if (fdc->sc_state != DEVIDLE) {
934 		printf("fdcstart: not idle\n");
935 		return;
936 	}
937 #endif
938 	(void) fdcintr(fdc);
939 }
940 
941 void
942 fdcstatus(struct device *dv, int n, const char *s)
943 {
944 	struct fdc_softc *fdc = (void *)device_parent(dv);
945 	char bits[64];
946 
947 	if (n == 0) {
948 		out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
949 		(void) fdcresult(fdc);
950 		n = 2;
951 	}
952 
953 	printf("%s: %s: state %d", dv->dv_xname, s, fdc->sc_state);
954 
955 	switch (n) {
956 	case 0:
957 		printf("\n");
958 		break;
959 	case 2:
960 		printf(" (st0 %s cyl %d)\n",
961 		    bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS,
962 		    bits, sizeof(bits)), fdc->sc_status[1]);
963 		break;
964 	case 7:
965 		printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
966 		    NE7_ST0BITS, bits, sizeof(bits)));
967 		printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
968 		    NE7_ST1BITS, bits, sizeof(bits)));
969 		printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
970 		    NE7_ST2BITS, bits, sizeof(bits)));
971 		printf(" cyl %d head %d sec %d)\n",
972 		    fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
973 		break;
974 #ifdef DIAGNOSTIC
975 	default:
976 		printf(" fdcstatus: weird size: %d\n", n);
977 		break;
978 #endif
979 	}
980 }
981 
982 void
983 fdctimeout(void *arg)
984 {
985 	struct fdc_softc *fdc = arg;
986 	struct fd_softc *fd = fdc->sc_drives.tqh_first;
987 	int s;
988 
989 	s = splbio();
990 	fdcstatus(&fd->sc_dev, 0, "timeout");
991 
992 	if (BUFQ_PEEK(fd->sc_q) != NULL)
993 		fdc->sc_state++;
994 	else
995 		fdc->sc_state = DEVIDLE;
996 
997 	(void) fdcintr(fdc);
998 	splx(s);
999 }
1000 
1001 #if 0
1002 void
1003 fdcpseudointr(void *arg)
1004 {
1005 	int s;
1006 	struct fdc_softc *fdc = arg;
1007 
1008 	/* just ensure it has the right spl */
1009 	s = splbio();
1010 	(void) fdcintr(fdc);
1011 	splx(s);
1012 }
1013 #endif
1014 
1015 int
1016 fdcintr(void *arg)
1017 {
1018 	struct fdc_softc *fdc = arg;
1019 #define	st0	fdc->sc_status[0]
1020 #define	cyl	fdc->sc_status[1]
1021 	struct fd_softc *fd;
1022 	struct buf *bp;
1023 	bus_space_tag_t iot = fdc->sc_iot;
1024 	bus_space_handle_t ioh = fdc->sc_ioh;
1025 	int read, head, sec, pos, i, sectrac, nblks;
1026 	int	tmp;
1027 	struct fd_type *type;
1028 
1029 loop:
1030 	fd = fdc->sc_drives.tqh_first;
1031 	if (fd == NULL) {
1032 		DPRINTF(("fdcintr: set DEVIDLE\n"));
1033 		if (fdc->sc_state == DEVIDLE) {
1034 			if (intio_get_sicilian_intr() & SICILIAN_STAT_FDC) {
1035 				out_fdc(iot, ioh, NE7CMD_SENSEI);
1036 				if ((tmp = fdcresult(fdc)) != 2 ||
1037 				    (st0 & 0xf8) != 0x20) {
1038 					goto loop;
1039 				}
1040 			}
1041 		}
1042 		/* no drives waiting; end */
1043 		fdc->sc_state = DEVIDLE;
1044 		return 1;
1045 	}
1046 
1047 	/* Is there a transfer to this drive?  If not, deactivate drive. */
1048 	bp = BUFQ_PEEK(fd->sc_q);
1049 	if (bp == NULL) {
1050 		fd->sc_ops = 0;
1051 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
1052 		fd->sc_active = 0;
1053 		goto loop;
1054 	}
1055 
1056 	switch (fdc->sc_state) {
1057 	case DEVIDLE:
1058 		DPRINTF(("fdcintr: in DEVIDLE\n"));
1059 		fdc->sc_errors = 0;
1060 		fd->sc_skip = 0;
1061 		fd->sc_bcount = bp->b_bcount;
1062 		fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
1063 		callout_stop(&fd->sc_motoroff_ch);
1064 		if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
1065 			fdc->sc_state = MOTORWAIT;
1066 			return 1;
1067 		}
1068 		if ((fd->sc_flags & FD_MOTOR) == 0) {
1069 			/* Turn on the motor */
1070 			/* being careful about other drives. */
1071 			for (i = 0; i < 4; i++) {
1072 				struct fd_softc *ofd = fdc->sc_fd[i];
1073 				if (ofd && ofd->sc_flags & FD_MOTOR) {
1074 					callout_stop(&ofd->sc_motoroff_ch);
1075 					ofd->sc_flags &=
1076 						~(FD_MOTOR | FD_MOTOR_WAIT);
1077 					break;
1078 				}
1079 			}
1080 			fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
1081 			fd_set_motor(fdc, 0);
1082 			fdc->sc_state = MOTORWAIT;
1083 			/* allow .5s for motor to stabilize */
1084 			callout_reset(&fd->sc_motoron_ch, hz / 2,
1085 			    fd_motor_on, fd);
1086 			return 1;
1087 		}
1088 		/* Make sure the right drive is selected. */
1089 		fd_set_motor(fdc, 0);
1090 
1091 		/* fall through */
1092 	case DOSEEK:
1093 	doseek:
1094 		DPRINTF(("fdcintr: in DOSEEK\n"));
1095 		if (fd->sc_cylin == bp->b_cylinder)
1096 			goto doio;
1097 
1098 		out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
1099 		out_fdc(iot, ioh, 0xd0);	/* XXX const */
1100 		out_fdc(iot, ioh, 0x10);
1101 
1102 		out_fdc(iot, ioh, NE7CMD_SEEK);	/* seek function */
1103 		out_fdc(iot, ioh, fd->sc_drive);	/* drive number */
1104 		out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step);
1105 
1106 		fd->sc_cylin = -1;
1107 		fdc->sc_state = SEEKWAIT;
1108 
1109 		iostat_seek(fd->sc_dk.dk_stats);
1110 		disk_busy(&fd->sc_dk);
1111 
1112 		callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
1113 		return 1;
1114 
1115 	case DOIO:
1116 	doio:
1117 		DPRINTF(("fdcintr: DOIO: "));
1118 		type = fd->sc_type;
1119 		sectrac = type->sectrac;
1120 		pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
1121 		sec = pos / (1 << (type->secsize - 2));
1122 		if (type->secsize == 2) {
1123 			fd->sc_part = SEC_P11;
1124 			nblks = (sectrac - sec) << (type->secsize - 2);
1125 			nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
1126 			DPRINTF(("nblks(0)"));
1127 		} else if ((fd->sc_blkno % 2) == 0) {
1128 			if (fd->sc_bcount & 0x00000200) {
1129 				if (fd->sc_bcount == FDC_BSIZE) {
1130 					fd->sc_part = SEC_P10;
1131 					nblks = 1;
1132 					DPRINTF(("nblks(1)"));
1133 				} else {
1134 					fd->sc_part = SEC_P11;
1135 					nblks = (sectrac - sec) * 2;
1136 					nblks = min(nblks, fd->sc_bcount
1137 						    / FDC_BSIZE - 1);
1138 					DPRINTF(("nblks(2)"));
1139 				}
1140 			} else {
1141 				fd->sc_part = SEC_P11;
1142 				nblks = (sectrac - sec)
1143 					<< (type->secsize - 2);
1144 				nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
1145 				DPRINTF(("nblks(3)"));
1146 			}
1147 		} else {
1148 			fd->sc_part = SEC_P01;
1149 			nblks = 1;
1150 			DPRINTF(("nblks(4)"));
1151 		}
1152 		nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
1153 		DPRINTF((" %d\n", nblks));
1154 		fd->sc_nblks = nblks;
1155 		fd->sc_nbytes = nblks * FDC_BSIZE;
1156 		head = (fd->sc_blkno
1157 			% (type->seccyl * (1 << (type->secsize - 2))))
1158 			 / (type->sectrac * (1 << (type->secsize - 2)));
1159 
1160 #ifdef DIAGNOSTIC
1161 		{int block;
1162 		 block = ((fd->sc_cylin * type->heads + head) * type->sectrac
1163 			  + sec) * (1 << (type->secsize - 2));
1164 		 block += (fd->sc_part == SEC_P01) ? 1 : 0;
1165 		 if (block != fd->sc_blkno) {
1166 			 printf("C H R N: %d %d %d %d\n",
1167 				fd->sc_cylin, head, sec, type->secsize);
1168 			 printf("fdcintr: doio: block %d != blkno %" PRId64 "\n",
1169 				block, fd->sc_blkno);
1170 #ifdef DDB
1171 			 Debugger();
1172 #endif
1173 		 }
1174 		}
1175 #endif
1176 		read = bp->b_flags & B_READ;
1177 		DPRINTF(("fdcintr: %s drive %d track %d "
1178 		         "head %d sec %d nblks %d, skip %d\n",
1179 			 read ? "read" : "write", fd->sc_drive, fd->sc_cylin,
1180 			 head, sec, nblks, fd->sc_skip));
1181 		DPRINTF(("C H R N: %d %d %d %d\n", fd->sc_cylin, head, sec,
1182 			 type->secsize));
1183 
1184 		if (fd->sc_part != SEC_P11)
1185 			goto docopy;
1186 
1187 		fdc_dmastart(fdc, read, (char *)bp->b_data + fd->sc_skip,
1188 			     fd->sc_nbytes);
1189 		if (read)
1190 			out_fdc(iot, ioh, NE7CMD_READ);	/* READ */
1191 		else
1192 			out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
1193 		out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1194 		out_fdc(iot, ioh, bp->b_cylinder);	/* cylinder */
1195 		out_fdc(iot, ioh, head);
1196 		out_fdc(iot, ioh, sec + 1);		/* sector +1 */
1197 		out_fdc(iot, ioh, type->secsize);	/* sector size */
1198 		out_fdc(iot, ioh, type->sectrac);	/* sectors/track */
1199 		out_fdc(iot, ioh, type->gap1);		/* gap1 size */
1200 		out_fdc(iot, ioh, type->datalen);	/* data length */
1201 		fdc->sc_state = IOCOMPLETE;
1202 
1203 		disk_busy(&fd->sc_dk);
1204 
1205 		/* allow 2 seconds for operation */
1206 		callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1207 		return 1;				/* will return later */
1208 
1209 	case DOCOPY:
1210 	docopy:
1211 		DPRINTF(("fdcintr: DOCOPY:\n"));
1212 		type = fd->sc_type;
1213 		head = (fd->sc_blkno
1214 			% (type->seccyl * (1 << (type->secsize - 2))))
1215 			 / (type->sectrac * (1 << (type->secsize - 2)));
1216 		pos = fd->sc_blkno % (type->sectrac * (1 << (type->secsize - 2)));
1217 		sec = pos / (1 << (type->secsize - 2));
1218 		fdc_dmastart(fdc, B_READ, fd->sc_copybuf, 1024);
1219 		out_fdc(iot, ioh, NE7CMD_READ);		/* READ */
1220 		out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1221 		out_fdc(iot, ioh, bp->b_cylinder);	/* cylinder */
1222 		out_fdc(iot, ioh, head);
1223 		out_fdc(iot, ioh, sec + 1);		/* sector +1 */
1224 		out_fdc(iot, ioh, type->secsize);	/* sector size */
1225 		out_fdc(iot, ioh, type->sectrac);	/* sectors/track */
1226 		out_fdc(iot, ioh, type->gap1);		/* gap1 size */
1227 		out_fdc(iot, ioh, type->datalen);	/* data length */
1228 		fdc->sc_state = COPYCOMPLETE;
1229 		/* allow 2 seconds for operation */
1230 		callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1231 		return 1;				/* will return later */
1232 
1233 	case DOIOHALF:
1234 	doiohalf:
1235 		DPRINTF((" DOIOHALF:\n"));
1236 
1237 		type = fd->sc_type;
1238 		sectrac = type->sectrac;
1239 		pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
1240 		sec = pos / (1 << (type->secsize - 2));
1241 		head = (fd->sc_blkno
1242 			% (type->seccyl * (1 << (type->secsize - 2))))
1243 			 / (type->sectrac * (1 << (type->secsize - 2)));
1244 #ifdef DIAGNOSTIC
1245 		{int block;
1246 		 block = ((fd->sc_cylin * type->heads + head) *
1247 			 type->sectrac + sec)
1248 			 * (1 << (type->secsize - 2));
1249 		 block += (fd->sc_part == SEC_P01) ? 1 : 0;
1250 		 if (block != fd->sc_blkno) {
1251 			 printf("fdcintr: block %d != blkno %" PRId64 "\n",
1252 				block, fd->sc_blkno);
1253 #ifdef DDB
1254 			 Debugger();
1255 #endif
1256 		 }
1257 		}
1258 #endif
1259 		if ((read = bp->b_flags & B_READ)) {
1260 			memcpy((char *)bp->b_data + fd->sc_skip, fd->sc_copybuf
1261 			    + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0),
1262 			    FDC_BSIZE);
1263 			fdc->sc_state = IOCOMPLETE;
1264 			goto iocomplete2;
1265 		} else {
1266 			memcpy((char *)fd->sc_copybuf
1267 			    + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0),
1268 			    (char *)bp->b_data + fd->sc_skip, FDC_BSIZE);
1269 			fdc_dmastart(fdc, read, fd->sc_copybuf, 1024);
1270 		}
1271 		out_fdc(iot, ioh, NE7CMD_WRITE);	/* WRITE */
1272 		out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1273 		out_fdc(iot, ioh, bp->b_cylinder);	/* cylinder */
1274 		out_fdc(iot, ioh, head);
1275 		out_fdc(iot, ioh, sec + 1);		/* sector +1 */
1276 		out_fdc(iot, ioh, fd->sc_type->secsize); /* sector size */
1277 		out_fdc(iot, ioh, sectrac);		/* sectors/track */
1278 		out_fdc(iot, ioh, fd->sc_type->gap1);	/* gap1 size */
1279 		out_fdc(iot, ioh, fd->sc_type->datalen); /* data length */
1280 		fdc->sc_state = IOCOMPLETE;
1281 		/* allow 2 seconds for operation */
1282 		callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1283 		return 1;				/* will return later */
1284 
1285 	case SEEKWAIT:
1286 		callout_stop(&fdc->sc_timo_ch);
1287 		fdc->sc_state = SEEKCOMPLETE;
1288 		/* allow 1/50 second for heads to settle */
1289 #if 0
1290 		callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc);
1291 #endif
1292 		return 1;
1293 
1294 	case SEEKCOMPLETE:
1295 		/* Make sure seek really happened */
1296 		DPRINTF(("fdcintr: SEEKCOMPLETE: FDC status = %x\n",
1297 			 bus_space_read_1(fdc->sc_iot, fdc->sc_ioh, fdsts)));
1298 		out_fdc(iot, ioh, NE7CMD_SENSEI);
1299 		tmp = fdcresult(fdc);
1300 		if ((st0 & 0xf8) == 0xc0) {
1301 			DPRINTF(("fdcintr: first seek!\n"));
1302 			fdc->sc_state = DORECAL;
1303 			goto loop;
1304 		} else if (tmp != 2 ||
1305 			   (st0 & 0xf8) != 0x20 ||
1306 			   cyl != bp->b_cylinder) {
1307 #ifdef FDDEBUG
1308 			fdcstatus(&fd->sc_dev, 2, "seek failed");
1309 #endif
1310 			fdcretry(fdc);
1311 			goto loop;
1312 		}
1313 		fd->sc_cylin = bp->b_cylinder;
1314 		goto doio;
1315 
1316 	case IOTIMEDOUT:
1317 #if 0
1318 		isa_dmaabort(fdc->sc_drq);
1319 #endif
1320 	case SEEKTIMEDOUT:
1321 	case RECALTIMEDOUT:
1322 	case RESETTIMEDOUT:
1323 		fdcretry(fdc);
1324 		goto loop;
1325 
1326 	case IOCOMPLETE: /* IO DONE, post-analyze */
1327 		callout_stop(&fdc->sc_timo_ch);
1328 		DPRINTF(("fdcintr: in IOCOMPLETE\n"));
1329 		if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
1330 			printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0);
1331 #if 0
1332 			isa_dmaabort(fdc->sc_drq);
1333 #endif
1334 			fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
1335 				  "read failed" : "write failed");
1336 			printf("blkno %" PRId64 " nblks %d\n",
1337 			    fd->sc_blkno, fd->sc_nblks);
1338 			fdcretry(fdc);
1339 			goto loop;
1340 		}
1341 #if 0
1342 		isa_dmadone(bp->b_flags & B_READ, bp->b_data + fd->sc_skip,
1343 		    nblks * FDC_BSIZE, fdc->sc_drq);
1344 #endif
1345 	iocomplete2:
1346 		if (fdc->sc_errors) {
1347 			diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF,
1348 			    fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
1349 			printf("\n");
1350 			fdc->sc_errors = 0;
1351 		}
1352 		fd->sc_blkno += fd->sc_nblks;
1353 		fd->sc_skip += fd->sc_nbytes;
1354 		fd->sc_bcount -= fd->sc_nbytes;
1355 		DPRINTF(("fd->sc_bcount = %d\n", fd->sc_bcount));
1356 		if (fd->sc_bcount > 0) {
1357 			bp->b_cylinder = fd->sc_blkno
1358 				/ (fd->sc_type->seccyl
1359 				   * (1 << (fd->sc_type->secsize - 2)));
1360 			goto doseek;
1361 		}
1362 		fdfinish(fd, bp);
1363 		goto loop;
1364 
1365 	case COPYCOMPLETE: /* IO DONE, post-analyze */
1366 		DPRINTF(("fdcintr: COPYCOMPLETE:"));
1367 		callout_stop(&fdc->sc_timo_ch);
1368 		if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
1369 			printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0);
1370 #if 0
1371 			isa_dmaabort(fdc->sc_drq);
1372 #endif
1373 			fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
1374 				  "read failed" : "write failed");
1375 			printf("blkno %" PRId64 " nblks %d\n",
1376 			    fd->sc_blkno, fd->sc_nblks);
1377 			fdcretry(fdc);
1378 			goto loop;
1379 		}
1380 		goto doiohalf;
1381 
1382 	case DORESET:
1383 		DPRINTF(("fdcintr: in DORESET\n"));
1384 		/* try a reset, keep motor on */
1385 		fd_set_motor(fdc, 1);
1386 		DELAY(100);
1387 		fd_set_motor(fdc, 0);
1388 		fdc->sc_state = RESETCOMPLETE;
1389 		callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc);
1390 		return 1;			/* will return later */
1391 
1392 	case RESETCOMPLETE:
1393 		DPRINTF(("fdcintr: in RESETCOMPLETE\n"));
1394 		callout_stop(&fdc->sc_timo_ch);
1395 		/* clear the controller output buffer */
1396 		for (i = 0; i < 4; i++) {
1397 			out_fdc(iot, ioh, NE7CMD_SENSEI);
1398 			(void) fdcresult(fdc);
1399 		}
1400 
1401 		/* fall through */
1402 	case DORECAL:
1403 		DPRINTF(("fdcintr: in DORECAL\n"));
1404 		out_fdc(iot, ioh, NE7CMD_RECAL); /* recalibrate function */
1405 		out_fdc(iot, ioh, fd->sc_drive);
1406 		fdc->sc_state = RECALWAIT;
1407 		callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc);
1408 		return 1;			/* will return later */
1409 
1410 	case RECALWAIT:
1411 		DPRINTF(("fdcintr: in RECALWAIT\n"));
1412 		callout_stop(&fdc->sc_timo_ch);
1413 		fdc->sc_state = RECALCOMPLETE;
1414 		/* allow 1/30 second for heads to settle */
1415 #if 0
1416 		callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc);
1417 #endif
1418 		return 1;			/* will return later */
1419 
1420 	case RECALCOMPLETE:
1421 		DPRINTF(("fdcintr: in RECALCOMPLETE\n"));
1422 		out_fdc(iot, ioh, NE7CMD_SENSEI);
1423 		tmp = fdcresult(fdc);
1424 		if ((st0 & 0xf8) == 0xc0) {
1425 			DPRINTF(("fdcintr: first seek!\n"));
1426 			fdc->sc_state = DORECAL;
1427 			goto loop;
1428 		} else if (tmp != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
1429 #ifdef FDDEBUG
1430 			fdcstatus(&fd->sc_dev, 2, "recalibrate failed");
1431 #endif
1432 			fdcretry(fdc);
1433 			goto loop;
1434 		}
1435 		fd->sc_cylin = 0;
1436 		goto doseek;
1437 
1438 	case MOTORWAIT:
1439 		if (fd->sc_flags & FD_MOTOR_WAIT)
1440 			return 1;		/* time's not up yet */
1441 		goto doseek;
1442 
1443 	default:
1444 		fdcstatus(&fd->sc_dev, 0, "stray interrupt");
1445 		return 1;
1446 	}
1447 #ifdef DIAGNOSTIC
1448 	panic("fdcintr: impossible");
1449 #endif
1450 #undef	st0
1451 #undef	cyl
1452 }
1453 
1454 void
1455 fdcretry(struct fdc_softc *fdc)
1456 {
1457 	struct fd_softc *fd;
1458 	struct buf *bp;
1459 	char bits[64];
1460 
1461 	DPRINTF(("fdcretry:\n"));
1462 	fd = fdc->sc_drives.tqh_first;
1463 	bp = BUFQ_PEEK(fd->sc_q);
1464 
1465 	switch (fdc->sc_errors) {
1466 	case 0:
1467 		/* try again */
1468 		fdc->sc_state = SEEKCOMPLETE;
1469 		break;
1470 
1471 	case 1: case 2: case 3:
1472 		/* didn't work; try recalibrating */
1473 		fdc->sc_state = DORECAL;
1474 		break;
1475 
1476 	case 4:
1477 		/* still no go; reset the bastard */
1478 		fdc->sc_state = DORESET;
1479 		break;
1480 
1481 	default:
1482 		diskerr(bp, "fd", "hard error", LOG_PRINTF,
1483 			fd->sc_skip, (struct disklabel *)NULL);
1484 		printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
1485 						    NE7_ST0BITS, bits,
1486 						    sizeof(bits)));
1487 		printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
1488 						   NE7_ST1BITS, bits,
1489 						   sizeof(bits)));
1490 		printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
1491 						   NE7_ST2BITS, bits,
1492 						   sizeof(bits)));
1493 		printf(" cyl %d head %d sec %d)\n",
1494 		       fdc->sc_status[3],
1495 		       fdc->sc_status[4],
1496 		       fdc->sc_status[5]);
1497 
1498 		bp->b_error = EIO;
1499 		fdfinish(fd, bp);
1500 	}
1501 	fdc->sc_errors++;
1502 }
1503 
1504 int
1505 fdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
1506 {
1507 	struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
1508 	struct fdc_softc *fdc = (void *)device_parent(&fd->sc_dev);
1509 	int unit = FDUNIT(dev);
1510 	int part = DISKPART(dev);
1511 	struct disklabel buffer;
1512 	int error;
1513 
1514 	DPRINTF(("fdioctl:\n"));
1515 	switch (cmd) {
1516 	case DIOCGDINFO:
1517 #if 1
1518 		*(struct disklabel *)addr = *(fd->sc_dk.dk_label);
1519 		return(0);
1520 #else
1521 		memset(&buffer, 0, sizeof(buffer));
1522 
1523 		buffer.d_secpercyl = fd->sc_type->seccyl;
1524 		buffer.d_type = DTYPE_FLOPPY;
1525 		buffer.d_secsize = 128 << fd->sc_type->secsize;
1526 
1527 		if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL)
1528 			return EINVAL;
1529 
1530 		*(struct disklabel *)addr = buffer;
1531 		return 0;
1532 #endif
1533 
1534 	case DIOCGPART:
1535 		((struct partinfo *)addr)->disklab = fd->sc_dk.dk_label;
1536 		((struct partinfo *)addr)->part =
1537 		    &fd->sc_dk.dk_label->d_partitions[part];
1538 		return(0);
1539 
1540 	case DIOCWLABEL:
1541 		if ((flag & FWRITE) == 0)
1542 			return EBADF;
1543 		/* XXX do something */
1544 		return 0;
1545 
1546 	case DIOCWDINFO:
1547 		if ((flag & FWRITE) == 0)
1548 			return EBADF;
1549 
1550 		error = setdisklabel(&buffer, (struct disklabel *)addr,
1551 		                     0, NULL);
1552 		if (error)
1553 			return error;
1554 
1555 		error = writedisklabel(dev, fdstrategy, &buffer, NULL);
1556 		return error;
1557 
1558 	case DIOCLOCK:
1559 		/*
1560 		 * Nothing to do here, really.
1561 		 */
1562 		return 0; /* XXX */
1563 
1564 	case DIOCEJECT:
1565 		if (*(int *)addr == 0) {
1566 			/*
1567 			 * Don't force eject: check that we are the only
1568 			 * partition open. If so, unlock it.
1569 			 */
1570 			if ((fd->sc_dk.dk_openmask & ~(1 << part)) != 0 ||
1571 			    fd->sc_dk.dk_bopenmask + fd->sc_dk.dk_copenmask !=
1572 			    fd->sc_dk.dk_openmask) {
1573 				return (EBUSY);
1574 			}
1575 		}
1576 		/* FALLTHROUGH */
1577 	case ODIOCEJECT:
1578 		fd_do_eject(fdc, unit);
1579 		return 0;
1580 
1581 	default:
1582 		return ENOTTY;
1583 	}
1584 
1585 #ifdef DIAGNOSTIC
1586 	panic("fdioctl: impossible");
1587 #endif
1588 }
1589 
1590 void
1591 fd_do_eject(struct fdc_softc *fdc, int unit)
1592 {
1593 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
1594 			  0x20 | ( 1 << unit));
1595 	DELAY(1); /* XXX */
1596 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0x20);
1597 }
1598 
1599 /*
1600  * Build disk label. For now we only create a label from what we know
1601  * from 'sc'.
1602  */
1603 static int
1604 fdgetdisklabel(struct fd_softc *sc, dev_t dev)
1605 {
1606 	struct disklabel *lp;
1607 	int part;
1608 
1609 	DPRINTF(("fdgetdisklabel()\n"));
1610 
1611 	part = DISKPART(dev);
1612 	lp = sc->sc_dk.dk_label;
1613 	memset(lp, 0, sizeof(struct disklabel));
1614 
1615 	lp->d_secsize     = 128 << sc->sc_type->secsize;
1616 	lp->d_ntracks     = sc->sc_type->heads;
1617 	lp->d_nsectors    = sc->sc_type->sectrac;
1618 	lp->d_secpercyl   = lp->d_ntracks * lp->d_nsectors;
1619 	lp->d_ncylinders  = sc->sc_type->size / lp->d_secpercyl;
1620 	lp->d_secperunit  = sc->sc_type->size;
1621 
1622 	lp->d_type        = DTYPE_FLOPPY;
1623 	lp->d_rpm         = 300; 	/* XXX */
1624 	lp->d_interleave  = 1;		/* FIXME: is this OK?		*/
1625 	lp->d_bbsize      = 0;
1626 	lp->d_sbsize      = 0;
1627 	lp->d_npartitions = part + 1;
1628 #define STEP_DELAY	6000	/* 6ms (6000us) delay after stepping	*/
1629 	lp->d_trkseek     = STEP_DELAY; /* XXX */
1630 	lp->d_magic       = DISKMAGIC;
1631 	lp->d_magic2      = DISKMAGIC;
1632 	lp->d_checksum    = dkcksum(lp);
1633 	lp->d_partitions[part].p_size   = lp->d_secperunit;
1634 	lp->d_partitions[part].p_fstype = FS_UNUSED;
1635 	lp->d_partitions[part].p_fsize  = 1024;
1636 	lp->d_partitions[part].p_frag   = 8;
1637 
1638 	return(0);
1639 }
1640 
1641 #include <dev/cons.h>
1642 
1643 /*
1644  * Mountroot hook: prompt the user to enter the root file system
1645  * floppy.
1646  */
1647 void
1648 fd_mountroot_hook(struct device *dev)
1649 {
1650 	struct fd_softc *fd = (void *)dev;
1651 	struct fdc_softc *fdc = (void *)device_parent(&fd->sc_dev);
1652 	int c;
1653 
1654 	/* XXX device_unit() abuse */
1655 	fd_do_eject(fdc, device_unit(dev));
1656 	printf("Insert filesystem floppy and press return.");
1657 	for (;;) {
1658 		c = cngetc();
1659 		if ((c == '\r') || (c == '\n')) {
1660 			printf("\n");
1661 			break;
1662 		}
1663 	}
1664 }
1665