fd.c revision 1.20 1 /* $NetBSD: fd.c,v 1.20 1998/08/04 16:51:51 minoura Exp $ */
2
3 /*-
4 * Copyright (c) 1993, 1994, 1995 Charles Hannum.
5 * Copyright (c) 1990 The Regents of the University of California.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * Don Ahn.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 *
39 * @(#)fd.c 7.4 (Berkeley) 5/25/91
40 */
41
42 #include "opt_ddb.h"
43
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/kernel.h>
47 #include <sys/conf.h>
48 #include <sys/file.h>
49 #include <sys/stat.h>
50 #include <sys/ioctl.h>
51 #include <sys/malloc.h>
52 #include <sys/device.h>
53 #include <sys/disklabel.h>
54 #include <sys/dkstat.h>
55 #include <sys/disk.h>
56 #include <sys/buf.h>
57 #include <sys/uio.h>
58 #include <sys/syslog.h>
59 #include <sys/queue.h>
60
61 #include <machine/cpu.h>
62
63 #include <x68k/x68k/iodevice.h>
64 #include <x68k/dev/dmavar.h>
65 #include <x68k/dev/fdreg.h>
66 #include <x68k/dev/opmreg.h>
67
68 #include "locators.h"
69
70 #define infdc (IODEVbase->io_fdc)
71
72 #ifdef DEBUG
73 #define DPRINTF(x) if (fddebug) printf x
74 int fddebug = 0;
75 #else
76 #define DPRINTF(x)
77 #endif
78
79 #define FDUNIT(dev) (minor(dev) / 8)
80 #define FDTYPE(dev) (minor(dev) % 8)
81
82 #define b_cylin b_resid
83
84 enum fdc_state {
85 DEVIDLE = 0,
86 MOTORWAIT,
87 DOSEEK,
88 SEEKWAIT,
89 SEEKTIMEDOUT,
90 SEEKCOMPLETE,
91 DOIO,
92 IOCOMPLETE,
93 IOTIMEDOUT,
94 DORESET,
95 RESETCOMPLETE,
96 RESETTIMEDOUT,
97 DORECAL,
98 RECALWAIT,
99 RECALTIMEDOUT,
100 RECALCOMPLETE,
101 DOCOPY,
102 DOIOHALF,
103 COPYCOMPLETE,
104 };
105
106 /* software state, per controller */
107 struct fdc_softc {
108 struct device sc_dev; /* boilerplate */
109 u_char sc_flags;
110
111 struct fd_softc *sc_fd[4]; /* pointers to children */
112 TAILQ_HEAD(drivehead, fd_softc) sc_drives;
113 enum fdc_state sc_state;
114 int sc_errors; /* number of retries so far */
115 u_char sc_status[7]; /* copy of registers */
116 } fdc_softc;
117
118 bdev_decl(fd);
119 cdev_decl(fd);
120
121 int fdcintr __P((void));
122 void fdcreset __P((void));
123
124 /* controller driver configuration */
125 int fdcprobe __P((struct device *, struct cfdata *, void *));
126 void fdcattach __P((struct device *, struct device *, void *));
127 int fdprint __P((void *, const char *));
128
129 struct cfattach fdc_ca = {
130 sizeof(struct fdc_softc), fdcprobe, fdcattach
131 };
132
133 extern struct cfdriver fdc_cd;
134
135 /*
136 * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how
137 * we tell them apart.
138 */
139 struct fd_type {
140 int sectrac; /* sectors per track */
141 int heads; /* number of heads */
142 int seccyl; /* sectors per cylinder */
143 int secsize; /* size code for sectors */
144 int datalen; /* data len when secsize = 0 */
145 int steprate; /* step rate and head unload time */
146 int gap1; /* gap len between sectors */
147 int gap2; /* formatting gap */
148 int tracks; /* total num of tracks */
149 int size; /* size of disk in sectors */
150 int step; /* steps per cylinder */
151 int rate; /* transfer speed code */
152 char *name;
153 };
154
155 /* The order of entries in the following table is important -- BEWARE! */
156 struct fd_type fd_types[] = {
157 { 8,2,16,3,0xff,0xdf,0x35,0x74,77,1232,1,FDC_500KBPS, "1.2MB/[1024bytes/sector]" }, /* 1.2 MB japanese format */
158 { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS,"1.44MB" }, /* 1.44MB diskette */
159 { 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS, "1.2MB" }, /* 1.2 MB AT-diskettes */
160 { 9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS, "360KB/AT" }, /* 360kB in 1.2MB drive */
161 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS, "360KB/PC" }, /* 360kB PC diskettes */
162 { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS, "720KB" }, /* 3.5" 720kB diskette */
163 { 9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS, "720KB/x" }, /* 720kB in 1.2MB drive */
164 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS, "360KB/x" }, /* 360kB in 720kB drive */
165 };
166
167 /* software state, per disk (with up to 4 disks per ctlr) */
168 struct fd_softc {
169 struct device sc_dev;
170 struct disk sc_dk;
171
172 struct fd_type *sc_deftype; /* default type descriptor */
173 struct fd_type *sc_type; /* current type descriptor */
174
175 daddr_t sc_blkno; /* starting block number */
176 int sc_bcount; /* byte count left */
177 int sc_skip; /* bytes already transferred */
178 int sc_nblks; /* number of blocks currently tranferring */
179 int sc_nbytes; /* number of bytes currently tranferring */
180
181 int sc_drive; /* physical unit number */
182 int sc_flags;
183 #define FD_BOPEN 0x01 /* it's open */
184 #define FD_COPEN 0x02 /* it's open */
185 #define FD_OPEN (FD_BOPEN|FD_COPEN) /* it's open */
186 #define FD_MOTOR 0x04 /* motor should be on */
187 #define FD_MOTOR_WAIT 0x08 /* motor coming up */
188 #define FD_ALIVE 0x10 /* alive */
189 int sc_cylin; /* where we think the head is */
190
191 TAILQ_ENTRY(fd_softc) sc_drivechain;
192 int sc_ops; /* I/O ops since last switch */
193 struct buf sc_q; /* head of buf chain */
194 u_char *sc_copybuf; /* for secsize >=3 */
195 u_char sc_part; /* for secsize >=3 */
196 #define SEC_P10 0x02 /* first part */
197 #define SEC_P01 0x01 /* second part */
198 #define SEC_P11 0x03 /* both part */
199 };
200
201 /* floppy driver configuration */
202 int fdprobe __P((struct device *, struct cfdata *, void *));
203 void fdattach __P((struct device *, struct device *, void *));
204
205 struct cfattach fd_ca = {
206 sizeof(struct fd_softc), fdprobe, fdattach
207 };
208
209 extern struct cfdriver fd_cd;
210
211 void fdstrategy __P((struct buf *));
212 void fdstart __P((struct fd_softc *fd));
213
214 struct dkdriver fddkdriver = { fdstrategy };
215
216 void fd_set_motor __P((struct fdc_softc *fdc, int reset));
217 void fd_motor_off __P((void *arg));
218 void fd_motor_on __P((void *arg));
219 int fdcresult __P((struct fdc_softc *fdc));
220 int out_fdc __P((u_char x));
221 void fdcstart __P((struct fdc_softc *fdc));
222 void fdcstatus __P((struct device *dv, int n, char *s));
223 void fdctimeout __P((void *arg));
224 void fdcpseudointr __P((void *arg));
225 void fdcretry __P((struct fdc_softc *fdc));
226 void fdfinish __P((struct fd_softc *fd, struct buf *bp));
227 __inline struct fd_type *fd_dev_to_type __P((struct fd_softc *, dev_t));
228 static int fdcpoll __P((struct fdc_softc *));
229 static int fdgetdisklabel __P((struct fd_softc *, dev_t));
230 static void fd_do_eject __P((int));
231
232 void fd_mountroot_hook __P((struct device *));
233
234 /* dma transfer routines */
235 __inline static void fdc_dmastart __P((int, caddr_t, int));
236 void fdcdmaintr __P((void));
237 void fdcdmaerrintr __P((void));
238
239 #define FDDI_EN 0x02
240 #define FDCI_EN 0x04
241 #define FDD_INT 0x40
242 #define FDC_INT 0x80
243
244 #define DMA_BRD 0x01
245 #define DMA_BWR 0x02
246
247 #define DRQ 0
248
249 static u_char *fdc_dmabuf;
250
251 __inline static void
252 fdc_dmastart(read, addr, count)
253 int read;
254 caddr_t addr;
255 int count;
256 {
257 volatile struct dmac *dmac = &IODEVbase->io_dma[DRQ];
258
259 DPRINTF(("fdc_dmastart: (%s, addr = %p, count = %d\n",
260 read ? "read" : "write", addr, count));
261 if (dmarangecheck((vm_offset_t)addr, count)) {
262 dma_bouncebytes[DRQ] = count;
263 dma_dataaddr[DRQ] = addr;
264 if (!(read)) {
265 bcopy(addr, dma_bouncebuf[DRQ], count);
266 dma_bounced[DRQ] = DMA_BWR;
267 } else {
268 dma_bounced[DRQ] = DMA_BRD;
269 }
270 addr = dma_bouncebuf[DRQ];
271 } else {
272 dma_bounced[DRQ] = 0;
273 }
274
275 dmac->csr = 0xff;
276 dmac->ocr = read ? 0xb2 : 0x32;
277 dmac->mtc = (unsigned short)count;
278 asm("nop");
279 asm("nop");
280 dmac->mar = (unsigned long)kvtop(addr);
281 #if defined(M68040) || defined(M68060)
282 /*
283 * Push back dirty cache lines
284 */
285 if (mmutype == MMU_68040)
286 DCFP(kvtop(addr));
287 #endif
288 dmac->ccr = 0x88;
289 }
290
291 void
292 fdcdmaintr()
293 {
294 volatile struct dmac *dmac = &IODEVbase->io_dma[DRQ];
295 dmac->csr = 0xff;
296 PCIA(); /* XXX? by oki */
297 if (dma_bounced[DRQ] == DMA_BRD) {
298 bcopy(dma_bouncebuf[DRQ], dma_dataaddr[DRQ], dma_bouncebytes[DRQ]);
299 }
300 dma_bounced[DRQ] = 0;
301 }
302
303 void
304 fdcdmaerrintr()
305 {
306 volatile struct dmac *dmac = &IODEVbase->io_dma[DRQ];
307 printf("fdcdmaerrintr: csr=%x, cer=%x\n", dmac->csr, dmac->cer);
308 dmac->csr = 0xff;
309 }
310
311 /* ARGSUSED */
312 int
313 fdcprobe(parent, cf, aux)
314 struct device *parent;
315 struct cfdata *cf;
316 void *aux;
317 {
318 if (strcmp("fdc", aux) != 0)
319 return 0;
320 return 1;
321 }
322
323 /*
324 * Arguments passed between fdcattach and fdprobe.
325 */
326 struct fdc_attach_args {
327 int fa_drive;
328 struct fd_type *fa_deftype;
329 };
330
331 /*
332 * Print the location of a disk drive (called just before attaching the
333 * the drive). If `fdc' is not NULL, the drive was found but was not
334 * in the system config file; print the drive name as well.
335 * Return QUIET (config_find ignores this if the device was configured) to
336 * avoid printing `fdN not configured' messages.
337 */
338 int
339 fdprint(aux, fdc)
340 void *aux;
341 const char *fdc;
342 {
343 register struct fdc_attach_args *fa = aux;
344
345 if (!fdc)
346 printf(" drive %d", fa->fa_drive);
347 return QUIET;
348 }
349
350 void
351 fdcattach(parent, self, aux)
352 struct device *parent, *self;
353 void *aux;
354 {
355 struct fdc_softc *fdc = (void *)self;
356 volatile struct dmac *dmac = &IODEVbase->io_dma[DRQ];
357 struct fdc_attach_args fa;
358
359 fdc->sc_state = DEVIDLE;
360 TAILQ_INIT(&fdc->sc_drives);
361
362 fdc->sc_flags = 0;
363
364 /* reset */
365 ioctlr.intr &= (~FDDI_EN);
366 ioctlr.intr |= FDCI_EN;
367 fdcresult(fdc);
368 fdcreset();
369
370 /* Initialize DMAC channel */
371 dmac->dcr = 0x80;
372 dmac->scr = 0x04;
373 dmac->csr = 0xff;
374 dmac->cpr = 0x00;
375 dmac->dar = (unsigned long) kvtop((void *)&infdc.data);
376 dmac->mfc = 0x05;
377 dmac->dfc = 0x05;
378 dmac->bfc = 0x05;
379 dmac->niv = 0x64;
380 dmac->eiv = 0x65;
381
382 printf(": uPD72065 FDC\n");
383 out_fdc(NE7CMD_SPECIFY);/* specify command */
384 out_fdc(0xd0);
385 out_fdc(0x10);
386
387 fdc_dmabuf = (u_char *)malloc(NBPG, M_DEVBUF, M_WAITOK);
388 if (fdc_dmabuf == 0)
389 printf("fdcattach: WARNING!! malloc() failed.\n");
390 dma_bouncebuf[DRQ] = fdc_dmabuf;
391
392 /* physical limit: four drives per controller. */
393 for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) {
394 (void)config_found(self, (void *)&fa, fdprint);
395 }
396 }
397
398 void
399 fdcreset()
400 {
401 infdc.stat = FDC_RESET;
402 }
403
404 static int
405 fdcpoll(fdc)
406 struct fdc_softc *fdc;
407 {
408 int i = 25000;
409 while (--i > 0) {
410 if ((ioctlr.intr & 0x80)) {
411 out_fdc(NE7CMD_SENSEI);
412 fdcresult(fdc);
413 break;
414 }
415 DELAY(100);
416 }
417 return i;
418 }
419
420 int
421 fdprobe(parent, cf, aux)
422 struct device *parent;
423 struct cfdata *cf;
424 void *aux;
425 {
426 struct fdc_softc *fdc = (void *)parent;
427 struct fd_type *type;
428 int drive = cf->cf_unit;
429 int n;
430 int found = 0;
431 int i;
432
433 if (cf->cf_loc[FDCCF_UNIT] != FDCCF_UNIT_DEFAULT &&
434 cf->cf_loc[FDCCF_UNIT] != drive)
435 return 0;
436
437 type = &fd_types[0]; /* XXX 1.2MB */
438
439 ioctlr.intr &= (~FDCI_EN);
440
441 /* select drive and turn on motor */
442 infdc.select = 0x80 | (type->rate << 4)| drive;
443 fdc_force_ready(FDCRDY);
444 fdcpoll(fdc);
445
446 retry:
447 out_fdc(NE7CMD_RECAL);
448 out_fdc(drive);
449
450 i = 25000;
451 while (--i > 0) {
452 if ((ioctlr.intr & 0x80)) {
453 out_fdc(NE7CMD_SENSEI);
454 n = fdcresult(fdc);
455 break;
456 }
457 DELAY(100);
458 }
459
460 #ifdef FDDEBUG
461 {
462 int i;
463 printf("fdprobe: status");
464 for (i = 0; i < n; i++)
465 printf(" %x", fdc->sc_status[i]);
466 printf("\n");
467 }
468 #endif
469
470 if (n == 2) {
471 if ((fdc->sc_status[0] & 0xf0) == 0x20) {
472 found = 1;
473 } else if ((fdc->sc_status[0] & 0xf0) == 0xc0) {
474 goto retry;
475 }
476 }
477
478 /* turn off motor */
479 infdc.select = (type->rate << 4)| drive;
480 fdc_force_ready(FDCSTBY);
481 if (!found) {
482 ioctlr.intr |= FDCI_EN;
483 return 0;
484 }
485
486 return 1;
487 }
488
489 void
490 fdattach(parent, self, aux)
491 struct device *parent;
492 struct device *self;
493 void *aux;
494 {
495 struct fdc_softc *fdc = (void *)parent;
496 register struct fd_softc *fd = (void *)self;
497 struct fdc_attach_args *fa = aux;
498 int drive = fa->fa_drive;
499 struct fd_type *type = &fd_types[0]; /* XXX 1.2MB */
500
501 fd->sc_flags = 0;
502
503 ioctlr.intr |= FDCI_EN;
504
505 if (type)
506 printf(": %s %d cyl, %d head, %d sec\n", type->name,
507 type->tracks, type->heads, type->sectrac);
508 else
509 printf(": density unknown\n");
510
511 fd->sc_cylin = -1;
512 fd->sc_drive = drive;
513 fd->sc_deftype = type;
514 fdc->sc_fd[drive] = fd;
515
516 fd->sc_copybuf = (u_char *)malloc(NBPG, M_DEVBUF, M_WAITOK);
517 if (fd->sc_copybuf == 0)
518 printf("fdprobe: WARNING!! malloc() failed.\n");
519 fd->sc_flags |= FD_ALIVE;
520
521 /*
522 * Initialize and attach the disk structure.
523 */
524 fd->sc_dk.dk_name = fd->sc_dev.dv_xname;
525 fd->sc_dk.dk_driver = &fddkdriver;
526 disk_attach(&fd->sc_dk);
527
528 /*
529 * Establish a mountroot_hook anyway in case we booted
530 * with RB_ASKNAME and get selected as the boot device.
531 */
532 mountroothook_establish(fd_mountroot_hook, &fd->sc_dev);
533 }
534
535 __inline struct fd_type *
536 fd_dev_to_type(fd, dev)
537 struct fd_softc *fd;
538 dev_t dev;
539 {
540 int type = FDTYPE(dev);
541
542 if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
543 return NULL;
544 return &fd_types[type];
545 }
546
547 void
548 fdstrategy(bp)
549 register struct buf *bp; /* IO operation to perform */
550 {
551 struct fd_softc *fd;
552 int unit = FDUNIT(bp->b_dev);
553 int sz;
554 int s;
555
556 if (unit >= fd_cd.cd_ndevs ||
557 (fd = fd_cd.cd_devs[unit]) == 0 ||
558 bp->b_blkno < 0 ||
559 (bp->b_bcount % FDC_BSIZE) != 0) {
560 #ifdef FDDEBUG
561 printf("fdstrategy: unit=%d, blkno=%d, bcount=%d\n", unit,
562 bp->b_blkno, bp->b_bcount);
563 #endif
564 bp->b_error = EINVAL;
565 goto bad;
566 }
567
568 /* If it's a null transfer, return immediately. */
569 if (bp->b_bcount == 0)
570 goto done;
571
572 sz = howmany(bp->b_bcount, FDC_BSIZE);
573
574 if (bp->b_blkno + sz > (fd->sc_type->size << (fd->sc_type->secsize - 2))) {
575 sz = (fd->sc_type->size << (fd->sc_type->secsize - 2)) - bp->b_blkno;
576 if (sz == 0) {
577 /* If exactly at end of disk, return EOF. */
578 bp->b_resid = bp->b_bcount;
579 goto done;
580 }
581 if (sz < 0) {
582 /* If past end of disk, return EINVAL. */
583 bp->b_error = EINVAL;
584 goto bad;
585 }
586 /* Otherwise, truncate request. */
587 bp->b_bcount = sz << DEV_BSHIFT;
588 }
589
590 bp->b_cylin = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE)
591 / (fd->sc_type->seccyl * (1 << (fd->sc_type->secsize - 2)));
592
593 DPRINTF(("fdstrategy: %s b_blkno %d b_bcount %ld cylin %ld\n",
594 bp->b_flags & B_READ ? "read" : "write",
595 bp->b_blkno, bp->b_bcount, bp->b_cylin));
596 /* Queue transfer on drive, activate drive and controller if idle. */
597 s = splbio();
598 disksort(&fd->sc_q, bp);
599 untimeout(fd_motor_off, fd); /* a good idea */
600 if (!fd->sc_q.b_active)
601 fdstart(fd);
602 #ifdef DIAGNOSTIC
603 else {
604 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
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 bad:
615 bp->b_flags |= B_ERROR;
616 done:
617 /* Toss transfer; we're done early. */
618 biodone(bp);
619 }
620
621 void
622 fdstart(fd)
623 struct fd_softc *fd;
624 {
625 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
626 int active = fdc->sc_drives.tqh_first != 0;
627
628 /* Link into controller queue. */
629 fd->sc_q.b_active = 1;
630 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
631
632 /* If controller not already active, start it. */
633 if (!active)
634 fdcstart(fdc);
635 }
636
637 void
638 fdfinish(fd, bp)
639 struct fd_softc *fd;
640 struct buf *bp;
641 {
642 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
643
644 /*
645 * Move this drive to the end of the queue to give others a `fair'
646 * chance. We only force a switch if N operations are completed while
647 * another drive is waiting to be serviced, since there is a long motor
648 * startup delay whenever we switch.
649 */
650 if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) {
651 fd->sc_ops = 0;
652 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
653 if (bp->b_actf) {
654 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
655 } else
656 fd->sc_q.b_active = 0;
657 }
658 bp->b_resid = fd->sc_bcount;
659 fd->sc_skip = 0;
660 fd->sc_q.b_actf = bp->b_actf;
661 biodone(bp);
662 /* turn off motor 5s from now */
663 timeout(fd_motor_off, fd, 5 * hz);
664 fdc->sc_state = DEVIDLE;
665 }
666
667 int
668 fdread(dev, uio, flags)
669 dev_t dev;
670 struct uio *uio;
671 int flags;
672 {
673
674 return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
675 }
676
677 int
678 fdwrite(dev, uio, flags)
679 dev_t dev;
680 struct uio *uio;
681 int flags;
682 {
683
684 return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
685 }
686
687 void
688 fd_set_motor(fdc, reset)
689 struct fdc_softc *fdc;
690 int reset;
691 {
692 struct fd_softc *fd;
693 int n;
694
695 DPRINTF(("fd_set_motor:\n"));
696 for (n = 0; n < 4; n++)
697 if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR)) {
698 infdc.select = 0x80 | (fd->sc_type->rate << 4)| n;
699 }
700 }
701
702 void
703 fd_motor_off(arg)
704 void *arg;
705 {
706 struct fd_softc *fd = arg;
707 int s;
708
709 DPRINTF(("fd_motor_off:\n"));
710
711 s = splbio();
712 fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
713 infdc.select = (fd->sc_type->rate << 4) | fd->sc_drive;
714 #if 0
715 fd_set_motor((struct fdc_softc *)&fdc_softc[0], 0); /* XXX */
716 #endif
717 splx(s);
718 }
719
720 void
721 fd_motor_on(arg)
722 void *arg;
723 {
724 struct fd_softc *fd = arg;
725 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
726 int s;
727
728 DPRINTF(("fd_motor_on:\n"));
729
730 s = splbio();
731 fd->sc_flags &= ~FD_MOTOR_WAIT;
732 if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT))
733 (void) fdcintr();
734 splx(s);
735 }
736
737 int
738 fdcresult(fdc)
739 struct fdc_softc *fdc;
740 {
741 u_char i;
742 int j = 100000,
743 n = 0;
744
745 for (; j; j--) {
746
747 i = infdc.stat & (NE7_DIO | NE7_RQM | NE7_CB);
748
749
750 if (i == NE7_RQM)
751 return n;
752 if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
753 if (n >= sizeof(fdc->sc_status)) {
754 log(LOG_ERR, "fdcresult: overrun\n");
755 return -1;
756 }
757 fdc->sc_status[n++] = infdc.data;
758 }
759 }
760 log(LOG_ERR, "fdcresult: timeout\n");
761 return -1;
762 }
763
764 int
765 out_fdc(x)
766 u_char x;
767 {
768 int i = 100000;
769
770 while ((infdc.stat & NE7_DIO) && i-- > 0);
771 if (i <= 0)
772 return -1;
773 while ((infdc.stat & NE7_RQM) == 0 && i-- > 0);
774 if (i <= 0)
775 return -1;
776
777 infdc.data = x;
778
779 return 0;
780 }
781
782 int
783 fdopen(dev, flags, mode, p)
784 dev_t dev;
785 int flags, mode;
786 struct proc *p;
787 {
788 int unit;
789 struct fd_softc *fd;
790 struct fd_type *type;
791
792 unit = FDUNIT(dev);
793 if (unit >= fd_cd.cd_ndevs)
794 return ENXIO;
795 fd = fd_cd.cd_devs[unit];
796 if (fd == 0)
797 return ENXIO;
798 type = fd_dev_to_type(fd, dev);
799 if (type == NULL)
800 return ENXIO;
801
802 if ((fd->sc_flags & FD_OPEN) != 0 &&
803 fd->sc_type != type)
804 return EBUSY;
805
806 if ((fd->sc_flags & FD_OPEN) == 0) {
807 /* Lock eject button */
808 infdc.drvstat = 0x40 | ( 1 << unit);
809 infdc.drvstat = 0x40;
810 }
811
812 fd->sc_type = type;
813 fd->sc_cylin = -1;
814
815 switch (mode) {
816 case S_IFCHR:
817 fd->sc_flags |= FD_COPEN;
818 break;
819 case S_IFBLK:
820 fd->sc_flags |= FD_BOPEN;
821 break;
822 }
823
824 fdgetdisklabel(fd, dev);
825
826 return 0;
827 }
828
829 int
830 fdclose(dev, flags, mode, p)
831 dev_t dev;
832 int flags, mode;
833 struct proc *p;
834 {
835 int unit = FDUNIT(dev);
836 struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
837
838 DPRINTF(("fdclose %d\n", unit));
839
840 switch (mode) {
841 case S_IFCHR:
842 fd->sc_flags &= ~FD_COPEN;
843 break;
844 case S_IFBLK:
845 fd->sc_flags &= ~FD_BOPEN;
846 break;
847 }
848
849 if ((fd->sc_flags & FD_OPEN) == 0) {
850 infdc.drvstat = ( 1 << unit);
851 infdc.drvstat = 0x00;
852 }
853 return 0;
854 }
855
856 void
857 fdcstart(fdc)
858 struct fdc_softc *fdc;
859 {
860
861 #ifdef DIAGNOSTIC
862 /* only got here if controller's drive queue was inactive; should
863 be in idle state */
864 if (fdc->sc_state != DEVIDLE) {
865 printf("fdcstart: not idle\n");
866 return;
867 }
868 #endif
869 (void) fdcintr();
870 }
871
872 void
873 fdcstatus(dv, n, s)
874 struct device *dv;
875 int n;
876 char *s;
877 {
878 struct fdc_softc *fdc = (void *)dv->dv_parent;
879 char bits[64];
880
881 if (n == 0) {
882 out_fdc(NE7CMD_SENSEI);
883 (void) fdcresult(fdc);
884 n = 2;
885 }
886
887 printf("%s: %s: state %d", dv->dv_xname, s, fdc->sc_state);
888
889 switch (n) {
890 case 0:
891 printf("\n");
892 break;
893 case 2:
894 printf(" (st0 %s cyl %d)\n",
895 bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS,
896 bits, sizeof(bits)), fdc->sc_status[1]);
897 break;
898 case 7:
899 printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
900 NE7_ST0BITS, bits, sizeof(bits)));
901 printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
902 NE7_ST1BITS, bits, sizeof(bits)));
903 printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
904 NE7_ST2BITS, bits, sizeof(bits)));
905 printf(" cyl %d head %d sec %d)\n",
906 fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
907 break;
908 #ifdef DIAGNOSTIC
909 default:
910 printf(" fdcstatus: weird size: %d\n", n);
911 break;
912 #endif
913 }
914 }
915
916 void
917 fdctimeout(arg)
918 void *arg;
919 {
920 struct fdc_softc *fdc = arg;
921 struct fd_softc *fd = fdc->sc_drives.tqh_first;
922 int s;
923
924 s = splbio();
925 fdcstatus(&fd->sc_dev, 0, "timeout");
926
927 if (fd->sc_q.b_actf)
928 fdc->sc_state++;
929 else
930 fdc->sc_state = DEVIDLE;
931
932 (void) fdcintr();
933 splx(s);
934 }
935
936 void
937 fdcpseudointr(arg)
938 void *arg;
939 {
940 int s;
941
942 /* just ensure it has the right spl */
943 s = splbio();
944 (void) fdcintr();
945 splx(s);
946 }
947
948 int
949 fdcintr()
950 {
951 struct fdc_softc *fdc = (void *)((struct fd_softc*)fd_cd.cd_devs[0])->sc_dev.dv_parent; /* XXX */
952 #define st0 fdc->sc_status[0]
953 #define cyl fdc->sc_status[1]
954 struct fd_softc *fd;
955 struct buf *bp;
956 int read, head, sec, pos, i, sectrac, nblks;
957 int tmp;
958 struct fd_type *type;
959
960 loop:
961 fd = fdc->sc_drives.tqh_first;
962 if (fd == NULL) {
963 DPRINTF(("fdcintr: set DEVIDLE\n"));
964 if (fdc->sc_state == DEVIDLE) {
965 if ((ioctlr.intr & 0x80)) {
966 out_fdc(NE7CMD_SENSEI);
967 if ((tmp = fdcresult(fdc)) != 2 || (st0 & 0xf8) != 0x20) {
968 goto loop;
969 }
970 }
971 }
972 /* no drives waiting; end */
973 fdc->sc_state = DEVIDLE;
974 return 1;
975 }
976
977 /* Is there a transfer to this drive? If not, deactivate drive. */
978 bp = fd->sc_q.b_actf;
979 if (bp == NULL) {
980 fd->sc_ops = 0;
981 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
982 fd->sc_q.b_active = 0;
983 goto loop;
984 }
985
986 switch (fdc->sc_state) {
987 case DEVIDLE:
988 DPRINTF(("fdcintr: in DEVIDLE\n"));
989 fdc->sc_errors = 0;
990 fd->sc_skip = 0;
991 fd->sc_bcount = bp->b_bcount;
992 fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
993 untimeout(fd_motor_off, fd);
994 if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
995 fdc->sc_state = MOTORWAIT;
996 return 1;
997 }
998 if ((fd->sc_flags & FD_MOTOR) == 0) {
999 /* Turn on the motor */
1000 /* being careful about other drives. */
1001 for (i = 0; i < 4; i++) {
1002 struct fd_softc *ofd = fdc->sc_fd[i];
1003 if (ofd && ofd->sc_flags & FD_MOTOR) {
1004 untimeout(fd_motor_off, ofd);
1005 ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
1006 break;
1007 }
1008 }
1009 fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
1010 fd_set_motor(fdc, 0);
1011 fdc->sc_state = MOTORWAIT;
1012 /* allow .5s for motor to stabilize */
1013 timeout(fd_motor_on, fd, hz / 2);
1014 return 1;
1015 }
1016 /* Make sure the right drive is selected. */
1017 fd_set_motor(fdc, 0);
1018
1019 /* fall through */
1020 case DOSEEK:
1021 doseek:
1022 DPRINTF(("fdcintr: in DOSEEK\n"));
1023 if (fd->sc_cylin == bp->b_cylin)
1024 goto doio;
1025
1026 out_fdc(NE7CMD_SPECIFY);/* specify command */
1027 out_fdc(0xd0); /* XXX const */
1028 out_fdc(0x10);
1029
1030 out_fdc(NE7CMD_SEEK); /* seek function */
1031 out_fdc(fd->sc_drive); /* drive number */
1032 out_fdc(bp->b_cylin * fd->sc_type->step);
1033
1034 fd->sc_cylin = -1;
1035 fdc->sc_state = SEEKWAIT;
1036
1037 fd->sc_dk.dk_seek++;
1038 disk_busy(&fd->sc_dk);
1039
1040 timeout(fdctimeout, fdc, 4 * hz);
1041 return 1;
1042
1043 case DOIO:
1044 doio:
1045 DPRINTF(("fdcintr: DOIO: "));
1046 type = fd->sc_type;
1047 sectrac = type->sectrac;
1048 pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
1049 sec = pos / (1 << (type->secsize - 2));
1050 if (type->secsize == 2) {
1051 fd->sc_part = SEC_P11;
1052 nblks = (sectrac - sec) << (type->secsize - 2);
1053 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
1054 DPRINTF(("nblks(0)"));
1055 } else if ((fd->sc_blkno % 2) == 0) {
1056 if (fd->sc_bcount & 0x00000200) {
1057 if (fd->sc_bcount == FDC_BSIZE) {
1058 fd->sc_part = SEC_P10;
1059 nblks = 1;
1060 DPRINTF(("nblks(1)"));
1061 } else {
1062 fd->sc_part = SEC_P11;
1063 nblks = (sectrac - sec) * 2;
1064 nblks = min(nblks, fd->sc_bcount
1065 / FDC_BSIZE - 1);
1066 DPRINTF(("nblks(2)"));
1067 }
1068 } else {
1069 fd->sc_part = SEC_P11;
1070 nblks = (sectrac - sec)
1071 << (type->secsize - 2);
1072 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
1073 DPRINTF(("nblks(3)"));
1074 }
1075 } else {
1076 fd->sc_part = SEC_P01;
1077 nblks = 1;
1078 DPRINTF(("nblks(4)"));
1079 }
1080 nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
1081 DPRINTF((" %d\n", nblks));
1082 fd->sc_nblks = nblks;
1083 fd->sc_nbytes = nblks * FDC_BSIZE;
1084 head = (fd->sc_blkno
1085 % (type->seccyl * (1 << (type->secsize - 2))))
1086 / (type->sectrac * (1 << (type->secsize - 2)));
1087
1088 #ifdef DIAGNOSTIC
1089 {int block;
1090 block = ((fd->sc_cylin * type->heads + head) * type->sectrac
1091 + sec) * (1 << (type->secsize - 2));
1092 block += (fd->sc_part == SEC_P01) ? 1 : 0;
1093 if (block != fd->sc_blkno) {
1094 printf("C H R N: %d %d %d %d\n", fd->sc_cylin, head, sec, type->secsize);
1095 printf("fdcintr: doio: block %d != blkno %d\n", block, fd->sc_blkno);
1096 #ifdef DDB
1097 Debugger();
1098 #endif
1099 }}
1100 #endif
1101 read = bp->b_flags & B_READ;
1102 DPRINTF(("fdcintr: %s drive %d track %d head %d sec %d nblks %d, skip %d\n",
1103 read ? "read" : "write", fd->sc_drive, fd->sc_cylin,
1104 head, sec, nblks, fd->sc_skip));
1105 DPRINTF(("C H R N: %d %d %d %d\n", fd->sc_cylin, head, sec,
1106 type->secsize));
1107
1108 if (fd->sc_part != SEC_P11)
1109 goto docopy;
1110
1111 fdc_dmastart(read, bp->b_data + fd->sc_skip, fd->sc_nbytes);
1112 if (read)
1113 out_fdc(NE7CMD_READ); /* READ */
1114 else
1115 out_fdc(NE7CMD_WRITE); /* WRITE */
1116 out_fdc((head << 2) | fd->sc_drive);
1117 out_fdc(bp->b_cylin); /* cylinder */
1118 out_fdc(head);
1119 out_fdc(sec + 1); /* sector +1 */
1120 out_fdc(type->secsize); /* sector size */
1121 out_fdc(type->sectrac); /* sectors/track */
1122 out_fdc(type->gap1); /* gap1 size */
1123 out_fdc(type->datalen); /* data length */
1124 fdc->sc_state = IOCOMPLETE;
1125
1126 disk_busy(&fd->sc_dk);
1127
1128 /* allow 2 seconds for operation */
1129 timeout(fdctimeout, fdc, 2 * hz);
1130 return 1; /* will return later */
1131
1132 case DOCOPY:
1133 docopy:
1134 DPRINTF(("fdcintr: DOCOPY:\n"));
1135 fdc_dmastart(B_READ, fd->sc_copybuf, 1024);
1136 out_fdc(NE7CMD_READ); /* READ */
1137 out_fdc((head << 2) | fd->sc_drive);
1138 out_fdc(bp->b_cylin); /* cylinder */
1139 out_fdc(head);
1140 out_fdc(sec + 1); /* sector +1 */
1141 out_fdc(type->secsize); /* sector size */
1142 out_fdc(type->sectrac); /* sectors/track */
1143 out_fdc(type->gap1); /* gap1 size */
1144 out_fdc(type->datalen); /* data length */
1145 fdc->sc_state = COPYCOMPLETE;
1146 /* allow 2 seconds for operation */
1147 timeout(fdctimeout, fdc, 2 * hz);
1148 return 1; /* will return later */
1149
1150 case DOIOHALF:
1151 doiohalf:
1152 DPRINTF((" DOIOHALF:\n"));
1153
1154 #ifdef DIAGNOSTIC
1155 type = fd->sc_type;
1156 sectrac = type->sectrac;
1157 pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
1158 sec = pos / (1 << (type->secsize - 2));
1159 head = (fd->sc_blkno
1160 % (type->seccyl * (1 << (type->secsize - 2))))
1161 / (type->sectrac * (1 << (type->secsize - 2)));
1162 {int block;
1163 block = ((fd->sc_cylin * type->heads + head) * type->sectrac + sec)
1164 * (1 << (type->secsize - 2));
1165 block += (fd->sc_part == SEC_P01) ? 1 : 0;
1166 if (block != fd->sc_blkno) {
1167 printf("fdcintr: block %d != blkno %d\n", block, fd->sc_blkno);
1168 #ifdef DDB
1169 Debugger();
1170 #endif
1171 }}
1172 #endif
1173 if (read = bp->b_flags & B_READ) {
1174 bcopy(fd->sc_copybuf
1175 + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0),
1176 bp->b_data + fd->sc_skip,
1177 FDC_BSIZE);
1178 fdc->sc_state = IOCOMPLETE;
1179 goto iocomplete2;
1180 } else {
1181 bcopy(bp->b_data + fd->sc_skip,
1182 fd->sc_copybuf
1183 + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0),
1184 FDC_BSIZE);
1185 fdc_dmastart(read, fd->sc_copybuf, 1024);
1186 }
1187 out_fdc(NE7CMD_WRITE); /* WRITE */
1188 out_fdc((head << 2) | fd->sc_drive);
1189 out_fdc(bp->b_cylin); /* cylinder */
1190 out_fdc(head);
1191 out_fdc(sec + 1); /* sector +1 */
1192 out_fdc(fd->sc_type->secsize); /* sector size */
1193 out_fdc(sectrac); /* sectors/track */
1194 out_fdc(fd->sc_type->gap1); /* gap1 size */
1195 out_fdc(fd->sc_type->datalen); /* data length */
1196 fdc->sc_state = IOCOMPLETE;
1197 /* allow 2 seconds for operation */
1198 timeout(fdctimeout, fdc, 2 * hz);
1199 return 1; /* will return later */
1200
1201 case SEEKWAIT:
1202 untimeout(fdctimeout, fdc);
1203 fdc->sc_state = SEEKCOMPLETE;
1204 /* allow 1/50 second for heads to settle */
1205 /* timeout(fdcpseudointr, fdc, hz / 50);*/
1206 return 1;
1207
1208 case SEEKCOMPLETE:
1209 /* Make sure seek really happened */
1210 DPRINTF(("fdcintr: SEEKCOMPLETE: FDC status = %x\n",
1211 infdc.stat));
1212 out_fdc(NE7CMD_SENSEI);
1213 tmp = fdcresult(fdc);
1214 if ((st0 & 0xf8) == 0xc0) {
1215 DPRINTF(("fdcintr: first seek!\n"));
1216 fdc->sc_state = DORECAL;
1217 goto loop;
1218 } else if (tmp != 2 || (st0 & 0xf8) != 0x20 || cyl != bp->b_cylin) {
1219 #ifdef FDDEBUG
1220 fdcstatus(&fd->sc_dev, 2, "seek failed");
1221 #endif
1222 fdcretry(fdc);
1223 goto loop;
1224 }
1225 fd->sc_cylin = bp->b_cylin;
1226 goto doio;
1227
1228 case IOTIMEDOUT:
1229 #if 0
1230 isa_dmaabort(fdc->sc_drq);
1231 #endif
1232 case SEEKTIMEDOUT:
1233 case RECALTIMEDOUT:
1234 case RESETTIMEDOUT:
1235 fdcretry(fdc);
1236 goto loop;
1237
1238 case IOCOMPLETE: /* IO DONE, post-analyze */
1239 untimeout(fdctimeout, fdc);
1240 DPRINTF(("fdcintr: in IOCOMPLETE\n"));
1241 if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
1242 printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0);
1243 #if 0
1244 isa_dmaabort(fdc->sc_drq);
1245 #endif
1246 fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
1247 "read failed" : "write failed");
1248 printf("blkno %d nblks %d\n",
1249 fd->sc_blkno, fd->sc_nblks);
1250 fdcretry(fdc);
1251 goto loop;
1252 }
1253 #if 0
1254 isa_dmadone(bp->b_flags & B_READ, bp->b_data + fd->sc_skip,
1255 nblks * FDC_BSIZE, fdc->sc_drq);
1256 #endif
1257 iocomplete2:
1258 if (fdc->sc_errors) {
1259 diskerr(bp, "fd", "soft error", LOG_PRINTF,
1260 fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
1261 printf("\n");
1262 fdc->sc_errors = 0;
1263 }
1264 fd->sc_blkno += fd->sc_nblks;
1265 fd->sc_skip += fd->sc_nbytes;
1266 fd->sc_bcount -= fd->sc_nbytes;
1267 DPRINTF(("fd->sc_bcount = %d\n", fd->sc_bcount));
1268 if (fd->sc_bcount > 0) {
1269 bp->b_cylin = fd->sc_blkno
1270 / (fd->sc_type->seccyl
1271 * (1 << (fd->sc_type->secsize - 2)));
1272 goto doseek;
1273 }
1274 fdfinish(fd, bp);
1275 goto loop;
1276
1277 case COPYCOMPLETE: /* IO DONE, post-analyze */
1278 DPRINTF(("fdcintr: COPYCOMPLETE:"));
1279 untimeout(fdctimeout, fdc);
1280 if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
1281 printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0);
1282 #if 0
1283 isa_dmaabort(fdc->sc_drq);
1284 #endif
1285 fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
1286 "read failed" : "write failed");
1287 printf("blkno %d nblks %d\n",
1288 fd->sc_blkno, fd->sc_nblks);
1289 fdcretry(fdc);
1290 goto loop;
1291 }
1292 goto doiohalf;
1293
1294 case DORESET:
1295 DPRINTF(("fdcintr: in DORESET\n"));
1296 /* try a reset, keep motor on */
1297 fd_set_motor(fdc, 1);
1298 DELAY(100);
1299 fd_set_motor(fdc, 0);
1300 fdc->sc_state = RESETCOMPLETE;
1301 timeout(fdctimeout, fdc, hz / 2);
1302 return 1; /* will return later */
1303
1304 case RESETCOMPLETE:
1305 DPRINTF(("fdcintr: in RESETCOMPLETE\n"));
1306 untimeout(fdctimeout, fdc);
1307 /* clear the controller output buffer */
1308 for (i = 0; i < 4; i++) {
1309 out_fdc(NE7CMD_SENSEI);
1310 (void) fdcresult(fdc);
1311 }
1312
1313 /* fall through */
1314 case DORECAL:
1315 DPRINTF(("fdcintr: in DORECAL\n"));
1316 out_fdc(NE7CMD_RECAL); /* recalibrate function */
1317 out_fdc(fd->sc_drive);
1318 fdc->sc_state = RECALWAIT;
1319 timeout(fdctimeout, fdc, 5 * hz);
1320 return 1; /* will return later */
1321
1322 case RECALWAIT:
1323 DPRINTF(("fdcintr: in RECALWAIT\n"));
1324 untimeout(fdctimeout, fdc);
1325 fdc->sc_state = RECALCOMPLETE;
1326 /* allow 1/30 second for heads to settle */
1327 /* timeout(fdcpseudointr, fdc, hz / 30);*/
1328 return 1; /* will return later */
1329
1330 case RECALCOMPLETE:
1331 DPRINTF(("fdcintr: in RECALCOMPLETE\n"));
1332 out_fdc(NE7CMD_SENSEI);
1333 tmp = fdcresult(fdc);
1334 if ((st0 & 0xf8) == 0xc0) {
1335 DPRINTF(("fdcintr: first seek!\n"));
1336 fdc->sc_state = DORECAL;
1337 goto loop;
1338 } else if (tmp != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
1339 #ifdef FDDEBUG
1340 fdcstatus(&fd->sc_dev, 2, "recalibrate failed");
1341 #endif
1342 fdcretry(fdc);
1343 goto loop;
1344 }
1345 fd->sc_cylin = 0;
1346 goto doseek;
1347
1348 case MOTORWAIT:
1349 if (fd->sc_flags & FD_MOTOR_WAIT)
1350 return 1; /* time's not up yet */
1351 goto doseek;
1352
1353 default:
1354 fdcstatus(&fd->sc_dev, 0, "stray interrupt");
1355 return 1;
1356 }
1357 #ifdef DIAGNOSTIC
1358 panic("fdcintr: impossible");
1359 #endif
1360 #undef st0
1361 #undef cyl
1362 }
1363
1364 void
1365 fdcretry(fdc)
1366 struct fdc_softc *fdc;
1367 {
1368 struct fd_softc *fd;
1369 struct buf *bp;
1370 char bits[64];
1371
1372 DPRINTF(("fdcretry:\n"));
1373 fd = fdc->sc_drives.tqh_first;
1374 bp = fd->sc_q.b_actf;
1375
1376 switch (fdc->sc_errors) {
1377 case 0:
1378 /* try again */
1379 fdc->sc_state = SEEKCOMPLETE;
1380 break;
1381
1382 case 1: case 2: case 3:
1383 /* didn't work; try recalibrating */
1384 fdc->sc_state = DORECAL;
1385 break;
1386
1387 case 4:
1388 /* still no go; reset the bastard */
1389 fdc->sc_state = DORESET;
1390 break;
1391
1392 default:
1393 diskerr(bp, "fd", "hard error", LOG_PRINTF,
1394 fd->sc_skip, (struct disklabel *)NULL);
1395 printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
1396 NE7_ST0BITS, bits,
1397 sizeof(bits)));
1398 printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
1399 NE7_ST1BITS, bits,
1400 sizeof(bits)));
1401 printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
1402 NE7_ST2BITS, bits,
1403 sizeof(bits)));
1404 printf(" cyl %d head %d sec %d)\n",
1405 fdc->sc_status[3],
1406 fdc->sc_status[4],
1407 fdc->sc_status[5]);
1408
1409 bp->b_flags |= B_ERROR;
1410 bp->b_error = EIO;
1411 fdfinish(fd, bp);
1412 }
1413 fdc->sc_errors++;
1414 }
1415
1416 int
1417 fdsize(dev)
1418 dev_t dev;
1419 {
1420
1421 /* Swapping to floppies would not make sense. */
1422 return -1;
1423 }
1424
1425 int
1426 fddump(dev, blkno, va, size)
1427 dev_t dev;
1428 daddr_t blkno;
1429 caddr_t va;
1430 size_t size;
1431 {
1432
1433 /* Not implemented. */
1434 return ENXIO;
1435 }
1436
1437 int
1438 fdioctl(dev, cmd, addr, flag, p)
1439 dev_t dev;
1440 u_long cmd;
1441 caddr_t addr;
1442 int flag;
1443 struct proc *p;
1444 {
1445 struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
1446 int unit = FDUNIT(dev);
1447 struct disklabel buffer;
1448 int error;
1449
1450 DPRINTF(("fdioctl:\n"));
1451 switch (cmd) {
1452 case DIOCGDINFO:
1453 #if 1
1454 *(struct disklabel *)addr = *(fd->sc_dk.dk_label);
1455 return(0);
1456 #else
1457 bzero(&buffer, sizeof(buffer));
1458
1459 buffer.d_secpercyl = fd->sc_type->seccyl;
1460 buffer.d_type = DTYPE_FLOPPY;
1461 buffer.d_secsize = 128 << fd->sc_type->secsize;
1462
1463 if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL)
1464 return EINVAL;
1465
1466 *(struct disklabel *)addr = buffer;
1467 return 0;
1468 #endif
1469
1470 case DIOCGPART:
1471 ((struct partinfo *)addr)->disklab = fd->sc_dk.dk_label;
1472 ((struct partinfo *)addr)->part =
1473 &fd->sc_dk.dk_label->d_partitions[DISKPART(dev)];
1474 return(0);
1475
1476 case DIOCWLABEL:
1477 if ((flag & FWRITE) == 0)
1478 return EBADF;
1479 /* XXX do something */
1480 return 0;
1481
1482 case DIOCWDINFO:
1483 if ((flag & FWRITE) == 0)
1484 return EBADF;
1485
1486 error = setdisklabel(&buffer, (struct disklabel *)addr, 0, NULL);
1487 if (error)
1488 return error;
1489
1490 error = writedisklabel(dev, fdstrategy, &buffer, NULL);
1491 return error;
1492
1493 case DIOCLOCK:
1494 /*
1495 * Nothing to do here, really.
1496 */
1497 return 0; /* XXX */
1498
1499 case DIOCEJECT:
1500 fd_do_eject(unit);
1501 return 0;
1502
1503 default:
1504 return ENOTTY;
1505 }
1506
1507 #ifdef DIAGNOSTIC
1508 panic("fdioctl: impossible");
1509 #endif
1510 }
1511
1512 void
1513 fd_do_eject(unit)
1514 int unit;
1515 {
1516 infdc.drvstat = 0x20 | ( 1 << unit);
1517 DELAY(1); /* XXX */
1518 infdc.drvstat = 0x20;
1519 }
1520
1521 /*
1522 * Build disk label. For now we only create a label from what we know
1523 * from 'sc'.
1524 */
1525 static int
1526 fdgetdisklabel(sc, dev)
1527 struct fd_softc *sc;
1528 dev_t dev;
1529 {
1530 struct disklabel *lp;
1531 int part;
1532
1533 #ifdef FDDEBUG
1534 printf("fdgetdisklabel()\n");
1535 #endif
1536
1537 part = DISKPART(dev);
1538 lp = sc->sc_dk.dk_label;
1539 bzero(lp, sizeof(struct disklabel));
1540
1541 lp->d_secsize = 128 << sc->sc_type->secsize;
1542 lp->d_ntracks = sc->sc_type->heads;
1543 lp->d_nsectors = sc->sc_type->sectrac;
1544 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
1545 lp->d_ncylinders = sc->sc_type->size / lp->d_secpercyl;
1546 lp->d_secperunit = sc->sc_type->size;
1547
1548 lp->d_type = DTYPE_FLOPPY;
1549 lp->d_rpm = 300; /* XXX */
1550 lp->d_interleave = 1; /* FIXME: is this OK? */
1551 lp->d_bbsize = 0;
1552 lp->d_sbsize = 0;
1553 lp->d_npartitions = part + 1;
1554 #define STEP_DELAY 6000 /* 6ms (6000us) delay after stepping */
1555 lp->d_trkseek = STEP_DELAY; /* XXX */
1556 lp->d_magic = DISKMAGIC;
1557 lp->d_magic2 = DISKMAGIC;
1558 lp->d_checksum = dkcksum(lp);
1559 lp->d_partitions[part].p_size = lp->d_secperunit;
1560 lp->d_partitions[part].p_fstype = FS_UNUSED;
1561 lp->d_partitions[part].p_fsize = 1024;
1562 lp->d_partitions[part].p_frag = 8;
1563
1564 return(0);
1565 }
1566
1567 /*
1568 * Mountroot hook: prompt the user to enter the root file system
1569 * floppy.
1570 */
1571 void
1572 fd_mountroot_hook(dev)
1573 struct device *dev;
1574 {
1575 int c;
1576
1577 fd_do_eject(dev->dv_unit);
1578 printf("Insert filesystem floppy and press return.");
1579 for (;;) {
1580 c = cngetc();
1581 if ((c == '\r') || (c == '\n')) {
1582 printf("\n");
1583 break;
1584 }
1585 }
1586 }
1587