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