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