Annotation of src/sys/arch/acorn32/mainbus/fd.c, Revision 1.4.2.4
1.4.2.4 ! jdolecek 1: /* $NetBSD: fd.c,v 1.4.2.3 2002/10/10 18:30:25 jdolecek Exp $ */
1.4.2.2 thorpej 2:
3: /*-
4: * Copyright (c) 1998 The NetBSD Foundation, Inc.
5: * All rights reserved.
6: *
7: * This code is derived from software contributed to The NetBSD Foundation
8: * by Charles M. Hannum.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: * 3. All advertising materials mentioning features or use of this software
19: * must display the following acknowledgement:
20: * This product includes software developed by the NetBSD
21: * Foundation, Inc. and its contributors.
22: * 4. Neither the name of The NetBSD Foundation nor the names of its
23: * contributors may be used to endorse or promote products derived
24: * from this software without specific prior written permission.
25: *
26: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36: * POSSIBILITY OF SUCH DAMAGE.
37: */
38:
39: /*-
40: * Copyright (c) 1990 The Regents of the University of California.
41: * All rights reserved.
42: *
43: * This code is derived from software contributed to Berkeley by
44: * Don Ahn.
45: *
46: * Redistribution and use in source and binary forms, with or without
47: * modification, are permitted provided that the following conditions
48: * are met:
49: * 1. Redistributions of source code must retain the above copyright
50: * notice, this list of conditions and the following disclaimer.
51: * 2. Redistributions in binary form must reproduce the above copyright
52: * notice, this list of conditions and the following disclaimer in the
53: * documentation and/or other materials provided with the distribution.
54: * 3. All advertising materials mentioning features or use of this software
55: * must display the following acknowledgement:
56: * This product includes software developed by the University of
57: * California, Berkeley and its contributors.
58: * 4. Neither the name of the University nor the names of its contributors
59: * may be used to endorse or promote products derived from this software
60: * without specific prior written permission.
61: *
62: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
63: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
64: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
65: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
66: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
67: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
68: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
69: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
70: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
71: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
72: * SUCH DAMAGE.
73: *
74: * @(#)fd.c 7.4 (Berkeley) 5/25/91
75: * from: fd.c,v 1.104 1997/01/09 04:30:08 mycroft Exp
76: */
77:
78: /*
79: * Floppy formatting facilities merged from FreeBSD fd.c driver:
80: * Id: fd.c,v 1.53 1995/03/12 22:40:56 joerg Exp
81: * which carries the same copyright/redistribution notice as shown above with
82: * the addition of the following statement before the "Redistribution and
83: * use ..." clause:
84: *
85: * Copyright (c) 1993, 1994 by
86: * jc@irbs.UUCP (John Capo)
87: * vak@zebub.msk.su (Serge Vakulenko)
88: * ache@astral.msk.su (Andrew A. Chernov)
89: *
90: * Copyright (c) 1993, 1994, 1995 by
91: * joerg_wunsch@uriah.sax.de (Joerg Wunsch)
92: * dufault@hda.com (Peter Dufault)
93: */
94:
95: #include "opt_ddb.h"
96:
97: #include <sys/param.h>
98: #include <sys/systm.h>
99: #include <sys/callout.h>
100: #include <sys/kernel.h>
101: #include <sys/file.h>
102: #include <sys/ioctl.h>
103: #include <sys/device.h>
104: #include <sys/disklabel.h>
105: #include <sys/dkstat.h>
106: #include <sys/disk.h>
107: #include <sys/buf.h>
108: #include <sys/malloc.h>
109: #include <sys/uio.h>
110: #include <sys/syslog.h>
111: #include <sys/queue.h>
112: #include <sys/proc.h>
113: #include <sys/fdio.h>
1.4.2.4 ! jdolecek 114: #include <sys/conf.h>
1.4.2.2 thorpej 115:
116: #include <uvm/uvm_extern.h>
117:
118: #include <arm/fiq.h>
119:
120: #include <machine/cpu.h>
121: #include <machine/intr.h>
122: #include <machine/io.h>
123: #include <arm/arm32/katelib.h>
124: #include <machine/bus.h>
125:
126: #include <arm/iomd/iomdreg.h>
127: #include <arm/iomd/iomdvar.h>
128:
129: #include <acorn32/mainbus/piocvar.h>
130: #include <acorn32/mainbus/fdreg.h>
131:
132: #include "locators.h"
133:
134: #define NE7CMD_CONFIGURE 0x13
135:
136: #define FDUNIT(dev) (minor(dev) / 8)
137: #define FDTYPE(dev) (minor(dev) % 8)
138:
139: /* XXX misuse a flag to identify format operation */
140: #define B_FORMAT B_XXX
141:
142: enum fdc_state {
143: DEVIDLE = 0,
144: MOTORWAIT,
145: DOSEEK,
146: SEEKWAIT,
147: SEEKTIMEDOUT,
148: SEEKCOMPLETE,
149: DOIO,
150: IOCOMPLETE,
151: IOTIMEDOUT,
152: DORESET,
153: RESETCOMPLETE,
154: RESETTIMEDOUT,
155: DORECAL,
156: RECALWAIT,
157: RECALTIMEDOUT,
158: RECALCOMPLETE,
159: };
160:
161: /* software state, per controller */
162: struct fdc_softc {
163: struct device sc_dev; /* boilerplate */
164: void *sc_ih;
165:
166: bus_space_tag_t sc_iot; /* ISA i/o space identifier */
167: bus_space_handle_t sc_ioh; /* ISA io handle */
168:
169: struct callout sc_timo_ch; /* timeout callout */
170: struct callout sc_intr_ch; /* pseudo-intr callout */
171:
172: /* ...for pseudo-DMA... */
173: struct fiqhandler sc_fh; /* FIQ handler descriptor */
174: struct fiqregs sc_fr; /* FIQ handler reg context */
175: int sc_drq;
176:
177: struct fd_softc *sc_fd[4]; /* pointers to children */
178: TAILQ_HEAD(drivehead, fd_softc) sc_drives;
179: enum fdc_state sc_state;
180: int sc_errors; /* number of retries so far */
181: u_char sc_status[7]; /* copy of registers */
182: };
183:
184: /* controller driver configuration */
185: int fdcprobe __P((struct device *, struct cfdata *, void *));
186: int fdprint __P((void *, const char *));
187: void fdcattach __P((struct device *, struct device *, void *));
188:
1.4.2.4 ! jdolecek 189: CFATTACH_DECL(fdc, sizeof(struct fdc_softc),
! 190: fdcprobe, fdcattach, NULL, NULL);
1.4.2.2 thorpej 191:
192: /*
193: * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how
194: * we tell them apart.
195: */
196: struct fd_type {
197: int sectrac; /* sectors per track */
198: int heads; /* number of heads */
199: int seccyl; /* sectors per cylinder */
200: int secsize; /* size code for sectors */
201: int datalen; /* data len when secsize = 0 */
202: int steprate; /* step rate and head unload time */
203: int gap1; /* gap len between sectors */
204: int gap2; /* formatting gap */
205: int cyls; /* total num of cylinders */
206: int size; /* size of disk in sectors */
207: int step; /* steps per cylinder */
208: int rate; /* transfer speed code */
209: u_char fillbyte; /* format fill byte */
210: u_char interleave; /* interleave factor (formatting) */
211: char *name;
212: };
213:
214: /* The order of entries in the following table is important -- BEWARE! */
215: struct fd_type fd_types[] = {
216: { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS,0xf6,1, "1.44MB" }, /* 1.44MB diskette */
217: { 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS,0xf6,1, "1.2MB" }, /* 1.2 MB AT-diskettes */
218: { 9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS,0xf6,1, "360KB/AT" }, /* 360kB in 1.2MB drive */
219: { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS,0xf6,1, "360KB/PC" }, /* 360kB PC diskettes */
220: { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS,0xf6,1, "720KB" }, /* 3.5" 720kB diskette */
221: { 9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS,0xf6,1, "720KB/x" }, /* 720kB in 1.2MB drive */
222: { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS,0xf6,1, "360KB/x" }, /* 360kB in 720kB drive */
223: };
224:
225: /* software state, per disk (with up to 4 disks per ctlr) */
226: struct fd_softc {
227: struct device sc_dev;
228: struct disk sc_dk;
229:
230: struct fd_type *sc_deftype; /* default type descriptor */
231: struct fd_type *sc_type; /* current type descriptor */
232: struct fd_type sc_type_copy; /* copy for fiddling when formatting */
233:
234: struct callout sc_motoron_ch;
235: struct callout sc_motoroff_ch;
236:
237: daddr_t sc_blkno; /* starting block number */
238: int sc_bcount; /* byte count left */
239: int sc_opts; /* user-set options */
240: int sc_skip; /* bytes already transferred */
241: int sc_nblks; /* number of blocks currently transferring */
242: int sc_nbytes; /* number of bytes currently transferring */
243:
244: int sc_drive; /* physical unit number */
245: int sc_flags;
246: #define FD_OPEN 0x01 /* it's open */
247: #define FD_MOTOR 0x02 /* motor should be on */
248: #define FD_MOTOR_WAIT 0x04 /* motor coming up */
249: int sc_cylin; /* where we think the head is */
250:
251: void *sc_sdhook; /* saved shutdown hook for drive. */
252:
253: TAILQ_ENTRY(fd_softc) sc_drivechain;
254: int sc_ops; /* I/O ops since last switch */
1.4.2.3 jdolecek 255: struct bufq_state sc_q; /* pending I/O requests */
1.4.2.2 thorpej 256: int sc_active; /* number of active I/O operations */
257: };
258:
259: /* floppy driver configuration */
260: int fdprobe __P((struct device *, struct cfdata *, void *));
261: void fdattach __P((struct device *, struct device *, void *));
262:
263: extern char floppy_read_fiq[], floppy_read_fiq_end[];
264: extern char floppy_write_fiq[], floppy_write_fiq_end[];
265:
1.4.2.4 ! jdolecek 266: CFATTACH_DECL(fd, sizeof(struct fd_softc),
! 267: fdprobe, fdattach, NULL, NULL);
1.4.2.2 thorpej 268:
269: extern struct cfdriver fd_cd;
270:
1.4.2.4 ! jdolecek 271: dev_type_open(fdopen);
! 272: dev_type_close(fdclose);
! 273: dev_type_read(fdread);
! 274: dev_type_write(fdwrite);
! 275: dev_type_ioctl(fdioctl);
! 276: dev_type_strategy(fdstrategy);
! 277:
! 278: const struct bdevsw fd_bdevsw = {
! 279: fdopen, fdclose, fdstrategy, fdioctl, nodump, nosize, D_DISK
! 280: };
! 281:
! 282: const struct cdevsw fd_cdevsw = {
! 283: fdopen, fdclose, fdread, fdwrite, fdioctl,
! 284: nostop, notty, nopoll, nommap, nokqfilter, D_DISK
! 285: };
! 286:
1.4.2.2 thorpej 287: void fdgetdisklabel __P((struct fd_softc *));
288: int fd_get_parms __P((struct fd_softc *));
289: void fdstart __P((struct fd_softc *));
290:
291: struct dkdriver fddkdriver = { fdstrategy };
292:
293: struct fd_type *fd_nvtotype __P((char *, int, int));
294: void fd_set_motor __P((struct fdc_softc *fdc, int reset));
295: void fd_motor_off __P((void *arg));
296: void fd_motor_on __P((void *arg));
297: int fdcresult __P((struct fdc_softc *fdc));
298: int out_fdc __P((bus_space_tag_t iot, bus_space_handle_t ioh, u_char x));
299: void fdcstart __P((struct fdc_softc *fdc));
300: void fdcstatus __P((struct device *dv, int n, char *s));
301: void fdctimeout __P((void *arg));
302: void fdcpseudointr __P((void *arg));
303: int fdcintr __P((void *));
304: void fdcretry __P((struct fdc_softc *fdc));
305: void fdfinish __P((struct fd_softc *fd, struct buf *bp));
306: __inline struct fd_type *fd_dev_to_type __P((struct fd_softc *, dev_t));
307: int fdformat __P((dev_t, struct ne7_fd_formb *, struct proc *));
308:
309: int
310: fdcprobe(parent, cf, aux)
311: struct device *parent;
312: struct cfdata *cf;
313: void *aux;
314: {
315: struct pioc_attach_args *pa = aux;
316: bus_space_tag_t iot;
317: bus_space_handle_t ioh;
318: int rv;
319:
320: if (pa->pa_name && strcmp(pa->pa_name, "fdc") != 0)
321: return(0);
322:
323: iot = pa->pa_iot;
324: rv = 0;
325:
326: /* Map the i/o space. */
327: if (bus_space_map(iot, pa->pa_iobase + pa->pa_offset, FDC_NPORT, 0, &ioh))
328: return 0;
329:
330: /* reset */
331: bus_space_write_2(iot, ioh, fdout, 0);
332: delay(100);
333: bus_space_write_2(iot, ioh, fdout, FDO_FRST);
334:
335: /* see if it can handle a command */
336: if (out_fdc(iot, ioh, NE7CMD_SPECIFY) < 0)
337: goto out;
338: out_fdc(iot, ioh, 0xdf);
339: out_fdc(iot, ioh, 2);
340:
341: rv = 1;
342: pa->pa_iosize = FDC_NPORT;
343:
344: out:
345: bus_space_unmap(iot, ioh, FDC_NPORT);
346: return rv;
347: }
348:
349: /*
350: * Arguments passed between fdcattach and fdprobe.
351: */
352: struct fdc_attach_args {
353: int fa_drive;
354: struct fd_type *fa_deftype;
355: };
356:
357: /*
358: * Print the location of a disk drive (called just before attaching the
359: * the drive). If `fdc' is not NULL, the drive was found but was not
360: * in the system config file; print the drive name as well.
361: * Return QUIET (config_find ignores this if the device was configured) to
362: * avoid printing `fdN not configured' messages.
363: */
364: int
365: fdprint(aux, fdc)
366: void *aux;
367: const char *fdc;
368: {
369: register struct fdc_attach_args *fa = aux;
370:
371: if (!fdc)
372: printf(" drive %d", fa->fa_drive);
373: return QUIET;
374: }
375:
376: void
377: fdcattach(parent, self, aux)
378: struct device *parent, *self;
379: void *aux;
380: {
381: struct fdc_softc *fdc = (void *)self;
382: bus_space_tag_t iot;
383: bus_space_handle_t ioh;
384: struct pioc_attach_args *pa = aux;
385: struct fdc_attach_args fa;
386: int type;
387:
388: iot = pa->pa_iot;
389:
390: /* Re-map the I/O space. */
391: if (bus_space_map(iot, pa->pa_iobase + pa->pa_offset, FDC_NPORT, 0, &ioh))
392: panic("fdcattach: couldn't map I/O ports");
393:
394: fdc->sc_iot = iot;
395: fdc->sc_ioh = ioh;
396:
397: fdc->sc_drq = pa->pa_iobase + pa->pa_offset + pa->pa_drq;
398: fdc->sc_state = DEVIDLE;
399: TAILQ_INIT(&fdc->sc_drives);
400:
401: printf("\n");
402:
403: callout_init(&fdc->sc_timo_ch);
404: callout_init(&fdc->sc_intr_ch);
405:
406: fdc->sc_ih = intr_claim(pa->pa_irq, IPL_BIO, "fdc",
407: fdcintr, fdc);
408: if (!fdc->sc_ih)
1.4.2.4 ! jdolecek 409: panic("%s: Cannot claim IRQ %d", self->dv_xname, pa->pa_irq);
1.4.2.2 thorpej 410:
411: #if 0
412: /*
413: * The NVRAM info only tells us about the first two disks on the
414: * `primary' floppy controller.
415: */
416: if (fdc->sc_dev.dv_unit == 0)
417: type = mc146818_read(NULL, NVRAM_DISKETTE); /* XXX softc */
418: else
419: type = -1;
420: #endif
421: type = 0x10; /* XXX - hardcoded for 1 floppy */
422:
423: /* physical limit: four drives per controller. */
424: for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) {
425: if (type >= 0 && fa.fa_drive < 2)
426: fa.fa_deftype = fd_nvtotype(fdc->sc_dev.dv_xname,
427: type, fa.fa_drive);
428: else
429: fa.fa_deftype = NULL; /* unknown */
430: (void)config_found(self, (void *)&fa, fdprint);
431: }
432: }
433:
434: int
435: fdprobe(parent, cf, aux)
436: struct device *parent;
437: struct cfdata *cf;
438: void *aux;
439: {
440: struct fdc_softc *fdc = (void *)parent;
441: struct fdc_attach_args *fa = aux;
442: int drive = fa->fa_drive;
443: bus_space_tag_t iot = fdc->sc_iot;
444: bus_space_handle_t ioh = fdc->sc_ioh;
445: int n;
446:
447: if (cf->cf_loc[FDCCF_DRIVE] != FDCCF_DRIVE_DEFAULT
448: && cf->cf_loc[FDCCF_DRIVE] != drive)
449: return 0;
450: /*
451: * XXX
452: * This is to work around some odd interactions between this driver
453: * and SMC Ethernet cards.
454: */
455:
456: /* Don't need this for arm32 port but leave for the time being (it won't hurt) */
457:
458: if (cf->cf_loc[FDCCF_DRIVE] == FDCCF_DRIVE_DEFAULT && drive >= 2)
459: return 0;
460:
461: /* select drive and turn on motor */
462: bus_space_write_2(iot, ioh, fdout, drive | FDO_FRST | FDO_MOEN(drive));
463: /* wait for motor to spin up */
464: delay(250000);
465: out_fdc(iot, ioh, NE7CMD_RECAL);
466: out_fdc(iot, ioh, drive);
467: /* wait for recalibrate */
468: delay(2000000);
469: out_fdc(iot, ioh, NE7CMD_SENSEI);
470: n = fdcresult(fdc);
471: #ifdef FD_DEBUG
472: {
473: int i;
474: printf("fdprobe: status");
475: for (i = 0; i < n; i++)
476: printf(" %x", fdc->sc_status[i]);
477: printf("\n");
478: }
479: #endif
480: /* turn off motor */
481: bus_space_write_1(iot, ioh, fdout, FDO_FRST);
482:
483: if (n != 2 || (fdc->sc_status[0] & 0xf8) != 0x20)
484: return 0;
485:
486: return 1;
487: }
488:
489: /*
490: * Controller is working, and drive responded. Attach it.
491: */
492: void
493: fdattach(parent, self, aux)
494: struct device *parent, *self;
495: void *aux;
496: {
497: struct fdc_softc *fdc = (void *)parent;
498: struct fd_softc *fd = (void *)self;
499: struct fdc_attach_args *fa = aux;
500: struct fd_type *type = fa->fa_deftype;
501: int drive = fa->fa_drive;
502:
503: callout_init(&fd->sc_motoron_ch);
504: callout_init(&fd->sc_motoroff_ch);
505:
506: /* XXX Allow `flags' to override device type? */
507:
508: if (type)
509: printf(": %s %d cyl, %d head, %d sec\n", type->name,
510: type->cyls, type->heads, type->sectrac);
511: else
512: printf(": density unknown\n");
513:
1.4.2.3 jdolecek 514: bufq_alloc(&fd->sc_q, BUFQ_DISKSORT|BUFQ_SORT_CYLINDER);
1.4.2.2 thorpej 515: fd->sc_cylin = -1;
516: fd->sc_drive = drive;
517: fd->sc_deftype = type;
518: fdc->sc_fd[drive] = fd;
519:
520: /*
521: * Initialize and attach the disk structure.
522: */
523: fd->sc_dk.dk_name = fd->sc_dev.dv_xname;
524: fd->sc_dk.dk_driver = &fddkdriver;
525: disk_attach(&fd->sc_dk);
526:
527: /* Needed to power off if the motor is on when we halt. */
528:
529: }
530:
531: /*
532: * Translate nvram type into internal data structure. Return NULL for
533: * none/unknown/unusable.
534: */
535: struct fd_type *
536: fd_nvtotype(fdc, nvraminfo, drive)
537: char *fdc;
538: int nvraminfo, drive;
539: {
540: int type;
541:
542: type = (drive == 0 ? nvraminfo : nvraminfo << 4) & 0xf0;
543: switch (type) {
544: #ifndef RC7500
545: case 0x00 :
546: return NULL;
547: #else
548: case 0x00 :
549: #endif /* !RC7500 */
550: case 0x10 :
551: return &fd_types[0];
552: default:
553: printf("%s: drive %d: unknown device type 0x%x\n",
554: fdc, drive, type);
555: return NULL;
556: }
557: }
558:
559: __inline struct fd_type *
560: fd_dev_to_type(fd, dev)
561: struct fd_softc *fd;
562: dev_t dev;
563: {
564: int type = FDTYPE(dev);
565:
566: if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
567: return NULL;
568: return type ? &fd_types[type - 1] : fd->sc_deftype;
569: }
570:
571: void
572: fdstrategy(bp)
573: register struct buf *bp; /* IO operation to perform */
574: {
575: struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(bp->b_dev)];
576: int sz;
577: int s;
578:
579: /* Valid unit, controller, and request? */
580: if (bp->b_blkno < 0 ||
581: ((bp->b_bcount % FDC_BSIZE) != 0 &&
582: (bp->b_flags & B_FORMAT) == 0)) {
583: bp->b_error = EINVAL;
584: goto bad;
585: }
586:
587: /* If it's a null transfer, return immediately. */
588: if (bp->b_bcount == 0)
589: goto done;
590:
591: sz = howmany(bp->b_bcount, FDC_BSIZE);
592:
593: if (bp->b_blkno + sz > fd->sc_type->size) {
594: sz = fd->sc_type->size - bp->b_blkno;
595: if (sz == 0) {
596: /* If exactly at end of disk, return EOF. */
597: goto done;
598: }
599: if (sz < 0) {
600: /* If past end of disk, return EINVAL. */
601: bp->b_error = EINVAL;
602: goto bad;
603: }
604: /* Otherwise, truncate request. */
605: bp->b_bcount = sz << DEV_BSHIFT;
606: }
607:
608: bp->b_rawblkno = bp->b_blkno;
609: bp->b_cylinder = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE) / fd->sc_type->seccyl;
610:
611: #ifdef FD_DEBUG
612: printf("fdstrategy: b_blkno %d b_bcount %d blkno %d cylin %d sz %d\n",
613: bp->b_blkno, bp->b_bcount, fd->sc_blkno, bp->b_cylinder, sz);
614: #endif
615:
616: /* Queue transfer on drive, activate drive and controller if idle. */
617: s = splbio();
1.4.2.3 jdolecek 618: BUFQ_PUT(&fd->sc_q, bp);
1.4.2.2 thorpej 619: callout_stop(&fd->sc_motoroff_ch); /* a good idea */
620: if (fd->sc_active == 0)
621: fdstart(fd);
622: #ifdef DIAGNOSTIC
623: else {
624: struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
625: if (fdc->sc_state == DEVIDLE) {
626: printf("fdstrategy: controller inactive\n");
627: fdcstart(fdc);
628: }
629: }
630: #endif
631: splx(s);
632: return;
633:
634: bad:
635: bp->b_flags |= B_ERROR;
636: done:
637: /* Toss transfer; we're done early. */
638: bp->b_resid = bp->b_bcount;
639: biodone(bp);
640: }
641:
642: void
643: fdstart(fd)
644: struct fd_softc *fd;
645: {
646: struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
647: int active = fdc->sc_drives.tqh_first != 0;
648:
649: /* Link into controller queue. */
650: fd->sc_active = 1;
651: TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
652:
653: /* If controller not already active, start it. */
654: if (!active)
655: fdcstart(fdc);
656: }
657:
658: void
659: fdfinish(fd, bp)
660: struct fd_softc *fd;
661: struct buf *bp;
662: {
663: struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
664:
665: /*
666: * Move this drive to the end of the queue to give others a `fair'
667: * chance. We only force a switch if N operations are completed while
668: * another drive is waiting to be serviced, since there is a long motor
669: * startup delay whenever we switch.
670: */
1.4.2.3 jdolecek 671: (void)BUFQ_GET(&fd->sc_q);
1.4.2.2 thorpej 672: if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) {
673: fd->sc_ops = 0;
674: TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
1.4.2.3 jdolecek 675: if (BUFQ_PEEK(&fd->sc_q) != NULL)
1.4.2.2 thorpej 676: TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
677: else
678: fd->sc_active = 0;
679: }
680: bp->b_resid = fd->sc_bcount;
681: fd->sc_skip = 0;
682:
683: biodone(bp);
684: /* turn off motor 5s from now */
685: callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd);
686: fdc->sc_state = DEVIDLE;
687: }
688:
689: int
690: fdread(dev, uio, flags)
691: dev_t dev;
692: struct uio *uio;
693: int flags;
694: {
695:
696: return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
697: }
698:
699: int
700: fdwrite(dev, uio, flags)
701: dev_t dev;
702: struct uio *uio;
703: int flags;
704: {
705:
706: return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
707: }
708:
709: void
710: fd_set_motor(fdc, reset)
711: struct fdc_softc *fdc;
712: int reset;
713: {
714: struct fd_softc *fd;
715: u_char status;
716: int n;
717:
718: if ((fd = fdc->sc_drives.tqh_first) != NULL)
719: status = fd->sc_drive;
720: else
721: status = 0;
722: if (!reset)
723: status |= FDO_FRST | FDO_FDMAEN;
724: for (n = 0; n < 4; n++)
725: if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR))
726: status |= FDO_MOEN(n);
727: bus_space_write_2(fdc->sc_iot, fdc->sc_ioh, fdout, status);
728: }
729:
730: void
731: fd_motor_off(arg)
732: void *arg;
733: {
734: struct fd_softc *fd = arg;
735: int s;
736:
737: s = splbio();
738: fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
739: fd_set_motor((struct fdc_softc *)fd->sc_dev.dv_parent, 0);
740: splx(s);
741: }
742:
743: void
744: fd_motor_on(arg)
745: void *arg;
746: {
747: struct fd_softc *fd = arg;
748: struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
749: int s;
750:
751: s = splbio();
752: fd->sc_flags &= ~FD_MOTOR_WAIT;
753: if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT))
754: (void) fdcintr(fdc);
755: splx(s);
756: }
757:
758: int
759: fdcresult(fdc)
760: struct fdc_softc *fdc;
761: {
762: bus_space_tag_t iot = fdc->sc_iot;
763: bus_space_handle_t ioh = fdc->sc_ioh;
764: u_char i;
765: int j = 100000,
766: n = 0;
767:
768: for (; j; j--) {
769: i = bus_space_read_1(iot, ioh, fdsts) &
770: (NE7_DIO | NE7_RQM | NE7_CB);
771: if (i == NE7_RQM)
772: return n;
773: if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
774: if (n >= sizeof(fdc->sc_status)) {
775: log(LOG_ERR, "fdcresult: overrun\n");
776: return -1;
777: }
778: fdc->sc_status[n++] =
779: bus_space_read_1(iot, ioh, fddata);
780: }
781: delay(10);
782: }
783: log(LOG_ERR, "fdcresult: timeout\n");
784: return -1;
785: }
786:
787: int
788: out_fdc(iot, ioh, x)
789: bus_space_tag_t iot;
790: bus_space_handle_t ioh;
791: u_char x;
792: {
793: int i = 100000;
794:
795: while ((bus_space_read_1(iot, ioh, fdsts) & NE7_DIO) && i-- > 0);
796: if (i <= 0)
797: return -1;
798: while ((bus_space_read_1(iot, ioh, fdsts) & NE7_RQM) == 0 && i-- > 0);
799: if (i <= 0)
800: return -1;
801: bus_space_write_2(iot, ioh, fddata, x);
802: return 0;
803: }
804:
805: int
806: fdopen(dev, flags, mode, p)
807: dev_t dev;
808: int flags;
809: int mode;
810: struct proc *p;
811: {
812: int unit;
813: struct fd_softc *fd;
814: struct fd_type *type;
815:
816: unit = FDUNIT(dev);
817: if (unit >= fd_cd.cd_ndevs)
818: return ENXIO;
819: fd = fd_cd.cd_devs[unit];
820: if (fd == 0)
821: return ENXIO;
822: type = fd_dev_to_type(fd, dev);
823: if (type == NULL)
824: return ENXIO;
825:
826: if ((fd->sc_flags & FD_OPEN) != 0 &&
827: memcmp(fd->sc_type, type, sizeof(*type)))
828: return EBUSY;
829:
830: fd->sc_type_copy = *type;
831: fd->sc_type = &fd->sc_type_copy;
832: fd->sc_cylin = -1;
833: fd->sc_flags |= FD_OPEN;
834:
835: return 0;
836: }
837:
838: int
839: fdclose(dev, flags, mode, p)
840: dev_t dev;
841: int flags;
842: int mode;
843: struct proc *p;
844: {
845: struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
846:
847: fd->sc_flags &= ~FD_OPEN;
848: fd->sc_opts &= ~(FDOPT_NORETRY|FDOPT_SILENT);
849: return 0;
850: }
851:
852: void
853: fdcstart(fdc)
854: struct fdc_softc *fdc;
855: {
856:
857: #ifdef DIAGNOSTIC
858: /* only got here if controller's drive queue was inactive; should
859: be in idle state */
860: if (fdc->sc_state != DEVIDLE) {
861: printf("fdcstart: not idle\n");
862: return;
863: }
864: #endif
865: (void) fdcintr(fdc);
866: }
867:
868: void
869: fdcstatus(dv, n, s)
870: struct device *dv;
871: int n;
872: char *s;
873: {
874: struct fdc_softc *fdc = (void *)dv->dv_parent;
875: char bits[64];
876:
877: if (n == 0) {
878: out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
879: (void) fdcresult(fdc);
880: n = 2;
881: }
882:
883: printf("%s: %s", dv->dv_xname, s);
884:
885: switch (n) {
886: case 0:
887: printf("\n");
888: break;
889: case 2:
890: printf(" (st0 %s cyl %d)\n",
891: bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS,
892: bits, sizeof(bits)), fdc->sc_status[1]);
893: break;
894: case 7:
895: printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
896: NE7_ST0BITS, bits, sizeof(bits)));
897: printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
898: NE7_ST1BITS, bits, sizeof(bits)));
899: printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
900: NE7_ST2BITS, bits, sizeof(bits)));
901: printf(" cyl %d head %d sec %d)\n",
902: fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
903: break;
904: #ifdef DIAGNOSTIC
905: default:
906: printf("\nfdcstatus: weird size");
907: break;
908: #endif
909: }
910: }
911:
912: void
913: fdctimeout(arg)
914: void *arg;
915: {
916: struct fdc_softc *fdc = arg;
917: struct fd_softc *fd = fdc->sc_drives.tqh_first;
918: int s;
919:
920: s = splbio();
921: #ifdef DEBUG
922: log(LOG_ERR,"fdctimeout: state %d\n", fdc->sc_state);
923: #endif
924: fdcstatus(&fd->sc_dev, 0, "timeout");
925:
1.4.2.3 jdolecek 926: if (BUFQ_PEEK(&fd->sc_q) != NULL)
1.4.2.2 thorpej 927: fdc->sc_state++;
928: else
929: fdc->sc_state = DEVIDLE;
930:
931: (void) fdcintr(fdc);
932: splx(s);
933: }
934:
935: void
936: fdcpseudointr(arg)
937: void *arg;
938: {
939: int s;
940:
941: /* Just ensure it has the right spl. */
942: s = splbio();
943: (void) fdcintr(arg);
944: splx(s);
945: }
946:
947: int
948: fdcintr(arg)
949: void *arg;
950: {
951: struct fdc_softc *fdc = arg;
952: #define st0 fdc->sc_status[0]
953: #define cyl fdc->sc_status[1]
954: struct fd_softc *fd;
955: struct buf *bp;
956: bus_space_tag_t iot = fdc->sc_iot;
957: bus_space_handle_t ioh = fdc->sc_ioh;
958: int read, head, sec, i, nblks;
959: struct fd_type *type;
960: struct ne7_fd_formb *finfo = NULL;
961:
962: loop:
963: /* Is there a drive for the controller to do a transfer with? */
964: fd = fdc->sc_drives.tqh_first;
965: if (fd == NULL) {
966: fdc->sc_state = DEVIDLE;
967: return 1;
968: }
969:
970: /* Is there a transfer to this drive? If not, deactivate drive. */
1.4.2.3 jdolecek 971: bp = BUFQ_PEEK(&fd->sc_q);
1.4.2.2 thorpej 972: if (bp == NULL) {
973: fd->sc_ops = 0;
974: TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
975: fd->sc_active = 0;
976: goto loop;
977: }
978:
979: if (bp->b_flags & B_FORMAT)
980: finfo = (struct ne7_fd_formb *)bp->b_data;
981:
982: switch (fdc->sc_state) {
983: case DEVIDLE:
984: fdc->sc_errors = 0;
985: fd->sc_skip = 0;
986: fd->sc_bcount = bp->b_bcount;
987: fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
988: callout_stop(&fd->sc_motoroff_ch);
989: if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
990: fdc->sc_state = MOTORWAIT;
991: return 1;
992: }
993: if ((fd->sc_flags & FD_MOTOR) == 0) {
994: /* Turn on the motor, being careful about pairing. */
995: struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1];
996: if (ofd && ofd->sc_flags & FD_MOTOR) {
997: callout_stop(&ofd->sc_motoroff_ch);
998: ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
999: }
1000: fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
1001: fd_set_motor(fdc, 0);
1002: fdc->sc_state = MOTORWAIT;
1003: /* Allow .25s for motor to stabilize. */
1004: callout_reset(&fd->sc_motoron_ch, hz / 4,
1005: fd_motor_on, fd);
1006: return 1;
1007: }
1008: /* Make sure the right drive is selected. */
1009: fd_set_motor(fdc, 0);
1010:
1011: /* fall through */
1012: case DOSEEK:
1013: doseek:
1014: if (fd->sc_cylin == bp->b_cylinder)
1015: goto doio;
1016:
1017: #if 1
1018: out_fdc(iot, ioh, NE7CMD_CONFIGURE);/* configure command */
1019: out_fdc(iot, ioh, 0);
1020: out_fdc(iot, ioh, 0x18);
1021: out_fdc(iot, ioh, 0);
1022: #endif
1023: out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
1024: out_fdc(iot, ioh, fd->sc_type->steprate);
1025: out_fdc(iot, ioh, 6); /* XXX head load time == 6ms */
1026:
1027: out_fdc(iot, ioh, NE7CMD_SEEK); /* seek function */
1028: out_fdc(iot, ioh, fd->sc_drive); /* drive number */
1029: out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step);
1030:
1031: fd->sc_cylin = -1;
1032: fdc->sc_state = SEEKWAIT;
1033:
1034: fd->sc_dk.dk_seek++;
1035: disk_busy(&fd->sc_dk);
1036:
1037: callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
1038: return 1;
1039:
1040: case DOIO:
1041: doio:
1042: type = fd->sc_type;
1043: if (finfo)
1044: fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) -
1045: (char *)finfo;
1046: sec = fd->sc_blkno % type->seccyl;
1047: nblks = type->seccyl - sec;
1048: nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
1049: nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
1050: fd->sc_nblks = nblks;
1051: fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FDC_BSIZE;
1052: head = sec / type->sectrac;
1053: sec -= head * type->sectrac;
1054: #ifdef DIAGNOSTIC
1055: {int block;
1056: block = (fd->sc_cylin * type->heads + head) * type->sectrac + sec;
1057: if (block != fd->sc_blkno) {
1058: printf("fdcintr: block %d != blkno %d\n",
1059: block, fd->sc_blkno);
1060: #ifdef DDB
1061: Debugger();
1062: #endif
1063: }}
1064: #endif
1065: read = bp->b_flags & B_READ;
1066: if (read) {
1067: fdc->sc_fh.fh_func = floppy_read_fiq;
1068: fdc->sc_fh.fh_size = floppy_read_fiq_end -
1069: floppy_read_fiq;
1070: } else {
1071: fdc->sc_fh.fh_func = floppy_write_fiq;
1072: fdc->sc_fh.fh_size = floppy_read_fiq_end -
1073: floppy_read_fiq;
1074: }
1075: fdc->sc_fh.fh_flags = 0;
1076: fdc->sc_fh.fh_regs = &fdc->sc_fr;
1077: fdc->sc_fr.fr_r9 = IOMD_BASE + (IOMD_FIQRQ << 2);
1078: fdc->sc_fr.fr_r10 = fd->sc_nbytes;
1079: fdc->sc_fr.fr_r11 = (u_int)(bp->b_data + fd->sc_skip);
1080: fdc->sc_fr.fr_r12 = fdc->sc_drq;
1081: #ifdef FD_DEBUG
1082: printf("fdc-doio:r9=%x r10=%x r11=%x r12=%x data=%x skip=%x\n",
1083: fdc->sc_fr.fr_r9, fdc->sc_fr.fh_r10, fdc->sc_fr.fh_r11,
1084: fdc->sc_fr.fh_r12, (u_int)bp->b_data, fd->sc_skip);
1085: #endif
1086: if (fiq_claim(&fdc->sc_fh) == -1)
1.4.2.4 ! jdolecek 1087: panic("%s: Cannot claim FIQ vector", fdc->sc_dev.dv_xname);
1.4.2.2 thorpej 1088: IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x01);
1089: bus_space_write_2(iot, ioh, fdctl, type->rate);
1090: #ifdef FD_DEBUG
1091: printf("fdcintr: %s drive %d track %d head %d sec %d nblks %d\n",
1092: read ? "read" : "write", fd->sc_drive, fd->sc_cylin,
1093: head, sec, nblks);
1094: #endif
1095: if (finfo) {
1096: /* formatting */
1097: if (out_fdc(iot, ioh, NE7CMD_FORMAT) < 0) {
1098: fdc->sc_errors = 4;
1099: fdcretry(fdc);
1100: goto loop;
1101: }
1102: out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1103: out_fdc(iot, ioh, finfo->fd_formb_secshift);
1104: out_fdc(iot, ioh, finfo->fd_formb_nsecs);
1105: out_fdc(iot, ioh, finfo->fd_formb_gaplen);
1106: out_fdc(iot, ioh, finfo->fd_formb_fillbyte);
1107: } else {
1108: if (read)
1109: out_fdc(iot, ioh, NE7CMD_READ); /* READ */
1110: else
1111: out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
1112: out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1113: out_fdc(iot, ioh, fd->sc_cylin); /* track */
1114: out_fdc(iot, ioh, head);
1115: out_fdc(iot, ioh, sec + 1); /* sector +1 */
1116: out_fdc(iot, ioh, type->secsize);/* sector size */
1117: out_fdc(iot, ioh, type->sectrac);/* sectors/track */
1118: out_fdc(iot, ioh, type->gap1); /* gap1 size */
1119: out_fdc(iot, ioh, type->datalen);/* data length */
1120: }
1121: fdc->sc_state = IOCOMPLETE;
1122:
1123: disk_busy(&fd->sc_dk);
1124:
1125: /* allow 2 seconds for operation */
1126: callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1127: return 1; /* will return later */
1128:
1129: case SEEKWAIT:
1130: callout_stop(&fdc->sc_timo_ch);
1131: fdc->sc_state = SEEKCOMPLETE;
1132: /* allow 1/50 second for heads to settle */
1133: #if 0
1134: callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc);
1135: #endif
1136: return 1;
1137:
1138: case SEEKCOMPLETE:
1139: disk_unbusy(&fd->sc_dk, 0); /* no data on seek */
1140:
1141: /* Make sure seek really happened. */
1142: out_fdc(iot, ioh, NE7CMD_SENSEI);
1143: if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 ||
1144: cyl != bp->b_cylinder * fd->sc_type->step) {
1145: #ifdef FD_DEBUG
1146: fdcstatus(&fd->sc_dev, 2, "seek failed");
1147: #endif
1148: fdcretry(fdc);
1149: goto loop;
1150: }
1151: fd->sc_cylin = bp->b_cylinder;
1152: goto doio;
1153:
1154: case IOTIMEDOUT:
1155: fiq_release(&fdc->sc_fh);
1156: IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x00);
1157: case SEEKTIMEDOUT:
1158: case RECALTIMEDOUT:
1159: case RESETTIMEDOUT:
1160: fdcretry(fdc);
1161: goto loop;
1162:
1163: case IOCOMPLETE: /* IO DONE, post-analyze */
1164: callout_stop(&fdc->sc_timo_ch);
1165:
1166: disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid));
1167:
1168: if (fdcresult(fdc) != 7 || (st0 & 0xf8) != 0) {
1169: fiq_release(&fdc->sc_fh);
1170: IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x00);
1171: #ifdef FD_DEBUG
1172: fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
1173: "read failed" : "write failed");
1174: printf("blkno %d nblks %d\n",
1175: fd->sc_blkno, fd->sc_nblks);
1176: #endif
1177: fdcretry(fdc);
1178: goto loop;
1179: }
1180: fiq_release(&fdc->sc_fh);
1181: IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x00);
1182: if (fdc->sc_errors) {
1183: #if 0
1184: diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF,
1185: fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
1186: printf("\n");
1187: #endif
1188: fdc->sc_errors = 0;
1189: }
1190: fd->sc_blkno += fd->sc_nblks;
1191: fd->sc_skip += fd->sc_nbytes;
1192: fd->sc_bcount -= fd->sc_nbytes;
1193: if (!finfo && fd->sc_bcount > 0) {
1194: bp->b_cylinder = fd->sc_blkno / fd->sc_type->seccyl;
1195: goto doseek;
1196: }
1197: fdfinish(fd, bp);
1198: goto loop;
1199:
1200: case DORESET:
1201: /* try a reset, keep motor on */
1202: fd_set_motor(fdc, 1);
1203: delay(100);
1204: fd_set_motor(fdc, 0);
1205: fdc->sc_state = RESETCOMPLETE;
1206: callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc);
1207: return 1; /* will return later */
1208:
1209: case RESETCOMPLETE:
1210: callout_stop(&fdc->sc_timo_ch);
1211: /* clear the controller output buffer */
1212: for (i = 0; i < 4; i++) {
1213: out_fdc(iot, ioh, NE7CMD_SENSEI);
1214: (void) fdcresult(fdc);
1215: }
1216:
1217: /* fall through */
1218: case DORECAL:
1219: out_fdc(iot, ioh, NE7CMD_RECAL); /* recalibrate function */
1220: out_fdc(iot, ioh, fd->sc_drive);
1221: fdc->sc_state = RECALWAIT;
1222: callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc);
1223: return 1; /* will return later */
1224:
1225: case RECALWAIT:
1226: callout_stop(&fdc->sc_timo_ch);
1227: fdc->sc_state = RECALCOMPLETE;
1228: /* allow 1/30 second for heads to settle */
1229: #if 0
1230: callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc);
1231: #endif
1232: return 1; /* will return later */
1233:
1234: case RECALCOMPLETE:
1235: out_fdc(iot, ioh, NE7CMD_SENSEI);
1236: if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
1237: #ifdef FD_DEBUG
1238: fdcstatus(&fd->sc_dev, 2, "recalibrate failed");
1239: #endif
1240: fdcretry(fdc);
1241: goto loop;
1242: }
1243: fd->sc_cylin = 0;
1244: goto doseek;
1245:
1246: case MOTORWAIT:
1247: if (fd->sc_flags & FD_MOTOR_WAIT)
1248: return 1; /* time's not up yet */
1249: goto doseek;
1250:
1251: default:
1252: fdcstatus(&fd->sc_dev, 0, "stray interrupt");
1253: return 1;
1254: }
1255: #ifdef DIAGNOSTIC
1256: panic("fdcintr: impossible");
1257: #endif
1258: #undef st0
1259: #undef cyl
1260: }
1261:
1262: void
1263: fdcretry(fdc)
1264: struct fdc_softc *fdc;
1265: {
1266: char bits[64];
1267: struct fd_softc *fd;
1268: struct buf *bp;
1269:
1270: fd = fdc->sc_drives.tqh_first;
1.4.2.3 jdolecek 1271: bp = BUFQ_PEEK(&fd->sc_q);
1.4.2.2 thorpej 1272:
1273: if (fd->sc_opts & FDOPT_NORETRY)
1274: goto fail;
1275: switch (fdc->sc_errors) {
1276: case 0:
1277: /* try again */
1278: fdc->sc_state = DOSEEK;
1279: break;
1280:
1281: case 1: case 2: case 3:
1282: /* didn't work; try recalibrating */
1283: fdc->sc_state = DORECAL;
1284: break;
1285:
1286: case 4:
1287: /* still no go; reset the bastard */
1288: fdc->sc_state = DORESET;
1289: break;
1290:
1291: default:
1292: fail:
1293: if ((fd->sc_opts & FDOPT_SILENT) == 0) {
1294: diskerr(bp, "fd", "hard error", LOG_PRINTF,
1295: fd->sc_skip / FDC_BSIZE,
1296: (struct disklabel *)NULL);
1297:
1298: printf(" (st0 %s",
1299: bitmask_snprintf(fdc->sc_status[0],
1300: NE7_ST0BITS, bits,
1301: sizeof(bits)));
1302: printf(" st1 %s",
1303: bitmask_snprintf(fdc->sc_status[1],
1304: NE7_ST1BITS, bits,
1305: sizeof(bits)));
1306: printf(" st2 %s",
1307: bitmask_snprintf(fdc->sc_status[2],
1308: NE7_ST2BITS, bits,
1309: sizeof(bits)));
1310: printf(" cyl %d head %d sec %d)\n",
1311: fdc->sc_status[3],
1312: fdc->sc_status[4],
1313: fdc->sc_status[5]);
1314: }
1315:
1316: bp->b_flags |= B_ERROR;
1317: bp->b_error = EIO;
1318: fdfinish(fd, bp);
1319: }
1320: fdc->sc_errors++;
1321: }
1322:
1323: int
1324: fdioctl(dev, cmd, addr, flag, p)
1325: dev_t dev;
1326: u_long cmd;
1327: caddr_t addr;
1328: int flag;
1329: struct proc *p;
1330: {
1331: struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
1332: struct fdformat_parms *form_parms;
1333: struct fdformat_cmd *form_cmd;
1334: struct ne7_fd_formb *fd_formb;
1335: struct disklabel buffer;
1336: int error;
1337: unsigned int scratch;
1338: int il[FD_MAX_NSEC + 1];
1339: register int i, j;
1340:
1341: switch (cmd) {
1342: case DIOCGDINFO:
1343: memset(&buffer, 0, sizeof(buffer));
1344:
1345: buffer.d_secpercyl = fd->sc_type->seccyl;
1346: buffer.d_type = DTYPE_FLOPPY;
1347: buffer.d_secsize = FDC_BSIZE;
1348:
1349: if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL)
1350: return EINVAL;
1351:
1352: *(struct disklabel *)addr = buffer;
1353: return 0;
1354:
1355: case DIOCWLABEL:
1356: if ((flag & FWRITE) == 0)
1357: return EBADF;
1358: /* XXX do something */
1359: return 0;
1360:
1361: case DIOCWDINFO:
1362: if ((flag & FWRITE) == 0)
1363: return EBADF;
1364:
1365: error = setdisklabel(&buffer, (struct disklabel *)addr, 0, NULL);
1366: if (error)
1367: return error;
1368:
1369: error = writedisklabel(dev, fdstrategy, &buffer, NULL);
1370: return error;
1371:
1372: case FDIOCGETFORMAT:
1373: form_parms = (struct fdformat_parms *)addr;
1374: form_parms->fdformat_version = FDFORMAT_VERSION;
1375: form_parms->nbps = 128 * (1 << fd->sc_type->secsize);
1376: form_parms->ncyl = fd->sc_type->cyls;
1377: form_parms->nspt = fd->sc_type->sectrac;
1378: form_parms->ntrk = fd->sc_type->heads;
1379: form_parms->stepspercyl = fd->sc_type->step;
1380: form_parms->gaplen = fd->sc_type->gap2;
1381: form_parms->fillbyte = fd->sc_type->fillbyte;
1382: form_parms->interleave = fd->sc_type->interleave;
1383: switch (fd->sc_type->rate) {
1384: case FDC_500KBPS:
1385: form_parms->xfer_rate = 500 * 1024;
1386: break;
1387: case FDC_300KBPS:
1388: form_parms->xfer_rate = 300 * 1024;
1389: break;
1390: case FDC_250KBPS:
1391: form_parms->xfer_rate = 250 * 1024;
1392: break;
1393: default:
1394: return EINVAL;
1395: }
1396: return 0;
1397:
1398: case FDIOCSETFORMAT:
1399: if((flag & FWRITE) == 0)
1400: return EBADF; /* must be opened for writing */
1401: form_parms = (struct fdformat_parms *)addr;
1402: if (form_parms->fdformat_version != FDFORMAT_VERSION)
1403: return EINVAL; /* wrong version of formatting prog */
1404:
1405: scratch = form_parms->nbps >> 7;
1406: if ((form_parms->nbps & 0x7f) || ffs(scratch) == 0 ||
1407: scratch & ~(1 << (ffs(scratch)-1)))
1408: /* not a power-of-two multiple of 128 */
1409: return EINVAL;
1410:
1411: switch (form_parms->xfer_rate) {
1412: case 500 * 1024:
1413: fd->sc_type->rate = FDC_500KBPS;
1414: break;
1415: case 300 * 1024:
1416: fd->sc_type->rate = FDC_300KBPS;
1417: break;
1418: case 250 * 1024:
1419: fd->sc_type->rate = FDC_250KBPS;
1420: break;
1421: default:
1422: return EINVAL;
1423: }
1424:
1425: if (form_parms->nspt > FD_MAX_NSEC ||
1426: form_parms->fillbyte > 0xff ||
1427: form_parms->interleave > 0xff)
1428: return EINVAL;
1429: fd->sc_type->sectrac = form_parms->nspt;
1430: if (form_parms->ntrk != 2 && form_parms->ntrk != 1)
1431: return EINVAL;
1432: fd->sc_type->heads = form_parms->ntrk;
1433: fd->sc_type->seccyl = form_parms->nspt * form_parms->ntrk;
1434: fd->sc_type->secsize = ffs(scratch)-1;
1435: fd->sc_type->gap2 = form_parms->gaplen;
1436: fd->sc_type->cyls = form_parms->ncyl;
1437: fd->sc_type->size = fd->sc_type->seccyl * form_parms->ncyl *
1438: form_parms->nbps / DEV_BSIZE;
1439: fd->sc_type->step = form_parms->stepspercyl;
1440: fd->sc_type->fillbyte = form_parms->fillbyte;
1441: fd->sc_type->interleave = form_parms->interleave;
1442: return 0;
1443:
1444: case FDIOCFORMAT_TRACK:
1445: if((flag & FWRITE) == 0)
1446: return EBADF; /* must be opened for writing */
1447: form_cmd = (struct fdformat_cmd *)addr;
1448: if (form_cmd->formatcmd_version != FDFORMAT_VERSION)
1449: return EINVAL; /* wrong version of formatting prog */
1450:
1451: if (form_cmd->head >= fd->sc_type->heads ||
1452: form_cmd->cylinder >= fd->sc_type->cyls) {
1453: return EINVAL;
1454: }
1455:
1456: fd_formb = malloc(sizeof(struct ne7_fd_formb),
1457: M_TEMP, M_NOWAIT);
1458: if(fd_formb == 0)
1459: return ENOMEM;
1460:
1461:
1462: fd_formb->head = form_cmd->head;
1463: fd_formb->cyl = form_cmd->cylinder;
1464: fd_formb->transfer_rate = fd->sc_type->rate;
1465: fd_formb->fd_formb_secshift = fd->sc_type->secsize;
1466: fd_formb->fd_formb_nsecs = fd->sc_type->sectrac;
1467: fd_formb->fd_formb_gaplen = fd->sc_type->gap2;
1468: fd_formb->fd_formb_fillbyte = fd->sc_type->fillbyte;
1469:
1470: memset(il, 0, sizeof il);
1471: for (j = 0, i = 1; i <= fd_formb->fd_formb_nsecs; i++) {
1472: while (il[(j%fd_formb->fd_formb_nsecs)+1])
1473: j++;
1474: il[(j%fd_formb->fd_formb_nsecs)+1] = i;
1475: j += fd->sc_type->interleave;
1476: }
1477: for (i = 0; i < fd_formb->fd_formb_nsecs; i++) {
1478: fd_formb->fd_formb_cylno(i) = form_cmd->cylinder;
1479: fd_formb->fd_formb_headno(i) = form_cmd->head;
1480: fd_formb->fd_formb_secno(i) = il[i+1];
1481: fd_formb->fd_formb_secsize(i) = fd->sc_type->secsize;
1482: }
1483:
1484: error = fdformat(dev, fd_formb, p);
1485: free(fd_formb, M_TEMP);
1486: return error;
1487:
1488: case FDIOCGETOPTS: /* get drive options */
1489: *(int *)addr = fd->sc_opts;
1490: return 0;
1491:
1492: case FDIOCSETOPTS: /* set drive options */
1493: fd->sc_opts = *(int *)addr;
1494: return 0;
1495:
1496: default:
1497: return ENOTTY;
1498: }
1499:
1500: #ifdef DIAGNOSTIC
1501: panic("fdioctl: impossible");
1502: #endif
1503: }
1504:
1505: int
1506: fdformat(dev, finfo, p)
1507: dev_t dev;
1508: struct ne7_fd_formb *finfo;
1509: struct proc *p;
1510: {
1511: int rv = 0, s;
1512: struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
1513: struct fd_type *type = fd->sc_type;
1514: struct buf *bp;
1515:
1516: /* set up a buffer header for fdstrategy() */
1517: bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT);
1518: if(bp == 0)
1519: return ENOBUFS;
1520: memset((void *)bp, 0, sizeof(struct buf));
1521: bp->b_flags = B_BUSY | B_PHYS | B_FORMAT;
1522: bp->b_proc = p;
1523: bp->b_dev = dev;
1524:
1525: /*
1526: * calculate a fake blkno, so fdstrategy() would initiate a
1527: * seek to the requested cylinder
1528: */
1529: bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads)
1530: + finfo->head * type->sectrac) * FDC_BSIZE / DEV_BSIZE;
1531:
1532: bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
1533: bp->b_data = (caddr_t)finfo;
1534:
1535: #ifdef DEBUG
1536: printf("fdformat: blkno %x count %lx\n", bp->b_blkno, bp->b_bcount);
1537: #endif
1538:
1539: /* now do the format */
1540: fdstrategy(bp);
1541:
1542: /* ...and wait for it to complete */
1543: s = splbio();
1544: while(!(bp->b_flags & B_DONE)) {
1545: rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 20 * hz);
1546: if (rv == EWOULDBLOCK)
1547: break;
1548: }
1549: splx(s);
1550:
1551: if (rv == EWOULDBLOCK) {
1552: /* timed out */
1553: rv = EIO;
1554: biodone(bp);
1555: }
1556: if(bp->b_flags & B_ERROR) {
1557: rv = bp->b_error;
1558: }
1559: free(bp, M_TEMP);
1560: return rv;
1561: }
1562:
1563: #include "md.h"
1564: #if NMD > 0
1565:
1566: #include <dev/md.h>
1567:
1568: int load_memory_disc_from_floppy __P((struct md_conf *md, dev_t dev));
1569:
1570: int
1571: load_memory_disc_from_floppy(md, dev)
1572: struct md_conf *md;
1573: dev_t dev;
1574: {
1575: struct buf *bp;
1576: int loop;
1577: int s;
1578: int type;
1579: int floppysize;
1580:
1.4.2.4 ! jdolecek 1581: if (bdevsw_lookup(dev) != &fd_bdevsw)
1.4.2.2 thorpej 1582: return(EINVAL);
1583:
1584: if (md->md_type == MD_UNCONFIGURED || md->md_addr == 0)
1585: return(EBUSY);
1586:
1587: type = FDTYPE(dev) - 1;
1588: if (type < 0) type = 0;
1589: floppysize = fd_types[type].size << (fd_types[type].secsize + 7);
1590:
1591: if (md->md_size < floppysize) {
1592: printf("Memory disc is not big enough for floppy image\n");
1593: return(EINVAL);
1594: }
1595:
1596: /* We have the memory disk ! */
1597:
1598: printf("Loading memory disc : %4dK ", 0);
1599:
1600: /* obtain a buffer */
1601:
1602: bp = geteblk(fd_types[type].sectrac * DEV_BSIZE);
1603:
1604: /* request no partition relocation by driver on I/O operations */
1605:
1606: bp->b_dev = dev;
1607:
1608: s = spl0();
1609:
1610: if (fdopen(bp->b_dev, 0, 0, curproc) != 0) {
1611: brelse(bp);
1612: printf("Cannot open floppy device\n");
1613: return(EINVAL);
1614: }
1615:
1616: for (loop = 0;
1617: loop < (floppysize / DEV_BSIZE / fd_types[type].sectrac);
1618: ++loop) {
1619: printf("\x08\x08\x08\x08\x08\x08%4dK ",
1620: loop * fd_types[type].sectrac * DEV_BSIZE / 1024);
1621: bp->b_blkno = loop * fd_types[type].sectrac;
1622: bp->b_bcount = fd_types[type].sectrac * DEV_BSIZE;
1623: bp->b_flags |= B_READ;
1624: bp->b_error = 0;
1625: bp->b_resid = 0;
1626: fdstrategy(bp);
1627:
1628: if (biowait(bp))
1.4.2.4 ! jdolecek 1629: panic("Cannot load floppy image");
1.4.2.2 thorpej 1630:
1631: memcpy((caddr_t)md->md_addr + loop * fd_types[type].sectrac
1632: * DEV_BSIZE, (caddr_t)bp->b_data,
1633: fd_types[type].sectrac * DEV_BSIZE);
1634: }
1635: printf("\x08\x08\x08\x08\x08\x08%4dK done\n",
1636: loop * fd_types[type].sectrac * DEV_BSIZE / 1024);
1637:
1638: fdclose(bp->b_dev, 0, 0, curproc);
1639:
1640: brelse(bp);
1641:
1642: splx(s);
1643: return(0);
1644: }
1645:
1646: #endif
CVSweb <webmaster@jp.NetBSD.org>