Sync usage with man page.
[netbsd-mini2440.git] / sys / arch / acorn32 / mainbus / fd.c
bloba88f879a91ce6152ec8d8c4ccf6633daab36da51
1 /* $NetBSD: fd.c,v 1.45 2009/03/14 21:04:01 dsl 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.
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
64 * from: fd.c,v 1.104 1997/01/09 04:30:08 mycroft Exp
68 * Floppy formatting facilities merged from FreeBSD fd.c driver:
69 * Id: fd.c,v 1.53 1995/03/12 22:40:56 joerg Exp
70 * which carries the same copyright/redistribution notice as shown above with
71 * the addition of the following statement before the "Redistribution and
72 * use ..." clause:
74 * Copyright (c) 1993, 1994 by
75 * jc@irbs.UUCP (John Capo)
76 * vak@zebub.msk.su (Serge Vakulenko)
77 * ache@astral.msk.su (Andrew A. Chernov)
79 * Copyright (c) 1993, 1994, 1995 by
80 * joerg_wunsch@uriah.sax.de (Joerg Wunsch)
81 * dufault@hda.com (Peter Dufault)
84 #include <sys/cdefs.h>
85 __KERNEL_RCSID(0, "$NetBSD: fd.c,v 1.45 2009/03/14 21:04:01 dsl Exp $");
87 #include "opt_ddb.h"
89 #include <sys/param.h>
90 #include <sys/systm.h>
91 #include <sys/callout.h>
92 #include <sys/kernel.h>
93 #include <sys/file.h>
94 #include <sys/ioctl.h>
95 #include <sys/device.h>
96 #include <sys/disklabel.h>
97 #include <sys/disk.h>
98 #include <sys/buf.h>
99 #include <sys/bufq.h>
100 #include <sys/malloc.h>
101 #include <sys/uio.h>
102 #include <sys/syslog.h>
103 #include <sys/queue.h>
104 #include <sys/proc.h>
105 #include <sys/fdio.h>
106 #include <sys/conf.h>
108 #include <uvm/uvm_extern.h>
110 #include <arm/fiq.h>
112 #include <machine/cpu.h>
113 #include <machine/intr.h>
114 #include <machine/io.h>
115 #include <arm/arm32/katelib.h>
116 #include <machine/bus.h>
118 #include <arm/iomd/iomdreg.h>
119 #include <arm/iomd/iomdvar.h>
121 #include <acorn32/mainbus/piocvar.h>
122 #include <acorn32/mainbus/fdreg.h>
124 #include "locators.h"
126 #define NE7CMD_CONFIGURE 0x13
128 #define FDUNIT(dev) (minor(dev) / 8)
129 #define FDTYPE(dev) (minor(dev) % 8)
131 /* (mis)use device use flag to identify format operation */
132 #define B_FORMAT B_DEVPRIVATE
134 enum fdc_state {
135 DEVIDLE = 0,
136 MOTORWAIT,
137 DOSEEK,
138 SEEKWAIT,
139 SEEKTIMEDOUT,
140 SEEKCOMPLETE,
141 DOIO,
142 IOCOMPLETE,
143 IOTIMEDOUT,
144 DORESET,
145 RESETCOMPLETE,
146 RESETTIMEDOUT,
147 DORECAL,
148 RECALWAIT,
149 RECALTIMEDOUT,
150 RECALCOMPLETE,
153 /* software state, per controller */
154 struct fdc_softc {
155 struct device sc_dev; /* boilerplate */
156 void *sc_ih;
158 bus_space_tag_t sc_iot; /* ISA i/o space identifier */
159 bus_space_handle_t sc_ioh; /* ISA io handle */
161 struct callout sc_timo_ch; /* timeout callout */
162 struct callout sc_intr_ch; /* pseudo-intr callout */
164 /* ...for pseudo-DMA... */
165 struct fiqhandler sc_fh; /* FIQ handler descriptor */
166 struct fiqregs sc_fr; /* FIQ handler reg context */
167 int sc_drq;
169 struct fd_softc *sc_fd[4]; /* pointers to children */
170 TAILQ_HEAD(drivehead, fd_softc) sc_drives;
171 enum fdc_state sc_state;
172 int sc_errors; /* number of retries so far */
173 u_char sc_status[7]; /* copy of registers */
176 /* controller driver configuration */
177 int fdcprobe(struct device *, struct cfdata *, void *);
178 int fdprint(void *, const char *);
179 void fdcattach(struct device *, struct device *, void *);
181 CFATTACH_DECL(fdc, sizeof(struct fdc_softc),
182 fdcprobe, fdcattach, NULL, NULL);
185 * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how
186 * we tell them apart.
188 struct fd_type {
189 int sectrac; /* sectors per track */
190 int heads; /* number of heads */
191 int seccyl; /* sectors per cylinder */
192 int secsize; /* size code for sectors */
193 int datalen; /* data len when secsize = 0 */
194 int steprate; /* step rate and head unload time */
195 int gap1; /* gap len between sectors */
196 int gap2; /* formatting gap */
197 int cyls; /* total num of cylinders */
198 int size; /* size of disk in sectors */
199 int step; /* steps per cylinder */
200 int rate; /* transfer speed code */
201 u_char fillbyte; /* format fill byte */
202 u_char interleave; /* interleave factor (formatting) */
203 const char *name;
206 /* The order of entries in the following table is important -- BEWARE! */
207 struct fd_type fd_types[] = {
208 { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS,0xf6,1, "1.44MB" }, /* 1.44MB diskette */
209 { 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS,0xf6,1, "1.2MB" }, /* 1.2 MB AT-diskettes */
210 { 9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS,0xf6,1, "360KB/AT" }, /* 360kB in 1.2MB drive */
211 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS,0xf6,1, "360KB/PC" }, /* 360kB PC diskettes */
212 { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS,0xf6,1, "720KB" }, /* 3.5" 720kB diskette */
213 { 9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS,0xf6,1, "720KB/x" }, /* 720kB in 1.2MB drive */
214 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS,0xf6,1, "360KB/x" }, /* 360kB in 720kB drive */
217 /* software state, per disk (with up to 4 disks per ctlr) */
218 struct fd_softc {
219 struct device sc_dev;
220 struct disk sc_dk;
222 struct fd_type *sc_deftype; /* default type descriptor */
223 struct fd_type *sc_type; /* current type descriptor */
224 struct fd_type sc_type_copy; /* copy for fiddling when formatting */
226 struct callout sc_motoron_ch;
227 struct callout sc_motoroff_ch;
229 daddr_t sc_blkno; /* starting block number */
230 int sc_bcount; /* byte count left */
231 int sc_opts; /* user-set options */
232 int sc_skip; /* bytes already transferred */
233 int sc_nblks; /* number of blocks currently transferring */
234 int sc_nbytes; /* number of bytes currently transferring */
236 int sc_drive; /* physical unit number */
237 int sc_flags;
238 #define FD_OPEN 0x01 /* it's open */
239 #define FD_MOTOR 0x02 /* motor should be on */
240 #define FD_MOTOR_WAIT 0x04 /* motor coming up */
241 int sc_cylin; /* where we think the head is */
243 void *sc_sdhook; /* saved shutdown hook for drive. */
245 TAILQ_ENTRY(fd_softc) sc_drivechain;
246 int sc_ops; /* I/O ops since last switch */
247 struct bufq_state *sc_q;/* pending I/O requests */
248 int sc_active; /* number of active I/O operations */
251 /* floppy driver configuration */
252 int fdprobe(struct device *, struct cfdata *, void *);
253 void fdattach(struct device *, struct device *, void *);
255 extern char floppy_read_fiq[], floppy_read_fiq_end[];
256 extern char floppy_write_fiq[], floppy_write_fiq_end[];
258 CFATTACH_DECL(fd, sizeof(struct fd_softc),
259 fdprobe, fdattach, NULL, NULL);
261 extern struct cfdriver fd_cd;
263 dev_type_open(fdopen);
264 dev_type_close(fdclose);
265 dev_type_read(fdread);
266 dev_type_write(fdwrite);
267 dev_type_ioctl(fdioctl);
268 dev_type_strategy(fdstrategy);
270 const struct bdevsw fd_bdevsw = {
271 fdopen, fdclose, fdstrategy, fdioctl, nodump, nosize, D_DISK
274 const struct cdevsw fd_cdevsw = {
275 fdopen, fdclose, fdread, fdwrite, fdioctl,
276 nostop, notty, nopoll, nommap, nokqfilter, D_DISK
279 void fdgetdisklabel(struct fd_softc *);
280 int fd_get_parms(struct fd_softc *);
281 void fdstart(struct fd_softc *);
283 struct dkdriver fddkdriver = { fdstrategy };
285 struct fd_type *fd_nvtotype(const char *, int, int);
286 void fd_set_motor(struct fdc_softc *fdc, int reset);
287 void fd_motor_off(void *arg);
288 void fd_motor_on(void *arg);
289 int fdcresult(struct fdc_softc *fdc);
290 int out_fdc(bus_space_tag_t iot, bus_space_handle_t ioh, u_char x);
291 void fdcstart(struct fdc_softc *fdc);
292 void fdcstatus(struct device *dv, int n, const char *s);
293 void fdctimeout(void *arg);
294 void fdcpseudointr(void *arg);
295 int fdcintr(void *);
296 void fdcretry(struct fdc_softc *fdc);
297 void fdfinish(struct fd_softc *fd, struct buf *bp);
298 inline struct fd_type *fd_dev_to_type(struct fd_softc *, dev_t);
299 int fdformat(dev_t, struct ne7_fd_formb *, struct lwp *);
302 fdcprobe(struct device *parent, struct cfdata *cf, void *aux)
304 struct pioc_attach_args *pa = aux;
305 bus_space_tag_t iot;
306 bus_space_handle_t ioh;
307 int rv;
309 if (pa->pa_name && strcmp(pa->pa_name, "fdc") != 0)
310 return(0);
312 iot = pa->pa_iot;
313 rv = 0;
315 /* Map the i/o space. */
316 if (bus_space_map(iot, pa->pa_iobase + pa->pa_offset, FDC_NPORT, 0, &ioh))
317 return 0;
319 /* reset */
320 bus_space_write_2(iot, ioh, fdout, 0);
321 delay(100);
322 bus_space_write_2(iot, ioh, fdout, FDO_FRST);
324 /* see if it can handle a command */
325 if (out_fdc(iot, ioh, NE7CMD_SPECIFY) < 0)
326 goto out;
327 out_fdc(iot, ioh, 0xdf);
328 out_fdc(iot, ioh, 2);
330 rv = 1;
331 pa->pa_iosize = FDC_NPORT;
333 out:
334 bus_space_unmap(iot, ioh, FDC_NPORT);
335 return rv;
339 * Arguments passed between fdcattach and fdprobe.
341 struct fdc_attach_args {
342 int fa_drive;
343 struct fd_type *fa_deftype;
347 * Print the location of a disk drive (called just before attaching the
348 * the drive). If `fdc' is not NULL, the drive was found but was not
349 * in the system config file; print the drive name as well.
350 * Return QUIET (config_find ignores this if the device was configured) to
351 * avoid printing `fdN not configured' messages.
354 fdprint(void *aux, const char *fdc)
356 register struct fdc_attach_args *fa = aux;
358 if (!fdc)
359 aprint_normal(" drive %d", fa->fa_drive);
360 return QUIET;
363 void
364 fdcattach(struct device *parent, struct device *self, void *aux)
366 struct fdc_softc *fdc = (void *)self;
367 bus_space_tag_t iot;
368 bus_space_handle_t ioh;
369 struct pioc_attach_args *pa = aux;
370 struct fdc_attach_args fa;
371 int type;
373 iot = pa->pa_iot;
375 /* Re-map the I/O space. */
376 if (bus_space_map(iot, pa->pa_iobase + pa->pa_offset, FDC_NPORT, 0, &ioh))
377 panic("fdcattach: couldn't map I/O ports");
379 fdc->sc_iot = iot;
380 fdc->sc_ioh = ioh;
382 fdc->sc_drq = pa->pa_iobase + pa->pa_offset + pa->pa_drq;
383 fdc->sc_state = DEVIDLE;
384 TAILQ_INIT(&fdc->sc_drives);
386 printf("\n");
388 callout_init(&fdc->sc_timo_ch, 0);
389 callout_init(&fdc->sc_intr_ch, 0);
391 fdc->sc_ih = intr_claim(pa->pa_irq, IPL_BIO, "fdc",
392 fdcintr, fdc);
393 if (!fdc->sc_ih)
394 panic("%s: Cannot claim IRQ %d", self->dv_xname, pa->pa_irq);
396 #if 0
398 * The NVRAM info only tells us about the first two disks on the
399 * `primary' floppy controller.
401 if (device_unit(&fdc->sc_dev) == 0)
402 type = mc146818_read(NULL, NVRAM_DISKETTE); /* XXX softc */
403 else
404 type = -1;
405 #endif
406 type = 0x10; /* XXX - hardcoded for 1 floppy */
408 /* physical limit: four drives per controller. */
409 for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) {
410 if (type >= 0 && fa.fa_drive < 2)
411 fa.fa_deftype = fd_nvtotype(device_xname(&fdc->sc_dev),
412 type, fa.fa_drive);
413 else
414 fa.fa_deftype = NULL; /* unknown */
415 (void)config_found(self, (void *)&fa, fdprint);
420 fdprobe(struct device *parent, struct cfdata *cf, void *aux)
422 struct fdc_softc *fdc = (void *)parent;
423 struct fdc_attach_args *fa = aux;
424 int drive = fa->fa_drive;
425 bus_space_tag_t iot = fdc->sc_iot;
426 bus_space_handle_t ioh = fdc->sc_ioh;
427 int n;
429 if (cf->cf_loc[FDCCF_DRIVE] != FDCCF_DRIVE_DEFAULT
430 && cf->cf_loc[FDCCF_DRIVE] != drive)
431 return 0;
433 * XXX
434 * This is to work around some odd interactions between this driver
435 * and SMC Ethernet cards.
438 /* Don't need this for arm32 port but leave for the time being (it won't hurt) */
440 if (cf->cf_loc[FDCCF_DRIVE] == FDCCF_DRIVE_DEFAULT && drive >= 2)
441 return 0;
443 /* select drive and turn on motor */
444 bus_space_write_2(iot, ioh, fdout, drive | FDO_FRST | FDO_MOEN(drive));
445 /* wait for motor to spin up */
446 delay(250000);
447 out_fdc(iot, ioh, NE7CMD_RECAL);
448 out_fdc(iot, ioh, drive);
449 /* wait for recalibrate */
450 delay(2000000);
451 out_fdc(iot, ioh, NE7CMD_SENSEI);
452 n = fdcresult(fdc);
453 #ifdef FD_DEBUG
455 int i;
456 printf("fdprobe: status");
457 for (i = 0; i < n; i++)
458 printf(" %x", fdc->sc_status[i]);
459 printf("\n");
461 #endif
462 /* turn off motor */
463 bus_space_write_1(iot, ioh, fdout, FDO_FRST);
465 if (n != 2 || (fdc->sc_status[0] & 0xf8) != 0x20)
466 return 0;
468 return 1;
472 * Controller is working, and drive responded. Attach it.
474 void
475 fdattach(struct device *parent, struct device *self, void *aux)
477 struct fdc_softc *fdc = (void *)parent;
478 struct fd_softc *fd = (void *)self;
479 struct fdc_attach_args *fa = aux;
480 struct fd_type *type = fa->fa_deftype;
481 int drive = fa->fa_drive;
483 callout_init(&fd->sc_motoron_ch, 0);
484 callout_init(&fd->sc_motoroff_ch, 0);
486 /* XXX Allow `flags' to override device type? */
488 if (type)
489 printf(": %s %d cyl, %d head, %d sec\n", type->name,
490 type->cyls, type->heads, type->sectrac);
491 else
492 printf(": density unknown\n");
494 bufq_alloc(&fd->sc_q, "disksort", BUFQ_SORT_CYLINDER);
495 fd->sc_cylin = -1;
496 fd->sc_drive = drive;
497 fd->sc_deftype = type;
498 fdc->sc_fd[drive] = fd;
501 * Initialize and attach the disk structure.
503 disk_init(&fd->sc_dk, device_xname(&fd->sc_dev), &fddkdriver);
504 disk_attach(&fd->sc_dk);
506 /* Needed to power off if the motor is on when we halt. */
511 * Translate nvram type into internal data structure. Return NULL for
512 * none/unknown/unusable.
514 struct fd_type *
515 fd_nvtotype(const char *fdc, int nvraminfo, int drive)
517 int type;
519 type = (drive == 0 ? nvraminfo : nvraminfo << 4) & 0xf0;
520 switch (type) {
521 #ifndef RC7500
522 case 0x00 :
523 return NULL;
524 #else
525 case 0x00 :
526 #endif /* !RC7500 */
527 case 0x10 :
528 return &fd_types[0];
529 default:
530 printf("%s: drive %d: unknown device type 0x%x\n",
531 fdc, drive, type);
532 return NULL;
536 inline struct fd_type *
537 fd_dev_to_type(struct fd_softc *fd, dev_t dev)
539 int type = FDTYPE(dev);
541 if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
542 return NULL;
543 return type ? &fd_types[type - 1] : fd->sc_deftype;
546 void
547 fdstrategy(struct buf *bp)
549 struct fd_softc *fd = device_lookup_private(&fd_cd,FDUNIT(bp->b_dev));
550 int sz;
551 int s;
553 /* Valid unit, controller, and request? */
554 if (bp->b_blkno < 0 ||
555 ((bp->b_bcount % FDC_BSIZE) != 0 &&
556 (bp->b_flags & B_FORMAT) == 0)) {
557 bp->b_error = EINVAL;
558 goto done;
561 /* If it's a null transfer, return immediately. */
562 if (bp->b_bcount == 0)
563 goto done;
565 sz = howmany(bp->b_bcount, FDC_BSIZE);
567 if (bp->b_blkno + sz > fd->sc_type->size) {
568 sz = fd->sc_type->size - bp->b_blkno;
569 if (sz == 0) {
570 /* If exactly at end of disk, return EOF. */
571 goto done;
573 if (sz < 0) {
574 /* If past end of disk, return EINVAL. */
575 bp->b_error = EINVAL;
576 goto done;
578 /* Otherwise, truncate request. */
579 bp->b_bcount = sz << DEV_BSHIFT;
582 bp->b_rawblkno = bp->b_blkno;
583 bp->b_cylinder = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE) / fd->sc_type->seccyl;
585 #ifdef FD_DEBUG
586 printf("fdstrategy: b_blkno %d b_bcount %d blkno %d cylin %d sz %d\n",
587 bp->b_blkno, bp->b_bcount, fd->sc_blkno, bp->b_cylinder, sz);
588 #endif
590 /* Queue transfer on drive, activate drive and controller if idle. */
591 s = splbio();
592 bufq_put(fd->sc_q, bp);
593 callout_stop(&fd->sc_motoroff_ch); /* a good idea */
594 if (fd->sc_active == 0)
595 fdstart(fd);
596 #ifdef DIAGNOSTIC
597 else {
598 struct fdc_softc *fdc = (void *) device_parent(&fd->sc_dev);
599 if (fdc->sc_state == DEVIDLE) {
600 printf("fdstrategy: controller inactive\n");
601 fdcstart(fdc);
604 #endif
605 splx(s);
606 return;
608 done:
609 /* Toss transfer; we're done early. */
610 bp->b_resid = bp->b_bcount;
611 biodone(bp);
614 void
615 fdstart(struct fd_softc *fd)
617 struct fdc_softc *fdc = (void *) device_parent(&fd->sc_dev);
618 int active = fdc->sc_drives.tqh_first != 0;
620 /* Link into controller queue. */
621 fd->sc_active = 1;
622 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
624 /* If controller not already active, start it. */
625 if (!active)
626 fdcstart(fdc);
629 void
630 fdfinish(struct fd_softc *fd, struct buf *bp)
632 struct fdc_softc *fdc = (void *) device_parent(&fd->sc_dev);
635 * Move this drive to the end of the queue to give others a `fair'
636 * chance. We only force a switch if N operations are completed while
637 * another drive is waiting to be serviced, since there is a long motor
638 * startup delay whenever we switch.
640 (void)bufq_get(fd->sc_q);
641 if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) {
642 fd->sc_ops = 0;
643 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
644 if (bufq_peek(fd->sc_q) != NULL)
645 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
646 else
647 fd->sc_active = 0;
649 bp->b_resid = fd->sc_bcount;
650 fd->sc_skip = 0;
652 biodone(bp);
653 /* turn off motor 5s from now */
654 callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd);
655 fdc->sc_state = DEVIDLE;
659 fdread(dev_t dev, struct uio *uio, int flags)
662 return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
666 fdwrite(dev_t dev, struct uio *uio, int flags)
669 return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
672 void
673 fd_set_motor(struct fdc_softc *fdc, int reset)
675 struct fd_softc *fd;
676 u_char status;
677 int n;
679 if ((fd = fdc->sc_drives.tqh_first) != NULL)
680 status = fd->sc_drive;
681 else
682 status = 0;
683 if (!reset)
684 status |= FDO_FRST | FDO_FDMAEN;
685 for (n = 0; n < 4; n++)
686 if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR))
687 status |= FDO_MOEN(n);
688 bus_space_write_2(fdc->sc_iot, fdc->sc_ioh, fdout, status);
691 void
692 fd_motor_off(void *arg)
694 struct fd_softc *fd = arg;
695 int s;
697 s = splbio();
698 fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
699 fd_set_motor((struct fdc_softc *) device_parent(&fd->sc_dev), 0);
700 splx(s);
703 void
704 fd_motor_on(void *arg)
706 struct fd_softc *fd = arg;
707 struct fdc_softc *fdc = (void *) device_parent(&fd->sc_dev);
708 int s;
710 s = splbio();
711 fd->sc_flags &= ~FD_MOTOR_WAIT;
712 if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT))
713 (void) fdcintr(fdc);
714 splx(s);
718 fdcresult(struct fdc_softc *fdc)
720 bus_space_tag_t iot = fdc->sc_iot;
721 bus_space_handle_t ioh = fdc->sc_ioh;
722 u_char i;
723 int j = 100000,
724 n = 0;
726 for (; j; j--) {
727 i = bus_space_read_1(iot, ioh, fdsts) &
728 (NE7_DIO | NE7_RQM | NE7_CB);
729 if (i == NE7_RQM)
730 return n;
731 if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
732 if (n >= sizeof(fdc->sc_status)) {
733 log(LOG_ERR, "fdcresult: overrun\n");
734 return -1;
736 fdc->sc_status[n++] =
737 bus_space_read_1(iot, ioh, fddata);
739 delay(10);
741 log(LOG_ERR, "fdcresult: timeout\n");
742 return -1;
746 out_fdc(bus_space_tag_t iot, bus_space_handle_t ioh, u_char x)
748 int i = 100000;
750 while ((bus_space_read_1(iot, ioh, fdsts) & NE7_DIO) && i-- > 0);
751 if (i <= 0)
752 return -1;
753 while ((bus_space_read_1(iot, ioh, fdsts) & NE7_RQM) == 0 && i-- > 0);
754 if (i <= 0)
755 return -1;
756 bus_space_write_2(iot, ioh, fddata, x);
757 return 0;
761 fdopen(dev_t dev, int flags, int mode, struct lwp *l)
763 struct fd_softc *fd;
764 struct fd_type *type;
766 fd = device_lookup_private(&fd_cd, FDUNIT(dev));
767 if (fd == NULL)
768 return ENXIO;
769 type = fd_dev_to_type(fd, dev);
770 if (type == NULL)
771 return ENXIO;
773 if ((fd->sc_flags & FD_OPEN) != 0 &&
774 memcmp(fd->sc_type, type, sizeof(*type)))
775 return EBUSY;
777 fd->sc_type_copy = *type;
778 fd->sc_type = &fd->sc_type_copy;
779 fd->sc_cylin = -1;
780 fd->sc_flags |= FD_OPEN;
782 return 0;
786 fdclose(dev_t dev, int flags, int mode, struct lwp *l)
788 struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(dev));
790 fd->sc_flags &= ~FD_OPEN;
791 fd->sc_opts &= ~(FDOPT_NORETRY|FDOPT_SILENT);
792 return 0;
795 void
796 fdcstart(struct fdc_softc *fdc)
799 #ifdef DIAGNOSTIC
800 /* only got here if controller's drive queue was inactive; should
801 be in idle state */
802 if (fdc->sc_state != DEVIDLE) {
803 printf("fdcstart: not idle\n");
804 return;
806 #endif
807 (void) fdcintr(fdc);
810 static void
811 fdcpstatus(int n, struct fdc_softc *fdc)
813 char bits[64];
815 switch (n) {
816 case 0:
817 printf("\n");
818 break;
819 case 2:
820 snprintb(bits, sizeof(bits), NE7_ST0BITS, fdc->sc_status[0]);
821 printf(" (st0 %s cyl %d)\n", bits, fdc->sc_status[1]);
822 break;
823 case 7:
824 snprintb(bits, sizeof(bits), NE7_ST0BITS, fdc->sc_status[0]);
825 printf(" (st0 %s", bits);
826 snprintb(bits, sizeof(bits), NE7_ST1BITS, fdc->sc_status[1]);
827 printf(" st1 %s", bits);
828 snprintb(bits, sizeof(bits), NE7_ST2BITS, fdc->sc_status[2]);
829 printf(" st2 %s", bits);
830 printf(" cyl %d head %d sec %d)\n",
831 fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
832 break;
833 #ifdef DIAGNOSTIC
834 default:
835 printf("\nfdcstatus: weird size");
836 break;
837 #endif
841 void
842 fdcstatus(struct device *dv, int n, const char *s)
844 struct fdc_softc *fdc = (void *) device_parent(dv);
846 if (n == 0) {
847 out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
848 (void) fdcresult(fdc);
849 n = 2;
852 printf("%s: %s", device_xname(dv), s);
853 fdcpstatus(n, fdc);
856 void
857 fdctimeout(void *arg)
859 struct fdc_softc *fdc = arg;
860 struct fd_softc *fd = fdc->sc_drives.tqh_first;
861 int s;
863 s = splbio();
864 #ifdef DEBUG
865 log(LOG_ERR,"fdctimeout: state %d\n", fdc->sc_state);
866 #endif
867 fdcstatus(&fd->sc_dev, 0, "timeout");
869 if (bufq_peek(fd->sc_q) != NULL)
870 fdc->sc_state++;
871 else
872 fdc->sc_state = DEVIDLE;
874 (void) fdcintr(fdc);
875 splx(s);
878 void
879 fdcpseudointr(void *arg)
881 int s;
883 /* Just ensure it has the right spl. */
884 s = splbio();
885 (void) fdcintr(arg);
886 splx(s);
890 fdcintr(void *arg)
892 struct fdc_softc *fdc = arg;
893 #define st0 fdc->sc_status[0]
894 #define cyl fdc->sc_status[1]
895 struct fd_softc *fd;
896 struct buf *bp;
897 bus_space_tag_t iot = fdc->sc_iot;
898 bus_space_handle_t ioh = fdc->sc_ioh;
899 int read, head, sec, i, nblks;
900 struct fd_type *type;
901 struct ne7_fd_formb *finfo = NULL;
903 loop:
904 /* Is there a drive for the controller to do a transfer with? */
905 fd = fdc->sc_drives.tqh_first;
906 if (fd == NULL) {
907 fdc->sc_state = DEVIDLE;
908 return 1;
911 /* Is there a transfer to this drive? If not, deactivate drive. */
912 bp = bufq_peek(fd->sc_q);
913 if (bp == NULL) {
914 fd->sc_ops = 0;
915 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
916 fd->sc_active = 0;
917 goto loop;
920 if (bp->b_flags & B_FORMAT)
921 finfo = (struct ne7_fd_formb *)bp->b_data;
923 switch (fdc->sc_state) {
924 case DEVIDLE:
925 fdc->sc_errors = 0;
926 fd->sc_skip = 0;
927 fd->sc_bcount = bp->b_bcount;
928 fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
929 callout_stop(&fd->sc_motoroff_ch);
930 if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
931 fdc->sc_state = MOTORWAIT;
932 return 1;
934 if ((fd->sc_flags & FD_MOTOR) == 0) {
935 /* Turn on the motor, being careful about pairing. */
936 struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1];
937 if (ofd && ofd->sc_flags & FD_MOTOR) {
938 callout_stop(&ofd->sc_motoroff_ch);
939 ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
941 fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
942 fd_set_motor(fdc, 0);
943 fdc->sc_state = MOTORWAIT;
944 /* Allow .25s for motor to stabilize. */
945 callout_reset(&fd->sc_motoron_ch, hz / 4,
946 fd_motor_on, fd);
947 return 1;
949 /* Make sure the right drive is selected. */
950 fd_set_motor(fdc, 0);
952 /* fall through */
953 case DOSEEK:
954 doseek:
955 if (fd->sc_cylin == bp->b_cylinder)
956 goto doio;
958 #if 1
959 out_fdc(iot, ioh, NE7CMD_CONFIGURE);/* configure command */
960 out_fdc(iot, ioh, 0);
961 out_fdc(iot, ioh, 0x18);
962 out_fdc(iot, ioh, 0);
963 #endif
964 out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
965 out_fdc(iot, ioh, fd->sc_type->steprate);
966 out_fdc(iot, ioh, 6); /* XXX head load time == 6ms */
968 out_fdc(iot, ioh, NE7CMD_SEEK); /* seek function */
969 out_fdc(iot, ioh, fd->sc_drive); /* drive number */
970 out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step);
972 fd->sc_cylin = -1;
973 fdc->sc_state = SEEKWAIT;
975 iostat_seek(fd->sc_dk.dk_stats);
976 disk_busy(&fd->sc_dk);
978 callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
979 return 1;
981 case DOIO:
982 doio:
983 type = fd->sc_type;
984 if (finfo)
985 fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) -
986 (char *)finfo;
987 sec = fd->sc_blkno % type->seccyl;
988 nblks = type->seccyl - sec;
989 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
990 nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
991 fd->sc_nblks = nblks;
992 fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FDC_BSIZE;
993 head = sec / type->sectrac;
994 sec -= head * type->sectrac;
995 #ifdef DIAGNOSTIC
996 {daddr_t block;
997 block = (fd->sc_cylin * type->heads + head) * type->sectrac + sec;
998 if (block != fd->sc_blkno) {
999 printf("fdcintr: block %" PRId64
1000 " != blkno %" PRId64 "\n",
1001 block, fd->sc_blkno);
1002 #ifdef DDB
1003 Debugger();
1004 #endif
1006 #endif
1007 read = bp->b_flags & B_READ;
1008 if (read) {
1009 fdc->sc_fh.fh_func = floppy_read_fiq;
1010 fdc->sc_fh.fh_size = floppy_read_fiq_end -
1011 floppy_read_fiq;
1012 } else {
1013 fdc->sc_fh.fh_func = floppy_write_fiq;
1014 fdc->sc_fh.fh_size = floppy_read_fiq_end -
1015 floppy_read_fiq;
1017 fdc->sc_fh.fh_flags = 0;
1018 fdc->sc_fh.fh_regs = &fdc->sc_fr;
1019 fdc->sc_fr.fr_r9 = IOMD_BASE + (IOMD_FIQRQ << 2);
1020 fdc->sc_fr.fr_r10 = fd->sc_nbytes;
1021 fdc->sc_fr.fr_r11 =
1022 (u_int)((uintptr_t)bp->b_data + fd->sc_skip);
1023 fdc->sc_fr.fr_r12 = fdc->sc_drq;
1024 #ifdef FD_DEBUG
1025 printf("fdc-doio:r9=%x r10=%x r11=%x r12=%x data=%x skip=%x\n",
1026 fdc->sc_fr.fr_r9, fdc->sc_fr.fh_r10, fdc->sc_fr.fh_r11,
1027 fdc->sc_fr.fh_r12, (u_int)bp->b_data, fd->sc_skip);
1028 #endif
1029 if (fiq_claim(&fdc->sc_fh) == -1)
1030 panic("%s: Cannot claim FIQ vector", fdc->sc_dev.dv_xname);
1031 IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x01);
1032 bus_space_write_2(iot, ioh, fdctl, type->rate);
1033 #ifdef FD_DEBUG
1034 printf("fdcintr: %s drive %d track %d head %d sec %d nblks %d\n",
1035 read ? "read" : "write", fd->sc_drive, fd->sc_cylin,
1036 head, sec, nblks);
1037 #endif
1038 if (finfo) {
1039 /* formatting */
1040 if (out_fdc(iot, ioh, NE7CMD_FORMAT) < 0) {
1041 fdc->sc_errors = 4;
1042 fdcretry(fdc);
1043 goto loop;
1045 out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1046 out_fdc(iot, ioh, finfo->fd_formb_secshift);
1047 out_fdc(iot, ioh, finfo->fd_formb_nsecs);
1048 out_fdc(iot, ioh, finfo->fd_formb_gaplen);
1049 out_fdc(iot, ioh, finfo->fd_formb_fillbyte);
1050 } else {
1051 if (read)
1052 out_fdc(iot, ioh, NE7CMD_READ); /* READ */
1053 else
1054 out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
1055 out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1056 out_fdc(iot, ioh, fd->sc_cylin); /* track */
1057 out_fdc(iot, ioh, head);
1058 out_fdc(iot, ioh, sec + 1); /* sector +1 */
1059 out_fdc(iot, ioh, type->secsize);/* sector size */
1060 out_fdc(iot, ioh, type->sectrac);/* sectors/track */
1061 out_fdc(iot, ioh, type->gap1); /* gap1 size */
1062 out_fdc(iot, ioh, type->datalen);/* data length */
1064 fdc->sc_state = IOCOMPLETE;
1066 disk_busy(&fd->sc_dk);
1068 /* allow 2 seconds for operation */
1069 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1070 return 1; /* will return later */
1072 case SEEKWAIT:
1073 callout_stop(&fdc->sc_timo_ch);
1074 fdc->sc_state = SEEKCOMPLETE;
1075 /* allow 1/50 second for heads to settle */
1076 #if 0
1077 callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc);
1078 #endif
1079 return 1;
1081 case SEEKCOMPLETE:
1082 /* no data on seek */
1083 disk_unbusy(&fd->sc_dk, 0, 0);
1085 /* Make sure seek really happened. */
1086 out_fdc(iot, ioh, NE7CMD_SENSEI);
1087 if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 ||
1088 cyl != bp->b_cylinder * fd->sc_type->step) {
1089 #ifdef FD_DEBUG
1090 fdcstatus(&fd->sc_dev, 2, "seek failed");
1091 #endif
1092 fdcretry(fdc);
1093 goto loop;
1095 fd->sc_cylin = bp->b_cylinder;
1096 goto doio;
1098 case IOTIMEDOUT:
1099 fiq_release(&fdc->sc_fh);
1100 IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x00);
1101 case SEEKTIMEDOUT:
1102 case RECALTIMEDOUT:
1103 case RESETTIMEDOUT:
1104 fdcretry(fdc);
1105 goto loop;
1107 case IOCOMPLETE: /* IO DONE, post-analyze */
1108 callout_stop(&fdc->sc_timo_ch);
1110 disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid),
1111 (bp->b_flags & B_READ));
1113 if (fdcresult(fdc) != 7 || (st0 & 0xf8) != 0) {
1114 fiq_release(&fdc->sc_fh);
1115 IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x00);
1116 #ifdef FD_DEBUG
1117 fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
1118 "read failed" : "write failed");
1119 printf("blkno %d nblks %d\n",
1120 fd->sc_blkno, fd->sc_nblks);
1121 #endif
1122 fdcretry(fdc);
1123 goto loop;
1125 fiq_release(&fdc->sc_fh);
1126 IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x00);
1127 if (fdc->sc_errors) {
1128 #if 0
1129 diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF,
1130 fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
1131 printf("\n");
1132 #endif
1133 fdc->sc_errors = 0;
1135 fd->sc_blkno += fd->sc_nblks;
1136 fd->sc_skip += fd->sc_nbytes;
1137 fd->sc_bcount -= fd->sc_nbytes;
1138 if (!finfo && fd->sc_bcount > 0) {
1139 bp->b_cylinder = fd->sc_blkno / fd->sc_type->seccyl;
1140 goto doseek;
1142 fdfinish(fd, bp);
1143 goto loop;
1145 case DORESET:
1146 /* try a reset, keep motor on */
1147 fd_set_motor(fdc, 1);
1148 delay(100);
1149 fd_set_motor(fdc, 0);
1150 fdc->sc_state = RESETCOMPLETE;
1151 callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc);
1152 return 1; /* will return later */
1154 case RESETCOMPLETE:
1155 callout_stop(&fdc->sc_timo_ch);
1156 /* clear the controller output buffer */
1157 for (i = 0; i < 4; i++) {
1158 out_fdc(iot, ioh, NE7CMD_SENSEI);
1159 (void) fdcresult(fdc);
1162 /* fall through */
1163 case DORECAL:
1164 out_fdc(iot, ioh, NE7CMD_RECAL); /* recalibrate function */
1165 out_fdc(iot, ioh, fd->sc_drive);
1166 fdc->sc_state = RECALWAIT;
1167 callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc);
1168 return 1; /* will return later */
1170 case RECALWAIT:
1171 callout_stop(&fdc->sc_timo_ch);
1172 fdc->sc_state = RECALCOMPLETE;
1173 /* allow 1/30 second for heads to settle */
1174 #if 0
1175 callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc);
1176 #endif
1177 return 1; /* will return later */
1179 case RECALCOMPLETE:
1180 out_fdc(iot, ioh, NE7CMD_SENSEI);
1181 if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
1182 #ifdef FD_DEBUG
1183 fdcstatus(&fd->sc_dev, 2, "recalibrate failed");
1184 #endif
1185 fdcretry(fdc);
1186 goto loop;
1188 fd->sc_cylin = 0;
1189 goto doseek;
1191 case MOTORWAIT:
1192 if (fd->sc_flags & FD_MOTOR_WAIT)
1193 return 1; /* time's not up yet */
1194 goto doseek;
1196 default:
1197 fdcstatus(&fd->sc_dev, 0, "stray interrupt");
1198 return 1;
1200 #ifdef DIAGNOSTIC
1201 panic("fdcintr: impossible");
1202 #endif
1203 #undef st0
1204 #undef cyl
1207 void
1208 fdcretry(struct fdc_softc *fdc)
1210 struct fd_softc *fd;
1211 struct buf *bp;
1213 fd = fdc->sc_drives.tqh_first;
1214 bp = bufq_peek(fd->sc_q);
1216 if (fd->sc_opts & FDOPT_NORETRY)
1217 goto fail;
1218 switch (fdc->sc_errors) {
1219 case 0:
1220 /* try again */
1221 fdc->sc_state = DOSEEK;
1222 break;
1224 case 1: case 2: case 3:
1225 /* didn't work; try recalibrating */
1226 fdc->sc_state = DORECAL;
1227 break;
1229 case 4:
1230 /* still no go; reset the bastard */
1231 fdc->sc_state = DORESET;
1232 break;
1234 default:
1235 fail:
1236 if ((fd->sc_opts & FDOPT_SILENT) == 0) {
1237 diskerr(bp, "fd", "hard error", LOG_PRINTF,
1238 fd->sc_skip / FDC_BSIZE,
1239 (struct disklabel *)NULL);
1240 fdcpstatus(7, fdc);
1243 bp->b_error = EIO;
1244 fdfinish(fd, bp);
1246 fdc->sc_errors++;
1250 fdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
1252 struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(dev));
1253 struct fdformat_parms *form_parms;
1254 struct fdformat_cmd *form_cmd;
1255 struct ne7_fd_formb *fd_formb;
1256 struct disklabel buffer;
1257 int error;
1258 unsigned int scratch;
1259 int il[FD_MAX_NSEC + 1];
1260 register int i, j;
1262 switch (cmd) {
1263 case DIOCGDINFO:
1264 memset(&buffer, 0, sizeof(buffer));
1266 buffer.d_secpercyl = fd->sc_type->seccyl;
1267 buffer.d_type = DTYPE_FLOPPY;
1268 buffer.d_secsize = FDC_BSIZE;
1270 if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL)
1271 return EINVAL;
1273 *(struct disklabel *)addr = buffer;
1274 return 0;
1276 case DIOCWLABEL:
1277 if ((flag & FWRITE) == 0)
1278 return EBADF;
1279 /* XXX do something */
1280 return 0;
1282 case DIOCWDINFO:
1283 if ((flag & FWRITE) == 0)
1284 return EBADF;
1286 error = setdisklabel(&buffer, (struct disklabel *)addr, 0, NULL);
1287 if (error)
1288 return error;
1290 error = writedisklabel(dev, fdstrategy, &buffer, NULL);
1291 return error;
1293 case FDIOCGETFORMAT:
1294 form_parms = (struct fdformat_parms *)addr;
1295 form_parms->fdformat_version = FDFORMAT_VERSION;
1296 form_parms->nbps = 128 * (1 << fd->sc_type->secsize);
1297 form_parms->ncyl = fd->sc_type->cyls;
1298 form_parms->nspt = fd->sc_type->sectrac;
1299 form_parms->ntrk = fd->sc_type->heads;
1300 form_parms->stepspercyl = fd->sc_type->step;
1301 form_parms->gaplen = fd->sc_type->gap2;
1302 form_parms->fillbyte = fd->sc_type->fillbyte;
1303 form_parms->interleave = fd->sc_type->interleave;
1304 switch (fd->sc_type->rate) {
1305 case FDC_500KBPS:
1306 form_parms->xfer_rate = 500 * 1024;
1307 break;
1308 case FDC_300KBPS:
1309 form_parms->xfer_rate = 300 * 1024;
1310 break;
1311 case FDC_250KBPS:
1312 form_parms->xfer_rate = 250 * 1024;
1313 break;
1314 default:
1315 return EINVAL;
1317 return 0;
1319 case FDIOCSETFORMAT:
1320 if((flag & FWRITE) == 0)
1321 return EBADF; /* must be opened for writing */
1322 form_parms = (struct fdformat_parms *)addr;
1323 if (form_parms->fdformat_version != FDFORMAT_VERSION)
1324 return EINVAL; /* wrong version of formatting prog */
1326 scratch = form_parms->nbps >> 7;
1327 if ((form_parms->nbps & 0x7f) || ffs(scratch) == 0 ||
1328 scratch & ~(1 << (ffs(scratch)-1)))
1329 /* not a power-of-two multiple of 128 */
1330 return EINVAL;
1332 switch (form_parms->xfer_rate) {
1333 case 500 * 1024:
1334 fd->sc_type->rate = FDC_500KBPS;
1335 break;
1336 case 300 * 1024:
1337 fd->sc_type->rate = FDC_300KBPS;
1338 break;
1339 case 250 * 1024:
1340 fd->sc_type->rate = FDC_250KBPS;
1341 break;
1342 default:
1343 return EINVAL;
1346 if (form_parms->nspt > FD_MAX_NSEC ||
1347 form_parms->fillbyte > 0xff ||
1348 form_parms->interleave > 0xff)
1349 return EINVAL;
1350 fd->sc_type->sectrac = form_parms->nspt;
1351 if (form_parms->ntrk != 2 && form_parms->ntrk != 1)
1352 return EINVAL;
1353 fd->sc_type->heads = form_parms->ntrk;
1354 fd->sc_type->seccyl = form_parms->nspt * form_parms->ntrk;
1355 fd->sc_type->secsize = ffs(scratch)-1;
1356 fd->sc_type->gap2 = form_parms->gaplen;
1357 fd->sc_type->cyls = form_parms->ncyl;
1358 fd->sc_type->size = fd->sc_type->seccyl * form_parms->ncyl *
1359 form_parms->nbps / DEV_BSIZE;
1360 fd->sc_type->step = form_parms->stepspercyl;
1361 fd->sc_type->fillbyte = form_parms->fillbyte;
1362 fd->sc_type->interleave = form_parms->interleave;
1363 return 0;
1365 case FDIOCFORMAT_TRACK:
1366 if((flag & FWRITE) == 0)
1367 return EBADF; /* must be opened for writing */
1368 form_cmd = (struct fdformat_cmd *)addr;
1369 if (form_cmd->formatcmd_version != FDFORMAT_VERSION)
1370 return EINVAL; /* wrong version of formatting prog */
1372 if (form_cmd->head >= fd->sc_type->heads ||
1373 form_cmd->cylinder >= fd->sc_type->cyls) {
1374 return EINVAL;
1377 fd_formb = malloc(sizeof(struct ne7_fd_formb),
1378 M_TEMP, M_NOWAIT);
1379 if(fd_formb == 0)
1380 return ENOMEM;
1383 fd_formb->head = form_cmd->head;
1384 fd_formb->cyl = form_cmd->cylinder;
1385 fd_formb->transfer_rate = fd->sc_type->rate;
1386 fd_formb->fd_formb_secshift = fd->sc_type->secsize;
1387 fd_formb->fd_formb_nsecs = fd->sc_type->sectrac;
1388 fd_formb->fd_formb_gaplen = fd->sc_type->gap2;
1389 fd_formb->fd_formb_fillbyte = fd->sc_type->fillbyte;
1391 memset(il, 0, sizeof il);
1392 for (j = 0, i = 1; i <= fd_formb->fd_formb_nsecs; i++) {
1393 while (il[(j%fd_formb->fd_formb_nsecs)+1])
1394 j++;
1395 il[(j%fd_formb->fd_formb_nsecs)+1] = i;
1396 j += fd->sc_type->interleave;
1398 for (i = 0; i < fd_formb->fd_formb_nsecs; i++) {
1399 fd_formb->fd_formb_cylno(i) = form_cmd->cylinder;
1400 fd_formb->fd_formb_headno(i) = form_cmd->head;
1401 fd_formb->fd_formb_secno(i) = il[i+1];
1402 fd_formb->fd_formb_secsize(i) = fd->sc_type->secsize;
1405 error = fdformat(dev, fd_formb, l);
1406 free(fd_formb, M_TEMP);
1407 return error;
1409 case FDIOCGETOPTS: /* get drive options */
1410 *(int *)addr = fd->sc_opts;
1411 return 0;
1413 case FDIOCSETOPTS: /* set drive options */
1414 fd->sc_opts = *(int *)addr;
1415 return 0;
1417 default:
1418 return ENOTTY;
1421 #ifdef DIAGNOSTIC
1422 panic("fdioctl: impossible");
1423 #endif
1427 fdformat(dev_t dev, struct ne7_fd_formb *finfo, struct lwp *l)
1429 int rv = 0;
1430 struct fd_softc *fd = device_lookup_private(&fd_cd,FDUNIT(dev));
1431 struct fd_type *type = fd->sc_type;
1432 struct buf *bp;
1434 /* set up a buffer header for fdstrategy() */
1435 bp = getiobuf(NULL, false);
1436 if(bp == 0)
1437 return ENOBUFS;
1438 bp->b_flags = B_PHYS | B_FORMAT;
1439 bp->b_cflags |= BC_BUSY;
1440 bp->b_proc = l->l_proc;
1441 bp->b_dev = dev;
1444 * calculate a fake blkno, so fdstrategy() would initiate a
1445 * seek to the requested cylinder
1447 bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads)
1448 + finfo->head * type->sectrac) * FDC_BSIZE / DEV_BSIZE;
1450 bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
1451 bp->b_data = (void *)finfo;
1453 #ifdef DEBUG
1454 printf("fdformat: blkno %llx count %lx\n",
1455 (unsigned long long)bp->b_blkno, bp->b_bcount);
1456 #endif
1458 /* now do the format */
1459 fdstrategy(bp);
1461 /* ...and wait for it to complete */
1462 /* XXX very dodgy */
1463 mutex_enter(bp->b_objlock);
1464 while (!(bp->b_oflags & BO_DONE)) {
1465 rv = cv_timedwait(&bp->b_done, bp->b_objlock, 20 * hz);
1466 if (rv == EWOULDBLOCK)
1467 break;
1469 mutex_exit(bp->b_objlock);
1471 if (rv == EWOULDBLOCK) {
1472 /* timed out */
1473 rv = EIO;
1474 biodone(bp);
1475 } else if (bp->b_error != 0)
1476 rv = bp->b_error;
1477 putiobuf(bp);
1478 return rv;
1481 #include "md.h"
1482 #if NMD > 0
1484 #include <dev/md.h>
1486 int load_memory_disc_from_floppy(struct md_conf *md, dev_t dev);
1489 load_memory_disc_from_floppy(struct md_conf *md, dev_t dev)
1491 struct buf *bp;
1492 int loop;
1493 int s;
1494 int type;
1495 int floppysize;
1497 if (bdevsw_lookup(dev) != &fd_bdevsw)
1498 return(EINVAL);
1500 if (md->md_type == MD_UNCONFIGURED || md->md_addr == 0)
1501 return(EBUSY);
1503 type = FDTYPE(dev) - 1;
1504 if (type < 0) type = 0;
1505 floppysize = fd_types[type].size << (fd_types[type].secsize + 7);
1507 if (md->md_size < floppysize) {
1508 printf("Memory disc is not big enough for floppy image\n");
1509 return(EINVAL);
1512 /* We have the memory disk ! */
1514 printf("Loading memory disc : %4dK ", 0);
1516 /* obtain a buffer */
1518 bp = geteblk(fd_types[type].sectrac * DEV_BSIZE);
1520 /* request no partition relocation by driver on I/O operations */
1522 bp->b_dev = dev;
1524 s = splbio();
1526 if (fdopen(bp->b_dev, 0, 0, curlwp) != 0) {
1527 brelse(bp, 0);
1528 printf("Cannot open floppy device\n");
1529 return(EINVAL);
1532 for (loop = 0;
1533 loop < (floppysize / DEV_BSIZE / fd_types[type].sectrac);
1534 ++loop) {
1535 printf("\x08\x08\x08\x08\x08\x08%4dK ",
1536 loop * fd_types[type].sectrac * DEV_BSIZE / 1024);
1537 bp->b_blkno = loop * fd_types[type].sectrac;
1538 bp->b_bcount = fd_types[type].sectrac * DEV_BSIZE;
1539 bp->b_flags |= B_READ;
1540 bp->b_error = 0;
1541 bp->b_resid = 0;
1542 fdstrategy(bp);
1544 if (biowait(bp))
1545 panic("Cannot load floppy image");
1547 memcpy((char *)md->md_addr + loop * fd_types[type].sectrac
1548 * DEV_BSIZE, (void *)bp->b_data,
1549 fd_types[type].sectrac * DEV_BSIZE);
1551 printf("\x08\x08\x08\x08\x08\x08%4dK done\n",
1552 loop * fd_types[type].sectrac * DEV_BSIZE / 1024);
1554 fdclose(bp->b_dev, 0, 0, curlwp);
1556 brelse(bp, 0);
1558 splx(s);
1559 return(0);
1562 #endif