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