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