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