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