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