xref: /netbsd-src/sys/arch/x68k/dev/fd.c (revision 404fbe5fb94ca1e054339640cabb2801ce52dd30)
1 /*	$NetBSD: fd.c,v 1.90 2009/01/10 06:45:06 isaki 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.90 2009/01/10 06:45:06 isaki Exp $");
68 
69 #include "rnd.h"
70 #include "opt_ddb.h"
71 #include "opt_m680x0.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 <machine/bus.h>
98 #include <machine/cpu.h>
99 
100 #include <arch/x68k/dev/intiovar.h>
101 #include <arch/x68k/dev/dmacvar.h>
102 #include <arch/x68k/dev/fdreg.h>
103 #include <arch/x68k/dev/opmvar.h> /* for CT1 access */
104 
105 #include "locators.h"
106 
107 #ifdef FDDEBUG
108 #define DPRINTF(x)      if (fddebug) printf x
109 int     fddebug = 0;
110 #else
111 #define DPRINTF(x)
112 #endif
113 
114 #define FDUNIT(dev)	(minor(dev) / 8)
115 #define FDTYPE(dev)	(minor(dev) % 8)
116 
117 enum fdc_state {
118 	DEVIDLE = 0,
119 	MOTORWAIT,
120 	DOSEEK,
121 	SEEKWAIT,
122 	SEEKTIMEDOUT,
123 	SEEKCOMPLETE,
124 	DOIO,
125 	IOCOMPLETE,
126 	IOTIMEDOUT,
127 	DORESET,
128 	RESETCOMPLETE,
129 	RESETTIMEDOUT,
130 	DORECAL,
131 	RECALWAIT,
132 	RECALTIMEDOUT,
133 	RECALCOMPLETE,
134 	DOCOPY,
135 	DOIOHALF,
136 	COPYCOMPLETE,
137 };
138 
139 /* software state, per controller */
140 struct fdc_softc {
141 	bus_space_tag_t sc_iot;		/* intio i/o space identifier */
142 	bus_space_handle_t sc_ioh;	/* intio io handle */
143 
144 	struct callout sc_timo_ch;	/* timeout callout */
145 	struct callout sc_intr_ch;	/* pseudo-intr callout */
146 
147 	bus_dma_tag_t sc_dmat;		/* intio DMA tag */
148 	bus_dmamap_t sc_dmamap;		/* DMA map */
149 	u_int8_t *sc_addr;			/* physical address */
150 	struct dmac_channel_stat *sc_dmachan; /* intio DMA channel */
151 	struct dmac_dma_xfer *sc_xfer;	/* DMA transfer */
152 
153 	struct fd_softc *sc_fd[4];	/* pointers to children */
154 	TAILQ_HEAD(drivehead, fd_softc) sc_drives;
155 	enum fdc_state sc_state;
156 	int sc_errors;			/* number of retries so far */
157 	u_char sc_status[7];		/* copy of registers */
158 } fdc_softc;
159 
160 int fdcintr(void *);
161 void fdcreset(struct fdc_softc *);
162 
163 /* controller driver configuration */
164 int fdcprobe(device_t, cfdata_t, void *);
165 void fdcattach(device_t, device_t, void *);
166 int fdprint(void *, const char *);
167 
168 CFATTACH_DECL_NEW(fdc, sizeof(struct fdc_softc),
169     fdcprobe, fdcattach, NULL, NULL);
170 
171 extern struct cfdriver fdc_cd;
172 
173 /*
174  * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how
175  * we tell them apart.
176  */
177 struct fd_type {
178 	int	sectrac;	/* sectors per track */
179 	int	heads;		/* number of heads */
180 	int	seccyl;		/* sectors per cylinder */
181 	int	secsize;	/* size code for sectors */
182 	int	datalen;	/* data len when secsize = 0 */
183 	int	steprate;	/* step rate and head unload time */
184 	int	gap1;		/* gap len between sectors */
185 	int	gap2;		/* formatting gap */
186 	int	cyls;		/* total num of cylinders */
187 	int	size;		/* size of disk in sectors */
188 	int	step;		/* steps per cylinder */
189 	int	rate;		/* transfer speed code */
190 	const char *name;
191 };
192 
193 /* The order of entries in the following table is important -- BEWARE! */
194 struct fd_type fd_types[] = {
195         {  8,2,16,3,0xff,0xdf,0x35,0x74,77,1232,1,FDC_500KBPS, "1.2MB/[1024bytes/sector]"    }, /* 1.2 MB japanese format */
196         { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS,"1.44MB"    }, /* 1.44MB diskette */
197         { 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS, "1.2MB"    }, /* 1.2 MB AT-diskettes */
198         {  9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS, "360KB/AT" }, /* 360kB in 1.2MB drive */
199         {  9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS, "360KB/PC" }, /* 360kB PC diskettes */
200         {  9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS, "720KB"    }, /* 3.5" 720kB diskette */
201         {  9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS, "720KB/x"  }, /* 720kB in 1.2MB drive */
202         {  9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS, "360KB/x"  }, /* 360kB in 720kB drive */
203 };
204 
205 /* software state, per disk (with up to 4 disks per ctlr) */
206 struct fd_softc {
207 	device_t sc_dev;
208 	struct disk sc_dk;
209 
210 	struct fd_type *sc_deftype;	/* default type descriptor */
211 	struct fd_type *sc_type;	/* current type descriptor */
212 
213 	struct callout sc_motoron_ch;
214 	struct callout sc_motoroff_ch;
215 
216 	daddr_t	sc_blkno;	/* starting block number */
217 	int sc_bcount;		/* byte count left */
218 	int sc_opts;		/* user-set options */
219 	int sc_skip;		/* bytes already transferred */
220 	int sc_nblks;		/* number of blocks currently transferring */
221 	int sc_nbytes;		/* number of bytes currently transferring */
222 
223 	int sc_drive;		/* physical unit number */
224 	int sc_flags;
225 #define	FD_BOPEN	0x01		/* it's open */
226 #define	FD_COPEN	0x02		/* it's open */
227 #define	FD_OPEN		(FD_BOPEN|FD_COPEN)	/* it's open */
228 #define	FD_MOTOR	0x04		/* motor should be on */
229 #define	FD_MOTOR_WAIT	0x08		/* motor coming up */
230 #define	FD_ALIVE	0x10		/* alive */
231 	int sc_cylin;		/* where we think the head is */
232 
233 	TAILQ_ENTRY(fd_softc) sc_drivechain;
234 	int sc_ops;		/* I/O ops since last switch */
235 	struct bufq_state *sc_q;/* pending I/O requests */
236 	int sc_active;		/* number of active I/O operations */
237 	u_char *sc_copybuf;	/* for secsize >=3 */
238 	u_char sc_part;		/* for secsize >=3 */
239 #define	SEC_P10	0x02		/* first part */
240 #define	SEC_P01	0x01		/* second part */
241 #define	SEC_P11	0x03		/* both part */
242 
243 #if NRND > 0
244 	rndsource_element_t	rnd_source;
245 #endif
246 };
247 
248 /* floppy driver configuration */
249 int fdprobe(device_t, cfdata_t, void *);
250 void fdattach(device_t, device_t, void *);
251 
252 CFATTACH_DECL_NEW(fd, sizeof(struct fd_softc),
253     fdprobe, fdattach, NULL, NULL);
254 
255 extern struct cfdriver fd_cd;
256 
257 dev_type_open(fdopen);
258 dev_type_close(fdclose);
259 dev_type_read(fdread);
260 dev_type_write(fdwrite);
261 dev_type_ioctl(fdioctl);
262 dev_type_strategy(fdstrategy);
263 
264 const struct bdevsw fd_bdevsw = {
265 	fdopen, fdclose, fdstrategy, fdioctl, nodump, nosize, D_DISK
266 };
267 
268 const struct cdevsw fd_cdevsw = {
269 	fdopen, fdclose, fdread, fdwrite, fdioctl,
270 	nostop, notty, nopoll, nommap, nokqfilter, D_DISK
271 };
272 
273 void fdstart(struct fd_softc *);
274 
275 struct dkdriver fddkdriver = { fdstrategy };
276 
277 void fd_set_motor(struct fdc_softc *, int);
278 void fd_motor_off(void *);
279 void fd_motor_on(void *);
280 int fdcresult(struct fdc_softc *);
281 int out_fdc(bus_space_tag_t, bus_space_handle_t, u_char);
282 void fdcstart(struct fdc_softc *);
283 void fdcstatus(device_t, int, const char *);
284 void fdctimeout(void *);
285 void fdcpseudointr(void *);
286 void fdcretry(struct fdc_softc *);
287 void fdfinish(struct fd_softc *, struct buf *);
288 inline struct fd_type *fd_dev_to_type(struct fd_softc *, dev_t);
289 static int fdcpoll(struct fdc_softc *);
290 static int fdgetdisklabel(struct fd_softc *, dev_t);
291 static void fd_do_eject(struct fdc_softc *, int);
292 
293 void fd_mountroot_hook(device_t);
294 
295 /* DMA transfer routines */
296 inline static void fdc_dmastart(struct fdc_softc *, int, void *, vsize_t);
297 static int fdcdmaintr(void *);
298 static int fdcdmaerrintr(void *);
299 
300 inline static void
301 fdc_dmastart(struct fdc_softc *fdc, int read, void *addr, vsize_t count)
302 {
303 	int error;
304 
305 	DPRINTF(("fdc_dmastart: %s, addr = %p, count = %ld\n",
306 		 read ? "read" : "write", (void *) addr, count));
307 
308 	error = bus_dmamap_load(fdc->sc_dmat, fdc->sc_dmamap, addr, count,
309 				0, BUS_DMA_NOWAIT);
310 	if (error) {
311 		panic ("fdc_dmastart: cannot load dmamap");
312 	}
313 
314 	bus_dmamap_sync(fdc->sc_dmat, fdc->sc_dmamap, 0, count,
315 			read?BUS_DMASYNC_PREREAD:BUS_DMASYNC_PREWRITE);
316 
317 	fdc->sc_xfer = dmac_prepare_xfer(fdc->sc_dmachan, fdc->sc_dmat,
318 					 fdc->sc_dmamap,
319 					 (read?
320 					  DMAC_OCR_DIR_DTM:DMAC_OCR_DIR_MTD),
321 					 (DMAC_SCR_MAC_COUNT_UP|
322 					  DMAC_SCR_DAC_NO_COUNT),
323 					 (u_int8_t*) (fdc->sc_addr +
324 						      fddata));	/* XXX */
325 
326 	dmac_start_xfer(fdc->sc_dmachan->ch_softc, fdc->sc_xfer);
327 }
328 
329 static int
330 fdcdmaintr(void *arg)
331 {
332 	struct fdc_softc *fdc = arg;
333 
334 	bus_dmamap_unload(fdc->sc_dmat, fdc->sc_dmamap);
335 
336 	return 0;
337 }
338 
339 static int
340 fdcdmaerrintr(void *dummy)
341 {
342 	DPRINTF(("fdcdmaerrintr\n"));
343 
344 	return 0;
345 }
346 
347 /* ARGSUSED */
348 int
349 fdcprobe(device_t parent, cfdata_t cf, void *aux)
350 {
351 	struct intio_attach_args *ia = aux;
352 
353 	if (strcmp(ia->ia_name, "fdc") != 0)
354 		return 0;
355 
356 	if (ia->ia_addr == INTIOCF_ADDR_DEFAULT)
357 		ia->ia_addr = FDC_ADDR;
358 	if (ia->ia_intr == INTIOCF_INTR_DEFAULT)
359 		ia->ia_intr = FDC_INTR;
360 	if (ia->ia_dma == INTIOCF_DMA_DEFAULT)
361 		ia->ia_dma = FDC_DMA;
362 	if (ia->ia_dmaintr == INTIOCF_DMAINTR_DEFAULT)
363 		ia->ia_dmaintr = FDC_DMAINTR;
364 
365 	if ((ia->ia_intr & 0x03) != 0)
366 		return 0;
367 
368 	ia->ia_size = 0x2000;
369 	if (intio_map_allocate_region (parent, ia, INTIO_MAP_TESTONLY))
370 		return 0;
371 
372 	/* builtin device; always there */
373 	return 1;
374 }
375 
376 /*
377  * Arguments passed between fdcattach and fdprobe.
378  */
379 struct fdc_attach_args {
380 	int fa_drive;
381 	struct fd_type *fa_deftype;
382 };
383 
384 /*
385  * Print the location of a disk drive (called just before attaching the
386  * the drive).  If `fdc' is not NULL, the drive was found but was not
387  * in the system config file; print the drive name as well.
388  * Return QUIET (config_find ignores this if the device was configured) to
389  * avoid printing `fdN not configured' messages.
390  */
391 int
392 fdprint(void *aux, const char *fdc)
393 {
394 	struct fdc_attach_args *fa = aux;
395 
396 	if (!fdc)
397 		aprint_normal(" drive %d", fa->fa_drive);
398 	return QUIET;
399 }
400 
401 void
402 fdcattach(device_t parent, device_t self, void *aux)
403 {
404 	struct fdc_softc *fdc = device_private(self);
405 	bus_space_tag_t iot;
406 	bus_space_handle_t ioh;
407 	struct intio_attach_args *ia = aux;
408 	struct fdc_attach_args fa;
409 
410 	iot = ia->ia_bst;
411 
412 	aprint_normal("\n");
413 
414 	callout_init(&fdc->sc_timo_ch, 0);
415 	callout_init(&fdc->sc_intr_ch, 0);
416 
417 	/* Re-map the I/O space. */
418 	bus_space_map(iot, ia->ia_addr, 0x2000, BUS_SPACE_MAP_SHIFTED, &ioh);
419 
420 	fdc->sc_iot = iot;
421 	fdc->sc_ioh = ioh;
422 	fdc->sc_addr = (void *)ia->ia_addr;
423 
424 	fdc->sc_dmat = ia->ia_dmat;
425 	fdc->sc_state = DEVIDLE;
426 	TAILQ_INIT(&fdc->sc_drives);
427 
428 	/* Initialize DMAC channel */
429 	fdc->sc_dmachan = dmac_alloc_channel(parent, ia->ia_dma, "fdc",
430 					     ia->ia_dmaintr, fdcdmaintr, fdc,
431 					     ia->ia_dmaintr+1, fdcdmaerrintr,
432 					     fdc);
433 	if (bus_dmamap_create(fdc->sc_dmat, FDC_MAXIOSIZE, 1, DMAC_MAXSEGSZ,
434 			      0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW,
435 			      &fdc->sc_dmamap)) {
436 		aprint_error_dev(self, "can't set up intio DMA map\n");
437 		return;
438 	}
439 
440 	if (intio_intr_establish(ia->ia_intr, "fdc", fdcintr, fdc))
441 		panic ("Could not establish interrupt (duplicated vector?).");
442 	intio_set_ivec(ia->ia_intr);
443 
444 	/* reset */
445 	intio_disable_intr(SICILIAN_INTR_FDD);
446 	intio_enable_intr(SICILIAN_INTR_FDC);
447 	fdcresult(fdc);
448 	fdcreset(fdc);
449 
450 	aprint_normal_dev(self, "uPD72065 FDC\n");
451 	out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
452 	out_fdc(iot, ioh, 0xd0);
453 	out_fdc(iot, ioh, 0x10);
454 
455 	/* physical limit: four drives per controller. */
456 	for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) {
457 		(void)config_found(self, (void *)&fa, fdprint);
458 	}
459 
460 	intio_enable_intr(SICILIAN_INTR_FDC);
461 }
462 
463 void
464 fdcreset(struct fdc_softc *fdc)
465 {
466 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdsts, NE7CMD_RESET);
467 }
468 
469 static int
470 fdcpoll(struct fdc_softc *fdc)
471 {
472 	int i = 25000, n;
473 	while (--i > 0) {
474 		if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC)) {
475 			out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
476 			n = fdcresult(fdc);
477 			break;
478 		}
479 		DELAY(100);
480 	}
481 	return i;
482 }
483 
484 int
485 fdprobe(device_t parent, cfdata_t cf, void *aux)
486 {
487 	struct fdc_softc *fdc = device_private(parent);
488 	struct fd_type *type;
489 	struct fdc_attach_args *fa = aux;
490 	int drive = fa->fa_drive;
491 	bus_space_tag_t iot = fdc->sc_iot;
492 	bus_space_handle_t ioh = fdc->sc_ioh;
493 	int n = 0;
494 	int found = 0;
495 	int i;
496 
497 	if (cf->cf_loc[FDCCF_UNIT] != FDCCF_UNIT_DEFAULT &&
498 	    cf->cf_loc[FDCCF_UNIT] != drive)
499 		return 0;
500 
501 	type = &fd_types[0];	/* XXX 1.2MB */
502 
503 	intio_disable_intr(SICILIAN_INTR_FDC);
504 
505 	/* select drive and turn on motor */
506 	bus_space_write_1(iot, ioh, fdctl, 0x80 | (type->rate << 4)| drive);
507 	fdc_force_ready(FDCRDY);
508 	fdcpoll(fdc);
509 
510 retry:
511 	out_fdc(iot, ioh, NE7CMD_RECAL);
512 	out_fdc(iot, ioh, drive);
513 
514 	i = 25000;
515 	while (--i > 0) {
516 		if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC)) {
517 			out_fdc(iot, ioh, NE7CMD_SENSEI);
518 			n = fdcresult(fdc);
519 			break;
520 		}
521 		DELAY(100);
522 	}
523 
524 #ifdef FDDEBUG
525 	{
526 		int _i;
527 		DPRINTF(("fdprobe: status"));
528 		for (_i = 0; _i < n; _i++)
529 			DPRINTF((" %x", fdc->sc_status[_i]));
530 		DPRINTF(("\n"));
531 	}
532 #endif
533 
534 	if (n == 2) {
535 		if ((fdc->sc_status[0] & 0xf0) == 0x20)
536 			found = 1;
537 		else if ((fdc->sc_status[0] & 0xf0) == 0xc0)
538 			goto retry;
539 	}
540 
541 	/* turn off motor */
542 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh,
543 			  fdctl, (type->rate << 4)| drive);
544 	fdc_force_ready(FDCSTBY);
545 	if (!found) {
546 		intio_enable_intr(SICILIAN_INTR_FDC);
547 		return 0;
548 	}
549 
550 	return 1;
551 }
552 
553 /*
554  * Controller is working, and drive responded.  Attach it.
555  */
556 void
557 fdattach(device_t parent, device_t self, void *aux)
558 {
559 	struct fdc_softc *fdc = device_private(parent);
560 	struct fd_softc *fd = device_private(self);
561 	struct fdc_attach_args *fa = aux;
562 	struct fd_type *type = &fd_types[0];	/* XXX 1.2MB */
563 	int drive = fa->fa_drive;
564 
565 	callout_init(&fd->sc_motoron_ch, 0);
566 	callout_init(&fd->sc_motoroff_ch, 0);
567 
568 	fd->sc_dev = self;
569 	fd->sc_flags = 0;
570 
571 	if (type)
572 		aprint_normal(": %s, %d cyl, %d head, %d sec\n", type->name,
573 		       type->cyls, type->heads, type->sectrac);
574 	else
575 		aprint_normal(": density unknown\n");
576 
577 	bufq_alloc(&fd->sc_q, "disksort", BUFQ_SORT_CYLINDER);
578 	fd->sc_cylin = -1;
579 	fd->sc_drive = drive;
580 	fd->sc_deftype = type;
581 	fdc->sc_fd[drive] = fd;
582 
583 	fd->sc_copybuf = (u_char *)malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK);
584 	if (fd->sc_copybuf == 0)
585 		aprint_error("%s: WARNING!! malloc() failed.\n", __func__);
586 	fd->sc_flags |= FD_ALIVE;
587 
588 	/*
589 	 * Initialize and attach the disk structure.
590 	 */
591 	disk_init(&fd->sc_dk, device_xname(fd->sc_dev), &fddkdriver);
592 	disk_attach(&fd->sc_dk);
593 
594 	/*
595 	 * Establish a mountroot_hook anyway in case we booted
596 	 * with RB_ASKNAME and get selected as the boot device.
597 	 */
598 	mountroothook_establish(fd_mountroot_hook, fd->sc_dev);
599 
600 #if NRND > 0
601 	rnd_attach_source(&fd->rnd_source, device_xname(fd->sc_dev),
602 			  RND_TYPE_DISK, 0);
603 #endif
604 }
605 
606 inline struct fd_type *
607 fd_dev_to_type(struct fd_softc *fd, dev_t dev)
608 {
609 	int type = FDTYPE(dev);
610 
611 	if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
612 		return NULL;
613 	return &fd_types[type];
614 }
615 
616 void
617 fdstrategy(struct buf *bp)
618 {
619 	struct fd_softc *fd;
620 	int unit;
621 	int sz;
622 	int s;
623 
624 	unit = FDUNIT(bp->b_dev);
625 	fd = device_lookup_private(&fd_cd, unit);
626 	if (fd == NULL) {
627 		bp->b_error = EINVAL;
628 		goto done;
629 	}
630 
631 	if (bp->b_blkno < 0 ||
632 	    (bp->b_bcount % FDC_BSIZE) != 0) {
633 		DPRINTF(("fdstrategy: unit=%d, blkno=%" PRId64 ", "
634 			 "bcount=%d\n", unit,
635 			 bp->b_blkno, bp->b_bcount));
636 		bp->b_error = EINVAL;
637 		goto done;
638 	}
639 
640 	/* If it's a null transfer, return immediately. */
641 	if (bp->b_bcount == 0)
642 		goto done;
643 
644 	sz = howmany(bp->b_bcount, FDC_BSIZE);
645 
646 	if (bp->b_blkno + sz >
647 	    (fd->sc_type->size << (fd->sc_type->secsize - 2))) {
648 		sz = (fd->sc_type->size << (fd->sc_type->secsize - 2))
649 		     - bp->b_blkno;
650 		if (sz == 0) {
651 			/* If exactly at end of disk, return EOF. */
652 			bp->b_resid = bp->b_bcount;
653 			goto done;
654 		}
655 		if (sz < 0) {
656 			/* If past end of disk, return EINVAL. */
657 			bp->b_error = EINVAL;
658 			goto done;
659 		}
660 		/* Otherwise, truncate request. */
661 		bp->b_bcount = sz << DEV_BSHIFT;
662 	}
663 
664 	bp->b_rawblkno = bp->b_blkno;
665 	bp->b_cylinder = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE)
666 		/ (fd->sc_type->seccyl * (1 << (fd->sc_type->secsize - 2)));
667 
668 	DPRINTF(("fdstrategy: %s b_blkno %" PRId64 " b_bcount %d cylin %d\n",
669 		 bp->b_flags & B_READ ? "read" : "write",
670 		 bp->b_blkno, bp->b_bcount, bp->b_cylinder));
671 	/* Queue transfer on drive, activate drive and controller if idle. */
672 	s = splbio();
673 	BUFQ_PUT(fd->sc_q, bp);
674 	callout_stop(&fd->sc_motoroff_ch);		/* a good idea */
675 	if (fd->sc_active == 0)
676 		fdstart(fd);
677 #ifdef DIAGNOSTIC
678 	else {
679 		struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
680 		if (fdc->sc_state == DEVIDLE) {
681 			printf("fdstrategy: controller inactive\n");
682 			fdcstart(fdc);
683 		}
684 	}
685 #endif
686 	splx(s);
687 	return;
688 
689 done:
690 	/* Toss transfer; we're done early. */
691 	biodone(bp);
692 }
693 
694 void
695 fdstart(struct fd_softc *fd)
696 {
697 	struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
698 	int active = !TAILQ_EMPTY(&fdc->sc_drives);
699 
700 	/* Link into controller queue. */
701 	fd->sc_active = 1;
702 	TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
703 
704 	/* If controller not already active, start it. */
705 	if (!active)
706 		fdcstart(fdc);
707 }
708 
709 void
710 fdfinish(struct fd_softc *fd, struct buf *bp)
711 {
712 	struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
713 
714 	/*
715 	 * Move this drive to the end of the queue to give others a `fair'
716 	 * chance.  We only force a switch if N operations are completed while
717 	 * another drive is waiting to be serviced, since there is a long motor
718 	 * startup delay whenever we switch.
719 	 */
720 	(void)BUFQ_GET(fd->sc_q);
721 	if (TAILQ_NEXT(fd, sc_drivechain) && ++fd->sc_ops >= 8) {
722 		fd->sc_ops = 0;
723 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
724 		if (BUFQ_PEEK(fd->sc_q) != NULL) {
725 			TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
726 		} else
727 			fd->sc_active = 0;
728 	}
729 	bp->b_resid = fd->sc_bcount;
730 	fd->sc_skip = 0;
731 
732 #if NRND > 0
733 	rnd_add_uint32(&fd->rnd_source, bp->b_blkno);
734 #endif
735 
736 	biodone(bp);
737 	/* turn off motor 5s from now */
738 	callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd);
739 	fdc->sc_state = DEVIDLE;
740 }
741 
742 int
743 fdread(dev_t dev, struct uio *uio, int flags)
744 {
745 
746 	return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
747 }
748 
749 int
750 fdwrite(dev_t dev, struct uio *uio, int flags)
751 {
752 
753 	return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
754 }
755 
756 void
757 fd_set_motor(struct fdc_softc *fdc, int reset)
758 {
759 	struct fd_softc *fd;
760 	int n;
761 
762 	DPRINTF(("fd_set_motor:\n"));
763 	for (n = 0; n < 4; n++)
764 		if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR)) {
765 			bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdctl,
766 					  0x80 | (fd->sc_type->rate << 4)| n);
767 		}
768 }
769 
770 void
771 fd_motor_off(void *arg)
772 {
773 	struct fd_softc *fd = arg;
774  	struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
775 	int s;
776 
777 	DPRINTF(("fd_motor_off:\n"));
778 
779 	s = splbio();
780 	fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
781 	bus_space_write_1 (fdc->sc_iot, fdc->sc_ioh, fdctl,
782 			   (fd->sc_type->rate << 4) | fd->sc_drive);
783 #if 0
784 	fd_set_motor(fdc, 0); /* XXX */
785 #endif
786 	splx(s);
787 }
788 
789 void
790 fd_motor_on(void *arg)
791 {
792 	struct fd_softc *fd = arg;
793 	struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
794 	int s;
795 
796 	DPRINTF(("fd_motor_on:\n"));
797 
798 	s = splbio();
799 	fd->sc_flags &= ~FD_MOTOR_WAIT;
800 	if ((TAILQ_FIRST(&fdc->sc_drives) == fd) && (fdc->sc_state == MOTORWAIT))
801 		(void) fdcintr(fdc);
802 	splx(s);
803 }
804 
805 int
806 fdcresult(struct fdc_softc *fdc)
807 {
808 	bus_space_tag_t iot = fdc->sc_iot;
809 	bus_space_handle_t ioh = fdc->sc_ioh;
810 	u_char i;
811 	int j = 100000,
812 	    n = 0;
813 
814 	for (; j; j--) {
815 		i = bus_space_read_1(iot, ioh, fdsts) &
816 		  (NE7_DIO | NE7_RQM | NE7_CB);
817 
818 		if (i == NE7_RQM)
819 			return n;
820 		if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
821 			if (n >= sizeof(fdc->sc_status)) {
822 				log(LOG_ERR, "fdcresult: overrun\n");
823 				return -1;
824 			}
825 			fdc->sc_status[n++] =
826 			  bus_space_read_1(iot, ioh, fddata);
827 		}
828 		delay(10);
829 	}
830 	log(LOG_ERR, "fdcresult: timeout\n");
831 	return -1;
832 }
833 
834 int
835 out_fdc(bus_space_tag_t iot, bus_space_handle_t ioh, u_char x)
836 {
837 	int i = 100000;
838 
839 	while ((bus_space_read_1(iot, ioh, fdsts) & NE7_DIO) && i-- > 0);
840 	if (i <= 0)
841 		return -1;
842 	while ((bus_space_read_1(iot, ioh, fdsts) & NE7_RQM) == 0 && i-- > 0);
843 	if (i <= 0)
844 		return -1;
845 	bus_space_write_1(iot, ioh, fddata, x);
846 	return 0;
847 }
848 
849 int
850 fdopen(dev_t dev, int flags, int mode, struct lwp *l)
851 {
852 	int unit;
853 	struct fd_softc *fd;
854 	struct fd_type *type;
855 	struct fdc_softc *fdc;
856 
857 	unit = FDUNIT(dev);
858 	fd = device_lookup_private(&fd_cd, unit);
859 	if (fd == NULL)
860 		return ENXIO;
861 	type = fd_dev_to_type(fd, dev);
862 	if (type == NULL)
863 		return ENXIO;
864 
865 	if ((fd->sc_flags & FD_OPEN) != 0 &&
866 	    fd->sc_type != type)
867 		return EBUSY;
868 
869 	fdc = device_private(device_parent(fd->sc_dev));
870 	if ((fd->sc_flags & FD_OPEN) == 0) {
871 		/* Lock eject button */
872 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
873 				  0x40 | ( 1 << unit));
874 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0x40);
875 	}
876 
877 	fd->sc_type = type;
878 	fd->sc_cylin = -1;
879 
880 	switch (mode) {
881 	case S_IFCHR:
882 		fd->sc_flags |= FD_COPEN;
883 		break;
884 	case S_IFBLK:
885 		fd->sc_flags |= FD_BOPEN;
886 		break;
887 	}
888 
889 	fdgetdisklabel(fd, dev);
890 
891 	return 0;
892 }
893 
894 int
895 fdclose(dev_t dev, int flags, int mode, struct lwp *l)
896 {
897 	int unit = FDUNIT(dev);
898 	struct fd_softc *fd = device_lookup_private(&fd_cd, unit);
899 	struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
900 
901 	DPRINTF(("fdclose %d\n", unit));
902 
903 	switch (mode) {
904 	case S_IFCHR:
905 		fd->sc_flags &= ~FD_COPEN;
906 		break;
907 	case S_IFBLK:
908 		fd->sc_flags &= ~FD_BOPEN;
909 		break;
910 	}
911 
912 	if ((fd->sc_flags & FD_OPEN) == 0) {
913 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
914 				  ( 1 << unit));
915 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0);
916 	}
917 	return 0;
918 }
919 
920 void
921 fdcstart(struct fdc_softc *fdc)
922 {
923 
924 #ifdef DIAGNOSTIC
925 	/* only got here if controller's drive queue was inactive; should
926 	   be in idle state */
927 	if (fdc->sc_state != DEVIDLE) {
928 		printf("fdcstart: not idle\n");
929 		return;
930 	}
931 #endif
932 	(void) fdcintr(fdc);
933 }
934 
935 
936 static void
937 fdcpstatus(int n, struct fdc_softc *fdc)
938 {
939 	char bits[64];
940 
941 	switch (n) {
942 	case 0:
943 		printf("\n");
944 		break;
945 	case 2:
946 		snprintb(bits, sizeof(bits), NE7_ST0BITS, fdc->sc_status[0]);
947 		printf(" (st0 %s cyl %d)\n", bits, fdc->sc_status[1]);
948 		break;
949 	case 7:
950 		snprintb(bits, sizeof(bits), NE7_ST0BITS, fdc->sc_status[0]);
951 		printf(" (st0 %s", bits);
952 		snprintb(bits, sizeof(bits), NE7_ST1BITS, fdc->sc_status[1]);
953 		printf(" st1 %s", bits);
954 		snprintb(bits, sizeof(bits), NE7_ST2BITS, fdc->sc_status[2]);
955 		printf(" st2 %s", bits);
956 		printf(" cyl %d head %d sec %d)\n",
957 		    fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
958 		break;
959 #ifdef DIAGNOSTIC
960 	default:
961 		printf("\nfdcstatus: weird size");
962 		break;
963 #endif
964 	}
965 }
966 
967 void
968 fdcstatus(device_t dv, int n, const char *s)
969 {
970 	struct fdc_softc *fdc = device_private(device_parent(dv));
971 
972 	if (n == 0) {
973 		out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
974 		(void) fdcresult(fdc);
975 		n = 2;
976 	}
977 
978 	printf("%s: %s: state %d", device_xname(dv), s, fdc->sc_state);
979 	fdcpstatus(n, fdc);
980 }
981 
982 void
983 fdctimeout(void *arg)
984 {
985 	struct fdc_softc *fdc = arg;
986 	struct fd_softc *fd = TAILQ_FIRST(&fdc->sc_drives);
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 = TAILQ_FIRST(&fdc->sc_drives);
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 #if 0
1331 			isa_dmaabort(fdc->sc_drq);
1332 #endif
1333 			fdcstatus(fd->sc_dev, tmp, bp->b_flags & B_READ ?
1334 				  "read failed" : "write failed");
1335 			printf("blkno %" PRId64 " nblks %d\n",
1336 			    fd->sc_blkno, fd->sc_nblks);
1337 			fdcretry(fdc);
1338 			goto loop;
1339 		}
1340 #if 0
1341 		isa_dmadone(bp->b_flags & B_READ, bp->b_data + fd->sc_skip,
1342 		    nblks * FDC_BSIZE, fdc->sc_drq);
1343 #endif
1344 	iocomplete2:
1345 		if (fdc->sc_errors) {
1346 			diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF,
1347 			    fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
1348 			printf("\n");
1349 			fdc->sc_errors = 0;
1350 		}
1351 		fd->sc_blkno += fd->sc_nblks;
1352 		fd->sc_skip += fd->sc_nbytes;
1353 		fd->sc_bcount -= fd->sc_nbytes;
1354 		DPRINTF(("fd->sc_bcount = %d\n", fd->sc_bcount));
1355 		if (fd->sc_bcount > 0) {
1356 			bp->b_cylinder = fd->sc_blkno
1357 				/ (fd->sc_type->seccyl
1358 				   * (1 << (fd->sc_type->secsize - 2)));
1359 			goto doseek;
1360 		}
1361 		fdfinish(fd, bp);
1362 		goto loop;
1363 
1364 	case COPYCOMPLETE: /* IO DONE, post-analyze */
1365 		DPRINTF(("fdcintr: COPYCOMPLETE:"));
1366 		callout_stop(&fdc->sc_timo_ch);
1367 		if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
1368 			printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0);
1369 #if 0
1370 			isa_dmaabort(fdc->sc_drq);
1371 #endif
1372 			fdcstatus(fd->sc_dev, 7, bp->b_flags & B_READ ?
1373 				  "read failed" : "write failed");
1374 			printf("blkno %" PRId64 " nblks %d\n",
1375 			    fd->sc_blkno, fd->sc_nblks);
1376 			fdcretry(fdc);
1377 			goto loop;
1378 		}
1379 		goto doiohalf;
1380 
1381 	case DORESET:
1382 		DPRINTF(("fdcintr: in DORESET\n"));
1383 		/* try a reset, keep motor on */
1384 		fd_set_motor(fdc, 1);
1385 		DELAY(100);
1386 		fd_set_motor(fdc, 0);
1387 		fdc->sc_state = RESETCOMPLETE;
1388 		callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc);
1389 		return 1;			/* will return later */
1390 
1391 	case RESETCOMPLETE:
1392 		DPRINTF(("fdcintr: in RESETCOMPLETE\n"));
1393 		callout_stop(&fdc->sc_timo_ch);
1394 		/* clear the controller output buffer */
1395 		for (i = 0; i < 4; i++) {
1396 			out_fdc(iot, ioh, NE7CMD_SENSEI);
1397 			(void) fdcresult(fdc);
1398 		}
1399 
1400 		/* fall through */
1401 	case DORECAL:
1402 		DPRINTF(("fdcintr: in DORECAL\n"));
1403 		out_fdc(iot, ioh, NE7CMD_RECAL); /* recalibrate function */
1404 		out_fdc(iot, ioh, fd->sc_drive);
1405 		fdc->sc_state = RECALWAIT;
1406 		callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc);
1407 		return 1;			/* will return later */
1408 
1409 	case RECALWAIT:
1410 		DPRINTF(("fdcintr: in RECALWAIT\n"));
1411 		callout_stop(&fdc->sc_timo_ch);
1412 		fdc->sc_state = RECALCOMPLETE;
1413 		/* allow 1/30 second for heads to settle */
1414 #if 0
1415 		callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc);
1416 #endif
1417 		return 1;			/* will return later */
1418 
1419 	case RECALCOMPLETE:
1420 		DPRINTF(("fdcintr: in RECALCOMPLETE\n"));
1421 		out_fdc(iot, ioh, NE7CMD_SENSEI);
1422 		tmp = fdcresult(fdc);
1423 		if ((st0 & 0xf8) == 0xc0) {
1424 			DPRINTF(("fdcintr: first seek!\n"));
1425 			fdc->sc_state = DORECAL;
1426 			goto loop;
1427 		} else if (tmp != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
1428 #ifdef FDDEBUG
1429 			fdcstatus(fd->sc_dev, 2, "recalibrate failed");
1430 #endif
1431 			fdcretry(fdc);
1432 			goto loop;
1433 		}
1434 		fd->sc_cylin = 0;
1435 		goto doseek;
1436 
1437 	case MOTORWAIT:
1438 		if (fd->sc_flags & FD_MOTOR_WAIT)
1439 			return 1;		/* time's not up yet */
1440 		goto doseek;
1441 
1442 	default:
1443 		fdcstatus(fd->sc_dev, 0, "stray interrupt");
1444 		return 1;
1445 	}
1446 #ifdef DIAGNOSTIC
1447 	panic("fdcintr: impossible");
1448 #endif
1449 #undef	st0
1450 #undef	cyl
1451 }
1452 
1453 void
1454 fdcretry(struct fdc_softc *fdc)
1455 {
1456 	struct fd_softc *fd;
1457 	struct buf *bp;
1458 
1459 	DPRINTF(("fdcretry:\n"));
1460 	fd = TAILQ_FIRST(&fdc->sc_drives);
1461 	bp = BUFQ_PEEK(fd->sc_q);
1462 
1463 	switch (fdc->sc_errors) {
1464 	case 0:
1465 		/* try again */
1466 		fdc->sc_state = SEEKCOMPLETE;
1467 		break;
1468 
1469 	case 1: case 2: case 3:
1470 		/* didn't work; try recalibrating */
1471 		fdc->sc_state = DORECAL;
1472 		break;
1473 
1474 	case 4:
1475 		/* still no go; reset the bastard */
1476 		fdc->sc_state = DORESET;
1477 		break;
1478 
1479 	default:
1480 		diskerr(bp, "fd", "hard error", LOG_PRINTF,
1481 			fd->sc_skip, (struct disklabel *)NULL);
1482 		fdcpstatus(7, fdc);
1483 
1484 		bp->b_error = EIO;
1485 		fdfinish(fd, bp);
1486 	}
1487 	fdc->sc_errors++;
1488 }
1489 
1490 int
1491 fdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
1492 {
1493 	struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(dev));
1494 	struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
1495 	int part = DISKPART(dev);
1496 	struct disklabel buffer;
1497 	int error;
1498 
1499 	DPRINTF(("fdioctl:"));
1500 	switch (cmd) {
1501 	case DIOCGDINFO:
1502 		DPRINTF(("DIOCGDINFO\n"));
1503 #if 1
1504 		*(struct disklabel *)addr = *(fd->sc_dk.dk_label);
1505 		return(0);
1506 #else
1507 		memset(&buffer, 0, sizeof(buffer));
1508 
1509 		buffer.d_secpercyl = fd->sc_type->seccyl;
1510 		buffer.d_type = DTYPE_FLOPPY;
1511 		buffer.d_secsize = 128 << fd->sc_type->secsize;
1512 
1513 		if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL)
1514 			return EINVAL;
1515 
1516 		*(struct disklabel *)addr = buffer;
1517 		return 0;
1518 #endif
1519 
1520 	case DIOCGPART:
1521 		DPRINTF(("DIOCGPART\n"));
1522 		((struct partinfo *)addr)->disklab = fd->sc_dk.dk_label;
1523 		((struct partinfo *)addr)->part =
1524 		    &fd->sc_dk.dk_label->d_partitions[part];
1525 		return(0);
1526 
1527 	case DIOCWLABEL:
1528 		DPRINTF(("DIOCWLABEL\n"));
1529 		if ((flag & FWRITE) == 0)
1530 			return EBADF;
1531 		/* XXX do something */
1532 		return 0;
1533 
1534 	case DIOCWDINFO:
1535 		DPRINTF(("DIOCWDINFO\n"));
1536 		if ((flag & FWRITE) == 0)
1537 			return EBADF;
1538 
1539 		error = setdisklabel(&buffer, (struct disklabel *)addr,
1540 		                     0, NULL);
1541 		if (error)
1542 			return error;
1543 
1544 		error = writedisklabel(dev, fdstrategy, &buffer, NULL);
1545 		return error;
1546 
1547 	case DIOCLOCK:
1548 		/*
1549 		 * Nothing to do here, really.
1550 		 */
1551 		return 0; /* XXX */
1552 
1553 	case DIOCEJECT:
1554 		DPRINTF(("DIOCEJECT\n"));
1555 		if (*(int *)addr == 0) {
1556 			/*
1557 			 * Don't force eject: check that we are the only
1558 			 * partition open. If so, unlock it.
1559 			 */
1560 			if ((fd->sc_dk.dk_openmask & ~(1 << part)) != 0 ||
1561 			    fd->sc_dk.dk_bopenmask + fd->sc_dk.dk_copenmask !=
1562 			    fd->sc_dk.dk_openmask) {
1563 				return (EBUSY);
1564 			}
1565 		}
1566 		/* FALLTHROUGH */
1567 	case ODIOCEJECT:
1568 		DPRINTF(("ODIOCEJECT\n"));
1569 		fd_do_eject(fdc, FDUNIT(dev));
1570 		return 0;
1571 
1572 	default:
1573 		return ENOTTY;
1574 	}
1575 
1576 #ifdef DIAGNOSTIC
1577 	panic("fdioctl: impossible");
1578 #endif
1579 }
1580 
1581 void
1582 fd_do_eject(struct fdc_softc *fdc, int unit)
1583 {
1584 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
1585 			  0x20 | ( 1 << unit));
1586 	DELAY(1); /* XXX */
1587 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0x20);
1588 }
1589 
1590 /*
1591  * Build disk label. For now we only create a label from what we know
1592  * from 'sc'.
1593  */
1594 static int
1595 fdgetdisklabel(struct fd_softc *sc, dev_t dev)
1596 {
1597 	struct disklabel *lp;
1598 	int part;
1599 
1600 	DPRINTF(("fdgetdisklabel()\n"));
1601 
1602 	part = DISKPART(dev);
1603 	lp = sc->sc_dk.dk_label;
1604 	memset(lp, 0, sizeof(struct disklabel));
1605 
1606 	lp->d_secsize     = 128 << sc->sc_type->secsize;
1607 	lp->d_ntracks     = sc->sc_type->heads;
1608 	lp->d_nsectors    = sc->sc_type->sectrac;
1609 	lp->d_secpercyl   = lp->d_ntracks * lp->d_nsectors;
1610 	lp->d_ncylinders  = sc->sc_type->size / lp->d_secpercyl;
1611 	lp->d_secperunit  = sc->sc_type->size;
1612 
1613 	lp->d_type        = DTYPE_FLOPPY;
1614 	lp->d_rpm         = 300; 	/* XXX */
1615 	lp->d_interleave  = 1;		/* FIXME: is this OK?		*/
1616 	lp->d_bbsize      = 0;
1617 	lp->d_sbsize      = 0;
1618 	lp->d_npartitions = part + 1;
1619 #define STEP_DELAY	6000	/* 6ms (6000us) delay after stepping	*/
1620 	lp->d_trkseek     = STEP_DELAY; /* XXX */
1621 	lp->d_magic       = DISKMAGIC;
1622 	lp->d_magic2      = DISKMAGIC;
1623 	lp->d_checksum    = dkcksum(lp);
1624 	lp->d_partitions[part].p_size   = lp->d_secperunit;
1625 	lp->d_partitions[part].p_fstype = FS_UNUSED;
1626 	lp->d_partitions[part].p_fsize  = 1024;
1627 	lp->d_partitions[part].p_frag   = 8;
1628 
1629 	return(0);
1630 }
1631 
1632 #include <dev/cons.h>
1633 
1634 /*
1635  * Mountroot hook: prompt the user to enter the root file system
1636  * floppy.
1637  */
1638 void
1639 fd_mountroot_hook(device_t dev)
1640 {
1641 	struct fd_softc *fd = device_private(dev);
1642 	struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
1643 	int c;
1644 
1645 	/* XXX device_unit() abuse */
1646 	fd_do_eject(fdc, device_unit(dev));
1647 	printf("Insert filesystem floppy and press return.");
1648 	for (;;) {
1649 		c = cngetc();
1650 		if ((c == '\r') || (c == '\n')) {
1651 			printf("\n");
1652 			break;
1653 		}
1654 	}
1655 }
1656