Sync usage with man page.
[netbsd-mini2440.git] / sys / arch / x68k / dev / fd.c
blob95c37b9a1958bd0715884912ffc1313f08b655ef
1 /* $NetBSD: fd.c,v 1.91 2009/01/13 13:35:52 yamt Exp $ */
3 /*-
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Charles M. Hannum and Minoura Makoto.
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.
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.
32 /*-
33 * Copyright (c) 1990 The Regents of the University of California.
34 * All rights reserved.
36 * This code is derived from software contributed to Berkeley by
37 * Don Ahn.
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.
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.
63 * @(#)fd.c 7.4 (Berkeley) 5/25/91
66 #include <sys/cdefs.h>
67 __KERNEL_RCSID(0, "$NetBSD: fd.c,v 1.91 2009/01/13 13:35:52 yamt Exp $");
69 #include "rnd.h"
70 #include "opt_ddb.h"
71 #include "opt_m680x0.h"
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
95 #include <uvm/uvm_extern.h>
97 #include <dev/cons.h>
99 #include <machine/bus.h>
100 #include <machine/cpu.h>
102 #include <arch/x68k/dev/intiovar.h>
103 #include <arch/x68k/dev/dmacvar.h>
104 #include <arch/x68k/dev/fdreg.h>
105 #include <arch/x68k/dev/opmvar.h> /* for CT1 access */
107 #include "locators.h"
109 #ifdef FDDEBUG
110 #define DPRINTF(x) if (fddebug) printf x
111 int fddebug = 0;
112 #else
113 #define DPRINTF(x)
114 #endif
116 #define FDUNIT(dev) (minor(dev) / 8)
117 #define FDTYPE(dev) (minor(dev) % 8)
119 enum fdc_state {
120 DEVIDLE = 0,
121 MOTORWAIT,
122 DOSEEK,
123 SEEKWAIT,
124 SEEKTIMEDOUT,
125 SEEKCOMPLETE,
126 DOIO,
127 IOCOMPLETE,
128 IOTIMEDOUT,
129 DORESET,
130 RESETCOMPLETE,
131 RESETTIMEDOUT,
132 DORECAL,
133 RECALWAIT,
134 RECALTIMEDOUT,
135 RECALCOMPLETE,
136 DOCOPY,
137 DOIOHALF,
138 COPYCOMPLETE,
141 /* software state, per controller */
142 struct fdc_softc {
143 bus_space_tag_t sc_iot; /* intio i/o space identifier */
144 bus_space_handle_t sc_ioh; /* intio io handle */
146 struct callout sc_timo_ch; /* timeout callout */
147 struct callout sc_intr_ch; /* pseudo-intr callout */
149 bus_dma_tag_t sc_dmat; /* intio DMA tag */
150 bus_dmamap_t sc_dmamap; /* DMA map */
151 u_int8_t *sc_addr; /* physical address */
152 struct dmac_channel_stat *sc_dmachan; /* intio DMA channel */
153 struct dmac_dma_xfer *sc_xfer; /* DMA transfer */
155 struct fd_softc *sc_fd[4]; /* pointers to children */
156 TAILQ_HEAD(drivehead, fd_softc) sc_drives;
157 enum fdc_state sc_state;
158 int sc_errors; /* number of retries so far */
159 u_char sc_status[7]; /* copy of registers */
160 } fdc_softc;
162 int fdcintr(void *);
163 void fdcreset(struct fdc_softc *);
165 /* controller driver configuration */
166 int fdcprobe(device_t, cfdata_t, void *);
167 void fdcattach(device_t, device_t, void *);
168 int fdprint(void *, const char *);
170 CFATTACH_DECL_NEW(fdc, sizeof(struct fdc_softc),
171 fdcprobe, fdcattach, NULL, NULL);
173 extern struct cfdriver fdc_cd;
176 * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how
177 * we tell them apart.
179 struct fd_type {
180 int sectrac; /* sectors per track */
181 int heads; /* number of heads */
182 int seccyl; /* sectors per cylinder */
183 int secsize; /* size code for sectors */
184 int datalen; /* data len when secsize = 0 */
185 int steprate; /* step rate and head unload time */
186 int gap1; /* gap len between sectors */
187 int gap2; /* formatting gap */
188 int cyls; /* total num of cylinders */
189 int size; /* size of disk in sectors */
190 int step; /* steps per cylinder */
191 int rate; /* transfer speed code */
192 const char *name;
195 /* The order of entries in the following table is important -- BEWARE! */
196 struct fd_type fd_types[] = {
197 { 8,2,16,3,0xff,0xdf,0x35,0x74,77,1232,1,FDC_500KBPS, "1.2MB/[1024bytes/sector]" }, /* 1.2 MB japanese format */
198 { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS,"1.44MB" }, /* 1.44MB diskette */
199 { 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS, "1.2MB" }, /* 1.2 MB AT-diskettes */
200 { 9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS, "360KB/AT" }, /* 360kB in 1.2MB drive */
201 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS, "360KB/PC" }, /* 360kB PC diskettes */
202 { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS, "720KB" }, /* 3.5" 720kB diskette */
203 { 9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS, "720KB/x" }, /* 720kB in 1.2MB drive */
204 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS, "360KB/x" }, /* 360kB in 720kB drive */
207 /* software state, per disk (with up to 4 disks per ctlr) */
208 struct fd_softc {
209 device_t sc_dev;
210 struct disk sc_dk;
212 struct fd_type *sc_deftype; /* default type descriptor */
213 struct fd_type *sc_type; /* current type descriptor */
215 struct callout sc_motoron_ch;
216 struct callout sc_motoroff_ch;
218 daddr_t sc_blkno; /* starting block number */
219 int sc_bcount; /* byte count left */
220 int sc_opts; /* user-set options */
221 int sc_skip; /* bytes already transferred */
222 int sc_nblks; /* number of blocks currently transferring */
223 int sc_nbytes; /* number of bytes currently transferring */
225 int sc_drive; /* physical unit number */
226 int sc_flags;
227 #define FD_BOPEN 0x01 /* it's open */
228 #define FD_COPEN 0x02 /* it's open */
229 #define FD_OPEN (FD_BOPEN|FD_COPEN) /* it's open */
230 #define FD_MOTOR 0x04 /* motor should be on */
231 #define FD_MOTOR_WAIT 0x08 /* motor coming up */
232 #define FD_ALIVE 0x10 /* alive */
233 int sc_cylin; /* where we think the head is */
235 TAILQ_ENTRY(fd_softc) sc_drivechain;
236 int sc_ops; /* I/O ops since last switch */
237 struct bufq_state *sc_q;/* pending I/O requests */
238 int sc_active; /* number of active I/O operations */
239 u_char *sc_copybuf; /* for secsize >=3 */
240 u_char sc_part; /* for secsize >=3 */
241 #define SEC_P10 0x02 /* first part */
242 #define SEC_P01 0x01 /* second part */
243 #define SEC_P11 0x03 /* both part */
245 #if NRND > 0
246 rndsource_element_t rnd_source;
247 #endif
250 /* floppy driver configuration */
251 int fdprobe(device_t, cfdata_t, void *);
252 void fdattach(device_t, device_t, void *);
254 CFATTACH_DECL_NEW(fd, sizeof(struct fd_softc),
255 fdprobe, fdattach, NULL, NULL);
257 extern struct cfdriver fd_cd;
259 dev_type_open(fdopen);
260 dev_type_close(fdclose);
261 dev_type_read(fdread);
262 dev_type_write(fdwrite);
263 dev_type_ioctl(fdioctl);
264 dev_type_strategy(fdstrategy);
266 const struct bdevsw fd_bdevsw = {
267 fdopen, fdclose, fdstrategy, fdioctl, nodump, nosize, D_DISK
270 const struct cdevsw fd_cdevsw = {
271 fdopen, fdclose, fdread, fdwrite, fdioctl,
272 nostop, notty, nopoll, nommap, nokqfilter, D_DISK
275 void fdstart(struct fd_softc *);
277 struct dkdriver fddkdriver = { fdstrategy };
279 void fd_set_motor(struct fdc_softc *, int);
280 void fd_motor_off(void *);
281 void fd_motor_on(void *);
282 int fdcresult(struct fdc_softc *);
283 int out_fdc(bus_space_tag_t, bus_space_handle_t, u_char);
284 void fdcstart(struct fdc_softc *);
285 void fdcstatus(device_t, int, const char *);
286 void fdctimeout(void *);
287 void fdcpseudointr(void *);
288 void fdcretry(struct fdc_softc *);
289 void fdfinish(struct fd_softc *, struct buf *);
290 inline struct fd_type *fd_dev_to_type(struct fd_softc *, dev_t);
291 static int fdcpoll(struct fdc_softc *);
292 static int fdgetdisklabel(struct fd_softc *, dev_t);
293 static void fd_do_eject(struct fdc_softc *, int);
295 void fd_mountroot_hook(device_t);
297 /* DMA transfer routines */
298 inline static void fdc_dmastart(struct fdc_softc *, int, void *, vsize_t);
299 static int fdcdmaintr(void *);
300 static int fdcdmaerrintr(void *);
302 inline static void
303 fdc_dmastart(struct fdc_softc *fdc, int read, void *addr, vsize_t count)
305 int error;
307 DPRINTF(("fdc_dmastart: %s, addr = %p, count = %ld\n",
308 read ? "read" : "write", (void *) addr, count));
310 error = bus_dmamap_load(fdc->sc_dmat, fdc->sc_dmamap, addr, count,
311 0, BUS_DMA_NOWAIT);
312 if (error) {
313 panic ("fdc_dmastart: cannot load dmamap");
316 bus_dmamap_sync(fdc->sc_dmat, fdc->sc_dmamap, 0, count,
317 read?BUS_DMASYNC_PREREAD:BUS_DMASYNC_PREWRITE);
319 fdc->sc_xfer = dmac_prepare_xfer(fdc->sc_dmachan, fdc->sc_dmat,
320 fdc->sc_dmamap,
321 (read?
322 DMAC_OCR_DIR_DTM:DMAC_OCR_DIR_MTD),
323 (DMAC_SCR_MAC_COUNT_UP|
324 DMAC_SCR_DAC_NO_COUNT),
325 (u_int8_t*) (fdc->sc_addr +
326 fddata)); /* XXX */
328 dmac_start_xfer(fdc->sc_dmachan->ch_softc, fdc->sc_xfer);
331 static int
332 fdcdmaintr(void *arg)
334 struct fdc_softc *fdc = arg;
336 bus_dmamap_unload(fdc->sc_dmat, fdc->sc_dmamap);
338 return 0;
341 static int
342 fdcdmaerrintr(void *dummy)
344 DPRINTF(("fdcdmaerrintr\n"));
346 return 0;
349 /* ARGSUSED */
351 fdcprobe(device_t parent, cfdata_t cf, void *aux)
353 struct intio_attach_args *ia = aux;
355 if (strcmp(ia->ia_name, "fdc") != 0)
356 return 0;
358 if (ia->ia_addr == INTIOCF_ADDR_DEFAULT)
359 ia->ia_addr = FDC_ADDR;
360 if (ia->ia_intr == INTIOCF_INTR_DEFAULT)
361 ia->ia_intr = FDC_INTR;
362 if (ia->ia_dma == INTIOCF_DMA_DEFAULT)
363 ia->ia_dma = FDC_DMA;
364 if (ia->ia_dmaintr == INTIOCF_DMAINTR_DEFAULT)
365 ia->ia_dmaintr = FDC_DMAINTR;
367 if ((ia->ia_intr & 0x03) != 0)
368 return 0;
370 ia->ia_size = 0x2000;
371 if (intio_map_allocate_region (parent, ia, INTIO_MAP_TESTONLY))
372 return 0;
374 /* builtin device; always there */
375 return 1;
379 * Arguments passed between fdcattach and fdprobe.
381 struct fdc_attach_args {
382 int fa_drive;
383 struct fd_type *fa_deftype;
387 * Print the location of a disk drive (called just before attaching the
388 * the drive). If `fdc' is not NULL, the drive was found but was not
389 * in the system config file; print the drive name as well.
390 * Return QUIET (config_find ignores this if the device was configured) to
391 * avoid printing `fdN not configured' messages.
394 fdprint(void *aux, const char *fdc)
396 struct fdc_attach_args *fa = aux;
398 if (!fdc)
399 aprint_normal(" drive %d", fa->fa_drive);
400 return QUIET;
403 void
404 fdcattach(device_t parent, device_t self, void *aux)
406 struct fdc_softc *fdc = device_private(self);
407 bus_space_tag_t iot;
408 bus_space_handle_t ioh;
409 struct intio_attach_args *ia = aux;
410 struct fdc_attach_args fa;
412 iot = ia->ia_bst;
414 aprint_normal("\n");
416 callout_init(&fdc->sc_timo_ch, 0);
417 callout_init(&fdc->sc_intr_ch, 0);
419 /* Re-map the I/O space. */
420 bus_space_map(iot, ia->ia_addr, 0x2000, BUS_SPACE_MAP_SHIFTED, &ioh);
422 fdc->sc_iot = iot;
423 fdc->sc_ioh = ioh;
424 fdc->sc_addr = (void *)ia->ia_addr;
426 fdc->sc_dmat = ia->ia_dmat;
427 fdc->sc_state = DEVIDLE;
428 TAILQ_INIT(&fdc->sc_drives);
430 /* Initialize DMAC channel */
431 fdc->sc_dmachan = dmac_alloc_channel(parent, ia->ia_dma, "fdc",
432 ia->ia_dmaintr, fdcdmaintr, fdc,
433 ia->ia_dmaintr+1, fdcdmaerrintr,
434 fdc);
435 if (bus_dmamap_create(fdc->sc_dmat, FDC_MAXIOSIZE, 1, DMAC_MAXSEGSZ,
436 0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW,
437 &fdc->sc_dmamap)) {
438 aprint_error_dev(self, "can't set up intio DMA map\n");
439 return;
442 if (intio_intr_establish(ia->ia_intr, "fdc", fdcintr, fdc))
443 panic ("Could not establish interrupt (duplicated vector?).");
444 intio_set_ivec(ia->ia_intr);
446 /* reset */
447 intio_disable_intr(SICILIAN_INTR_FDD);
448 intio_enable_intr(SICILIAN_INTR_FDC);
449 fdcresult(fdc);
450 fdcreset(fdc);
452 aprint_normal_dev(self, "uPD72065 FDC\n");
453 out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
454 out_fdc(iot, ioh, 0xd0);
455 out_fdc(iot, ioh, 0x10);
457 /* physical limit: four drives per controller. */
458 for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) {
459 (void)config_found(self, (void *)&fa, fdprint);
462 intio_enable_intr(SICILIAN_INTR_FDC);
465 void
466 fdcreset(struct fdc_softc *fdc)
468 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdsts, NE7CMD_RESET);
471 static int
472 fdcpoll(struct fdc_softc *fdc)
474 int i = 25000, n;
475 while (--i > 0) {
476 if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC)) {
477 out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
478 n = fdcresult(fdc);
479 break;
481 DELAY(100);
483 return i;
487 fdprobe(device_t parent, cfdata_t cf, void *aux)
489 struct fdc_softc *fdc = device_private(parent);
490 struct fd_type *type;
491 struct fdc_attach_args *fa = aux;
492 int drive = fa->fa_drive;
493 bus_space_tag_t iot = fdc->sc_iot;
494 bus_space_handle_t ioh = fdc->sc_ioh;
495 int n = 0;
496 int found = 0;
497 int i;
499 if (cf->cf_loc[FDCCF_UNIT] != FDCCF_UNIT_DEFAULT &&
500 cf->cf_loc[FDCCF_UNIT] != drive)
501 return 0;
503 type = &fd_types[0]; /* XXX 1.2MB */
505 intio_disable_intr(SICILIAN_INTR_FDC);
507 /* select drive and turn on motor */
508 bus_space_write_1(iot, ioh, fdctl, 0x80 | (type->rate << 4)| drive);
509 fdc_force_ready(FDCRDY);
510 fdcpoll(fdc);
512 retry:
513 out_fdc(iot, ioh, NE7CMD_RECAL);
514 out_fdc(iot, ioh, drive);
516 i = 25000;
517 while (--i > 0) {
518 if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC)) {
519 out_fdc(iot, ioh, NE7CMD_SENSEI);
520 n = fdcresult(fdc);
521 break;
523 DELAY(100);
526 #ifdef FDDEBUG
528 int _i;
529 DPRINTF(("fdprobe: status"));
530 for (_i = 0; _i < n; _i++)
531 DPRINTF((" %x", fdc->sc_status[_i]));
532 DPRINTF(("\n"));
534 #endif
536 if (n == 2) {
537 if ((fdc->sc_status[0] & 0xf0) == 0x20)
538 found = 1;
539 else if ((fdc->sc_status[0] & 0xf0) == 0xc0)
540 goto retry;
543 /* turn off motor */
544 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh,
545 fdctl, (type->rate << 4)| drive);
546 fdc_force_ready(FDCSTBY);
547 if (!found) {
548 intio_enable_intr(SICILIAN_INTR_FDC);
549 return 0;
552 return 1;
556 * Controller is working, and drive responded. Attach it.
558 void
559 fdattach(device_t parent, device_t self, void *aux)
561 struct fdc_softc *fdc = device_private(parent);
562 struct fd_softc *fd = device_private(self);
563 struct fdc_attach_args *fa = aux;
564 struct fd_type *type = &fd_types[0]; /* XXX 1.2MB */
565 int drive = fa->fa_drive;
567 callout_init(&fd->sc_motoron_ch, 0);
568 callout_init(&fd->sc_motoroff_ch, 0);
570 fd->sc_dev = self;
571 fd->sc_flags = 0;
573 if (type)
574 aprint_normal(": %s, %d cyl, %d head, %d sec\n", type->name,
575 type->cyls, type->heads, type->sectrac);
576 else
577 aprint_normal(": density unknown\n");
579 bufq_alloc(&fd->sc_q, "disksort", BUFQ_SORT_CYLINDER);
580 fd->sc_cylin = -1;
581 fd->sc_drive = drive;
582 fd->sc_deftype = type;
583 fdc->sc_fd[drive] = fd;
585 fd->sc_copybuf = (u_char *)malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK);
586 if (fd->sc_copybuf == 0)
587 aprint_error("%s: WARNING!! malloc() failed.\n", __func__);
588 fd->sc_flags |= FD_ALIVE;
591 * Initialize and attach the disk structure.
593 disk_init(&fd->sc_dk, device_xname(fd->sc_dev), &fddkdriver);
594 disk_attach(&fd->sc_dk);
597 * Establish a mountroot_hook anyway in case we booted
598 * with RB_ASKNAME and get selected as the boot device.
600 mountroothook_establish(fd_mountroot_hook, fd->sc_dev);
602 #if NRND > 0
603 rnd_attach_source(&fd->rnd_source, device_xname(fd->sc_dev),
604 RND_TYPE_DISK, 0);
605 #endif
608 inline struct fd_type *
609 fd_dev_to_type(struct fd_softc *fd, dev_t dev)
611 int type = FDTYPE(dev);
613 if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
614 return NULL;
615 return &fd_types[type];
618 void
619 fdstrategy(struct buf *bp)
621 struct fd_softc *fd;
622 int unit;
623 int sz;
624 int s;
626 unit = FDUNIT(bp->b_dev);
627 fd = device_lookup_private(&fd_cd, unit);
628 if (fd == NULL) {
629 bp->b_error = EINVAL;
630 goto done;
633 if (bp->b_blkno < 0 ||
634 (bp->b_bcount % FDC_BSIZE) != 0) {
635 DPRINTF(("fdstrategy: unit=%d, blkno=%" PRId64 ", "
636 "bcount=%d\n", unit,
637 bp->b_blkno, bp->b_bcount));
638 bp->b_error = EINVAL;
639 goto done;
642 /* If it's a null transfer, return immediately. */
643 if (bp->b_bcount == 0)
644 goto done;
646 sz = howmany(bp->b_bcount, FDC_BSIZE);
648 if (bp->b_blkno + sz >
649 (fd->sc_type->size << (fd->sc_type->secsize - 2))) {
650 sz = (fd->sc_type->size << (fd->sc_type->secsize - 2))
651 - bp->b_blkno;
652 if (sz == 0) {
653 /* If exactly at end of disk, return EOF. */
654 bp->b_resid = bp->b_bcount;
655 goto done;
657 if (sz < 0) {
658 /* If past end of disk, return EINVAL. */
659 bp->b_error = EINVAL;
660 goto done;
662 /* Otherwise, truncate request. */
663 bp->b_bcount = sz << DEV_BSHIFT;
666 bp->b_rawblkno = bp->b_blkno;
667 bp->b_cylinder = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE)
668 / (fd->sc_type->seccyl * (1 << (fd->sc_type->secsize - 2)));
670 DPRINTF(("fdstrategy: %s b_blkno %" PRId64 " b_bcount %d cylin %d\n",
671 bp->b_flags & B_READ ? "read" : "write",
672 bp->b_blkno, bp->b_bcount, bp->b_cylinder));
673 /* Queue transfer on drive, activate drive and controller if idle. */
674 s = splbio();
675 bufq_put(fd->sc_q, bp);
676 callout_stop(&fd->sc_motoroff_ch); /* a good idea */
677 if (fd->sc_active == 0)
678 fdstart(fd);
679 #ifdef DIAGNOSTIC
680 else {
681 struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
682 if (fdc->sc_state == DEVIDLE) {
683 printf("fdstrategy: controller inactive\n");
684 fdcstart(fdc);
687 #endif
688 splx(s);
689 return;
691 done:
692 /* Toss transfer; we're done early. */
693 biodone(bp);
696 void
697 fdstart(struct fd_softc *fd)
699 struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
700 int active = !TAILQ_EMPTY(&fdc->sc_drives);
702 /* Link into controller queue. */
703 fd->sc_active = 1;
704 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
706 /* If controller not already active, start it. */
707 if (!active)
708 fdcstart(fdc);
711 void
712 fdfinish(struct fd_softc *fd, struct buf *bp)
714 struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
717 * Move this drive to the end of the queue to give others a `fair'
718 * chance. We only force a switch if N operations are completed while
719 * another drive is waiting to be serviced, since there is a long motor
720 * startup delay whenever we switch.
722 (void)bufq_get(fd->sc_q);
723 if (TAILQ_NEXT(fd, sc_drivechain) && ++fd->sc_ops >= 8) {
724 fd->sc_ops = 0;
725 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
726 if (bufq_peek(fd->sc_q) != NULL) {
727 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
728 } else
729 fd->sc_active = 0;
731 bp->b_resid = fd->sc_bcount;
732 fd->sc_skip = 0;
734 #if NRND > 0
735 rnd_add_uint32(&fd->rnd_source, bp->b_blkno);
736 #endif
738 biodone(bp);
739 /* turn off motor 5s from now */
740 callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd);
741 fdc->sc_state = DEVIDLE;
745 fdread(dev_t dev, struct uio *uio, int flags)
748 return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
752 fdwrite(dev_t dev, struct uio *uio, int flags)
755 return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
758 void
759 fd_set_motor(struct fdc_softc *fdc, int reset)
761 struct fd_softc *fd;
762 int n;
764 DPRINTF(("fd_set_motor:\n"));
765 for (n = 0; n < 4; n++)
766 if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR)) {
767 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdctl,
768 0x80 | (fd->sc_type->rate << 4)| n);
772 void
773 fd_motor_off(void *arg)
775 struct fd_softc *fd = arg;
776 struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
777 int s;
779 DPRINTF(("fd_motor_off:\n"));
781 s = splbio();
782 fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
783 bus_space_write_1 (fdc->sc_iot, fdc->sc_ioh, fdctl,
784 (fd->sc_type->rate << 4) | fd->sc_drive);
785 #if 0
786 fd_set_motor(fdc, 0); /* XXX */
787 #endif
788 splx(s);
791 void
792 fd_motor_on(void *arg)
794 struct fd_softc *fd = arg;
795 struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
796 int s;
798 DPRINTF(("fd_motor_on:\n"));
800 s = splbio();
801 fd->sc_flags &= ~FD_MOTOR_WAIT;
802 if ((TAILQ_FIRST(&fdc->sc_drives) == fd) && (fdc->sc_state == MOTORWAIT))
803 (void) fdcintr(fdc);
804 splx(s);
808 fdcresult(struct fdc_softc *fdc)
810 bus_space_tag_t iot = fdc->sc_iot;
811 bus_space_handle_t ioh = fdc->sc_ioh;
812 u_char i;
813 int j = 100000,
814 n = 0;
816 for (; j; j--) {
817 i = bus_space_read_1(iot, ioh, fdsts) &
818 (NE7_DIO | NE7_RQM | NE7_CB);
820 if (i == NE7_RQM)
821 return n;
822 if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
823 if (n >= sizeof(fdc->sc_status)) {
824 log(LOG_ERR, "fdcresult: overrun\n");
825 return -1;
827 fdc->sc_status[n++] =
828 bus_space_read_1(iot, ioh, fddata);
830 delay(10);
832 log(LOG_ERR, "fdcresult: timeout\n");
833 return -1;
837 out_fdc(bus_space_tag_t iot, bus_space_handle_t ioh, u_char x)
839 int i = 100000;
841 while ((bus_space_read_1(iot, ioh, fdsts) & NE7_DIO) && i-- > 0);
842 if (i <= 0)
843 return -1;
844 while ((bus_space_read_1(iot, ioh, fdsts) & NE7_RQM) == 0 && i-- > 0);
845 if (i <= 0)
846 return -1;
847 bus_space_write_1(iot, ioh, fddata, x);
848 return 0;
852 fdopen(dev_t dev, int flags, int mode, struct lwp *l)
854 int unit;
855 struct fd_softc *fd;
856 struct fd_type *type;
857 struct fdc_softc *fdc;
859 unit = FDUNIT(dev);
860 fd = device_lookup_private(&fd_cd, unit);
861 if (fd == NULL)
862 return ENXIO;
863 type = fd_dev_to_type(fd, dev);
864 if (type == NULL)
865 return ENXIO;
867 if ((fd->sc_flags & FD_OPEN) != 0 &&
868 fd->sc_type != type)
869 return EBUSY;
871 fdc = device_private(device_parent(fd->sc_dev));
872 if ((fd->sc_flags & FD_OPEN) == 0) {
873 /* Lock eject button */
874 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
875 0x40 | ( 1 << unit));
876 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0x40);
879 fd->sc_type = type;
880 fd->sc_cylin = -1;
882 switch (mode) {
883 case S_IFCHR:
884 fd->sc_flags |= FD_COPEN;
885 break;
886 case S_IFBLK:
887 fd->sc_flags |= FD_BOPEN;
888 break;
891 fdgetdisklabel(fd, dev);
893 return 0;
897 fdclose(dev_t dev, int flags, int mode, struct lwp *l)
899 int unit = FDUNIT(dev);
900 struct fd_softc *fd = device_lookup_private(&fd_cd, unit);
901 struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
903 DPRINTF(("fdclose %d\n", unit));
905 switch (mode) {
906 case S_IFCHR:
907 fd->sc_flags &= ~FD_COPEN;
908 break;
909 case S_IFBLK:
910 fd->sc_flags &= ~FD_BOPEN;
911 break;
914 if ((fd->sc_flags & FD_OPEN) == 0) {
915 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
916 ( 1 << unit));
917 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0);
919 return 0;
922 void
923 fdcstart(struct fdc_softc *fdc)
926 #ifdef DIAGNOSTIC
927 /* only got here if controller's drive queue was inactive; should
928 be in idle state */
929 if (fdc->sc_state != DEVIDLE) {
930 printf("fdcstart: not idle\n");
931 return;
933 #endif
934 (void) fdcintr(fdc);
938 static void
939 fdcpstatus(int n, struct fdc_softc *fdc)
941 char bits[64];
943 switch (n) {
944 case 0:
945 printf("\n");
946 break;
947 case 2:
948 snprintb(bits, sizeof(bits), NE7_ST0BITS, fdc->sc_status[0]);
949 printf(" (st0 %s cyl %d)\n", bits, fdc->sc_status[1]);
950 break;
951 case 7:
952 snprintb(bits, sizeof(bits), NE7_ST0BITS, fdc->sc_status[0]);
953 printf(" (st0 %s", bits);
954 snprintb(bits, sizeof(bits), NE7_ST1BITS, fdc->sc_status[1]);
955 printf(" st1 %s", bits);
956 snprintb(bits, sizeof(bits), NE7_ST2BITS, fdc->sc_status[2]);
957 printf(" st2 %s", bits);
958 printf(" cyl %d head %d sec %d)\n",
959 fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
960 break;
961 #ifdef DIAGNOSTIC
962 default:
963 printf("\nfdcstatus: weird size");
964 break;
965 #endif
969 void
970 fdcstatus(device_t dv, int n, const char *s)
972 struct fdc_softc *fdc = device_private(device_parent(dv));
974 if (n == 0) {
975 out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
976 (void) fdcresult(fdc);
977 n = 2;
980 printf("%s: %s: state %d", device_xname(dv), s, fdc->sc_state);
981 fdcpstatus(n, fdc);
984 void
985 fdctimeout(void *arg)
987 struct fdc_softc *fdc = arg;
988 struct fd_softc *fd = TAILQ_FIRST(&fdc->sc_drives);
989 int s;
991 s = splbio();
992 fdcstatus(fd->sc_dev, 0, "timeout");
994 if (bufq_peek(fd->sc_q) != NULL)
995 fdc->sc_state++;
996 else
997 fdc->sc_state = DEVIDLE;
999 (void) fdcintr(fdc);
1000 splx(s);
1003 #if 0
1004 void
1005 fdcpseudointr(void *arg)
1007 int s;
1008 struct fdc_softc *fdc = arg;
1010 /* just ensure it has the right spl */
1011 s = splbio();
1012 (void) fdcintr(fdc);
1013 splx(s);
1015 #endif
1018 fdcintr(void *arg)
1020 struct fdc_softc *fdc = arg;
1021 #define st0 fdc->sc_status[0]
1022 #define cyl fdc->sc_status[1]
1023 struct fd_softc *fd;
1024 struct buf *bp;
1025 bus_space_tag_t iot = fdc->sc_iot;
1026 bus_space_handle_t ioh = fdc->sc_ioh;
1027 int read, head, sec, pos, i, sectrac, nblks;
1028 int tmp;
1029 struct fd_type *type;
1031 loop:
1032 fd = TAILQ_FIRST(&fdc->sc_drives);
1033 if (fd == NULL) {
1034 DPRINTF(("fdcintr: set DEVIDLE\n"));
1035 if (fdc->sc_state == DEVIDLE) {
1036 if (intio_get_sicilian_intr() & SICILIAN_STAT_FDC) {
1037 out_fdc(iot, ioh, NE7CMD_SENSEI);
1038 if ((tmp = fdcresult(fdc)) != 2 ||
1039 (st0 & 0xf8) != 0x20) {
1040 goto loop;
1044 /* no drives waiting; end */
1045 fdc->sc_state = DEVIDLE;
1046 return 1;
1049 /* Is there a transfer to this drive? If not, deactivate drive. */
1050 bp = bufq_peek(fd->sc_q);
1051 if (bp == NULL) {
1052 fd->sc_ops = 0;
1053 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
1054 fd->sc_active = 0;
1055 goto loop;
1058 switch (fdc->sc_state) {
1059 case DEVIDLE:
1060 DPRINTF(("fdcintr: in DEVIDLE\n"));
1061 fdc->sc_errors = 0;
1062 fd->sc_skip = 0;
1063 fd->sc_bcount = bp->b_bcount;
1064 fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
1065 callout_stop(&fd->sc_motoroff_ch);
1066 if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
1067 fdc->sc_state = MOTORWAIT;
1068 return 1;
1070 if ((fd->sc_flags & FD_MOTOR) == 0) {
1071 /* Turn on the motor */
1072 /* being careful about other drives. */
1073 for (i = 0; i < 4; i++) {
1074 struct fd_softc *ofd = fdc->sc_fd[i];
1075 if (ofd && ofd->sc_flags & FD_MOTOR) {
1076 callout_stop(&ofd->sc_motoroff_ch);
1077 ofd->sc_flags &=
1078 ~(FD_MOTOR | FD_MOTOR_WAIT);
1079 break;
1082 fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
1083 fd_set_motor(fdc, 0);
1084 fdc->sc_state = MOTORWAIT;
1085 /* allow .5s for motor to stabilize */
1086 callout_reset(&fd->sc_motoron_ch, hz / 2,
1087 fd_motor_on, fd);
1088 return 1;
1090 /* Make sure the right drive is selected. */
1091 fd_set_motor(fdc, 0);
1093 /* fall through */
1094 case DOSEEK:
1095 doseek:
1096 DPRINTF(("fdcintr: in DOSEEK\n"));
1097 if (fd->sc_cylin == bp->b_cylinder)
1098 goto doio;
1100 out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
1101 out_fdc(iot, ioh, 0xd0); /* XXX const */
1102 out_fdc(iot, ioh, 0x10);
1104 out_fdc(iot, ioh, NE7CMD_SEEK); /* seek function */
1105 out_fdc(iot, ioh, fd->sc_drive); /* drive number */
1106 out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step);
1108 fd->sc_cylin = -1;
1109 fdc->sc_state = SEEKWAIT;
1111 iostat_seek(fd->sc_dk.dk_stats);
1112 disk_busy(&fd->sc_dk);
1114 callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
1115 return 1;
1117 case DOIO:
1118 doio:
1119 DPRINTF(("fdcintr: DOIO: "));
1120 type = fd->sc_type;
1121 sectrac = type->sectrac;
1122 pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
1123 sec = pos / (1 << (type->secsize - 2));
1124 if (type->secsize == 2) {
1125 fd->sc_part = SEC_P11;
1126 nblks = (sectrac - sec) << (type->secsize - 2);
1127 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
1128 DPRINTF(("nblks(0)"));
1129 } else if ((fd->sc_blkno % 2) == 0) {
1130 if (fd->sc_bcount & 0x00000200) {
1131 if (fd->sc_bcount == FDC_BSIZE) {
1132 fd->sc_part = SEC_P10;
1133 nblks = 1;
1134 DPRINTF(("nblks(1)"));
1135 } else {
1136 fd->sc_part = SEC_P11;
1137 nblks = (sectrac - sec) * 2;
1138 nblks = min(nblks, fd->sc_bcount
1139 / FDC_BSIZE - 1);
1140 DPRINTF(("nblks(2)"));
1142 } else {
1143 fd->sc_part = SEC_P11;
1144 nblks = (sectrac - sec)
1145 << (type->secsize - 2);
1146 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
1147 DPRINTF(("nblks(3)"));
1149 } else {
1150 fd->sc_part = SEC_P01;
1151 nblks = 1;
1152 DPRINTF(("nblks(4)"));
1154 nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
1155 DPRINTF((" %d\n", nblks));
1156 fd->sc_nblks = nblks;
1157 fd->sc_nbytes = nblks * FDC_BSIZE;
1158 head = (fd->sc_blkno
1159 % (type->seccyl * (1 << (type->secsize - 2))))
1160 / (type->sectrac * (1 << (type->secsize - 2)));
1162 #ifdef DIAGNOSTIC
1163 {int block;
1164 block = ((fd->sc_cylin * type->heads + head) * type->sectrac
1165 + sec) * (1 << (type->secsize - 2));
1166 block += (fd->sc_part == SEC_P01) ? 1 : 0;
1167 if (block != fd->sc_blkno) {
1168 printf("C H R N: %d %d %d %d\n",
1169 fd->sc_cylin, head, sec, type->secsize);
1170 printf("fdcintr: doio: block %d != blkno %" PRId64 "\n",
1171 block, fd->sc_blkno);
1172 #ifdef DDB
1173 Debugger();
1174 #endif
1177 #endif
1178 read = bp->b_flags & B_READ;
1179 DPRINTF(("fdcintr: %s drive %d track %d "
1180 "head %d sec %d nblks %d, skip %d\n",
1181 read ? "read" : "write", fd->sc_drive, fd->sc_cylin,
1182 head, sec, nblks, fd->sc_skip));
1183 DPRINTF(("C H R N: %d %d %d %d\n", fd->sc_cylin, head, sec,
1184 type->secsize));
1186 if (fd->sc_part != SEC_P11)
1187 goto docopy;
1189 fdc_dmastart(fdc, read, (char *)bp->b_data + fd->sc_skip,
1190 fd->sc_nbytes);
1191 if (read)
1192 out_fdc(iot, ioh, NE7CMD_READ); /* READ */
1193 else
1194 out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
1195 out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1196 out_fdc(iot, ioh, bp->b_cylinder); /* cylinder */
1197 out_fdc(iot, ioh, head);
1198 out_fdc(iot, ioh, sec + 1); /* sector +1 */
1199 out_fdc(iot, ioh, type->secsize); /* sector size */
1200 out_fdc(iot, ioh, type->sectrac); /* sectors/track */
1201 out_fdc(iot, ioh, type->gap1); /* gap1 size */
1202 out_fdc(iot, ioh, type->datalen); /* data length */
1203 fdc->sc_state = IOCOMPLETE;
1205 disk_busy(&fd->sc_dk);
1207 /* allow 2 seconds for operation */
1208 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1209 return 1; /* will return later */
1211 case DOCOPY:
1212 docopy:
1213 DPRINTF(("fdcintr: DOCOPY:\n"));
1214 type = fd->sc_type;
1215 head = (fd->sc_blkno
1216 % (type->seccyl * (1 << (type->secsize - 2))))
1217 / (type->sectrac * (1 << (type->secsize - 2)));
1218 pos = fd->sc_blkno % (type->sectrac * (1 << (type->secsize - 2)));
1219 sec = pos / (1 << (type->secsize - 2));
1220 fdc_dmastart(fdc, B_READ, fd->sc_copybuf, 1024);
1221 out_fdc(iot, ioh, NE7CMD_READ); /* READ */
1222 out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1223 out_fdc(iot, ioh, bp->b_cylinder); /* cylinder */
1224 out_fdc(iot, ioh, head);
1225 out_fdc(iot, ioh, sec + 1); /* sector +1 */
1226 out_fdc(iot, ioh, type->secsize); /* sector size */
1227 out_fdc(iot, ioh, type->sectrac); /* sectors/track */
1228 out_fdc(iot, ioh, type->gap1); /* gap1 size */
1229 out_fdc(iot, ioh, type->datalen); /* data length */
1230 fdc->sc_state = COPYCOMPLETE;
1231 /* allow 2 seconds for operation */
1232 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1233 return 1; /* will return later */
1235 case DOIOHALF:
1236 doiohalf:
1237 DPRINTF((" DOIOHALF:\n"));
1239 type = fd->sc_type;
1240 sectrac = type->sectrac;
1241 pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
1242 sec = pos / (1 << (type->secsize - 2));
1243 head = (fd->sc_blkno
1244 % (type->seccyl * (1 << (type->secsize - 2))))
1245 / (type->sectrac * (1 << (type->secsize - 2)));
1246 #ifdef DIAGNOSTIC
1247 {int block;
1248 block = ((fd->sc_cylin * type->heads + head) *
1249 type->sectrac + sec)
1250 * (1 << (type->secsize - 2));
1251 block += (fd->sc_part == SEC_P01) ? 1 : 0;
1252 if (block != fd->sc_blkno) {
1253 printf("fdcintr: block %d != blkno %" PRId64 "\n",
1254 block, fd->sc_blkno);
1255 #ifdef DDB
1256 Debugger();
1257 #endif
1260 #endif
1261 if ((read = bp->b_flags & B_READ)) {
1262 memcpy((char *)bp->b_data + fd->sc_skip, fd->sc_copybuf
1263 + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0),
1264 FDC_BSIZE);
1265 fdc->sc_state = IOCOMPLETE;
1266 goto iocomplete2;
1267 } else {
1268 memcpy((char *)fd->sc_copybuf
1269 + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0),
1270 (char *)bp->b_data + fd->sc_skip, FDC_BSIZE);
1271 fdc_dmastart(fdc, read, fd->sc_copybuf, 1024);
1273 out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
1274 out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1275 out_fdc(iot, ioh, bp->b_cylinder); /* cylinder */
1276 out_fdc(iot, ioh, head);
1277 out_fdc(iot, ioh, sec + 1); /* sector +1 */
1278 out_fdc(iot, ioh, fd->sc_type->secsize); /* sector size */
1279 out_fdc(iot, ioh, sectrac); /* sectors/track */
1280 out_fdc(iot, ioh, fd->sc_type->gap1); /* gap1 size */
1281 out_fdc(iot, ioh, fd->sc_type->datalen); /* data length */
1282 fdc->sc_state = IOCOMPLETE;
1283 /* allow 2 seconds for operation */
1284 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1285 return 1; /* will return later */
1287 case SEEKWAIT:
1288 callout_stop(&fdc->sc_timo_ch);
1289 fdc->sc_state = SEEKCOMPLETE;
1290 /* allow 1/50 second for heads to settle */
1291 #if 0
1292 callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc);
1293 #endif
1294 return 1;
1296 case SEEKCOMPLETE:
1297 /* Make sure seek really happened */
1298 DPRINTF(("fdcintr: SEEKCOMPLETE: FDC status = %x\n",
1299 bus_space_read_1(fdc->sc_iot, fdc->sc_ioh, fdsts)));
1300 out_fdc(iot, ioh, NE7CMD_SENSEI);
1301 tmp = fdcresult(fdc);
1302 if ((st0 & 0xf8) == 0xc0) {
1303 DPRINTF(("fdcintr: first seek!\n"));
1304 fdc->sc_state = DORECAL;
1305 goto loop;
1306 } else if (tmp != 2 ||
1307 (st0 & 0xf8) != 0x20 ||
1308 cyl != bp->b_cylinder) {
1309 #ifdef FDDEBUG
1310 fdcstatus(fd->sc_dev, 2, "seek failed");
1311 #endif
1312 fdcretry(fdc);
1313 goto loop;
1315 fd->sc_cylin = bp->b_cylinder;
1316 goto doio;
1318 case IOTIMEDOUT:
1319 #if 0
1320 isa_dmaabort(fdc->sc_drq);
1321 #endif
1322 case SEEKTIMEDOUT:
1323 case RECALTIMEDOUT:
1324 case RESETTIMEDOUT:
1325 fdcretry(fdc);
1326 goto loop;
1328 case IOCOMPLETE: /* IO DONE, post-analyze */
1329 callout_stop(&fdc->sc_timo_ch);
1330 DPRINTF(("fdcintr: in IOCOMPLETE\n"));
1331 if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
1332 #if 0
1333 isa_dmaabort(fdc->sc_drq);
1334 #endif
1335 fdcstatus(fd->sc_dev, tmp, bp->b_flags & B_READ ?
1336 "read failed" : "write failed");
1337 printf("blkno %" PRId64 " nblks %d\n",
1338 fd->sc_blkno, fd->sc_nblks);
1339 fdcretry(fdc);
1340 goto loop;
1342 #if 0
1343 isa_dmadone(bp->b_flags & B_READ, bp->b_data + fd->sc_skip,
1344 nblks * FDC_BSIZE, fdc->sc_drq);
1345 #endif
1346 iocomplete2:
1347 if (fdc->sc_errors) {
1348 diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF,
1349 fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
1350 printf("\n");
1351 fdc->sc_errors = 0;
1353 fd->sc_blkno += fd->sc_nblks;
1354 fd->sc_skip += fd->sc_nbytes;
1355 fd->sc_bcount -= fd->sc_nbytes;
1356 DPRINTF(("fd->sc_bcount = %d\n", fd->sc_bcount));
1357 if (fd->sc_bcount > 0) {
1358 bp->b_cylinder = fd->sc_blkno
1359 / (fd->sc_type->seccyl
1360 * (1 << (fd->sc_type->secsize - 2)));
1361 goto doseek;
1363 fdfinish(fd, bp);
1364 goto loop;
1366 case COPYCOMPLETE: /* IO DONE, post-analyze */
1367 DPRINTF(("fdcintr: COPYCOMPLETE:"));
1368 callout_stop(&fdc->sc_timo_ch);
1369 if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
1370 printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0);
1371 #if 0
1372 isa_dmaabort(fdc->sc_drq);
1373 #endif
1374 fdcstatus(fd->sc_dev, 7, bp->b_flags & B_READ ?
1375 "read failed" : "write failed");
1376 printf("blkno %" PRId64 " nblks %d\n",
1377 fd->sc_blkno, fd->sc_nblks);
1378 fdcretry(fdc);
1379 goto loop;
1381 goto doiohalf;
1383 case DORESET:
1384 DPRINTF(("fdcintr: in DORESET\n"));
1385 /* try a reset, keep motor on */
1386 fd_set_motor(fdc, 1);
1387 DELAY(100);
1388 fd_set_motor(fdc, 0);
1389 fdc->sc_state = RESETCOMPLETE;
1390 callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc);
1391 return 1; /* will return later */
1393 case RESETCOMPLETE:
1394 DPRINTF(("fdcintr: in RESETCOMPLETE\n"));
1395 callout_stop(&fdc->sc_timo_ch);
1396 /* clear the controller output buffer */
1397 for (i = 0; i < 4; i++) {
1398 out_fdc(iot, ioh, NE7CMD_SENSEI);
1399 (void) fdcresult(fdc);
1402 /* fall through */
1403 case DORECAL:
1404 DPRINTF(("fdcintr: in DORECAL\n"));
1405 out_fdc(iot, ioh, NE7CMD_RECAL); /* recalibrate function */
1406 out_fdc(iot, ioh, fd->sc_drive);
1407 fdc->sc_state = RECALWAIT;
1408 callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc);
1409 return 1; /* will return later */
1411 case RECALWAIT:
1412 DPRINTF(("fdcintr: in RECALWAIT\n"));
1413 callout_stop(&fdc->sc_timo_ch);
1414 fdc->sc_state = RECALCOMPLETE;
1415 /* allow 1/30 second for heads to settle */
1416 #if 0
1417 callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc);
1418 #endif
1419 return 1; /* will return later */
1421 case RECALCOMPLETE:
1422 DPRINTF(("fdcintr: in RECALCOMPLETE\n"));
1423 out_fdc(iot, ioh, NE7CMD_SENSEI);
1424 tmp = fdcresult(fdc);
1425 if ((st0 & 0xf8) == 0xc0) {
1426 DPRINTF(("fdcintr: first seek!\n"));
1427 fdc->sc_state = DORECAL;
1428 goto loop;
1429 } else if (tmp != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
1430 #ifdef FDDEBUG
1431 fdcstatus(fd->sc_dev, 2, "recalibrate failed");
1432 #endif
1433 fdcretry(fdc);
1434 goto loop;
1436 fd->sc_cylin = 0;
1437 goto doseek;
1439 case MOTORWAIT:
1440 if (fd->sc_flags & FD_MOTOR_WAIT)
1441 return 1; /* time's not up yet */
1442 goto doseek;
1444 default:
1445 fdcstatus(fd->sc_dev, 0, "stray interrupt");
1446 return 1;
1448 #ifdef DIAGNOSTIC
1449 panic("fdcintr: impossible");
1450 #endif
1451 #undef st0
1452 #undef cyl
1455 void
1456 fdcretry(struct fdc_softc *fdc)
1458 struct fd_softc *fd;
1459 struct buf *bp;
1461 DPRINTF(("fdcretry:\n"));
1462 fd = TAILQ_FIRST(&fdc->sc_drives);
1463 bp = bufq_peek(fd->sc_q);
1465 switch (fdc->sc_errors) {
1466 case 0:
1467 /* try again */
1468 fdc->sc_state = SEEKCOMPLETE;
1469 break;
1471 case 1: case 2: case 3:
1472 /* didn't work; try recalibrating */
1473 fdc->sc_state = DORECAL;
1474 break;
1476 case 4:
1477 /* still no go; reset the bastard */
1478 fdc->sc_state = DORESET;
1479 break;
1481 default:
1482 diskerr(bp, "fd", "hard error", LOG_PRINTF,
1483 fd->sc_skip, (struct disklabel *)NULL);
1484 fdcpstatus(7, fdc);
1486 bp->b_error = EIO;
1487 fdfinish(fd, bp);
1489 fdc->sc_errors++;
1493 fdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
1495 struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(dev));
1496 struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
1497 int part = DISKPART(dev);
1498 struct disklabel buffer;
1499 int error;
1501 DPRINTF(("fdioctl:"));
1502 switch (cmd) {
1503 case DIOCGDINFO:
1504 DPRINTF(("DIOCGDINFO\n"));
1505 #if 1
1506 *(struct disklabel *)addr = *(fd->sc_dk.dk_label);
1507 return(0);
1508 #else
1509 memset(&buffer, 0, sizeof(buffer));
1511 buffer.d_secpercyl = fd->sc_type->seccyl;
1512 buffer.d_type = DTYPE_FLOPPY;
1513 buffer.d_secsize = 128 << fd->sc_type->secsize;
1515 if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL)
1516 return EINVAL;
1518 *(struct disklabel *)addr = buffer;
1519 return 0;
1520 #endif
1522 case DIOCGPART:
1523 DPRINTF(("DIOCGPART\n"));
1524 ((struct partinfo *)addr)->disklab = fd->sc_dk.dk_label;
1525 ((struct partinfo *)addr)->part =
1526 &fd->sc_dk.dk_label->d_partitions[part];
1527 return(0);
1529 case DIOCWLABEL:
1530 DPRINTF(("DIOCWLABEL\n"));
1531 if ((flag & FWRITE) == 0)
1532 return EBADF;
1533 /* XXX do something */
1534 return 0;
1536 case DIOCWDINFO:
1537 DPRINTF(("DIOCWDINFO\n"));
1538 if ((flag & FWRITE) == 0)
1539 return EBADF;
1541 error = setdisklabel(&buffer, (struct disklabel *)addr,
1542 0, NULL);
1543 if (error)
1544 return error;
1546 error = writedisklabel(dev, fdstrategy, &buffer, NULL);
1547 return error;
1549 case DIOCLOCK:
1551 * Nothing to do here, really.
1553 return 0; /* XXX */
1555 case DIOCEJECT:
1556 DPRINTF(("DIOCEJECT\n"));
1557 if (*(int *)addr == 0) {
1559 * Don't force eject: check that we are the only
1560 * partition open. If so, unlock it.
1562 if ((fd->sc_dk.dk_openmask & ~(1 << part)) != 0 ||
1563 fd->sc_dk.dk_bopenmask + fd->sc_dk.dk_copenmask !=
1564 fd->sc_dk.dk_openmask) {
1565 return (EBUSY);
1568 /* FALLTHROUGH */
1569 case ODIOCEJECT:
1570 DPRINTF(("ODIOCEJECT\n"));
1571 fd_do_eject(fdc, FDUNIT(dev));
1572 return 0;
1574 default:
1575 return ENOTTY;
1578 #ifdef DIAGNOSTIC
1579 panic("fdioctl: impossible");
1580 #endif
1583 void
1584 fd_do_eject(struct fdc_softc *fdc, int unit)
1586 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
1587 0x20 | ( 1 << unit));
1588 DELAY(1); /* XXX */
1589 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0x20);
1593 * Build disk label. For now we only create a label from what we know
1594 * from 'sc'.
1596 static int
1597 fdgetdisklabel(struct fd_softc *sc, dev_t dev)
1599 struct disklabel *lp;
1600 int part;
1602 DPRINTF(("fdgetdisklabel()\n"));
1604 part = DISKPART(dev);
1605 lp = sc->sc_dk.dk_label;
1606 memset(lp, 0, sizeof(struct disklabel));
1608 lp->d_secsize = 128 << sc->sc_type->secsize;
1609 lp->d_ntracks = sc->sc_type->heads;
1610 lp->d_nsectors = sc->sc_type->sectrac;
1611 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
1612 lp->d_ncylinders = sc->sc_type->size / lp->d_secpercyl;
1613 lp->d_secperunit = sc->sc_type->size;
1615 lp->d_type = DTYPE_FLOPPY;
1616 lp->d_rpm = 300; /* XXX */
1617 lp->d_interleave = 1; /* FIXME: is this OK? */
1618 lp->d_bbsize = 0;
1619 lp->d_sbsize = 0;
1620 lp->d_npartitions = part + 1;
1621 #define STEP_DELAY 6000 /* 6ms (6000us) delay after stepping */
1622 lp->d_trkseek = STEP_DELAY; /* XXX */
1623 lp->d_magic = DISKMAGIC;
1624 lp->d_magic2 = DISKMAGIC;
1625 lp->d_checksum = dkcksum(lp);
1626 lp->d_partitions[part].p_size = lp->d_secperunit;
1627 lp->d_partitions[part].p_fstype = FS_UNUSED;
1628 lp->d_partitions[part].p_fsize = 1024;
1629 lp->d_partitions[part].p_frag = 8;
1631 return(0);
1635 * Mountroot hook: prompt the user to enter the root file system
1636 * floppy.
1638 void
1639 fd_mountroot_hook(device_t dev)
1641 struct fd_softc *fd = device_private(dev);
1642 struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
1643 int c;
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;