Annotation of sys/dev/isa/fd.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: fd.c,v 1.67 2007/06/20 18:15:46 deraadt Exp $ */
2: /* $NetBSD: fd.c,v 1.90 1996/05/12 23:12:03 mycroft Exp $ */
3:
4: /*-
5: * Copyright (c) 1993, 1994, 1995, 1996 Charles Hannum.
6: * Copyright (c) 1990 The Regents of the University of California.
7: * All rights reserved.
8: *
9: * This code is derived from software contributed to Berkeley by
10: * Don Ahn.
11: *
12: * Portions Copyright (c) 1993, 1994 by
13: * jc@irbs.UUCP (John Capo)
14: * vak@zebub.msk.su (Serge Vakulenko)
15: * ache@astral.msk.su (Andrew A. Chernov)
16: * joerg_wunsch@uriah.sax.de (Joerg Wunsch)
17: *
18: * Redistribution and use in source and binary forms, with or without
19: * modification, are permitted provided that the following conditions
20: * are met:
21: * 1. Redistributions of source code must retain the above copyright
22: * notice, this list of conditions and the following disclaimer.
23: * 2. Redistributions in binary form must reproduce the above copyright
24: * notice, this list of conditions and the following disclaimer in the
25: * documentation and/or other materials provided with the distribution.
26: * 3. Neither the name of the University nor the names of its contributors
27: * may be used to endorse or promote products derived from this software
28: * without specific prior written permission.
29: *
30: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
31: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
34: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40: * SUCH DAMAGE.
41: *
42: * @(#)fd.c 7.4 (Berkeley) 5/25/91
43: */
44:
45: #include <sys/param.h>
46: #include <sys/systm.h>
47: #include <sys/kernel.h>
48: #include <sys/file.h>
49: #include <sys/ioctl.h>
50: #include <sys/device.h>
51: #include <sys/disklabel.h>
52: #include <sys/dkstat.h>
53: #include <sys/disk.h>
54: #include <sys/buf.h>
55: #include <sys/malloc.h>
56: #include <sys/uio.h>
57: #include <sys/mtio.h>
58: #include <sys/proc.h>
59: #include <sys/syslog.h>
60: #include <sys/queue.h>
61: #include <sys/timeout.h>
62:
63: #include <machine/cpu.h>
64: #include <machine/bus.h>
65: #include <machine/conf.h>
66: #include <machine/intr.h>
67: #include <machine/ioctl_fd.h>
68:
69: #include <dev/isa/isavar.h>
70: #include <dev/isa/isadmavar.h>
71: #include <dev/isa/fdreg.h>
72:
73: #if defined(__i386__) || defined(__amd64__) /* XXX */
74: #include <i386/isa/nvram.h>
75: #endif
76:
77: #include <dev/isa/fdlink.h>
78:
79: /* XXX misuse a flag to identify format operation */
80: #define B_FORMAT B_XXX
81:
82: /* fd_type struct now in ioctl_fd.h */
83:
84: /* The order of entries in the following table is important -- BEWARE! */
85: struct fd_type fd_types[] = {
86: { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS,"1.44MB" }, /* 1.44MB diskette */
87: { 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS, "1.2MB" }, /* 1.2 MB AT-diskettes */
88: { 9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS, "360KB/AT" }, /* 360kB in 1.2MB drive */
89: { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS, "360KB/PC" }, /* 360kB PC diskettes */
90: { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS, "720KB" }, /* 3.5" 720kB diskette */
91: { 9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS, "720KB/x" }, /* 720kB in 1.2MB drive */
92: { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS, "360KB/x" }, /* 360kB in 720kB drive */
93: { 36,2,72,2,0xff,0xaf,0x1b,0x54,80,5760,1,FDC_500KBPS,"2.88MB" }, /* 2.88MB diskette */
94: { 8,2,16,3,0xff,0xdf,0x35,0x74,77,1232,1,FDC_500KBPS,"1.2MB/[1024bytes/sector]" } /* 1.2 MB japanese format */
95: };
96:
97: /* software state, per disk (with up to 4 disks per ctlr) */
98: struct fd_softc {
99: struct device sc_dev;
100: struct disk sc_dk;
101:
102: struct fd_type *sc_deftype; /* default type descriptor */
103: struct fd_type *sc_type; /* current type descriptor */
104:
105: daddr64_t sc_blkno; /* starting block number */
106: int sc_bcount; /* byte count left */
107: int sc_opts; /* user-set options */
108: int sc_skip; /* bytes already transferred */
109: int sc_nblks; /* number of blocks currently transferring */
110: int sc_nbytes; /* number of bytes currently transferring */
111:
112: int sc_drive; /* physical unit number */
113: int sc_flags;
114: #define FD_OPEN 0x01 /* it's open */
115: #define FD_MOTOR 0x02 /* motor should be on */
116: #define FD_MOTOR_WAIT 0x04 /* motor coming up */
117: int sc_cylin; /* where we think the head is */
118:
119: void *sc_sdhook; /* saved shutdown hook for drive. */
120:
121: TAILQ_ENTRY(fd_softc) sc_drivechain;
122: int sc_ops; /* I/O ops since last switch */
123: struct buf sc_q; /* head of buf chain */
124: struct timeout fd_motor_on_to;
125: struct timeout fd_motor_off_to;
126: struct timeout fdtimeout_to;
127: };
128:
129: /* floppy driver configuration */
130: int fdprobe(struct device *, void *, void *);
131: void fdattach(struct device *, struct device *, void *);
132:
133: struct cfattach fd_ca = {
134: sizeof(struct fd_softc), fdprobe, fdattach
135: };
136:
137: struct cfdriver fd_cd = {
138: NULL, "fd", DV_DISK
139: };
140:
141: void fdgetdisklabel(struct fd_softc *);
142: int fd_get_parms(struct fd_softc *);
143: void fdstrategy(struct buf *);
144: void fdstart(struct fd_softc *);
145: int fdintr(struct fdc_softc *);
146:
147: struct dkdriver fddkdriver = { fdstrategy };
148:
149: void fd_set_motor(struct fdc_softc *fdc, int reset);
150: void fd_motor_off(void *arg);
151: void fd_motor_on(void *arg);
152: void fdfinish(struct fd_softc *fd, struct buf *bp);
153: int fdformat(dev_t, struct fd_formb *, struct proc *);
154: static __inline struct fd_type *fd_dev_to_type(struct fd_softc *, dev_t);
155: void fdretry(struct fd_softc *);
156: void fdtimeout(void *);
157:
158: int
159: fdprobe(parent, match, aux)
160: struct device *parent;
161: void *match, *aux;
162: {
163: struct fdc_softc *fdc = (void *)parent;
164: struct cfdata *cf = match;
165: struct fdc_attach_args *fa = aux;
166: int drive = fa->fa_drive;
167: bus_space_tag_t iot = fdc->sc_iot;
168: bus_space_handle_t ioh = fdc->sc_ioh;
169: int n;
170:
171: if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != drive)
172: return 0;
173: /*
174: * XXX
175: * This is to work around some odd interactions between this driver
176: * and SMC Ethernet cards.
177: */
178: if (cf->cf_loc[0] == -1 && drive >= 2)
179: return 0;
180:
181: /*
182: * We want to keep the flags config gave us.
183: */
184: fa->fa_flags = cf->cf_flags;
185:
186: /* select drive and turn on motor */
187: bus_space_write_1(iot, ioh, fdout, drive | FDO_FRST | FDO_MOEN(drive));
188: /* wait for motor to spin up */
189: delay(250000);
190: out_fdc(iot, ioh, NE7CMD_RECAL);
191: out_fdc(iot, ioh, drive);
192: /* wait for recalibrate */
193: delay(2000000);
194: out_fdc(iot, ioh, NE7CMD_SENSEI);
195: n = fdcresult(fdc);
196: #ifdef FD_DEBUG
197: {
198: int i;
199: printf("fdprobe: status");
200: for (i = 0; i < n; i++)
201: printf(" %x", fdc->sc_status[i]);
202: printf("\n");
203: }
204: #endif
205:
206: /* turn off motor */
207: delay(250000);
208: bus_space_write_1(iot, ioh, fdout, FDO_FRST);
209:
210: /* flags & 0x20 forces the drive to be found even if it won't probe */
211: if (!(fa->fa_flags & 0x20) && (n != 2 || (fdc->sc_status[0] & 0xf8) != 0x20))
212: return 0;
213:
214: return 1;
215: }
216:
217: /*
218: * Controller is working, and drive responded. Attach it.
219: */
220: void
221: fdattach(parent, self, aux)
222: struct device *parent, *self;
223: void *aux;
224: {
225: struct fdc_softc *fdc = (void *)parent;
226: struct fd_softc *fd = (void *)self;
227: struct fdc_attach_args *fa = aux;
228: struct fd_type *type = fa->fa_deftype;
229: int drive = fa->fa_drive;
230:
231: if (!type || (fa->fa_flags & 0x10)) {
232: /* The config has overridden this. */
233: switch (fa->fa_flags & 0x07) {
234: case 1: /* 2.88MB */
235: type = &fd_types[7];
236: break;
237: case 2: /* 1.44MB */
238: type = &fd_types[0];
239: break;
240: case 3: /* 1.2MB */
241: type = &fd_types[1];
242: break;
243: case 4: /* 720K */
244: type = &fd_types[4];
245: break;
246: case 5: /* 360K */
247: type = &fd_types[3];
248: break;
249: case 6: /* 1.2 MB japanese format */
250: type = &fd_types[8];
251: break;
252: #ifdef __alpha__
253: default:
254: /* 1.44MB, how to detect others?
255: * idea from NetBSD -- jay@rootaction.net
256: */
257: type = &fd_types[0];
258: #endif
259: }
260: }
261:
262: if (type)
263: printf(": %s %d cyl, %d head, %d sec\n", type->name,
264: type->tracks, type->heads, type->sectrac);
265: else
266: printf(": density unknown\n");
267:
268: fd->sc_cylin = -1;
269: fd->sc_drive = drive;
270: fd->sc_deftype = type;
271: fdc->sc_type[drive] = FDC_TYPE_DISK;
272: fdc->sc_link.fdlink.sc_fd[drive] = fd;
273:
274: /*
275: * Initialize and attach the disk structure.
276: */
277: fd->sc_dk.dk_name = fd->sc_dev.dv_xname;
278: fd->sc_dk.dk_driver = &fddkdriver;
279: disk_attach(&fd->sc_dk);
280:
281: /* Needed to power off if the motor is on when we halt. */
282: fd->sc_sdhook = shutdownhook_establish(fd_motor_off, fd);
283:
284: /* Setup timeout structures */
285: timeout_set(&fd->fd_motor_on_to, fd_motor_on, fd);
286: timeout_set(&fd->fd_motor_off_to, fd_motor_off, fd);
287: timeout_set(&fd->fdtimeout_to, fdtimeout, fd);
288: }
289:
290: /*
291: * Translate nvram type into internal data structure. Return NULL for
292: * none/unknown/unusable.
293: */
294: struct fd_type *
295: fd_nvtotype(fdc, nvraminfo, drive)
296: char *fdc;
297: int nvraminfo, drive;
298: {
299: #ifdef __alpha__
300: /* Alpha: assume 1.44MB, idea from NetBSD sys/dev/isa/fd.c
301: * -- jay@rootaction.net
302: */
303: return &fd_types[0]; /* 1.44MB */
304: #else
305: int type;
306:
307: type = (drive == 0 ? nvraminfo : nvraminfo << 4) & 0xf0;
308: switch (type) {
309: case NVRAM_DISKETTE_NONE:
310: return NULL;
311: case NVRAM_DISKETTE_12M:
312: return &fd_types[1];
313: case NVRAM_DISKETTE_TYPE5:
314: case NVRAM_DISKETTE_TYPE6:
315: return &fd_types[7];
316: case NVRAM_DISKETTE_144M:
317: return &fd_types[0];
318: case NVRAM_DISKETTE_360K:
319: return &fd_types[3];
320: case NVRAM_DISKETTE_720K:
321: return &fd_types[4];
322: default:
323: printf("%s: drive %d: unknown device type 0x%x\n",
324: fdc, drive, type);
325: return NULL;
326: }
327: #endif
328: }
329:
330: static __inline struct fd_type *
331: fd_dev_to_type(fd, dev)
332: struct fd_softc *fd;
333: dev_t dev;
334: {
335: int type = FDTYPE(dev);
336:
337: if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
338: return NULL;
339: return type ? &fd_types[type - 1] : fd->sc_deftype;
340: }
341:
342: void
343: fdstrategy(bp)
344: register struct buf *bp; /* IO operation to perform */
345: {
346: struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(bp->b_dev)];
347: int sz;
348: int s;
349: int fd_bsize = FD_BSIZE(fd);
350: int bf = fd_bsize / DEV_BSIZE;
351:
352: /* Valid unit, controller, and request? */
353: if (bp->b_blkno < 0 ||
354: (((bp->b_blkno % bf) != 0 ||
355: (bp->b_bcount % fd_bsize) != 0) &&
356: (bp->b_flags & B_FORMAT) == 0)) {
357: bp->b_error = EINVAL;
358: goto bad;
359: }
360:
361: /* If it's a null transfer, return immediately. */
362: if (bp->b_bcount == 0)
363: goto done;
364:
365: sz = howmany(bp->b_bcount, DEV_BSIZE);
366:
367: if (bp->b_blkno + sz > fd->sc_type->size * bf) {
368: sz = fd->sc_type->size * bf - bp->b_blkno;
369: if (sz == 0)
370: /* If exactly at end of disk, return EOF. */
371: goto done;
372: if (sz < 0) {
373: /* If past end of disk, return EINVAL. */
374: bp->b_error = EINVAL;
375: goto bad;
376: }
377: /* Otherwise, truncate request. */
378: bp->b_bcount = sz << DEV_BSHIFT;
379: }
380:
381: bp->b_cylinder = bp->b_blkno / (fd_bsize / DEV_BSIZE) / fd->sc_type->seccyl;
382:
383: #ifdef FD_DEBUG
384: printf("fdstrategy: b_blkno %d b_bcount %d blkno %d cylin %d sz %d\n",
385: bp->b_blkno, bp->b_bcount, fd->sc_blkno, bp->b_cylinder, sz);
386: #endif
387:
388: /* Queue transfer on drive, activate drive and controller if idle. */
389: s = splbio();
390: disksort(&fd->sc_q, bp);
391: timeout_del(&fd->fd_motor_off_to); /* a good idea */
392: if (!fd->sc_q.b_active)
393: fdstart(fd);
394: #ifdef DIAGNOSTIC
395: else {
396: struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
397: if (fdc->sc_state == DEVIDLE) {
398: printf("fdstrategy: controller inactive\n");
399: fdcstart(fdc);
400: }
401: }
402: #endif
403: splx(s);
404: return;
405:
406: bad:
407: bp->b_flags |= B_ERROR;
408: done:
409: /* Toss transfer; we're done early. */
410: bp->b_resid = bp->b_bcount;
411: s = splbio();
412: biodone(bp);
413: splx(s);
414: }
415:
416: void
417: fdstart(fd)
418: struct fd_softc *fd;
419: {
420: struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
421: int active = !TAILQ_EMPTY(&fdc->sc_link.fdlink.sc_drives);
422:
423: /* Link into controller queue. */
424: fd->sc_q.b_active = 1;
425: TAILQ_INSERT_TAIL(&fdc->sc_link.fdlink.sc_drives, fd, sc_drivechain);
426:
427: /* If controller not already active, start it. */
428: if (!active)
429: fdcstart(fdc);
430: }
431:
432: void
433: fdfinish(fd, bp)
434: struct fd_softc *fd;
435: struct buf *bp;
436: {
437: struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
438:
439: splassert(IPL_BIO);
440:
441: /*
442: * Move this drive to the end of the queue to give others a `fair'
443: * chance. We only force a switch if N operations are completed while
444: * another drive is waiting to be serviced, since there is a long motor
445: * startup delay whenever we switch.
446: */
447: if (TAILQ_NEXT(fd, sc_drivechain) != NULL && ++fd->sc_ops >= 8) {
448: fd->sc_ops = 0;
449: TAILQ_REMOVE(&fdc->sc_link.fdlink.sc_drives, fd, sc_drivechain);
450: if (bp->b_actf) {
451: TAILQ_INSERT_TAIL(&fdc->sc_link.fdlink.sc_drives, fd,
452: sc_drivechain);
453: } else
454: fd->sc_q.b_active = 0;
455: }
456: bp->b_resid = fd->sc_bcount;
457: fd->sc_skip = 0;
458: fd->sc_q.b_actf = bp->b_actf;
459:
460: biodone(bp);
461: /* turn off motor 5s from now */
462: timeout_add(&fd->fd_motor_off_to, 5 * hz);
463: fdc->sc_state = DEVIDLE;
464: }
465:
466: int
467: fdread(dev, uio, flags)
468: dev_t dev;
469: struct uio *uio;
470: int flags;
471: {
472:
473: return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
474: }
475:
476: int
477: fdwrite(dev, uio, flags)
478: dev_t dev;
479: struct uio *uio;
480: int flags;
481: {
482:
483: return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
484: }
485:
486: void
487: fd_set_motor(fdc, reset)
488: struct fdc_softc *fdc;
489: int reset;
490: {
491: struct fd_softc *fd;
492: u_char status;
493: int n;
494:
495: if ((fd = TAILQ_FIRST(&fdc->sc_link.fdlink.sc_drives)) != NULL)
496: status = fd->sc_drive;
497: else
498: status = 0;
499: if (!reset)
500: status |= FDO_FRST | FDO_FDMAEN;
501: for (n = 0; n < 4; n++)
502: if ((fd = fdc->sc_link.fdlink.sc_fd[n])
503: && (fd->sc_flags & FD_MOTOR))
504: status |= FDO_MOEN(n);
505: bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, status);
506: }
507:
508: void
509: fd_motor_off(arg)
510: void *arg;
511: {
512: struct fd_softc *fd = arg;
513: int s;
514:
515: s = splbio();
516: fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
517: fd_set_motor((struct fdc_softc *)fd->sc_dev.dv_parent, 0);
518: splx(s);
519: }
520:
521: void
522: fd_motor_on(arg)
523: void *arg;
524: {
525: struct fd_softc *fd = arg;
526: struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
527: int s;
528:
529: s = splbio();
530: fd->sc_flags &= ~FD_MOTOR_WAIT;
531: if ((TAILQ_FIRST(&fdc->sc_link.fdlink.sc_drives) == fd)
532: && (fdc->sc_state == MOTORWAIT))
533: (void) fdintr(fdc);
534: splx(s);
535: }
536:
537: int
538: fdopen(dev, flags, mode, p)
539: dev_t dev;
540: int flags;
541: int mode;
542: struct proc *p;
543: {
544: int unit;
545: struct fd_softc *fd;
546: struct fd_type *type;
547:
548: unit = FDUNIT(dev);
549: if (unit >= fd_cd.cd_ndevs)
550: return ENXIO;
551: fd = fd_cd.cd_devs[unit];
552: if (fd == 0)
553: return ENXIO;
554: type = fd_dev_to_type(fd, dev);
555: if (type == NULL)
556: return ENXIO;
557:
558: if ((fd->sc_flags & FD_OPEN) != 0 &&
559: fd->sc_type != type)
560: return EBUSY;
561:
562: fd->sc_type = type;
563: fd->sc_cylin = -1;
564: fd->sc_flags |= FD_OPEN;
565:
566: return 0;
567: }
568:
569: int
570: fdclose(dev, flags, mode, p)
571: dev_t dev;
572: int flags;
573: int mode;
574: struct proc *p;
575: {
576: struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
577:
578: fd->sc_flags &= ~FD_OPEN;
579: fd->sc_opts &= ~FDOPT_NORETRY;
580: return 0;
581: }
582:
583: daddr64_t
584: fdsize(dev)
585: dev_t dev;
586: {
587:
588: /* Swapping to floppies would not make sense. */
589: return -1;
590: }
591:
592: int
593: fddump(dev, blkno, va, size)
594: dev_t dev;
595: daddr64_t blkno;
596: caddr_t va;
597: size_t size;
598: {
599:
600: /* Not implemented. */
601: return ENXIO;
602: }
603:
604: /*
605: * Called from the controller.
606: */
607: int
608: fdintr(fdc)
609: struct fdc_softc *fdc;
610: {
611: #define st0 fdc->sc_status[0]
612: #define cyl fdc->sc_status[1]
613: struct fd_softc *fd;
614: struct buf *bp;
615: bus_space_tag_t iot = fdc->sc_iot;
616: bus_space_handle_t ioh = fdc->sc_ioh;
617: bus_space_handle_t ioh_ctl = fdc->sc_ioh_ctl;
618: int read, head, sec, i, nblks;
619: struct fd_type *type;
620: struct fd_formb *finfo = NULL;
621: int fd_bsize;
622:
623: loop:
624: /* Is there a transfer to this drive? If not, deactivate drive. */
625: fd = TAILQ_FIRST(&fdc->sc_link.fdlink.sc_drives);
626: if (fd == NULL) {
627: fdc->sc_state = DEVIDLE;
628: return 1;
629: }
630: fd_bsize = FD_BSIZE(fd);
631:
632: bp = fd->sc_q.b_actf;
633: if (bp == NULL) {
634: fd->sc_ops = 0;
635: TAILQ_REMOVE(&fdc->sc_link.fdlink.sc_drives, fd, sc_drivechain);
636: fd->sc_q.b_active = 0;
637: goto loop;
638: }
639:
640: if (bp->b_flags & B_FORMAT)
641: finfo = (struct fd_formb *)bp->b_data;
642:
643: switch (fdc->sc_state) {
644: case DEVIDLE:
645: fdc->sc_errors = 0;
646: fd->sc_skip = 0;
647: fd->sc_bcount = bp->b_bcount;
648: fd->sc_blkno = bp->b_blkno / (fd_bsize / DEV_BSIZE);
649: timeout_del(&fd->fd_motor_off_to);
650: if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
651: fdc->sc_state = MOTORWAIT;
652: return 1;
653: }
654: if ((fd->sc_flags & FD_MOTOR) == 0) {
655: /* Turn on the motor, being careful about pairing. */
656: struct fd_softc *ofd =
657: fdc->sc_link.fdlink.sc_fd[fd->sc_drive ^ 1];
658: if (ofd && ofd->sc_flags & FD_MOTOR) {
659: timeout_del(&ofd->fd_motor_off_to);
660: ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
661: }
662: fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
663: fd_set_motor(fdc, 0);
664: fdc->sc_state = MOTORWAIT;
665: /* Allow .25s for motor to stabilize. */
666: timeout_add(&fd->fd_motor_on_to, hz / 4);
667: return 1;
668: }
669: /* Make sure the right drive is selected. */
670: fd_set_motor(fdc, 0);
671:
672: /* FALLTHROUGH */
673: case DOSEEK:
674: doseek:
675: if (fd->sc_cylin == bp->b_cylinder)
676: goto doio;
677:
678: out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
679: out_fdc(iot, ioh, fd->sc_type->steprate);
680: out_fdc(iot, ioh, 6); /* XXX head load time == 6ms */
681:
682: out_fdc(iot, ioh, NE7CMD_SEEK); /* seek function */
683: out_fdc(iot, ioh, fd->sc_drive); /* drive number */
684: out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step);
685:
686: fd->sc_cylin = -1;
687: fdc->sc_state = SEEKWAIT;
688:
689: fd->sc_dk.dk_seek++;
690: disk_busy(&fd->sc_dk);
691:
692: timeout_add(&fd->fdtimeout_to, 4 * hz);
693: return 1;
694:
695: case DOIO:
696: doio:
697: type = fd->sc_type;
698: if (finfo)
699: fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) -
700: (char *)finfo;
701: sec = fd->sc_blkno % type->seccyl;
702: nblks = type->seccyl - sec;
703: nblks = min(nblks, fd->sc_bcount / fd_bsize);
704: nblks = min(nblks, FDC_MAXIOSIZE / fd_bsize);
705: fd->sc_nblks = nblks;
706: fd->sc_nbytes = finfo ? bp->b_bcount : nblks * fd_bsize;
707: head = sec / type->sectrac;
708: sec -= head * type->sectrac;
709: #ifdef DIAGNOSTIC
710: {int block;
711: block = (fd->sc_cylin * type->heads + head) * type->sectrac + sec;
712: if (block != fd->sc_blkno) {
713: printf("fdintr: block %d != blkno %d\n", block, fd->sc_blkno);
714: #ifdef DDB
715: Debugger();
716: #endif
717: }}
718: #endif
719: read = bp->b_flags & B_READ ? DMAMODE_READ : DMAMODE_WRITE;
720: isadma_start(bp->b_data + fd->sc_skip, fd->sc_nbytes,
721: fdc->sc_drq, read);
722: bus_space_write_1(iot, ioh_ctl, fdctl, type->rate);
723: #ifdef FD_DEBUG
724: printf("fdintr: %s drive %d track %d head %d sec %d nblks %d\n",
725: read ? "read" : "write", fd->sc_drive, fd->sc_cylin, head,
726: sec, nblks);
727: #endif
728: if (finfo) {
729: /* formatting */
730: if (out_fdc(iot, ioh, NE7CMD_FORMAT) < 0) {
731: fdc->sc_errors = 4;
732: fdretry(fd);
733: goto loop;
734: }
735: out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
736: out_fdc(iot, ioh, finfo->fd_formb_secshift);
737: out_fdc(iot, ioh, finfo->fd_formb_nsecs);
738: out_fdc(iot, ioh, finfo->fd_formb_gaplen);
739: out_fdc(iot, ioh, finfo->fd_formb_fillbyte);
740: } else {
741: if (read)
742: out_fdc(iot, ioh, NE7CMD_READ); /* READ */
743: else
744: out_fdc(iot, ioh, NE7CMD_WRITE);/* WRITE */
745: out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
746: out_fdc(iot, ioh, fd->sc_cylin); /* track */
747: out_fdc(iot, ioh, head);
748: out_fdc(iot, ioh, sec + 1); /* sec +1 */
749: out_fdc(iot, ioh, type->secsize); /* sec size */
750: out_fdc(iot, ioh, type->sectrac); /* secs/track */
751: out_fdc(iot, ioh, type->gap1); /* gap1 size */
752: out_fdc(iot, ioh, type->datalen); /* data len */
753: }
754: fdc->sc_state = IOCOMPLETE;
755:
756: disk_busy(&fd->sc_dk);
757:
758: /* allow 2 seconds for operation */
759: timeout_add(&fd->fdtimeout_to, 2 * hz);
760: return 1; /* will return later */
761:
762: case SEEKWAIT:
763: timeout_del(&fd->fdtimeout_to);
764: fdc->sc_state = SEEKCOMPLETE;
765: /* allow 1/50 second for heads to settle */
766: timeout_add(&fdc->fdcpseudointr_to, hz / 50);
767: return 1;
768:
769: case SEEKCOMPLETE:
770: disk_unbusy(&fd->sc_dk, 0, 0); /* no data on seek */
771:
772: /* Make sure seek really happened. */
773: out_fdc(iot, ioh, NE7CMD_SENSEI);
774: if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 ||
775: cyl != bp->b_cylinder * fd->sc_type->step) {
776: #ifdef FD_DEBUG
777: fdcstatus(&fd->sc_dev, 2, "seek failed");
778: #endif
779: fdretry(fd);
780: goto loop;
781: }
782: fd->sc_cylin = bp->b_cylinder;
783: goto doio;
784:
785: case IOTIMEDOUT:
786: isadma_abort(fdc->sc_drq);
787: case SEEKTIMEDOUT:
788: case RECALTIMEDOUT:
789: case RESETTIMEDOUT:
790: fdretry(fd);
791: goto loop;
792:
793: case IOCOMPLETE: /* IO DONE, post-analyze */
794: timeout_del(&fd->fdtimeout_to);
795:
796: disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid),
797: (bp->b_flags & B_READ));
798:
799: if (fdcresult(fdc) != 7 || (st0 & 0xf8) != 0) {
800: isadma_abort(fdc->sc_drq);
801: #ifdef FD_DEBUG
802: fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
803: "read failed" : "write failed");
804: printf("blkno %d nblks %d\n",
805: fd->sc_blkno, fd->sc_nblks);
806: #endif
807: fdretry(fd);
808: goto loop;
809: }
810: read = bp->b_flags & B_READ ? DMAMODE_READ : DMAMODE_WRITE;
811: isadma_done(fdc->sc_drq);
812: if (fdc->sc_errors) {
813: diskerr(bp, "fd", "soft error", LOG_PRINTF,
814: fd->sc_skip / fd_bsize, (struct disklabel *)NULL);
815: printf("\n");
816: fdc->sc_errors = 0;
817: }
818: fd->sc_blkno += fd->sc_nblks;
819: fd->sc_skip += fd->sc_nbytes;
820: fd->sc_bcount -= fd->sc_nbytes;
821: if (!finfo && fd->sc_bcount > 0) {
822: bp->b_cylinder = fd->sc_blkno / fd->sc_type->seccyl;
823: goto doseek;
824: }
825: fdfinish(fd, bp);
826: goto loop;
827:
828: case DORESET:
829: /* try a reset, keep motor on */
830: fd_set_motor(fdc, 1);
831: delay(100);
832: fd_set_motor(fdc, 0);
833: fdc->sc_state = RESETCOMPLETE;
834: timeout_add(&fd->fdtimeout_to, hz / 2);
835: return 1; /* will return later */
836:
837: case RESETCOMPLETE:
838: timeout_del(&fd->fdtimeout_to);
839: /* clear the controller output buffer */
840: for (i = 0; i < 4; i++) {
841: out_fdc(iot, ioh, NE7CMD_SENSEI);
842: (void) fdcresult(fdc);
843: }
844:
845: /* FALLTHROUGH */
846: case DORECAL:
847: out_fdc(iot, ioh, NE7CMD_RECAL); /* recal function */
848: out_fdc(iot, ioh, fd->sc_drive);
849: fdc->sc_state = RECALWAIT;
850: timeout_add(&fd->fdtimeout_to, 5 * hz);
851: return 1; /* will return later */
852:
853: case RECALWAIT:
854: timeout_del(&fd->fdtimeout_to);
855: fdc->sc_state = RECALCOMPLETE;
856: /* allow 1/30 second for heads to settle */
857: timeout_add(&fdc->fdcpseudointr_to, hz / 30);
858: return 1; /* will return later */
859:
860: case RECALCOMPLETE:
861: out_fdc(iot, ioh, NE7CMD_SENSEI);
862: if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
863: #ifdef FD_DEBUG
864: fdcstatus(&fd->sc_dev, 2, "recalibrate failed");
865: #endif
866: fdretry(fd);
867: goto loop;
868: }
869: fd->sc_cylin = 0;
870: goto doseek;
871:
872: case MOTORWAIT:
873: if (fd->sc_flags & FD_MOTOR_WAIT)
874: return 1; /* time's not up yet */
875: goto doseek;
876:
877: default:
878: fdcstatus(&fd->sc_dev, 0, "stray interrupt");
879: return 1;
880: }
881: #ifdef DIAGNOSTIC
882: panic("fdintr: impossible");
883: #endif
884: #undef st0
885: #undef cyl
886: }
887:
888: void
889: fdtimeout(arg)
890: void *arg;
891: {
892: struct fd_softc *fd = arg;
893: struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
894: int s;
895:
896: s = splbio();
897: #ifdef DEBUG
898: log(LOG_ERR,"fdtimeout: state %d\n", fdc->sc_state);
899: #endif
900: fdcstatus(&fd->sc_dev, 0, "timeout");
901:
902: if (fd->sc_q.b_actf)
903: fdc->sc_state++;
904: else
905: fdc->sc_state = DEVIDLE;
906:
907: (void) fdintr(fdc);
908: splx(s);
909: }
910:
911: void
912: fdretry(fd)
913: struct fd_softc *fd;
914: {
915: struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
916: struct buf *bp = fd->sc_q.b_actf;
917:
918: if (fd->sc_opts & FDOPT_NORETRY)
919: goto fail;
920: switch (fdc->sc_errors) {
921: case 0:
922: /* try again */
923: fdc->sc_state = DOSEEK;
924: break;
925:
926: case 1: case 2: case 3:
927: /* didn't work; try recalibrating */
928: fdc->sc_state = DORECAL;
929: break;
930:
931: case 4:
932: /* still no go; reset the bastard */
933: fdc->sc_state = DORESET;
934: break;
935:
936: default:
937: fail:
938: diskerr(bp, "fd", "hard error", LOG_PRINTF,
939: fd->sc_skip / FD_BSIZE(fd), (struct disklabel *)NULL);
940: printf(" (st0 %b st1 %b st2 %b cyl %d head %d sec %d)\n",
941: fdc->sc_status[0], NE7_ST0BITS,
942: fdc->sc_status[1], NE7_ST1BITS,
943: fdc->sc_status[2], NE7_ST2BITS,
944: fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
945:
946: bp->b_flags |= B_ERROR;
947: bp->b_error = EIO;
948: fdfinish(fd, bp);
949: }
950: fdc->sc_errors++;
951: }
952:
953: int
954: fdioctl(dev, cmd, addr, flag, p)
955: dev_t dev;
956: u_long cmd;
957: caddr_t addr;
958: int flag;
959: struct proc *p;
960: {
961: struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
962: struct disklabel dl, *lp = &dl;
963: char *errstring;
964: int error;
965:
966: switch (cmd) {
967: case MTIOCTOP:
968: if (((struct mtop *)addr)->mt_op != MTOFFL)
969: return EIO;
970: return (0);
971: case DIOCGDINFO:
972: bzero(lp, sizeof(*lp));
973:
974: lp->d_secsize = FD_BSIZE(fd);
975: lp->d_secpercyl = fd->sc_type->seccyl;
976: lp->d_ntracks = fd->sc_type->heads;
977: lp->d_nsectors = fd->sc_type->sectrac;
978: lp->d_ncylinders = fd->sc_type->tracks;
979:
980: strncpy(lp->d_typename, "floppy disk", sizeof lp->d_typename);
981: lp->d_type = DTYPE_FLOPPY;
982: strncpy(lp->d_packname, "fictitious", sizeof lp->d_packname);
983: DL_SETDSIZE(lp, fd->sc_type->size);
984: lp->d_rpm = 300;
985: lp->d_interleave = 1;
986: lp->d_version = 1;
987:
988: lp->d_magic = DISKMAGIC;
989: lp->d_magic2 = DISKMAGIC;
990: lp->d_checksum = dkcksum(lp);
991:
992: errstring = readdisklabel(DISKLABELDEV(dev), fdstrategy, lp, 0);
993: if (errstring) {
994: /*printf("%s: %s\n", fd->sc_dev.dv_xname, errstring);*/
995: }
996:
997: *(struct disklabel *)addr = *lp;
998: return 0;
999:
1000: case DIOCWLABEL:
1001: if ((flag & FWRITE) == 0)
1002: return EBADF;
1003: /* XXX do something */
1004: return 0;
1005:
1006: case DIOCWDINFO:
1007: if ((flag & FWRITE) == 0)
1008: return EBADF;
1009:
1010: error = setdisklabel(lp, (struct disklabel *)addr, 0);
1011: if (error)
1012: return error;
1013:
1014: error = writedisklabel(DISKLABELDEV(dev), fdstrategy, lp);
1015: return error;
1016:
1017: case FD_FORM:
1018: if((flag & FWRITE) == 0)
1019: return EBADF; /* must be opened for writing */
1020: else if(((struct fd_formb *)addr)->format_version !=
1021: FD_FORMAT_VERSION)
1022: return EINVAL; /* wrong version of formatting prog */
1023: else
1024: return fdformat(dev, (struct fd_formb *)addr, p);
1025: break;
1026:
1027: case FD_GTYPE: /* get drive type */
1028: *(struct fd_type *)addr = *fd->sc_type;
1029: return 0;
1030:
1031: case FD_GOPTS: /* get drive options */
1032: *(int *)addr = fd->sc_opts;
1033: return 0;
1034:
1035: case FD_SOPTS: /* set drive options */
1036: fd->sc_opts = *(int *)addr;
1037: return 0;
1038:
1039: default:
1040: return ENOTTY;
1041: }
1042:
1043: #ifdef DIAGNOSTIC
1044: panic("fdioctl: impossible");
1045: #endif
1046: }
1047:
1048: int
1049: fdformat(dev, finfo, p)
1050: dev_t dev;
1051: struct fd_formb *finfo;
1052: struct proc *p;
1053: {
1054: int rv = 0;
1055: struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
1056: struct fd_type *type = fd->sc_type;
1057: struct buf *bp;
1058: int fd_bsize = FD_BSIZE(fd);
1059:
1060: /* set up a buffer header for fdstrategy() */
1061: bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT);
1062: if (bp == NULL)
1063: return ENOBUFS;
1064:
1065: bzero((void *)bp, sizeof(struct buf));
1066: bp->b_flags = B_BUSY | B_PHYS | B_FORMAT;
1067: bp->b_proc = p;
1068: bp->b_dev = dev;
1069:
1070: /*
1071: * calculate a fake blkno, so fdstrategy() would initiate a
1072: * seek to the requested cylinder
1073: */
1074: bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads)
1075: + finfo->head * type->sectrac) * fd_bsize / DEV_BSIZE;
1076:
1077: bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
1078: bp->b_data = (caddr_t)finfo;
1079:
1080: #ifdef DEBUG
1081: printf("fdformat: blkno %x count %x\n", bp->b_blkno, bp->b_bcount);
1082: #endif
1083:
1084: /* now do the format */
1085: fdstrategy(bp);
1086:
1087: /* ...and wait for it to complete */
1088: rv = biowait(bp);
1089: free(bp, M_TEMP);
1090: return (rv);
1091: }
CVSweb