fd.c revision 1.1 1 /* $NetBSD: fd.c,v 1.1 2000/12/24 09:25:28 ur Exp $ */
2 /* $OpenBSD: fd.c,v 1.6 1998/10/03 21:18:57 millert Exp $ */
3 /* NetBSD: fd.c,v 1.78 1995/07/04 07:23:09 mycroft Exp */
4
5 /*-
6 * Copyright (c) 1998 The NetBSD Foundation, Inc.
7 * All rights reserved.
8 *
9 * This code is derived from software contributed to The NetBSD Foundation
10 * by Charles M. Hannum.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the NetBSD
23 * Foundation, Inc. and its contributors.
24 * 4. Neither the name of The NetBSD Foundation nor the names of its
25 * contributors may be used to endorse or promote products derived
26 * from this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38 * POSSIBILITY OF SUCH DAMAGE.
39 */
40
41 /*-
42 * Copyright (c) 1990 The Regents of the University of California.
43 * All rights reserved.
44 *
45 * This code is derived from software contributed to Berkeley by
46 * Don Ahn.
47 *
48 * Redistribution and use in source and binary forms, with or without
49 * modification, are permitted provided that the following conditions
50 * are met:
51 * 1. Redistributions of source code must retain the above copyright
52 * notice, this list of conditions and the following disclaimer.
53 * 2. Redistributions in binary form must reproduce the above copyright
54 * notice, this list of conditions and the following disclaimer in the
55 * documentation and/or other materials provided with the distribution.
56 * 3. All advertising materials mentioning features or use of this software
57 * must display the following acknowledgement:
58 * This product includes software developed by the University of
59 * California, Berkeley and its contributors.
60 * 4. Neither the name of the University nor the names of its contributors
61 * may be used to endorse or promote products derived from this software
62 * without specific prior written permission.
63 *
64 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
65 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
66 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
67 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
68 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
69 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
70 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
71 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
72 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
73 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
74 * SUCH DAMAGE.
75 *
76 * @(#)fd.c 7.4 (Berkeley) 5/25/91
77 */
78
79 #include <sys/param.h>
80 #include <sys/systm.h>
81 #include <sys/callout.h>
82 #include <sys/kernel.h>
83 #include <sys/conf.h>
84 #include <sys/file.h>
85 #include <sys/ioctl.h>
86 #include <sys/device.h>
87 #include <sys/disklabel.h>
88 #include <sys/dkstat.h>
89 #include <sys/disk.h>
90 #include <sys/buf.h>
91 #include <sys/uio.h>
92 #include <sys/syslog.h>
93 #include <sys/queue.h>
94
95 #include <uvm/uvm_extern.h>
96
97 #include <machine/bus.h>
98 #include <machine/cpu.h>
99 #include <machine/pio.h>
100 #include <machine/autoconf.h>
101
102 #include <mips/locore.h> /* for mips3_HitFlushDCache() */
103 #include <arc/jazz/fdreg.h>
104 #include <arc/jazz/jazziovar.h>
105 #include <arc/jazz/jazzdmatlbreg.h>
106 #include <arc/jazz/dma.h>
107
108 #include "locators.h"
109
110
111 #define FDUNIT(dev) ((dev & 0x080) >> 7)
112 #define FDTYPE(dev) ((minor(dev) & 0x70) >> 4)
113 #define FDPART(dev) (minor(dev) & 0x0f)
114
115 enum fdc_state {
116 DEVIDLE = 0,
117 MOTORWAIT,
118 DOSEEK,
119 SEEKWAIT,
120 SEEKTIMEDOUT,
121 SEEKCOMPLETE,
122 DOIO,
123 IOCOMPLETE,
124 IOTIMEDOUT,
125 DORESET,
126 RESETCOMPLETE,
127 RESETTIMEDOUT,
128 DORECAL,
129 RECALWAIT,
130 RECALTIMEDOUT,
131 RECALCOMPLETE,
132 };
133
134 /* software state, per controller */
135 struct fdc_softc {
136 struct device sc_dev; /* boilerplate */
137
138 struct callout sc_timo_ch; /* timeout callout */
139 struct callout sc_intr_ch; /* pseudo-intr callout */
140
141 struct dma_softc __dma;
142 struct dma_softc *dma;
143
144 int sc_iobase;
145
146 struct fd_softc *sc_fd[4]; /* pointers to children */
147 TAILQ_HEAD(drivehead, fd_softc) sc_drives;
148 enum fdc_state sc_state;
149 int sc_errors; /* number of retries so far */
150 u_char sc_status[7]; /* copy of registers */
151 };
152
153 /* controller driver configuration */
154 int fdcprobe __P((struct device *, struct cfdata *, void *));
155 void fdcattach __P((struct device *, struct device *, void *));
156
157 struct cfattach fdc_ca = {
158 sizeof(struct fdc_softc), fdcprobe, fdcattach
159 };
160
161 /*
162 * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how
163 * we tell them apart.
164 */
165 struct fd_type {
166 int sectrac; /* sectors per track */
167 int heads; /* number of heads */
168 int seccyl; /* sectors per cylinder */
169 int secsize; /* size code for sectors */
170 int datalen; /* data len when secsize = 0 */
171 int steprate; /* step rate and head unload time */
172 int gap1; /* gap len between sectors */
173 int gap2; /* formatting gap */
174 int tracks; /* total num of tracks */
175 int size; /* size of disk in sectors */
176 int step; /* steps per cylinder */
177 int rate; /* transfer speed code */
178 char *name;
179 };
180
181 /* The order of entries in the following table is important -- BEWARE! */
182 struct fd_type fd_types[] = {
183 { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS,"1.44MB" }, /* 1.44MB diskette */
184 { 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS, "1.2MB" }, /* 1.2 MB AT-diskettes */
185 { 9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS, "360KB/AT" }, /* 360kB in 1.2MB drive */
186 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS, "360KB/PC" }, /* 360kB PC diskettes */
187 { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS, "720KB" }, /* 3.5" 720kB diskette */
188 { 9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS, "720KB/x" }, /* 720kB in 1.2MB drive */
189 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS, "360KB/x" }, /* 360kB in 720kB drive */
190 };
191
192 /* software state, per disk (with up to 4 disks per ctlr) */
193 struct fd_softc {
194 struct device sc_dev;
195 struct disk sc_dk;
196
197 struct fd_type *sc_deftype; /* default type descriptor */
198 struct fd_type *sc_type; /* current type descriptor */
199
200 struct callout sc_motoron_ch;
201 struct callout sc_motoroff_ch;
202
203 daddr_t sc_blkno; /* starting block number */
204 int sc_bcount; /* byte count left */
205 int sc_skip; /* bytes already transferred */
206 int sc_nblks; /* number of blocks currently tranferring */
207 int sc_nbytes; /* number of bytes currently tranferring */
208
209 int sc_drive; /* physical unit number */
210 int sc_flags;
211 #define FD_OPEN 0x01 /* it's open */
212 #define FD_MOTOR 0x02 /* motor should be on */
213 #define FD_MOTOR_WAIT 0x04 /* motor coming up */
214 int sc_cylin; /* where we think the head is */
215
216 void *sc_sdhook; /* saved shutdown hook for drive. */
217
218 TAILQ_ENTRY(fd_softc) sc_drivechain;
219 int sc_ops; /* I/O ops since last switch */
220 struct buf_queue sc_q; /* pending I/O requests */
221 int sc_active; /* number of active I/O operations */
222 };
223
224 /* floppy driver configuration */
225 int fdprobe __P((struct device *, struct cfdata *, void *));
226 void fdattach __P((struct device *, struct device *, void *));
227
228 struct cfattach fd_ca = {
229 sizeof(struct fd_softc), fdprobe, fdattach
230 };
231 extern struct cfdriver fd_cd;
232
233 void fdgetdisklabel __P((struct fd_softc *));
234 int fd_get_parms __P((struct fd_softc *));
235 void fdstrategy __P((struct buf *));
236 void fdstart __P((struct fd_softc *));
237 int fdioctl __P((dev_t, u_long, caddr_t, int));
238 int fddump __P((dev_t, daddr_t, caddr_t, size_t));
239 int fdsize __P((dev_t));
240 int fdopen __P((dev_t, int));
241 int fdclose __P((dev_t, int));
242 int fdwrite __P((dev_t, struct uio *));
243 int fdread __P((dev_t, struct uio *));
244
245 struct dkdriver fddkdriver = { fdstrategy };
246
247 int fdprint __P((void *, const char *));
248 struct fd_type *fd_nvtotype __P((char *, int, int));
249 void fd_set_motor __P((struct fdc_softc *fdc, int reset));
250 void fd_motor_off __P((void *arg));
251 void fd_motor_on __P((void *arg));
252 int fdcresult __P((struct fdc_softc *fdc));
253 int out_fdc __P((int iobase, u_char x));
254 void fdcstart __P((struct fdc_softc *fdc));
255 void fdcstatus __P((struct device *dv, int n, char *s));
256 void fdctimeout __P((void *arg));
257 void fdcpseudointr __P((void *arg));
258 int fdcintr __P((void *));
259 void fdcretry __P((struct fdc_softc *fdc));
260 void fdfinish __P((struct fd_softc *fd, struct buf *bp));
261
262 int
263 fdcprobe(parent, match, aux)
264 struct device *parent;
265 struct cfdata *match;
266 void *aux;
267 {
268 struct jazzio_attach_args *ja = aux;
269 int iobase = ja->ja_addr;
270
271 if (strcmp(ja->ja_name, "fdc") != 0)
272 return (0);
273
274 /* reset */
275 outb(iobase + fdout, 0);
276 delay(100);
277 outb(iobase + fdout, FDO_FRST);
278
279 /* see if it can handle a command */
280 if (out_fdc(iobase, NE7CMD_SPECIFY) < 0)
281 return 0;
282 out_fdc(iobase, 0xdf);
283 out_fdc(iobase, 2);
284
285 return 1;
286 }
287
288 /*
289 * Arguments passed between fdcattach and fdprobe.
290 */
291 struct fdc_attach_args {
292 int fa_drive;
293 struct fd_type *fa_deftype;
294 };
295
296 /*
297 * Print the location of a disk drive (called just before attaching the
298 * the drive). If `fdc' is not NULL, the drive was found but was not
299 * in the system config file; print the drive name as well.
300 * Return QUIET (config_find ignores this if the device was configured) to
301 * avoid printing `fdN not configured' messages.
302 */
303 int
304 fdprint(aux, fdc)
305 void *aux;
306 const char *fdc;
307 {
308 register struct fdc_attach_args *fa = aux;
309
310 if (!fdc)
311 printf(" drive %d", fa->fa_drive);
312 return QUIET;
313 }
314
315 void
316 fdcattach(parent, self, aux)
317 struct device *parent, *self;
318 void *aux;
319 {
320 struct fdc_softc *fdc = (void *)self;
321 struct jazzio_attach_args *ja = aux;
322 struct fdc_attach_args fa;
323 int type;
324
325 fdc->sc_iobase = ja->ja_addr;
326 fdc->sc_state = DEVIDLE;
327 TAILQ_INIT(&fdc->sc_drives);
328
329 fdc->dma = &fdc->__dma;
330 fdc_dma_init(fdc->dma);
331
332 printf("\n");
333
334 callout_init(&fdc->sc_timo_ch);
335 callout_init(&fdc->sc_intr_ch);
336
337 jazzio_intr_establish(ja->ja_intr, fdcintr, fdc);
338
339 /*
340 * No way yet to determine default disk types.
341 * we assume 1.44 3.5" type for the moment.
342 */
343 type = 0;
344
345 /* physical limit: two drives per controller. */
346 for (fa.fa_drive = 0; fa.fa_drive < 2; fa.fa_drive++) {
347 if (type >= 0 && fa.fa_drive < 2)
348 fa.fa_deftype = fd_nvtotype(fdc->sc_dev.dv_xname,
349 type, fa.fa_drive);
350 else
351 fa.fa_deftype = NULL; /* unknown */
352 (void)config_found(self, (void *)&fa, fdprint);
353 }
354 }
355
356 int
357 fdprobe(parent, match, aux)
358 struct device *parent;
359 struct cfdata *match;
360 void *aux;
361 {
362 struct fdc_softc *fdc = (void *)parent;
363 struct fdc_attach_args *fa = aux;
364 int drive = fa->fa_drive;
365 int iobase = fdc->sc_iobase;
366 int n;
367
368 if (match->cf_loc[FDCCF_DRIVE] != FDCCF_DRIVE_DEFAULT &&
369 match->cf_loc[FDCCF_DRIVE] != drive)
370 return 0;
371
372 /* select drive and turn on motor */
373 outb(iobase + fdout, drive | FDO_FRST | FDO_MOEN(drive));
374 /* wait for motor to spin up */
375 delay(500000);
376 out_fdc(iobase, NE7CMD_RECAL);
377 out_fdc(iobase, drive);
378 /* wait for recalibrate */
379 delay(2000000);
380 out_fdc(iobase, NE7CMD_SENSEI);
381 n = fdcresult(fdc);
382 #ifdef FD_DEBUG
383 {
384 int i;
385 printf("fdprobe: status");
386 for (i = 0; i < n; i++)
387 printf(" %x", fdc->sc_status[i]);
388 printf("\n");
389 }
390 #endif
391 if (n != 2 || (fdc->sc_status[0] & 0xf8) != 0x20)
392 return 0;
393 /* turn off motor */
394 outb(iobase + fdout, FDO_FRST);
395
396 return 1;
397 }
398
399 /*
400 * Controller is working, and drive responded. Attach it.
401 */
402 void
403 fdattach(parent, self, aux)
404 struct device *parent, *self;
405 void *aux;
406 {
407 struct fdc_softc *fdc = (void *)parent;
408 struct fd_softc *fd = (void *)self;
409 struct fdc_attach_args *fa = aux;
410 struct fd_type *type = fa->fa_deftype;
411 int drive = fa->fa_drive;
412
413 callout_init(&fd->sc_motoron_ch);
414 callout_init(&fd->sc_motoroff_ch);
415
416 /* XXX Allow `flags' to override device type? */
417
418 if (type)
419 printf(": %s %d cyl, %d head, %d sec\n", type->name,
420 type->tracks, type->heads, type->sectrac);
421 else
422 printf(": density unknown\n");
423
424 BUFQ_INIT(&fd->sc_q);
425 fd->sc_cylin = -1;
426 fd->sc_drive = drive;
427 fd->sc_deftype = type;
428 fdc->sc_fd[drive] = fd;
429 fd->sc_dk.dk_name = fd->sc_dev.dv_xname;
430 fd->sc_dk.dk_driver = &fddkdriver;
431
432 /* Needed to power off if the motor is on when we halt. */
433 fd->sc_sdhook = shutdownhook_establish(fd_motor_off, fd);
434 }
435
436 /*
437 * Translate nvram type into internal data structure. Return NULL for
438 * none/unknown/unusable.
439 */
440 struct fd_type *
441 fd_nvtotype(fdc, nvraminfo, drive)
442 char *fdc;
443 int nvraminfo, drive;
444 {
445 int type;
446
447 type = (drive == 0 ? nvraminfo : nvraminfo << 4) & 0xf0;
448 #if 0
449 switch (type) {
450 case NVRAM_DISKETTE_NONE:
451 return NULL;
452 case NVRAM_DISKETTE_12M:
453 return &fd_types[1];
454 case NVRAM_DISKETTE_TYPE5:
455 case NVRAM_DISKETTE_TYPE6:
456 /* XXX We really ought to handle 2.88MB format. */
457 case NVRAM_DISKETTE_144M:
458 return &fd_types[0];
459 case NVRAM_DISKETTE_360K:
460 return &fd_types[3];
461 case NVRAM_DISKETTE_720K:
462 return &fd_types[4];
463 default:
464 printf("%s: drive %d: unknown device type 0x%x\n",
465 fdc, drive, type);
466 return NULL;
467 }
468 #else
469 return &fd_types[0]; /* Use only 1.44 for now */
470 #endif
471 }
472
473 void
474 fdstrategy(bp)
475 register struct buf *bp; /* IO operation to perform */
476 {
477 struct fd_softc *fd;
478 int unit = FDUNIT(bp->b_dev);
479 int sz;
480 int s;
481
482 /* Valid unit, controller, and request? */
483 if (unit >= fd_cd.cd_ndevs ||
484 (fd = fd_cd.cd_devs[unit]) == 0 ||
485 bp->b_blkno < 0 ||
486 (bp->b_bcount % FDC_BSIZE) != 0) {
487 bp->b_error = EINVAL;
488 goto bad;
489 }
490
491 /* If it's a null transfer, return immediately. */
492 if (bp->b_bcount == 0)
493 goto done;
494
495 sz = howmany(bp->b_bcount, FDC_BSIZE);
496
497 if (bp->b_blkno + sz > fd->sc_type->size) {
498 sz = fd->sc_type->size - bp->b_blkno;
499 if (sz == 0) {
500 /* If exactly at end of disk, return EOF. */
501 bp->b_resid = bp->b_bcount;
502 goto done;
503 }
504 if (sz < 0) {
505 /* If past end of disk, return EINVAL. */
506 bp->b_error = EINVAL;
507 goto bad;
508 }
509 /* Otherwise, truncate request. */
510 bp->b_bcount = sz << DEV_BSHIFT;
511 }
512
513 bp->b_rawblkno = bp->b_blkno;
514 bp->b_cylinder = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE) / fd->sc_type->seccyl;
515
516 #ifdef FD_DEBUG
517 printf("fdstrategy: b_blkno %d b_bcount %d blkno %d cylin %d sz %d\n",
518 bp->b_blkno, bp->b_bcount, fd->sc_blkno, bp->b_cylinder, sz);
519 #endif
520
521 /* Queue transfer on drive, activate drive and controller if idle. */
522 s = splbio();
523 disksort_cylinder(&fd->sc_q, bp);
524 callout_stop(&fd->sc_motoroff_ch); /* a good idea */
525 if (fd->sc_active == 0)
526 fdstart(fd);
527 #ifdef DIAGNOSTIC
528 else {
529 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
530 if (fdc->sc_state == DEVIDLE) {
531 printf("fdstrategy: controller inactive\n");
532 fdcstart(fdc);
533 }
534 }
535 #endif
536 splx(s);
537 return;
538
539 bad:
540 bp->b_flags |= B_ERROR;
541 done:
542 /* Toss transfer; we're done early. */
543 biodone(bp);
544 }
545
546 void
547 fdstart(fd)
548 struct fd_softc *fd;
549 {
550 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
551 int active = fdc->sc_drives.tqh_first != 0;
552
553 /* Link into controller queue. */
554 fd->sc_active = 1;
555 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
556
557 /* If controller not already active, start it. */
558 if (!active)
559 fdcstart(fdc);
560 }
561
562 void
563 fdfinish(fd, bp)
564 struct fd_softc *fd;
565 struct buf *bp;
566 {
567 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
568
569 /*
570 * Move this drive to the end of the queue to give others a `fair'
571 * chance. We only force a switch if N operations are completed while
572 * another drive is waiting to be serviced, since there is a long motor
573 * startup delay whenever we switch.
574 */
575 if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) {
576 fd->sc_ops = 0;
577 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
578 if (BUFQ_NEXT(bp) != NULL) {
579 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
580 } else
581 fd->sc_active = 0;
582 }
583 bp->b_resid = fd->sc_bcount;
584 fd->sc_skip = 0;
585 BUFQ_REMOVE(&fd->sc_q, bp);
586 biodone(bp);
587 /* turn off motor 5s from now */
588 callout_reset(&fd->sc_motoroff_ch, 10 * hz, fd_motor_off, fd);
589 fdc->sc_state = DEVIDLE;
590 }
591
592 int
593 fdread(dev, uio)
594 dev_t dev;
595 struct uio *uio;
596 {
597
598 return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
599 }
600
601 int
602 fdwrite(dev, uio)
603 dev_t dev;
604 struct uio *uio;
605 {
606
607 return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
608 }
609
610 void
611 fd_set_motor(fdc, reset)
612 struct fdc_softc *fdc;
613 int reset;
614 {
615 struct fd_softc *fd;
616 u_char status;
617 int n;
618
619 if ((fd = fdc->sc_drives.tqh_first) != NULL)
620 status = fd->sc_drive;
621 else
622 status = 0;
623 if (!reset)
624 status |= FDO_FRST | FDO_FDMAEN;
625 for (n = 0; n < 4; n++)
626 if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR))
627 status |= FDO_MOEN(n);
628 outb(fdc->sc_iobase + fdout, status);
629 }
630
631 void
632 fd_motor_off(arg)
633 void *arg;
634 {
635 struct fd_softc *fd = arg;
636 int s;
637
638 s = splbio();
639 fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
640 fd_set_motor((struct fdc_softc *)fd->sc_dev.dv_parent, 0);
641 splx(s);
642 }
643
644 void
645 fd_motor_on(arg)
646 void *arg;
647 {
648 struct fd_softc *fd = arg;
649 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
650 int s;
651
652 s = splbio();
653 fd->sc_flags &= ~FD_MOTOR_WAIT;
654 if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT))
655 (void) fdcintr(fdc);
656 splx(s);
657 }
658
659 int
660 fdcresult(fdc)
661 struct fdc_softc *fdc;
662 {
663 int iobase = fdc->sc_iobase;
664 u_char i;
665 int j = 400000, /* Empirical, should do at 150 Mhz to */
666 n = 0;
667
668 for (; j; --j) {
669 i = inb(iobase + fdsts) & (NE7_DIO | NE7_RQM | NE7_CB);
670 if (i == NE7_RQM) {
671 return n;
672 }
673 if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
674 if (n >= sizeof(fdc->sc_status)) {
675 log(LOG_ERR, "fdcresult: overrun\n");
676 return -1;
677 }
678 fdc->sc_status[n++] = inb(iobase + fddata);
679 }
680 }
681 log(LOG_ERR, "fdcresult: timeout\n");
682 return -1;
683 }
684
685 int
686 out_fdc(iobase, x)
687 int iobase;
688 u_char x;
689 {
690 int i = 100000;
691
692 while ((inb(iobase + fdsts) & NE7_DIO) && i-- > 0);
693 if (i <= 0)
694 return -1;
695 while ((inb(iobase + fdsts) & NE7_RQM) == 0 && i-- > 0);
696 if (i <= 0)
697 return -1;
698 outb(iobase + fddata, x);
699 return 0;
700 }
701
702 int
703 fdopen(dev, flags)
704 dev_t dev;
705 int flags;
706 {
707 int unit;
708 struct fd_softc *fd;
709 struct fd_type *type;
710
711 unit = FDUNIT(dev);
712 if (unit >= fd_cd.cd_ndevs)
713 return ENXIO;
714 fd = fd_cd.cd_devs[unit];
715 if (fd == 0)
716 return ENXIO;
717
718 if (FDTYPE(dev) > (sizeof(fd_types) / sizeof(fd_types[0])))
719 type = NULL;
720 else if(FDTYPE(dev))
721 type = &fd_types[FDTYPE(dev) - 1];
722 else
723 type = fd->sc_deftype;
724
725 if (type == NULL)
726 return ENXIO;
727
728 if ((fd->sc_flags & FD_OPEN) != 0 &&
729 fd->sc_type != type)
730 return EBUSY;
731
732 fd->sc_type = type;
733 fd->sc_cylin = -1;
734 fd->sc_flags |= FD_OPEN;
735
736 return 0;
737 }
738
739 int
740 fdclose(dev, flags)
741 dev_t dev;
742 int flags;
743 {
744 struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
745
746 fd->sc_flags &= ~FD_OPEN;
747 return 0;
748 }
749
750 void
751 fdcstart(fdc)
752 struct fdc_softc *fdc;
753 {
754
755 #ifdef DIAGNOSTIC
756 /* only got here if controller's drive queue was inactive; should
757 be in idle state */
758 if (fdc->sc_state != DEVIDLE) {
759 printf("fdcstart: not idle\n");
760 return;
761 }
762 #endif
763 (void) fdcintr(fdc);
764 }
765
766 void
767 fdcstatus(dv, n, s)
768 struct device *dv;
769 int n;
770 char *s;
771 {
772 struct fdc_softc *fdc = (void *)dv->dv_parent;
773 char bits[64];
774
775 if (n == 0) {
776 out_fdc(fdc->sc_iobase, NE7CMD_SENSEI);
777 (void) fdcresult(fdc);
778 n = 2;
779 }
780
781 printf("%s: %s", dv->dv_xname, s);
782
783 switch (n) {
784 case 0:
785 printf("\n");
786 break;
787 case 2:
788 printf(" (st0 %s cyl %d)\n",
789 bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS,
790 bits, sizeof(bits)), fdc->sc_status[1]);
791 break;
792 case 7:
793 printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
794 NE7_ST0BITS, bits, sizeof(bits)));
795 printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
796 NE7_ST1BITS, bits, sizeof(bits)));
797 printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
798 NE7_ST2BITS, bits, sizeof(bits)));
799 printf(" cyl %d head %d sec %d)\n",
800 fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
801 break;
802 #ifdef DIAGNOSTIC
803 default:
804 printf("\nfdcstatus: weird size");
805 break;
806 #endif
807 }
808 }
809
810 void
811 fdctimeout(arg)
812 void *arg;
813 {
814 struct fdc_softc *fdc = arg;
815 struct fd_softc *fd = fdc->sc_drives.tqh_first;
816 int s;
817
818 s = splbio();
819 fdcstatus(&fd->sc_dev, 0, "timeout");
820
821 if (BUFQ_FIRST(&fd->sc_q) != NULL)
822 fdc->sc_state++;
823 else
824 fdc->sc_state = DEVIDLE;
825
826 (void) fdcintr(fdc);
827 splx(s);
828 }
829
830 void
831 fdcpseudointr(arg)
832 void *arg;
833 {
834 int s;
835
836 /* Just ensure it has the right spl. */
837 s = splbio();
838 (void) fdcintr(arg);
839 splx(s);
840 }
841
842 int
843 fdcintr(arg)
844 void *arg;
845 {
846 struct fdc_softc *fdc = arg;
847 #define st0 fdc->sc_status[0]
848 #define cyl fdc->sc_status[1]
849 struct fd_softc *fd;
850 struct buf *bp;
851 int iobase = fdc->sc_iobase;
852 int read, head, sec, i, nblks;
853 struct fd_type *type;
854
855 loop:
856 /* Is there a drive for the controller to do a transfer with? */
857 fd = fdc->sc_drives.tqh_first;
858 if (fd == NULL) {
859 fdc->sc_state = DEVIDLE;
860 return 1;
861 }
862
863 /* Is there a transfer to this drive? If not, deactivate drive. */
864 bp = BUFQ_FIRST(&fd->sc_q);
865 if (bp == NULL) {
866 fd->sc_ops = 0;
867 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
868 fd->sc_active = 0;
869 goto loop;
870 }
871
872 switch (fdc->sc_state) {
873 case DEVIDLE:
874 fdc->sc_errors = 0;
875 fd->sc_skip = 0;
876 fd->sc_bcount = bp->b_bcount;
877 fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
878 callout_stop(&fd->sc_motoroff_ch);
879 if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
880 fdc->sc_state = MOTORWAIT;
881 return 1;
882 }
883 if ((fd->sc_flags & FD_MOTOR) == 0) {
884 /* Turn on the motor, being careful about pairing. */
885 struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1];
886 if (ofd && ofd->sc_flags & FD_MOTOR) {
887 callout_stop(&ofd->sc_motoroff_ch);
888 ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
889 }
890 fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
891 fd_set_motor(fdc, 0);
892 fdc->sc_state = MOTORWAIT;
893 /* Allow .5s for motor to stabilize. */
894 callout_reset(&fd->sc_motoron_ch, hz / 2,
895 fd_motor_on, fd);
896 return 1;
897 }
898 /* Make sure the right drive is selected. */
899 fd_set_motor(fdc, 0);
900
901 /* fall through */
902 case DOSEEK:
903 doseek:
904 if (fd->sc_cylin == bp->b_cylinder)
905 goto doio;
906
907 out_fdc(iobase, NE7CMD_SPECIFY);/* specify command */
908 out_fdc(iobase, fd->sc_type->steprate);
909 out_fdc(iobase, 6); /* XXX head load time == 6ms */
910
911 out_fdc(iobase, NE7CMD_SEEK); /* seek function */
912 out_fdc(iobase, fd->sc_drive); /* drive number */
913 out_fdc(iobase, bp->b_cylinder * fd->sc_type->step);
914
915 fd->sc_cylin = -1;
916 fdc->sc_state = SEEKWAIT;
917 callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
918 return 1;
919
920 case DOIO:
921 doio:
922 type = fd->sc_type;
923 sec = fd->sc_blkno % type->seccyl;
924 nblks = type->seccyl - sec;
925 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
926 nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
927 fd->sc_nblks = nblks;
928 fd->sc_nbytes = nblks * FDC_BSIZE;
929 head = sec / type->sectrac;
930 sec -= head * type->sectrac;
931 #ifdef DIAGNOSTIC
932 {int block;
933 block = (fd->sc_cylin * type->heads + head) * type->sectrac + sec;
934 if (block != fd->sc_blkno) {
935 printf("fdcintr: block %d != blkno %d\n", block, fd->sc_blkno);
936 #ifdef DDB
937 Debugger();
938 #endif
939 }}
940 #endif
941 mips3_FlushDCache((vaddr_t) (bp->b_data + fd->sc_skip),
942 (vsize_t) fd->sc_nbytes);
943 read = bp->b_flags & B_READ ? DMA_FROM_DEV : DMA_TO_DEV;
944 DMA_START(fdc->dma, bp->b_data + fd->sc_skip, fd->sc_nbytes, read);
945 outb(iobase + fdctl, type->rate);
946 #ifdef FD_DEBUG
947 printf("fdcintr: %s drive %d track %d head %d sec %d nblks %d\n",
948 read ? "read" : "write", fd->sc_drive, fd->sc_cylin, head,
949 sec, nblks);
950 #endif
951 if (read)
952 out_fdc(iobase, NE7CMD_READ); /* READ */
953 else
954 out_fdc(iobase, NE7CMD_WRITE); /* WRITE */
955 out_fdc(iobase, (head << 2) | fd->sc_drive);
956 out_fdc(iobase, fd->sc_cylin); /* track */
957 out_fdc(iobase, head);
958 out_fdc(iobase, sec + 1); /* sector +1 */
959 out_fdc(iobase, type->secsize); /* sector size */
960 out_fdc(iobase, type->sectrac); /* sectors/track */
961 out_fdc(iobase, type->gap1); /* gap1 size */
962 out_fdc(iobase, type->datalen); /* data length */
963 fdc->sc_state = IOCOMPLETE;
964 /* allow 2 seconds for operation */
965 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
966 return 1; /* will return later */
967
968 case SEEKWAIT:
969 callout_stop(&fdc->sc_timo_ch);
970 fdc->sc_state = SEEKCOMPLETE;
971 /* allow 1/50 second for heads to settle */
972 callout_reset(&fdc->sc_intr_ch, hz / 50,
973 fdcpseudointr, fdc);
974 return 1;
975
976 case SEEKCOMPLETE:
977 /* Make sure seek really happened. */
978 out_fdc(iobase, NE7CMD_SENSEI);
979 if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 ||
980 cyl != bp->b_cylinder * fd->sc_type->step) {
981 #ifdef FD_DEBUG
982 fdcstatus(&fd->sc_dev, 2, "seek failed");
983 #endif
984 fdcretry(fdc);
985 goto loop;
986 }
987 fd->sc_cylin = bp->b_cylinder;
988 goto doio;
989
990 case IOTIMEDOUT:
991 DMA_RESET(fdc->dma);
992
993 case SEEKTIMEDOUT:
994 case RECALTIMEDOUT:
995 case RESETTIMEDOUT:
996 fdcretry(fdc);
997 goto loop;
998
999 case IOCOMPLETE: /* IO DONE, post-analyze */
1000 callout_stop(&fdc->sc_timo_ch);
1001 if (fdcresult(fdc) != 7 || (st0 & 0xf8) != 0) {
1002 DMA_RESET(fdc->dma);
1003 #ifdef FD_DEBUG
1004 fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
1005 "read failed" : "write failed");
1006 printf("blkno %d nblks %d\n",
1007 fd->sc_blkno, fd->sc_nblks);
1008 #endif
1009 fdcretry(fdc);
1010 goto loop;
1011 }
1012 DMA_END(fdc->dma);
1013 read = bp->b_flags & B_READ;
1014 if (fdc->sc_errors) {
1015 diskerr(bp, "fd", "soft error", LOG_PRINTF,
1016 fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
1017 printf("\n");
1018 fdc->sc_errors = 0;
1019 }
1020 fd->sc_blkno += fd->sc_nblks;
1021 fd->sc_skip += fd->sc_nbytes;
1022 fd->sc_bcount -= fd->sc_nbytes;
1023 if (fd->sc_bcount > 0) {
1024 bp->b_cylinder = fd->sc_blkno / fd->sc_type->seccyl;
1025 goto doseek;
1026 }
1027 fdfinish(fd, bp);
1028 goto loop;
1029
1030 case DORESET:
1031 /* try a reset, keep motor on */
1032 fd_set_motor(fdc, 1);
1033 delay(100);
1034 fd_set_motor(fdc, 0);
1035 fdc->sc_state = RESETCOMPLETE;
1036 callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc);
1037 return 1; /* will return later */
1038
1039 case RESETCOMPLETE:
1040 callout_stop(&fdc->sc_timo_ch);
1041 /* clear the controller output buffer */
1042 for (i = 0; i < 4; i++) {
1043 out_fdc(iobase, NE7CMD_SENSEI);
1044 (void) fdcresult(fdc);
1045 }
1046
1047 /* fall through */
1048 case DORECAL:
1049 out_fdc(iobase, NE7CMD_RECAL); /* recalibrate function */
1050 out_fdc(iobase, fd->sc_drive);
1051 fdc->sc_state = RECALWAIT;
1052 callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc);
1053 return 1; /* will return later */
1054
1055 case RECALWAIT:
1056 callout_stop(&fdc->sc_timo_ch);
1057 fdc->sc_state = RECALCOMPLETE;
1058 /* allow 1/30 second for heads to settle */
1059 callout_reset(&fdc->sc_intr_ch, hz / 30,
1060 fdcpseudointr, fdc);
1061 return 1; /* will return later */
1062
1063 case RECALCOMPLETE:
1064 out_fdc(iobase, NE7CMD_SENSEI);
1065 if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
1066 #ifdef FD_DEBUG
1067 fdcstatus(&fd->sc_dev, 2, "recalibrate failed");
1068 #endif
1069 fdcretry(fdc);
1070 goto loop;
1071 }
1072 fd->sc_cylin = 0;
1073 goto doseek;
1074
1075 case MOTORWAIT:
1076 if (fd->sc_flags & FD_MOTOR_WAIT)
1077 return 1; /* time's not up yet */
1078 goto doseek;
1079
1080 default:
1081 fdcstatus(&fd->sc_dev, 0, "stray interrupt");
1082 return 1;
1083 }
1084 #ifdef DIAGNOSTIC
1085 panic("fdcintr: impossible");
1086 #endif
1087 #undef st0
1088 #undef cyl
1089 }
1090
1091 void
1092 fdcretry(fdc)
1093 struct fdc_softc *fdc;
1094 {
1095 struct fd_softc *fd;
1096 struct buf *bp;
1097 char bits[64];
1098
1099 fd = fdc->sc_drives.tqh_first;
1100 bp = BUFQ_FIRST(&fd->sc_q);
1101
1102 switch (fdc->sc_errors) {
1103 case 0:
1104 /* try again */
1105 fdc->sc_state = SEEKCOMPLETE;
1106 break;
1107
1108 case 1: case 2: case 3:
1109 /* didn't work; try recalibrating */
1110 fdc->sc_state = DORECAL;
1111 break;
1112
1113 case 4:
1114 /* still no go; reset the bastard */
1115 fdc->sc_state = DORESET;
1116 break;
1117
1118 default:
1119 diskerr(bp, "fd", "hard error", LOG_PRINTF,
1120 fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
1121
1122 printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
1123 NE7_ST0BITS, bits, sizeof(bits)));
1124 printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
1125 NE7_ST1BITS, bits, sizeof(bits)));
1126 printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
1127 NE7_ST2BITS, bits, sizeof(bits)));
1128 printf(" cyl %d head %d sec %d)\n",
1129 fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
1130
1131 bp->b_flags |= B_ERROR;
1132 bp->b_error = EIO;
1133 fdfinish(fd, bp);
1134 }
1135 fdc->sc_errors++;
1136 }
1137
1138 int
1139 fdsize(dev)
1140 dev_t dev;
1141 {
1142
1143 /* Swapping to floppies would not make sense. */
1144 return -1;
1145 }
1146
1147 int
1148 fddump(dev, blkno, va, size)
1149 dev_t dev;
1150 daddr_t blkno;
1151 caddr_t va;
1152 size_t size;
1153 {
1154
1155 /* Not implemented. */
1156 return ENXIO;
1157 }
1158
1159 int
1160 fdioctl(dev, cmd, addr, flag)
1161 dev_t dev;
1162 u_long cmd;
1163 caddr_t addr;
1164 int flag;
1165 {
1166 struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
1167 struct disklabel buffer;
1168 int error;
1169
1170 switch (cmd) {
1171 case DIOCGDINFO:
1172 bzero(&buffer, sizeof(buffer));
1173
1174 buffer.d_secpercyl = fd->sc_type->seccyl;
1175 buffer.d_type = DTYPE_FLOPPY;
1176 buffer.d_secsize = FDC_BSIZE;
1177
1178 if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL)
1179 return EINVAL;
1180
1181 *(struct disklabel *)addr = buffer;
1182 return 0;
1183
1184 case DIOCWLABEL:
1185 if ((flag & FWRITE) == 0)
1186 return EBADF;
1187 /* XXX do something */
1188 return 0;
1189
1190 case DIOCWDINFO:
1191 if ((flag & FWRITE) == 0)
1192 return EBADF;
1193
1194 error = setdisklabel(&buffer, (struct disklabel *)addr, 0, NULL);
1195 if (error)
1196 return error;
1197
1198 error = writedisklabel(dev, fdstrategy, &buffer, NULL);
1199 return error;
1200
1201 default:
1202 return ENOTTY;
1203 }
1204
1205 #ifdef DIAGNOSTIC
1206 panic("fdioctl: impossible");
1207 #endif
1208 }
1209