1 /* $OpenBSD: fd.c,v 1.50 2005/03/16 19:58:40 miod Exp $ */
2 /* $NetBSD: fd.c,v 1.90 1996/05/12 23:12:03 mycroft Exp $ */
3
4 /*-
5 * Copyright (c) 1993, 1994, 1995, 1996 Charles Hannum.
6 * Copyright (c) 1990 The Regents of the University of California.
7 * All rights reserved.
8 *
9 * This code is derived from software contributed to Berkeley by
10 * Don Ahn.
11 *
12 * Portions Copyright (c) 1993, 1994 by
13 * jc@irbs.UUCP (John Capo)
14 * vak@zebub.msk.su (Serge Vakulenko)
15 * ache@astral.msk.su (Andrew A. Chernov)
16 * joerg_wunsch@uriah.sax.de (Joerg Wunsch)
17 *
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions
20 * are met:
21 * 1. Redistributions of source code must retain the above copyright
22 * notice, this list of conditions and the following disclaimer.
23 * 2. Redistributions in binary form must reproduce the above copyright
24 * notice, this list of conditions and the following disclaimer in the
25 * documentation and/or other materials provided with the distribution.
26 * 3. Neither the name of the University nor the names of its contributors
27 * may be used to endorse or promote products derived from this software
28 * without specific prior written permission.
29 *
30 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
31 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
34 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 * SUCH DAMAGE.
41 *
42 * @(#)fd.c 7.4 (Berkeley) 5/25/91
43 */
44
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/kernel.h>
48 #include <sys/file.h>
49 #include <sys/ioctl.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/malloc.h>
56 #include <sys/uio.h>
57 #include <sys/mtio.h>
58 #include <sys/proc.h>
59 #include <sys/syslog.h>
60 #include <sys/queue.h>
61 #include <sys/timeout.h>
62
63 #include <machine/cpu.h>
64 #include <machine/bus.h>
65 #include <machine/conf.h>
66 #include <machine/intr.h>
67 #include <machine/ioctl_fd.h>
68
69 #include <dev/isa/isavar.h>
70 #include <dev/isa/isadmavar.h>
71 #include <dev/isa/fdreg.h>
72
73 #if defined(i386)
74 #include <i386/isa/nvram.h>
75 #endif
76
77 #include <dev/isa/fdlink.h>
78
79 /* XXX misuse a flag to identify format operation */
80 #define B_FORMAT B_XXX
81
82 #define b_cylin b_resid
83
84 /* fd_type struct now in ioctl_fd.h */
85
86 /* The order of entries in the following table is important -- BEWARE! */
87 struct fd_type fd_types[] = {
88 { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS,"1.44MB" }, /* 1.44MB diskette */
89 { 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS, "1.2MB" }, /* 1.2 MB AT-diskettes */
90 { 9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS, "360KB/AT" }, /* 360kB in 1.2MB drive */
91 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS, "360KB/PC" }, /* 360kB PC diskettes */
92 { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS, "720KB" }, /* 3.5" 720kB diskette */
93 { 9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS, "720KB/x" }, /* 720kB in 1.2MB drive */
94 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS, "360KB/x" }, /* 360kB in 720kB drive */
95 { 36,2,72,2,0xff,0xaf,0x1b,0x54,80,5760,1,FDC_500KBPS,"2.88MB" }, /* 2.88MB diskette */
96 { 8,2,16,3,0xff,0xdf,0x35,0x74,77,1232,1,FDC_500KBPS,"1.2MB/[1024bytes/sector]" } /* 1.2 MB japanese format */
97 };
98
99 /* software state, per disk (with up to 4 disks per ctlr) */
100 struct fd_softc {
101 struct device sc_dev;
102 struct disk sc_dk;
103
104 struct fd_type *sc_deftype; /* default type descriptor */
105 struct fd_type *sc_type; /* current type descriptor */
106
107 daddr_t sc_blkno; /* starting block number */
108 int sc_bcount; /* byte count left */
109 int sc_opts; /* user-set options */
110 int sc_skip; /* bytes already transferred */
111 int sc_nblks; /* number of blocks currently tranferring */
112 int sc_nbytes; /* number of bytes currently tranferring */
113
114 int sc_drive; /* physical unit number */
115 int sc_flags;
116 #define FD_OPEN 0x01 /* it's open */
117 #define FD_MOTOR 0x02 /* motor should be on */
118 #define FD_MOTOR_WAIT 0x04 /* motor coming up */
119 int sc_cylin; /* where we think the head is */
120
121 void *sc_sdhook; /* saved shutdown hook for drive. */
122
123 TAILQ_ENTRY(fd_softc) sc_drivechain;
124 int sc_ops; /* I/O ops since last switch */
125 struct buf sc_q; /* head of buf chain */
126 struct timeout fd_motor_on_to;
127 struct timeout fd_motor_off_to;
128 struct timeout fdtimeout_to;
129 };
130
131 /* floppy driver configuration */
132 int fdprobe(struct device *, void *, void *);
133 void fdattach(struct device *, struct device *, void *);
134
135 struct cfattach fd_ca = {
136 sizeof(struct fd_softc), fdprobe, fdattach
137 };
138
139 struct cfdriver fd_cd = {
140 NULL, "fd", DV_DISK
141 };
142
143 void fdgetdisklabel(struct fd_softc *);
144 int fd_get_parms(struct fd_softc *);
145 void fdstrategy(struct buf *);
146 void fdstart(struct fd_softc *);
147 int fdintr(struct fdc_softc *);
148
149 struct dkdriver fddkdriver = { fdstrategy };
150
151 void fd_set_motor(struct fdc_softc *fdc, int reset);
152 void fd_motor_off(void *arg);
153 void fd_motor_on(void *arg);
154 void fdfinish(struct fd_softc *fd, struct buf *bp);
155 int fdformat(dev_t, struct fd_formb *, struct proc *);
156 __inline struct fd_type *fd_dev_to_type(struct fd_softc *, dev_t);
157 void fdretry(struct fd_softc *);
158 void fdtimeout(void *);
159
160 int
fdprobe(parent,match,aux)161 fdprobe(parent, match, aux)
162 struct device *parent;
163 void *match, *aux;
164 {
165 struct fdc_softc *fdc = (void *)parent;
166 struct cfdata *cf = match;
167 struct fdc_attach_args *fa = aux;
168 int drive = fa->fa_drive;
169 bus_space_tag_t iot = fdc->sc_iot;
170 bus_space_handle_t ioh = fdc->sc_ioh;
171 int n;
172
173 if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != drive)
174 return 0;
175 /*
176 * XXX
177 * This is to work around some odd interactions between this driver
178 * and SMC Ethernet cards.
179 */
180 if (cf->cf_loc[0] == -1 && drive >= 2)
181 return 0;
182
183 /*
184 * We want to keep the flags config gave us.
185 */
186 fa->fa_flags = cf->cf_flags;
187
188 /* select drive and turn on motor */
189 bus_space_write_1(iot, ioh, fdout, drive | FDO_FRST | FDO_MOEN(drive));
190 /* wait for motor to spin up */
191 delay(250000);
192 out_fdc(iot, ioh, NE7CMD_RECAL);
193 out_fdc(iot, ioh, drive);
194 /* wait for recalibrate */
195 delay(2000000);
196 out_fdc(iot, ioh, NE7CMD_SENSEI);
197 n = fdcresult(fdc);
198 #ifdef FD_DEBUG
199 {
200 int i;
201 printf("fdprobe: status");
202 for (i = 0; i < n; i++)
203 printf(" %x", fdc->sc_status[i]);
204 printf("\n");
205 }
206 #endif
207
208 /* turn off motor */
209 delay(250000);
210 bus_space_write_1(iot, ioh, fdout, FDO_FRST);
211
212 /* flags & 0x20 forces the drive to be found even if it won't probe */
213 if (!(fa->fa_flags & 0x20) && (n != 2 || (fdc->sc_status[0] & 0xf8) != 0x20))
214 return 0;
215
216 return 1;
217 }
218
219 /*
220 * Controller is working, and drive responded. Attach it.
221 */
222 void
fdattach(parent,self,aux)223 fdattach(parent, self, aux)
224 struct device *parent, *self;
225 void *aux;
226 {
227 struct fdc_softc *fdc = (void *)parent;
228 struct fd_softc *fd = (void *)self;
229 struct fdc_attach_args *fa = aux;
230 struct fd_type *type = fa->fa_deftype;
231 int drive = fa->fa_drive;
232
233 if (!type || (fa->fa_flags & 0x10)) {
234 /* The config has overridden this. */
235 switch (fa->fa_flags & 0x07) {
236 case 1: /* 2.88MB */
237 type = &fd_types[7];
238 break;
239 case 2: /* 1.44MB */
240 type = &fd_types[0];
241 break;
242 case 3: /* 1.2MB */
243 type = &fd_types[1];
244 break;
245 case 4: /* 720K */
246 type = &fd_types[4];
247 break;
248 case 5: /* 360K */
249 type = &fd_types[3];
250 break;
251 case 6: /* 1.2 MB japanese format */
252 type = &fd_types[8];
253 break;
254 #ifdef __alpha__
255 default:
256 /* 1.44MB, how to detect others?
257 * idea from NetBSD -- jay@rootaction.net
258 */
259 type = &fd_types[0];
260 #endif
261 }
262 }
263
264 if (type)
265 printf(": %s %d cyl, %d head, %d sec\n", type->name,
266 type->tracks, type->heads, type->sectrac);
267 else
268 printf(": density unknown\n");
269
270 fd->sc_cylin = -1;
271 fd->sc_drive = drive;
272 fd->sc_deftype = type;
273 fdc->sc_type[drive] = FDC_TYPE_DISK;
274 fdc->sc_link.fdlink.sc_fd[drive] = fd;
275
276 /*
277 * Initialize and attach the disk structure.
278 */
279 fd->sc_dk.dk_name = fd->sc_dev.dv_xname;
280 fd->sc_dk.dk_driver = &fddkdriver;
281 disk_attach(&fd->sc_dk);
282
283 dk_establish(&fd->sc_dk, &fd->sc_dev);
284 /* Needed to power off if the motor is on when we halt. */
285 fd->sc_sdhook = shutdownhook_establish(fd_motor_off, fd);
286
287 /* Setup timeout structures */
288 timeout_set(&fd->fd_motor_on_to, fd_motor_on, fd);
289 timeout_set(&fd->fd_motor_off_to, fd_motor_off, fd);
290 timeout_set(&fd->fdtimeout_to, fdtimeout, fd);
291 }
292
293 /*
294 * Translate nvram type into internal data structure. Return NULL for
295 * none/unknown/unusable.
296 */
297 struct fd_type *
fd_nvtotype(fdc,nvraminfo,drive)298 fd_nvtotype(fdc, nvraminfo, drive)
299 char *fdc;
300 int nvraminfo, drive;
301 {
302 #ifdef __alpha__
303 /* Alpha: assume 1.44MB, idea from NetBSD sys/dev/isa/fd.c
304 * -- jay@rootaction.net
305 */
306 return &fd_types[0]; /* 1.44MB */
307 #else
308 int type;
309
310 type = (drive == 0 ? nvraminfo : nvraminfo << 4) & 0xf0;
311 switch (type) {
312 case NVRAM_DISKETTE_NONE:
313 return NULL;
314 case NVRAM_DISKETTE_12M:
315 return &fd_types[1];
316 case NVRAM_DISKETTE_TYPE5:
317 case NVRAM_DISKETTE_TYPE6:
318 return &fd_types[7];
319 case NVRAM_DISKETTE_144M:
320 return &fd_types[0];
321 case NVRAM_DISKETTE_360K:
322 return &fd_types[3];
323 case NVRAM_DISKETTE_720K:
324 return &fd_types[4];
325 default:
326 printf("%s: drive %d: unknown device type 0x%x\n",
327 fdc, drive, type);
328 return NULL;
329 }
330 #endif
331 }
332
333 __inline struct fd_type *
fd_dev_to_type(fd,dev)334 fd_dev_to_type(fd, dev)
335 struct fd_softc *fd;
336 dev_t dev;
337 {
338 int type = FDTYPE(dev);
339
340 if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
341 return NULL;
342 return type ? &fd_types[type - 1] : fd->sc_deftype;
343 }
344
345 void
fdstrategy(bp)346 fdstrategy(bp)
347 register struct buf *bp; /* IO operation to perform */
348 {
349 struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(bp->b_dev)];
350 int sz;
351 int s;
352 int fd_bsize = 128 << fd->sc_type->secsize;
353 int bf = fd_bsize / DEV_BSIZE;
354
355 /* Valid unit, controller, and request? */
356 if (bp->b_blkno < 0 ||
357 (((bp->b_blkno % bf) != 0 ||
358 (bp->b_bcount % fd_bsize) != 0) &&
359 (bp->b_flags & B_FORMAT) == 0)) {
360 bp->b_error = EINVAL;
361 goto bad;
362 }
363
364 /* If it's a null transfer, return immediately. */
365 if (bp->b_bcount == 0)
366 goto done;
367
368 sz = howmany(bp->b_bcount, DEV_BSIZE);
369
370 if (bp->b_blkno + sz > fd->sc_type->size * bf) {
371 sz = fd->sc_type->size * bf - bp->b_blkno;
372 if (sz == 0)
373 /* If exactly at end of disk, return EOF. */
374 goto done;
375 if (sz < 0) {
376 /* If past end of disk, return EINVAL. */
377 bp->b_error = EINVAL;
378 goto bad;
379 }
380 /* Otherwise, truncate request. */
381 bp->b_bcount = sz << DEV_BSHIFT;
382 }
383
384 bp->b_cylin = bp->b_blkno / (fd_bsize / DEV_BSIZE) / fd->sc_type->seccyl;
385
386 #ifdef FD_DEBUG
387 printf("fdstrategy: b_blkno %d b_bcount %d blkno %d cylin %d sz %d\n",
388 bp->b_blkno, bp->b_bcount, fd->sc_blkno, bp->b_cylin, sz);
389 #endif
390
391 /* Queue transfer on drive, activate drive and controller if idle. */
392 s = splbio();
393 disksort(&fd->sc_q, bp);
394 timeout_del(&fd->fd_motor_off_to); /* a good idea */
395 if (!fd->sc_q.b_active)
396 fdstart(fd);
397 #ifdef DIAGNOSTIC
398 else {
399 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
400 if (fdc->sc_state == DEVIDLE) {
401 printf("fdstrategy: controller inactive\n");
402 fdcstart(fdc);
403 }
404 }
405 #endif
406 splx(s);
407 return;
408
409 bad:
410 bp->b_flags |= B_ERROR;
411 done:
412 /* Toss transfer; we're done early. */
413 bp->b_resid = bp->b_bcount;
414 s = splbio();
415 biodone(bp);
416 splx(s);
417 }
418
419 void
fdstart(fd)420 fdstart(fd)
421 struct fd_softc *fd;
422 {
423 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
424 int active = !TAILQ_EMPTY(&fdc->sc_link.fdlink.sc_drives);
425
426 /* Link into controller queue. */
427 fd->sc_q.b_active = 1;
428 TAILQ_INSERT_TAIL(&fdc->sc_link.fdlink.sc_drives, fd, sc_drivechain);
429
430 /* If controller not already active, start it. */
431 if (!active)
432 fdcstart(fdc);
433 }
434
435 void
fdfinish(fd,bp)436 fdfinish(fd, bp)
437 struct fd_softc *fd;
438 struct buf *bp;
439 {
440 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
441
442 splassert(IPL_BIO);
443
444 /*
445 * Move this drive to the end of the queue to give others a `fair'
446 * chance. We only force a switch if N operations are completed while
447 * another drive is waiting to be serviced, since there is a long motor
448 * startup delay whenever we switch.
449 */
450 if (TAILQ_NEXT(fd, sc_drivechain) != NULL && ++fd->sc_ops >= 8) {
451 fd->sc_ops = 0;
452 TAILQ_REMOVE(&fdc->sc_link.fdlink.sc_drives, fd, sc_drivechain);
453 if (bp->b_actf) {
454 TAILQ_INSERT_TAIL(&fdc->sc_link.fdlink.sc_drives, fd,
455 sc_drivechain);
456 } else
457 fd->sc_q.b_active = 0;
458 }
459 bp->b_resid = fd->sc_bcount;
460 fd->sc_skip = 0;
461 fd->sc_q.b_actf = bp->b_actf;
462
463 biodone(bp);
464 /* turn off motor 5s from now */
465 timeout_add(&fd->fd_motor_off_to, 5 * hz);
466 fdc->sc_state = DEVIDLE;
467 }
468
469 int
fdread(dev,uio,flags)470 fdread(dev, uio, flags)
471 dev_t dev;
472 struct uio *uio;
473 int flags;
474 {
475
476 return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
477 }
478
479 int
fdwrite(dev,uio,flags)480 fdwrite(dev, uio, flags)
481 dev_t dev;
482 struct uio *uio;
483 int flags;
484 {
485
486 return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
487 }
488
489 void
fd_set_motor(fdc,reset)490 fd_set_motor(fdc, reset)
491 struct fdc_softc *fdc;
492 int reset;
493 {
494 struct fd_softc *fd;
495 u_char status;
496 int n;
497
498 if ((fd = TAILQ_FIRST(&fdc->sc_link.fdlink.sc_drives)) != NULL)
499 status = fd->sc_drive;
500 else
501 status = 0;
502 if (!reset)
503 status |= FDO_FRST | FDO_FDMAEN;
504 for (n = 0; n < 4; n++)
505 if ((fd = fdc->sc_link.fdlink.sc_fd[n])
506 && (fd->sc_flags & FD_MOTOR))
507 status |= FDO_MOEN(n);
508 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, status);
509 }
510
511 void
fd_motor_off(arg)512 fd_motor_off(arg)
513 void *arg;
514 {
515 struct fd_softc *fd = arg;
516 int s;
517
518 s = splbio();
519 fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
520 fd_set_motor((struct fdc_softc *)fd->sc_dev.dv_parent, 0);
521 splx(s);
522 }
523
524 void
fd_motor_on(arg)525 fd_motor_on(arg)
526 void *arg;
527 {
528 struct fd_softc *fd = arg;
529 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
530 int s;
531
532 s = splbio();
533 fd->sc_flags &= ~FD_MOTOR_WAIT;
534 if ((TAILQ_FIRST(&fdc->sc_link.fdlink.sc_drives) == fd)
535 && (fdc->sc_state == MOTORWAIT))
536 (void) fdintr(fdc);
537 splx(s);
538 }
539
540 int
fdopen(dev,flags,mode,p)541 fdopen(dev, flags, mode, p)
542 dev_t dev;
543 int flags;
544 int mode;
545 struct proc *p;
546 {
547 int unit;
548 struct fd_softc *fd;
549 struct fd_type *type;
550
551 unit = FDUNIT(dev);
552 if (unit >= fd_cd.cd_ndevs)
553 return ENXIO;
554 fd = fd_cd.cd_devs[unit];
555 if (fd == 0)
556 return ENXIO;
557 type = fd_dev_to_type(fd, dev);
558 if (type == NULL)
559 return ENXIO;
560
561 if ((fd->sc_flags & FD_OPEN) != 0 &&
562 fd->sc_type != type)
563 return EBUSY;
564
565 fd->sc_type = type;
566 fd->sc_cylin = -1;
567 fd->sc_flags |= FD_OPEN;
568
569 return 0;
570 }
571
572 int
fdclose(dev,flags,mode,p)573 fdclose(dev, flags, mode, p)
574 dev_t dev;
575 int flags;
576 int mode;
577 struct proc *p;
578 {
579 struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
580
581 fd->sc_flags &= ~FD_OPEN;
582 fd->sc_opts &= ~FDOPT_NORETRY;
583 return 0;
584 }
585
586 int
fdsize(dev)587 fdsize(dev)
588 dev_t dev;
589 {
590
591 /* Swapping to floppies would not make sense. */
592 return -1;
593 }
594
595 int
fddump(dev,blkno,va,size)596 fddump(dev, blkno, va, size)
597 dev_t dev;
598 daddr_t blkno;
599 caddr_t va;
600 size_t size;
601 {
602
603 /* Not implemented. */
604 return ENXIO;
605 }
606
607 /*
608 * Called from the controller.
609 */
610 int
fdintr(fdc)611 fdintr(fdc)
612 struct fdc_softc *fdc;
613 {
614 #define st0 fdc->sc_status[0]
615 #define cyl fdc->sc_status[1]
616 struct fd_softc *fd;
617 struct buf *bp;
618 bus_space_tag_t iot = fdc->sc_iot;
619 bus_space_handle_t ioh = fdc->sc_ioh;
620 bus_space_handle_t ioh_ctl = fdc->sc_ioh_ctl;
621 int read, head, sec, i, nblks;
622 struct fd_type *type;
623 struct fd_formb *finfo = NULL;
624 int fd_bsize, bf;
625
626 loop:
627 /* Is there a transfer to this drive? If not, deactivate drive. */
628 fd = TAILQ_FIRST(&fdc->sc_link.fdlink.sc_drives);
629 if (fd == NULL) {
630 fdc->sc_state = DEVIDLE;
631 return 1;
632 }
633 fd_bsize = 128 << fd->sc_type->secsize;
634 bf = fd_bsize / FDC_BSIZE;
635
636 bp = fd->sc_q.b_actf;
637 if (bp == NULL) {
638 fd->sc_ops = 0;
639 TAILQ_REMOVE(&fdc->sc_link.fdlink.sc_drives, fd, sc_drivechain);
640 fd->sc_q.b_active = 0;
641 goto loop;
642 }
643
644 if (bp->b_flags & B_FORMAT)
645 finfo = (struct fd_formb *)bp->b_data;
646
647 switch (fdc->sc_state) {
648 case DEVIDLE:
649 fdc->sc_errors = 0;
650 fd->sc_skip = 0;
651 fd->sc_bcount = bp->b_bcount;
652 fd->sc_blkno = bp->b_blkno / (fd_bsize / DEV_BSIZE);
653 timeout_del(&fd->fd_motor_off_to);
654 if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
655 fdc->sc_state = MOTORWAIT;
656 return 1;
657 }
658 if ((fd->sc_flags & FD_MOTOR) == 0) {
659 /* Turn on the motor, being careful about pairing. */
660 struct fd_softc *ofd =
661 fdc->sc_link.fdlink.sc_fd[fd->sc_drive ^ 1];
662 if (ofd && ofd->sc_flags & FD_MOTOR) {
663 timeout_del(&ofd->fd_motor_off_to);
664 ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
665 }
666 fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
667 fd_set_motor(fdc, 0);
668 fdc->sc_state = MOTORWAIT;
669 /* Allow .25s for motor to stabilize. */
670 timeout_add(&fd->fd_motor_on_to, hz / 4);
671 return 1;
672 }
673 /* Make sure the right drive is selected. */
674 fd_set_motor(fdc, 0);
675
676 /* fall through */
677 case DOSEEK:
678 doseek:
679 if (fd->sc_cylin == bp->b_cylin)
680 goto doio;
681
682 out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
683 out_fdc(iot, ioh, fd->sc_type->steprate);
684 out_fdc(iot, ioh, 6); /* XXX head load time == 6ms */
685
686 out_fdc(iot, ioh, NE7CMD_SEEK); /* seek function */
687 out_fdc(iot, ioh, fd->sc_drive); /* drive number */
688 out_fdc(iot, ioh, bp->b_cylin * fd->sc_type->step);
689
690 fd->sc_cylin = -1;
691 fdc->sc_state = SEEKWAIT;
692
693 fd->sc_dk.dk_seek++;
694 disk_busy(&fd->sc_dk);
695
696 timeout_add(&fd->fdtimeout_to, 4 * hz);
697 return 1;
698
699 case DOIO:
700 doio:
701 type = fd->sc_type;
702 if (finfo)
703 fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) -
704 (char *)finfo;
705 sec = fd->sc_blkno % type->seccyl;
706 nblks = type->seccyl - sec;
707 nblks = min(nblks, fd->sc_bcount / fd_bsize);
708 nblks = min(nblks, FDC_MAXIOSIZE / fd_bsize);
709 fd->sc_nblks = nblks;
710 fd->sc_nbytes = finfo ? bp->b_bcount : nblks * fd_bsize;
711 head = sec / type->sectrac;
712 sec -= head * type->sectrac;
713 #ifdef DIAGNOSTIC
714 {int block;
715 block = (fd->sc_cylin * type->heads + head) * type->sectrac + sec;
716 if (block != fd->sc_blkno) {
717 printf("fdintr: block %d != blkno %d\n", block, fd->sc_blkno);
718 #ifdef DDB
719 Debugger();
720 #endif
721 }}
722 #endif
723 read = bp->b_flags & B_READ ? DMAMODE_READ : DMAMODE_WRITE;
724 isadma_start(bp->b_data + fd->sc_skip, fd->sc_nbytes,
725 fdc->sc_drq, read);
726 bus_space_write_1(iot, ioh_ctl, fdctl, type->rate);
727 #ifdef FD_DEBUG
728 printf("fdintr: %s drive %d track %d head %d sec %d nblks %d\n",
729 read ? "read" : "write", fd->sc_drive, fd->sc_cylin, head,
730 sec, nblks);
731 #endif
732 if (finfo) {
733 /* formatting */
734 if (out_fdc(iot, ioh, NE7CMD_FORMAT) < 0) {
735 fdc->sc_errors = 4;
736 fdretry(fd);
737 goto loop;
738 }
739 out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
740 out_fdc(iot, ioh, finfo->fd_formb_secshift);
741 out_fdc(iot, ioh, finfo->fd_formb_nsecs);
742 out_fdc(iot, ioh, finfo->fd_formb_gaplen);
743 out_fdc(iot, ioh, finfo->fd_formb_fillbyte);
744 } else {
745 if (read)
746 out_fdc(iot, ioh, NE7CMD_READ); /* READ */
747 else
748 out_fdc(iot, ioh, NE7CMD_WRITE);/* WRITE */
749 out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
750 out_fdc(iot, ioh, fd->sc_cylin); /* track */
751 out_fdc(iot, ioh, head);
752 out_fdc(iot, ioh, sec + 1); /* sec +1 */
753 out_fdc(iot, ioh, type->secsize); /* sec size */
754 out_fdc(iot, ioh, type->sectrac); /* secs/track */
755 out_fdc(iot, ioh, type->gap1); /* gap1 size */
756 out_fdc(iot, ioh, type->datalen); /* data len */
757 }
758 fdc->sc_state = IOCOMPLETE;
759
760 disk_busy(&fd->sc_dk);
761
762 /* allow 2 seconds for operation */
763 timeout_add(&fd->fdtimeout_to, 2 * hz);
764 return 1; /* will return later */
765
766 case SEEKWAIT:
767 timeout_del(&fd->fdtimeout_to);
768 fdc->sc_state = SEEKCOMPLETE;
769 /* allow 1/50 second for heads to settle */
770 timeout_add(&fdc->fdcpseudointr_to, hz / 50);
771 return 1;
772
773 case SEEKCOMPLETE:
774 disk_unbusy(&fd->sc_dk, 0, 0); /* no data on seek */
775
776 /* Make sure seek really happened. */
777 out_fdc(iot, ioh, NE7CMD_SENSEI);
778 if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 ||
779 cyl != bp->b_cylin * fd->sc_type->step) {
780 #ifdef FD_DEBUG
781 fdcstatus(&fd->sc_dev, 2, "seek failed");
782 #endif
783 fdretry(fd);
784 goto loop;
785 }
786 fd->sc_cylin = bp->b_cylin;
787 goto doio;
788
789 case IOTIMEDOUT:
790 isadma_abort(fdc->sc_drq);
791 case SEEKTIMEDOUT:
792 case RECALTIMEDOUT:
793 case RESETTIMEDOUT:
794 fdretry(fd);
795 goto loop;
796
797 case IOCOMPLETE: /* IO DONE, post-analyze */
798 timeout_del(&fd->fdtimeout_to);
799
800 disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid),
801 (bp->b_flags & B_READ));
802
803 if (fdcresult(fdc) != 7 || (st0 & 0xf8) != 0) {
804 isadma_abort(fdc->sc_drq);
805 #ifdef FD_DEBUG
806 fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
807 "read failed" : "write failed");
808 printf("blkno %d nblks %d\n",
809 fd->sc_blkno, fd->sc_nblks);
810 #endif
811 fdretry(fd);
812 goto loop;
813 }
814 read = bp->b_flags & B_READ ? DMAMODE_READ : DMAMODE_WRITE;
815 isadma_done(fdc->sc_drq);
816 if (fdc->sc_errors) {
817 diskerr(bp, "fd", "soft error", LOG_PRINTF,
818 fd->sc_skip / fd_bsize, (struct disklabel *)NULL);
819 printf("\n");
820 fdc->sc_errors = 0;
821 }
822 fd->sc_blkno += fd->sc_nblks;
823 fd->sc_skip += fd->sc_nbytes;
824 fd->sc_bcount -= fd->sc_nbytes;
825 if (!finfo && fd->sc_bcount > 0) {
826 bp->b_cylin = fd->sc_blkno / fd->sc_type->seccyl;
827 goto doseek;
828 }
829 fdfinish(fd, bp);
830 goto loop;
831
832 case DORESET:
833 /* try a reset, keep motor on */
834 fd_set_motor(fdc, 1);
835 delay(100);
836 fd_set_motor(fdc, 0);
837 fdc->sc_state = RESETCOMPLETE;
838 timeout_add(&fd->fdtimeout_to, hz / 2);
839 return 1; /* will return later */
840
841 case RESETCOMPLETE:
842 timeout_del(&fd->fdtimeout_to);
843 /* clear the controller output buffer */
844 for (i = 0; i < 4; i++) {
845 out_fdc(iot, ioh, NE7CMD_SENSEI);
846 (void) fdcresult(fdc);
847 }
848
849 /* fall through */
850 case DORECAL:
851 out_fdc(iot, ioh, NE7CMD_RECAL); /* recal function */
852 out_fdc(iot, ioh, fd->sc_drive);
853 fdc->sc_state = RECALWAIT;
854 timeout_add(&fd->fdtimeout_to, 5 * hz);
855 return 1; /* will return later */
856
857 case RECALWAIT:
858 timeout_del(&fd->fdtimeout_to);
859 fdc->sc_state = RECALCOMPLETE;
860 /* allow 1/30 second for heads to settle */
861 timeout_add(&fdc->fdcpseudointr_to, hz / 30);
862 return 1; /* will return later */
863
864 case RECALCOMPLETE:
865 out_fdc(iot, ioh, NE7CMD_SENSEI);
866 if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
867 #ifdef FD_DEBUG
868 fdcstatus(&fd->sc_dev, 2, "recalibrate failed");
869 #endif
870 fdretry(fd);
871 goto loop;
872 }
873 fd->sc_cylin = 0;
874 goto doseek;
875
876 case MOTORWAIT:
877 if (fd->sc_flags & FD_MOTOR_WAIT)
878 return 1; /* time's not up yet */
879 goto doseek;
880
881 default:
882 fdcstatus(&fd->sc_dev, 0, "stray interrupt");
883 return 1;
884 }
885 #ifdef DIAGNOSTIC
886 panic("fdintr: impossible");
887 #endif
888 #undef st0
889 #undef cyl
890 }
891
892 void
fdtimeout(arg)893 fdtimeout(arg)
894 void *arg;
895 {
896 struct fd_softc *fd = arg;
897 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
898 int s;
899
900 s = splbio();
901 #ifdef DEBUG
902 log(LOG_ERR,"fdtimeout: state %d\n", fdc->sc_state);
903 #endif
904 fdcstatus(&fd->sc_dev, 0, "timeout");
905
906 if (fd->sc_q.b_actf)
907 fdc->sc_state++;
908 else
909 fdc->sc_state = DEVIDLE;
910
911 (void) fdintr(fdc);
912 splx(s);
913 }
914
915 void
fdretry(fd)916 fdretry(fd)
917 struct fd_softc *fd;
918 {
919 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
920 struct buf *bp = fd->sc_q.b_actf;
921
922 if (fd->sc_opts & FDOPT_NORETRY)
923 goto fail;
924 switch (fdc->sc_errors) {
925 case 0:
926 /* try again */
927 fdc->sc_state = DOSEEK;
928 break;
929
930 case 1: case 2: case 3:
931 /* didn't work; try recalibrating */
932 fdc->sc_state = DORECAL;
933 break;
934
935 case 4:
936 /* still no go; reset the bastard */
937 fdc->sc_state = DORESET;
938 break;
939
940 default:
941 fail:
942 diskerr(bp, "fd", "hard error", LOG_PRINTF,
943 fd->sc_skip / (128 << fd->sc_type->secsize),
944 (struct disklabel *)NULL);
945 printf(" (st0 %b st1 %b st2 %b cyl %d head %d sec %d)\n",
946 fdc->sc_status[0], NE7_ST0BITS,
947 fdc->sc_status[1], NE7_ST1BITS,
948 fdc->sc_status[2], NE7_ST2BITS,
949 fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
950
951 bp->b_flags |= B_ERROR;
952 bp->b_error = EIO;
953 fdfinish(fd, bp);
954 }
955 fdc->sc_errors++;
956 }
957
958 int
fdioctl(dev,cmd,addr,flag,p)959 fdioctl(dev, cmd, addr, flag, p)
960 dev_t dev;
961 u_long cmd;
962 caddr_t addr;
963 int flag;
964 struct proc *p;
965 {
966 struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
967 struct disklabel dl, *lp = &dl;
968 struct cpu_disklabel cdl;
969 char *errstring;
970 int error;
971
972 switch (cmd) {
973 case MTIOCTOP:
974 if (((struct mtop *)addr)->mt_op != MTOFFL)
975 return EIO;
976 return (0);
977 case DIOCGDINFO:
978 bzero(lp, sizeof(*lp));
979 bzero(&cdl, sizeof(struct cpu_disklabel));
980
981 lp->d_secsize = 128 << fd->sc_type->secsize;
982 lp->d_secpercyl = fd->sc_type->seccyl;
983 lp->d_ntracks = fd->sc_type->heads;
984 lp->d_nsectors = fd->sc_type->sectrac;
985 lp->d_ncylinders = fd->sc_type->tracks;
986
987 strncpy(lp->d_typename, "floppy disk", sizeof lp->d_typename);
988 lp->d_type = DTYPE_FLOPPY;
989 strncpy(lp->d_packname, "fictitious", sizeof lp->d_packname);
990 lp->d_secperunit = fd->sc_type->size;
991 lp->d_rpm = 300;
992 lp->d_interleave = 1;
993 lp->d_flags = D_REMOVABLE;
994
995 lp->d_partitions[RAW_PART].p_offset = 0;
996 lp->d_partitions[RAW_PART].p_size =
997 lp->d_secperunit * (lp->d_secsize / DEV_BSIZE);
998 lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
999 lp->d_npartitions = RAW_PART + 1;
1000
1001 lp->d_magic = DISKMAGIC;
1002 lp->d_magic2 = DISKMAGIC;
1003 lp->d_checksum = dkcksum(lp);
1004
1005 errstring = readdisklabel(dev, fdstrategy, lp, &cdl, 0);
1006 if (errstring) {
1007 /*printf("%s: %s\n", fd->sc_dev.dv_xname, errstring); */
1008 }
1009
1010 *(struct disklabel *)addr = *lp;
1011 return 0;
1012
1013 case DIOCWLABEL:
1014 if ((flag & FWRITE) == 0)
1015 return EBADF;
1016 /* XXX do something */
1017 return 0;
1018
1019 case DIOCWDINFO:
1020 if ((flag & FWRITE) == 0)
1021 return EBADF;
1022
1023 error = setdisklabel(lp, (struct disklabel *)addr, 0, NULL);
1024 if (error)
1025 return error;
1026
1027 error = writedisklabel(dev, fdstrategy, lp, NULL);
1028 return error;
1029
1030 case FD_FORM:
1031 if((flag & FWRITE) == 0)
1032 return EBADF; /* must be opened for writing */
1033 else if(((struct fd_formb *)addr)->format_version !=
1034 FD_FORMAT_VERSION)
1035 return EINVAL; /* wrong version of formatting prog */
1036 else
1037 return fdformat(dev, (struct fd_formb *)addr, p);
1038 break;
1039
1040 case FD_GTYPE: /* get drive type */
1041 *(struct fd_type *)addr = *fd->sc_type;
1042 return 0;
1043
1044 case FD_GOPTS: /* get drive options */
1045 *(int *)addr = fd->sc_opts;
1046 return 0;
1047
1048 case FD_SOPTS: /* set drive options */
1049 fd->sc_opts = *(int *)addr;
1050 return 0;
1051
1052 default:
1053 return ENOTTY;
1054 }
1055
1056 #ifdef DIAGNOSTIC
1057 panic("fdioctl: impossible");
1058 #endif
1059 }
1060
1061 int
fdformat(dev,finfo,p)1062 fdformat(dev, finfo, p)
1063 dev_t dev;
1064 struct fd_formb *finfo;
1065 struct proc *p;
1066 {
1067 int rv = 0;
1068 struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
1069 struct fd_type *type = fd->sc_type;
1070 struct buf *bp;
1071 int fd_bsize = 128 << fd->sc_type->secsize;
1072
1073 /* set up a buffer header for fdstrategy() */
1074 bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT);
1075 if (bp == NULL)
1076 return ENOBUFS;
1077
1078 PHOLD(p);
1079 bzero((void *)bp, sizeof(struct buf));
1080 bp->b_flags = B_BUSY | B_PHYS | B_FORMAT;
1081 bp->b_proc = p;
1082 bp->b_dev = dev;
1083
1084 /*
1085 * calculate a fake blkno, so fdstrategy() would initiate a
1086 * seek to the requested cylinder
1087 */
1088 bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads)
1089 + finfo->head * type->sectrac) * fd_bsize / DEV_BSIZE;
1090
1091 bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
1092 bp->b_data = (caddr_t)finfo;
1093
1094 #ifdef DEBUG
1095 printf("fdformat: blkno %x count %x\n", bp->b_blkno, bp->b_bcount);
1096 #endif
1097
1098 /* now do the format */
1099 fdstrategy(bp);
1100
1101 /* ...and wait for it to complete */
1102 rv = biowait(bp);
1103 PRELE(p);
1104 free(bp, M_TEMP);
1105 return (rv);
1106 }
1107