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