1 /* $OpenBSD: fd.c,v 1.43 2001/10/26 01:28:06 nate 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 #ifdef __alpha__ 259 default: 260 /* 1.44MB, how to detect others? 261 * idea from NetBSD -- jay@rootaction.net 262 */ 263 type = &fd_types[0]; 264 #endif 265 } 266 } 267 268 if (type) 269 printf(": %s %d cyl, %d head, %d sec\n", type->name, 270 type->tracks, type->heads, type->sectrac); 271 else 272 printf(": density unknown\n"); 273 274 fd->sc_cylin = -1; 275 fd->sc_drive = drive; 276 fd->sc_deftype = type; 277 fdc->sc_type[drive] = FDC_TYPE_DISK; 278 fdc->sc_link.fdlink.sc_fd[drive] = fd; 279 280 /* 281 * Initialize and attach the disk structure. 282 */ 283 fd->sc_dk.dk_name = fd->sc_dev.dv_xname; 284 fd->sc_dk.dk_driver = &fddkdriver; 285 disk_attach(&fd->sc_dk); 286 287 dk_establish(&fd->sc_dk, &fd->sc_dev); 288 /* Needed to power off if the motor is on when we halt. */ 289 fd->sc_sdhook = shutdownhook_establish(fd_motor_off, fd); 290 291 /* Setup timeout structures */ 292 timeout_set(&fd->fd_motor_on_to, fd_motor_on, fd); 293 timeout_set(&fd->fd_motor_off_to, fd_motor_off, fd); 294 timeout_set(&fd->fdtimeout_to, fdtimeout, fd); 295 } 296 297 /* 298 * Translate nvram type into internal data structure. Return NULL for 299 * none/unknown/unusable. 300 */ 301 struct fd_type * 302 fd_nvtotype(fdc, nvraminfo, drive) 303 char *fdc; 304 int nvraminfo, drive; 305 { 306 #ifdef __alpha__ 307 /* Alpha: assume 1.44MB, idea from NetBSD sys/dev/isa/fd.c 308 * -- jay@rootaction.net 309 */ 310 return &fd_types[0]; /* 1.44MB */ 311 #else 312 int type; 313 314 type = (drive == 0 ? nvraminfo : nvraminfo << 4) & 0xf0; 315 switch (type) { 316 case NVRAM_DISKETTE_NONE: 317 return NULL; 318 case NVRAM_DISKETTE_12M: 319 return &fd_types[1]; 320 case NVRAM_DISKETTE_TYPE5: 321 case NVRAM_DISKETTE_TYPE6: 322 return &fd_types[7]; 323 case NVRAM_DISKETTE_144M: 324 return &fd_types[0]; 325 case NVRAM_DISKETTE_360K: 326 return &fd_types[3]; 327 case NVRAM_DISKETTE_720K: 328 return &fd_types[4]; 329 default: 330 printf("%s: drive %d: unknown device type 0x%x\n", 331 fdc, drive, type); 332 return NULL; 333 } 334 #endif 335 } 336 337 __inline struct fd_type * 338 fd_dev_to_type(fd, dev) 339 struct fd_softc *fd; 340 dev_t dev; 341 { 342 int type = FDTYPE(dev); 343 344 if (type > (sizeof(fd_types) / sizeof(fd_types[0]))) 345 return NULL; 346 return type ? &fd_types[type - 1] : fd->sc_deftype; 347 } 348 349 void 350 fdstrategy(bp) 351 register struct buf *bp; /* IO operation to perform */ 352 { 353 struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(bp->b_dev)]; 354 int sz; 355 int s; 356 int fd_bsize = 128 << fd->sc_type->secsize; 357 int bf = fd_bsize / DEV_BSIZE; 358 359 /* Valid unit, controller, and request? */ 360 if (bp->b_blkno < 0 || 361 (((bp->b_blkno % bf) != 0 || 362 (bp->b_bcount % fd_bsize) != 0) && 363 (bp->b_flags & B_FORMAT) == 0)) { 364 bp->b_error = EINVAL; 365 goto bad; 366 } 367 368 /* If it's a null transfer, return immediately. */ 369 if (bp->b_bcount == 0) 370 goto done; 371 372 sz = howmany(bp->b_bcount, DEV_BSIZE); 373 374 if (bp->b_blkno + sz > fd->sc_type->size * bf) { 375 sz = fd->sc_type->size * bf - bp->b_blkno; 376 if (sz == 0) 377 /* If exactly at end of disk, return EOF. */ 378 goto done; 379 if (sz < 0) { 380 /* If past end of disk, return EINVAL. */ 381 bp->b_error = EINVAL; 382 goto bad; 383 } 384 /* Otherwise, truncate request. */ 385 bp->b_bcount = sz << DEV_BSHIFT; 386 } 387 388 bp->b_cylin = bp->b_blkno / (fd_bsize / DEV_BSIZE) / fd->sc_type->seccyl; 389 390 #ifdef FD_DEBUG 391 printf("fdstrategy: b_blkno %d b_bcount %d blkno %d cylin %d sz %d\n", 392 bp->b_blkno, bp->b_bcount, fd->sc_blkno, bp->b_cylin, sz); 393 #endif 394 395 /* Queue transfer on drive, activate drive and controller if idle. */ 396 s = splbio(); 397 disksort(&fd->sc_q, bp); 398 timeout_del(&fd->fd_motor_off_to); /* a good idea */ 399 if (!fd->sc_q.b_active) 400 fdstart(fd); 401 #ifdef DIAGNOSTIC 402 else { 403 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; 404 if (fdc->sc_state == DEVIDLE) { 405 printf("fdstrategy: controller inactive\n"); 406 fdcstart(fdc); 407 } 408 } 409 #endif 410 splx(s); 411 return; 412 413 bad: 414 bp->b_flags |= B_ERROR; 415 done: 416 /* Toss transfer; we're done early. */ 417 bp->b_resid = bp->b_bcount; 418 biodone(bp); 419 } 420 421 void 422 fdstart(fd) 423 struct fd_softc *fd; 424 { 425 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; 426 int active = (fdc->sc_link.fdlink.sc_drives.tqh_first != NULL); 427 428 /* Link into controller queue. */ 429 fd->sc_q.b_active = 1; 430 TAILQ_INSERT_TAIL(&fdc->sc_link.fdlink.sc_drives, fd, sc_drivechain); 431 432 /* If controller not already active, start it. */ 433 if (!active) 434 fdcstart(fdc); 435 } 436 437 void 438 fdfinish(fd, bp) 439 struct fd_softc *fd; 440 struct buf *bp; 441 { 442 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; 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 (fd->sc_drivechain.tqe_next && ++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 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 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 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 = fdc->sc_link.fdlink.sc_drives.tqh_first) != 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 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 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 ((fdc->sc_link.fdlink.sc_drives.tqh_first == fd) 535 && (fdc->sc_state == MOTORWAIT)) 536 (void) fdintr(fdc); 537 splx(s); 538 } 539 540 int 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 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 587 fdsize(dev) 588 dev_t dev; 589 { 590 591 /* Swapping to floppies would not make sense. */ 592 return -1; 593 } 594 595 int 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 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 = fdc->sc_link.fdlink.sc_drives.tqh_first; 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); /* 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 802 if (fdcresult(fdc) != 7 || (st0 & 0xf8) != 0) { 803 isadma_abort(fdc->sc_drq); 804 #ifdef FD_DEBUG 805 fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ? 806 "read failed" : "write failed"); 807 printf("blkno %d nblks %d\n", 808 fd->sc_blkno, fd->sc_nblks); 809 #endif 810 fdretry(fd); 811 goto loop; 812 } 813 read = bp->b_flags & B_READ ? DMAMODE_READ : DMAMODE_WRITE; 814 isadma_done(fdc->sc_drq); 815 if (fdc->sc_errors) { 816 diskerr(bp, "fd", "soft error", LOG_PRINTF, 817 fd->sc_skip / fd_bsize, (struct disklabel *)NULL); 818 printf("\n"); 819 fdc->sc_errors = 0; 820 } 821 fd->sc_blkno += fd->sc_nblks; 822 fd->sc_skip += fd->sc_nbytes; 823 fd->sc_bcount -= fd->sc_nbytes; 824 if (!finfo && fd->sc_bcount > 0) { 825 bp->b_cylin = fd->sc_blkno / fd->sc_type->seccyl; 826 goto doseek; 827 } 828 fdfinish(fd, bp); 829 goto loop; 830 831 case DORESET: 832 /* try a reset, keep motor on */ 833 fd_set_motor(fdc, 1); 834 delay(100); 835 fd_set_motor(fdc, 0); 836 fdc->sc_state = RESETCOMPLETE; 837 timeout_add(&fd->fdtimeout_to, hz / 2); 838 return 1; /* will return later */ 839 840 case RESETCOMPLETE: 841 timeout_del(&fd->fdtimeout_to); 842 /* clear the controller output buffer */ 843 for (i = 0; i < 4; i++) { 844 out_fdc(iot, ioh, NE7CMD_SENSEI); 845 (void) fdcresult(fdc); 846 } 847 848 /* fall through */ 849 case DORECAL: 850 out_fdc(iot, ioh, NE7CMD_RECAL); /* recal function */ 851 out_fdc(iot, ioh, fd->sc_drive); 852 fdc->sc_state = RECALWAIT; 853 timeout_add(&fd->fdtimeout_to, 5 * hz); 854 return 1; /* will return later */ 855 856 case RECALWAIT: 857 timeout_del(&fd->fdtimeout_to); 858 fdc->sc_state = RECALCOMPLETE; 859 /* allow 1/30 second for heads to settle */ 860 timeout_add(&fdc->fdcpseudointr_to, hz / 30); 861 return 1; /* will return later */ 862 863 case RECALCOMPLETE: 864 out_fdc(iot, ioh, NE7CMD_SENSEI); 865 if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) { 866 #ifdef FD_DEBUG 867 fdcstatus(&fd->sc_dev, 2, "recalibrate failed"); 868 #endif 869 fdretry(fd); 870 goto loop; 871 } 872 fd->sc_cylin = 0; 873 goto doseek; 874 875 case MOTORWAIT: 876 if (fd->sc_flags & FD_MOTOR_WAIT) 877 return 1; /* time's not up yet */ 878 goto doseek; 879 880 default: 881 fdcstatus(&fd->sc_dev, 0, "stray interrupt"); 882 return 1; 883 } 884 #ifdef DIAGNOSTIC 885 panic("fdintr: impossible"); 886 #endif 887 #undef st0 888 #undef cyl 889 } 890 891 void 892 fdtimeout(arg) 893 void *arg; 894 { 895 struct fd_softc *fd = arg; 896 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; 897 int s; 898 899 s = splbio(); 900 #ifdef DEBUG 901 log(LOG_ERR,"fdtimeout: state %d\n", fdc->sc_state); 902 #endif 903 fdcstatus(&fd->sc_dev, 0, "timeout"); 904 905 if (fd->sc_q.b_actf) 906 fdc->sc_state++; 907 else 908 fdc->sc_state = DEVIDLE; 909 910 (void) fdintr(fdc); 911 splx(s); 912 } 913 914 void 915 fdretry(fd) 916 struct fd_softc *fd; 917 { 918 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; 919 struct buf *bp = fd->sc_q.b_actf; 920 921 if (fd->sc_opts & FDOPT_NORETRY) 922 goto fail; 923 switch (fdc->sc_errors) { 924 case 0: 925 /* try again */ 926 fdc->sc_state = DOSEEK; 927 break; 928 929 case 1: case 2: case 3: 930 /* didn't work; try recalibrating */ 931 fdc->sc_state = DORECAL; 932 break; 933 934 case 4: 935 /* still no go; reset the bastard */ 936 fdc->sc_state = DORESET; 937 break; 938 939 default: 940 fail: 941 diskerr(bp, "fd", "hard error", LOG_PRINTF, 942 fd->sc_skip / (128 << fd->sc_type->secsize), 943 (struct disklabel *)NULL); 944 printf(" (st0 %b st1 %b st2 %b cyl %d head %d sec %d)\n", 945 fdc->sc_status[0], NE7_ST0BITS, 946 fdc->sc_status[1], NE7_ST1BITS, 947 fdc->sc_status[2], NE7_ST2BITS, 948 fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]); 949 950 bp->b_flags |= B_ERROR; 951 bp->b_error = EIO; 952 fdfinish(fd, bp); 953 } 954 fdc->sc_errors++; 955 } 956 957 int 958 fdioctl(dev, cmd, addr, flag, p) 959 dev_t dev; 960 u_long cmd; 961 caddr_t addr; 962 int flag; 963 struct proc *p; 964 { 965 struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)]; 966 struct disklabel dl, *lp = &dl; 967 struct cpu_disklabel cdl; 968 char *errstring; 969 int error; 970 971 switch (cmd) { 972 case MTIOCTOP: 973 if (((struct mtop *)addr)->mt_op != MTOFFL) 974 return EIO; 975 return (0); 976 case DIOCGDINFO: 977 bzero(lp, sizeof(*lp)); 978 bzero(&cdl, sizeof(struct cpu_disklabel)); 979 980 lp->d_secsize = 128 << fd->sc_type->secsize; 981 lp->d_secpercyl = fd->sc_type->seccyl; 982 lp->d_ntracks = fd->sc_type->heads; 983 lp->d_nsectors = fd->sc_type->sectrac; 984 lp->d_ncylinders = fd->sc_type->tracks; 985 986 strncpy(lp->d_typename, "floppy disk", 16); 987 lp->d_type = DTYPE_FLOPPY; 988 strncpy(lp->d_packname, "fictitious", 16); 989 lp->d_secperunit = fd->sc_type->size; 990 lp->d_rpm = 300; 991 lp->d_interleave = 1; 992 lp->d_flags = D_REMOVABLE; 993 994 lp->d_partitions[RAW_PART].p_offset = 0; 995 lp->d_partitions[RAW_PART].p_size = 996 lp->d_secperunit * (lp->d_secsize / DEV_BSIZE); 997 lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED; 998 lp->d_npartitions = RAW_PART + 1; 999 1000 lp->d_magic = DISKMAGIC; 1001 lp->d_magic2 = DISKMAGIC; 1002 lp->d_checksum = dkcksum(lp); 1003 1004 errstring = readdisklabel(dev, fdstrategy, lp, &cdl, 0); 1005 if (errstring) { 1006 /*printf("%s: %s\n", fd->sc_dev.dv_xname, errstring); */ 1007 } 1008 1009 *(struct disklabel *)addr = *lp; 1010 return 0; 1011 1012 case DIOCWLABEL: 1013 if ((flag & FWRITE) == 0) 1014 return EBADF; 1015 /* XXX do something */ 1016 return 0; 1017 1018 case DIOCWDINFO: 1019 if ((flag & FWRITE) == 0) 1020 return EBADF; 1021 1022 error = setdisklabel(lp, (struct disklabel *)addr, 0, NULL); 1023 if (error) 1024 return error; 1025 1026 error = writedisklabel(dev, fdstrategy, lp, NULL); 1027 return error; 1028 1029 case FD_FORM: 1030 if((flag & FWRITE) == 0) 1031 return EBADF; /* must be opened for writing */ 1032 else if(((struct fd_formb *)addr)->format_version != 1033 FD_FORMAT_VERSION) 1034 return EINVAL; /* wrong version of formatting prog */ 1035 else 1036 return fdformat(dev, (struct fd_formb *)addr, p); 1037 break; 1038 1039 case FD_GTYPE: /* get drive type */ 1040 *(struct fd_type *)addr = *fd->sc_type; 1041 return 0; 1042 1043 case FD_GOPTS: /* get drive options */ 1044 *(int *)addr = fd->sc_opts; 1045 return 0; 1046 1047 case FD_SOPTS: /* set drive options */ 1048 fd->sc_opts = *(int *)addr; 1049 return 0; 1050 1051 default: 1052 return ENOTTY; 1053 } 1054 1055 #ifdef DIAGNOSTIC 1056 panic("fdioctl: impossible"); 1057 #endif 1058 } 1059 1060 int 1061 fdformat(dev, finfo, p) 1062 dev_t dev; 1063 struct fd_formb *finfo; 1064 struct proc *p; 1065 { 1066 int rv = 0, s; 1067 struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)]; 1068 struct fd_type *type = fd->sc_type; 1069 struct buf *bp; 1070 int fd_bsize = 128 << fd->sc_type->secsize; 1071 1072 /* set up a buffer header for fdstrategy() */ 1073 bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT); 1074 if(bp == 0) 1075 return ENOBUFS; 1076 bzero((void *)bp, sizeof(struct buf)); 1077 bp->b_flags = B_BUSY | B_PHYS | B_FORMAT; 1078 bp->b_proc = p; 1079 bp->b_dev = dev; 1080 1081 /* 1082 * calculate a fake blkno, so fdstrategy() would initiate a 1083 * seek to the requested cylinder 1084 */ 1085 bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads) 1086 + finfo->head * type->sectrac) * fd_bsize / DEV_BSIZE; 1087 1088 bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs; 1089 bp->b_data = (caddr_t)finfo; 1090 1091 #ifdef DEBUG 1092 printf("fdformat: blkno %x count %x\n", bp->b_blkno, bp->b_bcount); 1093 #endif 1094 1095 /* now do the format */ 1096 fdstrategy(bp); 1097 1098 /* ...and wait for it to complete */ 1099 s = splbio(); 1100 while(!(bp->b_flags & B_DONE)) 1101 { 1102 rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 0); 1103 if(rv == EWOULDBLOCK) 1104 /*break*/; 1105 } 1106 splx(s); 1107 1108 if(rv == EWOULDBLOCK) { 1109 /* timed out */ 1110 rv = EIO; 1111 /* XXX what to do to the buf? it will eventually fall 1112 out as finished, but ... ?*/ 1113 /*biodone(bp);*/ 1114 } 1115 if(bp->b_flags & B_ERROR) 1116 rv = bp->b_error; 1117 free(bp, M_TEMP); 1118 return rv; 1119 } 1120