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