1 /* $NetBSD: hdfd.c,v 1.2 1996/11/13 06:48:24 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 1996 Leo Weppelman 5 * Copyright (c) 1993, 1994, 1995, 1996 6 * Charles M. Hannum. All rights reserved. 7 * Copyright (c) 1990 The Regents of the University of California. 8 * All rights reserved. 9 * 10 * This code is derived from software contributed to Berkeley by 11 * Don Ahn. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. All advertising materials mentioning features or use of this software 22 * must display the following acknowledgement: 23 * This product includes software developed by the University of 24 * California, Berkeley and its contributors. 25 * 4. Neither the name of the University nor the names of its contributors 26 * may be used to endorse or promote products derived from this software 27 * without specific prior written permission. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 39 * SUCH DAMAGE. 40 * 41 * @(#)fd.c 7.4 (Berkeley) 5/25/91 42 */ 43 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/kernel.h> 47 #include <sys/file.h> 48 #include <sys/ioctl.h> 49 #include <sys/device.h> 50 #include <sys/disklabel.h> 51 #include <sys/dkstat.h> 52 #include <sys/disk.h> 53 #include <sys/buf.h> 54 #include <sys/uio.h> 55 #include <sys/syslog.h> 56 #include <sys/queue.h> 57 #include <sys/conf.h> 58 #include <sys/device.h> 59 60 #include <machine/cpu.h> 61 #include <machine/bus.h> 62 #include <machine/iomap.h> 63 #include <machine/mfp.h> 64 65 #include <atari/dev/hdfdreg.h> 66 #include <atari/atari/device.h> 67 68 /* 69 * {b,c}devsw[] function prototypes 70 */ 71 dev_type_open(fdopen); 72 dev_type_close(fdclose); 73 dev_type_read(fdread); 74 dev_type_write(fdwrite); 75 dev_type_ioctl(fdioctl); 76 dev_type_size(fdsize); 77 dev_type_dump(fddump); 78 79 volatile u_char *fdio_addr; 80 81 #define wrt_fdc_reg(reg, val) { fdio_addr[reg] = val; } 82 #define rd_fdc_reg(reg) ( fdio_addr[reg] ) 83 84 #define fdc_ienable() MFP2->mf_ierb |= IB_DCHG; 85 86 /* 87 * Interface to the pseudo-dma handler 88 */ 89 void fddma_intr(void); 90 caddr_t fddmaaddr = NULL; 91 int fddmalen = 0; 92 93 /* 94 * Argument to fdcintr..... 95 */ 96 static void *intr_arg = NULL; /* XXX: arg. to intr_establish() */ 97 98 99 #define FDUNIT(dev) (minor(dev) / 8) 100 #define FDTYPE(dev) (minor(dev) % 8) 101 102 #define b_cylin b_resid 103 104 enum fdc_state { 105 DEVIDLE = 0, 106 MOTORWAIT, 107 DOSEEK, 108 SEEKWAIT, 109 SEEKTIMEDOUT, 110 SEEKCOMPLETE, 111 DOIO, 112 IOCOMPLETE, 113 IOTIMEDOUT, 114 DORESET, 115 RESETCOMPLETE, 116 RESETTIMEDOUT, 117 DORECAL, 118 RECALWAIT, 119 RECALTIMEDOUT, 120 RECALCOMPLETE, 121 }; 122 123 /* software state, per controller */ 124 struct fdc_softc { 125 struct device sc_dev; /* boilerplate */ 126 struct fd_softc *sc_fd[4]; /* pointers to children */ 127 TAILQ_HEAD(drivehead, fd_softc) sc_drives; 128 enum fdc_state sc_state; 129 int sc_errors; /* number of retries so far */ 130 int sc_overruns; /* number of overruns so far */ 131 u_char sc_status[7]; /* copy of registers */ 132 }; 133 134 /* controller driver configuration */ 135 int fdcprobe __P((struct device *, void *, void *)); 136 int fdprint __P((void *, const char *)); 137 void fdcattach __P((struct device *, struct device *, void *)); 138 139 struct cfattach fdc_ca = { 140 sizeof(struct fdc_softc), fdcprobe, fdcattach 141 }; 142 143 struct cfdriver fdc_cd = { 144 NULL, "fdc", DV_DULL 145 }; 146 147 /* 148 * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how 149 * we tell them apart. 150 */ 151 struct fd_type { 152 int sectrac; /* sectors per track */ 153 int heads; /* number of heads */ 154 int seccyl; /* sectors per cylinder */ 155 int secsize; /* size code for sectors */ 156 int datalen; /* data len when secsize = 0 */ 157 int steprate; /* step rate and head unload time */ 158 int gap1; /* gap len between sectors */ 159 int gap2; /* formatting gap */ 160 int tracks; /* total num of tracks */ 161 int size; /* size of disk in sectors */ 162 int step; /* steps per cylinder */ 163 int rate; /* transfer speed code */ 164 char *name; 165 }; 166 167 /* 168 * The order of entries in the following table is important -- BEWARE! 169 * The order of the types is the same as for the TT/Falcon.... 170 */ 171 struct fd_type fd_types[] = { 172 /* 360kB in 720kB drive */ 173 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_125KBPS, "360KB" }, 174 /* 3.5" 720kB diskette */ 175 { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_125KBPS, "720KB" }, 176 /* 1.44MB diskette */ 177 { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_250KBPS, "1.44MB" }, 178 }; 179 180 /* software state, per disk (with up to 4 disks per ctlr) */ 181 struct fd_softc { 182 struct device sc_dev; 183 struct disk sc_dk; 184 185 struct fd_type *sc_deftype; /* default type descriptor */ 186 struct fd_type *sc_type; /* current type descriptor */ 187 188 daddr_t sc_blkno; /* starting block number */ 189 int sc_bcount; /* byte count left */ 190 int sc_skip; /* bytes already transferred */ 191 int sc_nblks; /* #blocks currently tranferring */ 192 int sc_nbytes; /* #bytes currently tranferring */ 193 194 int sc_drive; /* physical unit number */ 195 int sc_flags; 196 #define FD_OPEN 0x01 /* it's open */ 197 #define FD_MOTOR 0x02 /* motor should be on */ 198 #define FD_MOTOR_WAIT 0x04 /* motor coming up */ 199 int sc_cylin; /* where we think the head is */ 200 201 void *sc_sdhook; /* saved shutdown hook for drive. */ 202 203 TAILQ_ENTRY(fd_softc) sc_drivechain; 204 int sc_ops; /* I/O ops since last switch */ 205 struct buf sc_q; /* head of buf chain */ 206 }; 207 208 /* floppy driver configuration */ 209 int fdprobe __P((struct device *, void *, void *)); 210 void fdattach __P((struct device *, struct device *, void *)); 211 212 struct cfattach hdfd_ca = { 213 sizeof(struct fd_softc), fdprobe, fdattach 214 }; 215 216 struct cfdriver hdfd_cd = { 217 NULL, "hdfd", DV_DISK 218 }; 219 220 void fdstrategy __P((struct buf *)); 221 void fdstart __P((struct fd_softc *)); 222 223 struct dkdriver fddkdriver = { fdstrategy }; 224 225 void fd_set_motor __P((struct fdc_softc *fdc, int reset)); 226 void fd_motor_off __P((void *arg)); 227 void fd_motor_on __P((void *arg)); 228 int fdcresult __P((struct fdc_softc *fdc)); 229 int out_fdc __P((u_char x)); 230 void fdc_ctrl_intr __P((struct clockframe *)); 231 void fdcstart __P((struct fdc_softc *fdc)); 232 void fdcstatus __P((struct device *dv, int n, char *s)); 233 void fdctimeout __P((void *arg)); 234 void fdcpseudointr __P((void *arg)); 235 int fdcintr __P((void *)); 236 void fdcretry __P((struct fdc_softc *fdc)); 237 void fdfinish __P((struct fd_softc *fd, struct buf *bp)); 238 __inline struct fd_type *fd_dev_to_type __P((struct fd_softc *, dev_t)); 239 240 int 241 fdcprobe(parent, match, aux) 242 struct device *parent; 243 void *match, *aux; 244 { 245 int rv = 0; 246 struct cfdata *cfp = match; 247 248 if(strcmp("fdc", aux) || cfp->cf_unit != 0) 249 return(0); 250 251 if (!atari_realconfig) 252 return 0; 253 254 if (bus_space_map(NULL, 0xfff00000, NBPG, 0, (caddr_t*)&fdio_addr)) { 255 printf("fdcprobe: cannot map io-area\n"); 256 return (0); 257 } 258 259 #ifdef FD_DEBUG 260 printf("fdcprobe: I/O mapping done va: %p\n", fdio_addr); 261 #endif 262 263 /* reset */ 264 wrt_fdc_reg(fdout, 0); 265 delay(100); 266 wrt_fdc_reg(fdout, FDO_FRST); 267 268 /* see if it can handle a command */ 269 if (out_fdc(NE7CMD_SPECIFY) < 0) 270 goto out; 271 out_fdc(0xdf); 272 out_fdc(7); 273 274 rv = 1; 275 276 out: 277 if (rv == 0) 278 bus_space_unmap(NULL, (caddr_t)fdio_addr, NBPG); 279 280 return rv; 281 } 282 283 /* 284 * Arguments passed between fdcattach and fdprobe. 285 */ 286 struct fdc_attach_args { 287 int fa_drive; 288 struct fd_type *fa_deftype; 289 }; 290 291 /* 292 * Print the location of a disk drive (called just before attaching the 293 * the drive). If `fdc' is not NULL, the drive was found but was not 294 * in the system config file; print the drive name as well. 295 * Return QUIET (config_find ignores this if the device was configured) to 296 * avoid printing `fdN not configured' messages. 297 */ 298 int 299 fdprint(aux, fdc) 300 void *aux; 301 const char *fdc; 302 { 303 register struct fdc_attach_args *fa = aux; 304 305 if (!fdc) 306 printf(" drive %d", fa->fa_drive); 307 return QUIET; 308 } 309 310 void 311 fdcattach(parent, self, aux) 312 struct device *parent, *self; 313 void *aux; 314 { 315 struct fdc_softc *fdc = (void *)self; 316 struct fdc_attach_args fa; 317 int has_fifo; 318 319 has_fifo = 0; 320 321 fdc->sc_state = DEVIDLE; 322 TAILQ_INIT(&fdc->sc_drives); 323 324 out_fdc(NE7CMD_CONFIGURE); 325 if (out_fdc(0) == 0) { 326 out_fdc(0x1a); /* No polling, fifo depth = 10 */ 327 out_fdc(0); 328 329 /* Retain configuration across resets */ 330 out_fdc(NE7CMD_LOCK); 331 (void)fdcresult(fdc); 332 has_fifo = 1; 333 } 334 else { 335 (void)rd_fdc_reg(fddata); 336 printf(": no fifo"); 337 } 338 339 printf("\n"); 340 341 /* 342 * Setup the interrupt vector. 343 * XXX: While no int_establish() functions are available, 344 * we do it the Dirty(Tm) way... 345 */ 346 { 347 extern u_long uservects[]; 348 extern void mfp_hdfd_nf(void), mfp_hdfd_fifo(void); 349 350 uservects[22] = (u_long)(has_fifo ? mfp_hdfd_fifo:mfp_hdfd_nf); 351 } 352 353 /* 354 * Setup the interrupt logic. 355 */ 356 MFP2->mf_iprb &= ~IB_DCHG; 357 MFP2->mf_imrb |= IB_DCHG; 358 MFP2->mf_aer |= 0x10; /* fdc int low->high */ 359 360 /* physical limit: four drives per controller. */ 361 for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) { 362 /* 363 * XXX: Choose something sensible as a default... 364 */ 365 fa.fa_deftype = &fd_types[2]; /* 1.44MB */ 366 (void)config_found(self, (void *)&fa, fdprint); 367 } 368 } 369 370 int 371 fdprobe(parent, match, aux) 372 struct device *parent; 373 void *match, *aux; 374 { 375 struct fdc_softc *fdc = (void *)parent; 376 struct cfdata *cf = match; 377 struct fdc_attach_args *fa = aux; 378 int drive = fa->fa_drive; 379 int n; 380 381 if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != drive) 382 return 0; 383 /* 384 * XXX 385 * This is to work around some odd interactions between this driver 386 * and SMC Ethernet cards. 387 */ 388 if (cf->cf_loc[0] == -1 && drive >= 2) 389 return 0; 390 391 /* select drive and turn on motor */ 392 wrt_fdc_reg(fdout, drive | FDO_FRST | FDO_MOEN(drive)); 393 394 /* wait for motor to spin up */ 395 delay(250000); 396 out_fdc(NE7CMD_RECAL); 397 out_fdc(drive); 398 399 /* wait for recalibrate */ 400 delay(2000000); 401 out_fdc(NE7CMD_SENSEI); 402 n = fdcresult(fdc); 403 404 #ifdef FD_DEBUG 405 { 406 int i; 407 printf("fdprobe: status"); 408 for (i = 0; i < n; i++) 409 printf(" %x", fdc->sc_status[i]); 410 printf("\n"); 411 } 412 #endif 413 intr_arg = (void*)fdc; 414 if (n != 2 || (fdc->sc_status[0] & 0xf8) != 0x20) 415 return 0; 416 /* turn off motor */ 417 wrt_fdc_reg(fdout, FDO_FRST); 418 419 return 1; 420 } 421 422 /* 423 * Controller is working, and drive responded. Attach it. 424 */ 425 void 426 fdattach(parent, self, aux) 427 struct device *parent, *self; 428 void *aux; 429 { 430 struct fdc_softc *fdc = (void *)parent; 431 struct fd_softc *fd = (void *)self; 432 struct fdc_attach_args *fa = aux; 433 struct fd_type *type = fa->fa_deftype; 434 int drive = fa->fa_drive; 435 436 /* XXX Allow `flags' to override device type? */ 437 438 if (type) 439 printf(": %s %d cyl, %d head, %d sec\n", type->name, 440 type->tracks, type->heads, type->sectrac); 441 else 442 printf(": density unknown\n"); 443 444 fd->sc_cylin = -1; 445 fd->sc_drive = drive; 446 fd->sc_deftype = type; 447 fdc->sc_fd[drive] = fd; 448 449 /* 450 * Initialize and attach the disk structure. 451 */ 452 fd->sc_dk.dk_name = fd->sc_dev.dv_xname; 453 fd->sc_dk.dk_driver = &fddkdriver; 454 disk_attach(&fd->sc_dk); 455 456 /* XXX Need to do some more fiddling with sc_dk. */ 457 dk_establish(&fd->sc_dk, &fd->sc_dev); 458 459 /* Needed to power off if the motor is on when we halt. */ 460 fd->sc_sdhook = shutdownhook_establish(fd_motor_off, fd); 461 } 462 463 /* 464 * This is called from the assembly part of the interrupt handler 465 * when it is clear that the interrupt was not related to shoving 466 * data. 467 */ 468 void 469 fdc_ctrl_intr(frame) 470 register struct clockframe *frame; 471 { 472 int s; 473 474 /* 475 * Disable further interrupts. The fdcintr() routine 476 * explicitely enables them when needed. 477 */ 478 MFP2->mf_ierb &= ~IB_DCHG; 479 480 /* 481 * Set fddmalen to zero so no pseudo-dma transfers will 482 * occur. 483 */ 484 fddmalen = 0; 485 486 if (!BASEPRI(frame->sr)) { 487 /* 488 * We don't want to stay on ipl6..... 489 */ 490 add_sicallback((si_farg)fdcpseudointr, intr_arg, 0); 491 } 492 else { 493 s = splbio(); 494 (void) fdcintr(intr_arg); 495 splx(s); 496 } 497 } 498 499 __inline struct fd_type * 500 fd_dev_to_type(fd, dev) 501 struct fd_softc *fd; 502 dev_t dev; 503 { 504 int type = FDTYPE(dev); 505 506 if (type > (sizeof(fd_types) / sizeof(fd_types[0]))) 507 return NULL; 508 return type ? &fd_types[type - 1] : fd->sc_deftype; 509 } 510 511 void 512 fdstrategy(bp) 513 register struct buf *bp; /* IO operation to perform */ 514 { 515 struct fd_softc *fd = hdfd_cd.cd_devs[FDUNIT(bp->b_dev)]; 516 int sz; 517 int s; 518 519 /* Valid unit, controller, and request? */ 520 if (bp->b_blkno < 0 || 521 (bp->b_bcount % FDC_BSIZE) != 0) { 522 bp->b_error = EINVAL; 523 goto bad; 524 } 525 526 /* If it's a null transfer, return immediately. */ 527 if (bp->b_bcount == 0) 528 goto done; 529 530 sz = howmany(bp->b_bcount, FDC_BSIZE); 531 532 if (bp->b_blkno + sz > fd->sc_type->size) { 533 sz = fd->sc_type->size - bp->b_blkno; 534 if (sz == 0) { 535 /* If exactly at end of disk, return EOF. */ 536 goto done; 537 } 538 if (sz < 0) { 539 /* If past end of disk, return EINVAL. */ 540 bp->b_error = EINVAL; 541 goto bad; 542 } 543 /* Otherwise, truncate request. */ 544 bp->b_bcount = sz << DEV_BSHIFT; 545 } 546 547 bp->b_cylin = bp->b_blkno / (FDC_BSIZE/DEV_BSIZE) / fd->sc_type->seccyl; 548 549 #ifdef FD_DEBUG 550 printf("fdstrategy: b_blkno %d b_bcount %ld blkno %ld cylin %ld sz" 551 " %d\n", bp->b_blkno, bp->b_bcount, (long)fd->sc_blkno, 552 bp->b_cylin, sz); 553 #endif 554 555 /* Queue transfer on drive, activate drive and controller if idle. */ 556 s = splbio(); 557 disksort(&fd->sc_q, bp); 558 untimeout(fd_motor_off, fd); /* a good idea */ 559 if (!fd->sc_q.b_active) 560 fdstart(fd); 561 #ifdef DIAGNOSTIC 562 else { 563 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; 564 if (fdc->sc_state == DEVIDLE) { 565 printf("fdstrategy: controller inactive\n"); 566 fdcstart(fdc); 567 } 568 } 569 #endif 570 splx(s); 571 return; 572 573 bad: 574 bp->b_flags |= B_ERROR; 575 done: 576 /* Toss transfer; we're done early. */ 577 bp->b_resid = bp->b_bcount; 578 biodone(bp); 579 } 580 581 void 582 fdstart(fd) 583 struct fd_softc *fd; 584 { 585 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; 586 int active = fdc->sc_drives.tqh_first != 0; 587 588 /* Link into controller queue. */ 589 fd->sc_q.b_active = 1; 590 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain); 591 592 /* If controller not already active, start it. */ 593 if (!active) 594 fdcstart(fdc); 595 } 596 597 void 598 fdfinish(fd, bp) 599 struct fd_softc *fd; 600 struct buf *bp; 601 { 602 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; 603 604 /* 605 * Move this drive to the end of the queue to give others a `fair' 606 * chance. We only force a switch if N operations are completed while 607 * another drive is waiting to be serviced, since there is a long motor 608 * startup delay whenever we switch. 609 */ 610 if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) { 611 fd->sc_ops = 0; 612 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain); 613 if (bp->b_actf) { 614 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain); 615 } else 616 fd->sc_q.b_active = 0; 617 } 618 bp->b_resid = fd->sc_bcount; 619 fd->sc_skip = 0; 620 fd->sc_q.b_actf = bp->b_actf; 621 622 biodone(bp); 623 /* turn off motor 5s from now */ 624 timeout(fd_motor_off, fd, 5 * hz); 625 fdc->sc_state = DEVIDLE; 626 } 627 628 int 629 fdread(dev, uio, flags) 630 dev_t dev; 631 struct uio *uio; 632 int flags; 633 { 634 return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio)); 635 } 636 637 int 638 fdwrite(dev, uio, flags) 639 dev_t dev; 640 struct uio *uio; 641 int flags; 642 { 643 return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio)); 644 } 645 646 void 647 fd_set_motor(fdc, reset) 648 struct fdc_softc *fdc; 649 int reset; 650 { 651 struct fd_softc *fd; 652 u_char status; 653 int n; 654 655 if ((fd = fdc->sc_drives.tqh_first) != NULL) 656 status = fd->sc_drive; 657 else 658 status = 0; 659 if (!reset) 660 status |= FDO_FRST | FDO_FDMAEN; 661 for (n = 0; n < 4; n++) 662 if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR)) 663 status |= FDO_MOEN(n); 664 wrt_fdc_reg(fdout, status); 665 } 666 667 void 668 fd_motor_off(arg) 669 void *arg; 670 { 671 struct fd_softc *fd = arg; 672 int s; 673 674 s = splbio(); 675 fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT); 676 fd_set_motor((struct fdc_softc *)fd->sc_dev.dv_parent, 0); 677 splx(s); 678 } 679 680 void 681 fd_motor_on(arg) 682 void *arg; 683 { 684 struct fd_softc *fd = arg; 685 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; 686 int s; 687 688 s = splbio(); 689 fd->sc_flags &= ~FD_MOTOR_WAIT; 690 if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT)) 691 (void) fdcintr(fdc); 692 splx(s); 693 } 694 695 int 696 fdcresult(fdc) 697 struct fdc_softc *fdc; 698 { 699 u_char i; 700 int j = 100000, 701 n = 0; 702 703 for (; j; j--) { 704 i = rd_fdc_reg(fdsts) & (NE7_DIO | NE7_RQM | NE7_CB); 705 if (i == NE7_RQM) 706 return n; 707 if (i == (NE7_DIO | NE7_RQM | NE7_CB)) { 708 if (n >= sizeof(fdc->sc_status)) { 709 log(LOG_ERR, "fdcresult: overrun\n"); 710 return -1; 711 } 712 fdc->sc_status[n++] = rd_fdc_reg(fddata); 713 } 714 } 715 log(LOG_ERR, "fdcresult: timeout\n"); 716 return -1; 717 } 718 719 int 720 out_fdc(x) 721 u_char x; 722 { 723 int i = 100000; 724 725 while ((rd_fdc_reg(fdsts) & NE7_RQM) == 0 && i-- > 0); 726 if (i <= 0) 727 return -1; 728 while ((rd_fdc_reg(fdsts) & NE7_DIO) && i-- > 0); 729 if (i <= 0) 730 return -1; 731 wrt_fdc_reg(fddata, x); 732 return 0; 733 } 734 735 int 736 fdopen(dev, flags, mode, p) 737 dev_t dev; 738 int flags; 739 int mode; 740 struct proc *p; 741 { 742 int unit; 743 struct fd_softc *fd; 744 struct fd_type *type; 745 746 unit = FDUNIT(dev); 747 if (unit >= hdfd_cd.cd_ndevs) 748 return ENXIO; 749 fd = hdfd_cd.cd_devs[unit]; 750 if (fd == 0) 751 return ENXIO; 752 type = fd_dev_to_type(fd, dev); 753 if (type == NULL) 754 return ENXIO; 755 756 if ((fd->sc_flags & FD_OPEN) != 0 && 757 fd->sc_type != type) 758 return EBUSY; 759 760 fd->sc_type = type; 761 fd->sc_cylin = -1; 762 fd->sc_flags |= FD_OPEN; 763 764 return 0; 765 } 766 767 int 768 fdclose(dev, flags, mode, p) 769 dev_t dev; 770 int flags; 771 int mode; 772 struct proc *p; 773 { 774 struct fd_softc *fd = hdfd_cd.cd_devs[FDUNIT(dev)]; 775 776 fd->sc_flags &= ~FD_OPEN; 777 return 0; 778 } 779 780 void 781 fdcstart(fdc) 782 struct fdc_softc *fdc; 783 { 784 785 #ifdef DIAGNOSTIC 786 /* only got here if controller's drive queue was inactive; should 787 be in idle state */ 788 if (fdc->sc_state != DEVIDLE) { 789 printf("fdcstart: not idle\n"); 790 return; 791 } 792 #endif 793 (void) fdcintr(fdc); 794 } 795 796 void 797 fdcstatus(dv, n, s) 798 struct device *dv; 799 int n; 800 char *s; 801 { 802 struct fdc_softc *fdc = (void *)dv->dv_parent; 803 char bits[64]; 804 805 if (n == 0) { 806 out_fdc(NE7CMD_SENSEI); 807 (void) fdcresult(fdc); 808 n = 2; 809 } 810 811 printf("%s: %s", dv->dv_xname, s); 812 813 switch (n) { 814 case 0: 815 printf("\n"); 816 break; 817 case 2: 818 printf(" (st0 %s cyl %d)\n", 819 bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS, 820 bits, sizeof(bits)), fdc->sc_status[1]); 821 break; 822 case 7: 823 printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0], 824 NE7_ST0BITS, bits, sizeof(bits))); 825 printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1], 826 NE7_ST1BITS, bits, sizeof(bits))); 827 printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2], 828 NE7_ST2BITS, bits, sizeof(bits))); 829 printf(" cyl %d head %d sec %d)\n", 830 fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]); 831 break; 832 #ifdef DIAGNOSTIC 833 default: 834 printf("\nfdcstatus: weird size"); 835 break; 836 #endif 837 } 838 } 839 840 void 841 fdctimeout(arg) 842 void *arg; 843 { 844 struct fdc_softc *fdc = arg; 845 struct fd_softc *fd = fdc->sc_drives.tqh_first; 846 int s; 847 848 s = splbio(); 849 fdcstatus(&fd->sc_dev, 0, "timeout"); 850 851 if (fd->sc_q.b_actf) 852 fdc->sc_state++; 853 else 854 fdc->sc_state = DEVIDLE; 855 856 (void) fdcintr(fdc); 857 splx(s); 858 } 859 860 void 861 fdcpseudointr(arg) 862 void *arg; 863 { 864 int s; 865 866 /* Just ensure it has the right spl. */ 867 s = splbio(); 868 (void) fdcintr(arg); 869 splx(s); 870 } 871 872 int 873 fdcintr(arg) 874 void *arg; 875 { 876 struct fdc_softc *fdc = arg; 877 #define st0 fdc->sc_status[0] 878 #define st1 fdc->sc_status[1] 879 #define cyl fdc->sc_status[1] 880 struct fd_softc *fd; 881 struct buf *bp; 882 int read, head, sec, i, nblks; 883 struct fd_type *type; 884 885 loop: 886 /* Is there a drive for the controller to do a transfer with? */ 887 fd = fdc->sc_drives.tqh_first; 888 if (fd == NULL) { 889 fdc->sc_state = DEVIDLE; 890 return 1; 891 } 892 893 /* Is there a transfer to this drive? If not, deactivate drive. */ 894 bp = fd->sc_q.b_actf; 895 if (bp == NULL) { 896 fd->sc_ops = 0; 897 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain); 898 fd->sc_q.b_active = 0; 899 goto loop; 900 } 901 902 switch (fdc->sc_state) { 903 case DEVIDLE: 904 fdc->sc_errors = 0; 905 fdc->sc_overruns = 0; 906 fd->sc_skip = 0; 907 fd->sc_bcount = bp->b_bcount; 908 fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE); 909 untimeout(fd_motor_off, fd); 910 if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) { 911 fdc->sc_state = MOTORWAIT; 912 return 1; 913 } 914 if ((fd->sc_flags & FD_MOTOR) == 0) { 915 /* Turn on the motor, being careful about pairing. */ 916 struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1]; 917 if (ofd && ofd->sc_flags & FD_MOTOR) { 918 untimeout(fd_motor_off, ofd); 919 ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT); 920 } 921 fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT; 922 fd_set_motor(fdc, 0); 923 fdc->sc_state = MOTORWAIT; 924 /* Allow .25s for motor to stabilize. */ 925 timeout(fd_motor_on, fd, hz / 4); 926 return 1; 927 } 928 /* Make sure the right drive is selected. */ 929 fd_set_motor(fdc, 0); 930 931 /* fall through */ 932 case DOSEEK: 933 doseek: 934 if (fd->sc_cylin == bp->b_cylin) 935 goto doio; 936 937 out_fdc(NE7CMD_SPECIFY);/* specify command */ 938 out_fdc(fd->sc_type->steprate); 939 out_fdc(0x7); /* XXX head load time == 6ms - non-dma */ 940 941 fdc_ienable(); 942 943 out_fdc(NE7CMD_SEEK); /* seek function */ 944 out_fdc(fd->sc_drive); /* drive number */ 945 out_fdc(bp->b_cylin * fd->sc_type->step); 946 947 fd->sc_cylin = -1; 948 fdc->sc_state = SEEKWAIT; 949 950 fd->sc_dk.dk_seek++; 951 disk_busy(&fd->sc_dk); 952 953 timeout(fdctimeout, fdc, 4 * hz); 954 return 1; 955 956 case DOIO: 957 doio: 958 type = fd->sc_type; 959 sec = fd->sc_blkno % type->seccyl; 960 head = sec / type->sectrac; 961 sec -= head * type->sectrac; 962 nblks = type->sectrac - sec; 963 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE); 964 nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE); 965 fd->sc_nblks = nblks; 966 fd->sc_nbytes = nblks * FDC_BSIZE; 967 #ifdef DIAGNOSTIC 968 { 969 int block; 970 971 block = (fd->sc_cylin * type->heads + head) 972 * type->sectrac + sec; 973 if (block != fd->sc_blkno) { 974 printf("fdcintr: block %d != blkno %d\n", 975 block, fd->sc_blkno); 976 #ifdef DDB 977 Debugger(); 978 #endif 979 } 980 } 981 #endif 982 read = bp->b_flags & B_READ ? 1 : 0; 983 984 /* 985 * Setup pseudo-dma address & count 986 */ 987 fddmaaddr = bp->b_data + fd->sc_skip; 988 fddmalen = fd->sc_nbytes; 989 990 wrt_fdc_reg(fdctl, type->rate); 991 #ifdef FD_DEBUG 992 printf("fdcintr: %s drive %d track %d head %d sec %d" 993 " nblks %d\n", read ? "read" : "write", 994 fd->sc_drive, fd->sc_cylin, head, sec, nblks); 995 #endif 996 fdc_ienable(); 997 998 if (read) 999 out_fdc(NE7CMD_READ); /* READ */ 1000 else 1001 out_fdc(NE7CMD_WRITE); /* WRITE */ 1002 out_fdc((head << 2) | fd->sc_drive); 1003 out_fdc(fd->sc_cylin); /* track */ 1004 out_fdc(head); /* head */ 1005 out_fdc(sec + 1); /* sector +1 */ 1006 out_fdc(type->secsize); /* sector size */ 1007 out_fdc(sec + nblks); /* last sectors */ 1008 out_fdc(type->gap1); /* gap1 size */ 1009 out_fdc(type->datalen); /* data length */ 1010 fdc->sc_state = IOCOMPLETE; 1011 1012 disk_busy(&fd->sc_dk); 1013 1014 /* allow 2 seconds for operation */ 1015 timeout(fdctimeout, fdc, 2 * hz); 1016 return 1; /* will return later */ 1017 1018 case SEEKWAIT: 1019 untimeout(fdctimeout, fdc); 1020 fdc->sc_state = SEEKCOMPLETE; 1021 /* allow 1/50 second for heads to settle */ 1022 timeout(fdcpseudointr, fdc, hz / 50); 1023 return 1; 1024 1025 case SEEKCOMPLETE: 1026 disk_unbusy(&fd->sc_dk, 0); /* no data on seek */ 1027 1028 /* Make sure seek really happened. */ 1029 out_fdc(NE7CMD_SENSEI); 1030 if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || 1031 cyl != bp->b_cylin * fd->sc_type->step) { 1032 #ifdef FD_DEBUG 1033 fdcstatus(&fd->sc_dev, 2, "seek failed"); 1034 #endif 1035 fdcretry(fdc); 1036 goto loop; 1037 } 1038 fd->sc_cylin = bp->b_cylin; 1039 goto doio; 1040 1041 case IOTIMEDOUT: 1042 case SEEKTIMEDOUT: 1043 case RECALTIMEDOUT: 1044 case RESETTIMEDOUT: 1045 fdcretry(fdc); 1046 goto loop; 1047 1048 case IOCOMPLETE: /* IO DONE, post-analyze */ 1049 untimeout(fdctimeout, fdc); 1050 1051 disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid)); 1052 1053 if (fdcresult(fdc) != 7 || (st1 & 0x37) != 0) { 1054 /* 1055 * As the damn chip doesn't seem to have a FIFO, 1056 * accept a few overruns as a fact of life *sigh* 1057 */ 1058 if ((st1 & 0x10) && (++fdc->sc_overruns < 4)) { 1059 fdc->sc_state = DOSEEK; 1060 goto loop; 1061 } 1062 #ifdef FD_DEBUG 1063 fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ? 1064 "read failed" : "write failed"); 1065 printf("blkno %d nblks %d\n", 1066 fd->sc_blkno, fd->sc_nblks); 1067 #endif 1068 fdcretry(fdc); 1069 goto loop; 1070 } 1071 if (fdc->sc_errors) { 1072 diskerr(bp, "fd", "soft error", LOG_PRINTF, 1073 fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL); 1074 printf("\n"); 1075 fdc->sc_errors = 0; 1076 } 1077 fdc->sc_overruns = 0; 1078 fd->sc_blkno += fd->sc_nblks; 1079 fd->sc_skip += fd->sc_nbytes; 1080 fd->sc_bcount -= fd->sc_nbytes; 1081 if (fd->sc_bcount > 0) { 1082 bp->b_cylin = fd->sc_blkno / fd->sc_type->seccyl; 1083 goto doseek; 1084 } 1085 fdfinish(fd, bp); 1086 goto loop; 1087 1088 case DORESET: 1089 /* try a reset, keep motor on */ 1090 fd_set_motor(fdc, 1); 1091 delay(100); 1092 fd_set_motor(fdc, 0); 1093 fdc->sc_state = RESETCOMPLETE; 1094 timeout(fdctimeout, fdc, hz / 2); 1095 return 1; /* will return later */ 1096 1097 case RESETCOMPLETE: 1098 untimeout(fdctimeout, fdc); 1099 /* clear the controller output buffer */ 1100 for (i = 0; i < 4; i++) { 1101 out_fdc(NE7CMD_SENSEI); 1102 (void) fdcresult(fdc); 1103 } 1104 1105 /* fall through */ 1106 case DORECAL: 1107 fdc_ienable(); 1108 1109 out_fdc(NE7CMD_RECAL); /* recalibrate function */ 1110 out_fdc(fd->sc_drive); 1111 fdc->sc_state = RECALWAIT; 1112 timeout(fdctimeout, fdc, 5 * hz); 1113 return 1; /* will return later */ 1114 1115 case RECALWAIT: 1116 untimeout(fdctimeout, fdc); 1117 fdc->sc_state = RECALCOMPLETE; 1118 /* allow 1/30 second for heads to settle */ 1119 timeout(fdcpseudointr, fdc, hz / 30); 1120 return 1; /* will return later */ 1121 1122 case RECALCOMPLETE: 1123 out_fdc(NE7CMD_SENSEI); 1124 if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) { 1125 #ifdef FD_DEBUG 1126 fdcstatus(&fd->sc_dev, 2, "recalibrate failed"); 1127 #endif 1128 fdcretry(fdc); 1129 goto loop; 1130 } 1131 fd->sc_cylin = 0; 1132 goto doseek; 1133 1134 case MOTORWAIT: 1135 if (fd->sc_flags & FD_MOTOR_WAIT) 1136 return 1; /* time's not up yet */ 1137 goto doseek; 1138 1139 default: 1140 fdcstatus(&fd->sc_dev, 0, "stray interrupt"); 1141 return 1; 1142 } 1143 #ifdef DIAGNOSTIC 1144 panic("fdcintr: impossible"); 1145 #endif 1146 #undef st0 1147 #undef st1 1148 #undef cyl 1149 } 1150 1151 void 1152 fdcretry(fdc) 1153 struct fdc_softc *fdc; 1154 { 1155 char bits[64]; 1156 struct fd_softc *fd; 1157 struct buf *bp; 1158 1159 fd = fdc->sc_drives.tqh_first; 1160 bp = fd->sc_q.b_actf; 1161 1162 switch (fdc->sc_errors) { 1163 case 0: 1164 /* try again */ 1165 fdc->sc_state = DOSEEK; 1166 break; 1167 1168 case 1: case 2: case 3: 1169 /* didn't work; try recalibrating */ 1170 fdc->sc_state = DORECAL; 1171 break; 1172 1173 case 4: 1174 /* still no go; reset the bastard */ 1175 fdc->sc_state = DORESET; 1176 break; 1177 1178 default: 1179 diskerr(bp, "fd", "hard error", LOG_PRINTF, 1180 fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL); 1181 1182 printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0], 1183 NE7_ST0BITS, bits, sizeof(bits))); 1184 printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1], 1185 NE7_ST1BITS, bits, sizeof(bits))); 1186 printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2], 1187 NE7_ST2BITS, bits, sizeof(bits))); 1188 printf(" cyl %d head %d sec %d)\n", 1189 fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]); 1190 1191 bp->b_flags |= B_ERROR; 1192 bp->b_error = EIO; 1193 fdfinish(fd, bp); 1194 } 1195 fdc->sc_errors++; 1196 } 1197 1198 int 1199 fdsize(dev) 1200 dev_t dev; 1201 { 1202 1203 /* Swapping to floppies would not make sense. */ 1204 return -1; 1205 } 1206 1207 int 1208 fddump(dev, blkno, va, size) 1209 dev_t dev; 1210 daddr_t blkno; 1211 caddr_t va; 1212 size_t size; 1213 { 1214 1215 /* Not implemented. */ 1216 return ENXIO; 1217 } 1218 1219 int 1220 fdioctl(dev, cmd, addr, flag, p) 1221 dev_t dev; 1222 u_long cmd; 1223 caddr_t addr; 1224 int flag; 1225 struct proc *p; 1226 { 1227 struct fd_softc *fd; 1228 struct disklabel buffer; 1229 struct cpu_disklabel cpulab; 1230 int error; 1231 1232 fd = hdfd_cd.cd_devs[FDUNIT(dev)]; 1233 1234 switch (cmd) { 1235 case DIOCGDINFO: 1236 bzero(&buffer, sizeof(buffer)); 1237 bzero(&cpulab, sizeof(cpulab)); 1238 1239 buffer.d_secpercyl = fd->sc_type->seccyl; 1240 buffer.d_type = DTYPE_FLOPPY; 1241 buffer.d_secsize = FDC_BSIZE; 1242 buffer.d_secperunit = fd->sc_type->size; 1243 1244 if (readdisklabel(dev, fdstrategy, &buffer, &cpulab) != NULL) 1245 return EINVAL; 1246 *(struct disklabel *)addr = buffer; 1247 return 0; 1248 1249 case DIOCWLABEL: 1250 if ((flag & FWRITE) == 0) 1251 return EBADF; 1252 /* XXX do something */ 1253 return 0; 1254 1255 case DIOCWDINFO: 1256 if ((flag & FWRITE) == 0) 1257 return EBADF; 1258 1259 error = setdisklabel(&buffer, (struct disklabel *)addr, 0, NULL); 1260 if (error) 1261 return error; 1262 1263 error = writedisklabel(dev, fdstrategy, &buffer, NULL); 1264 return error; 1265 1266 default: 1267 return ENOTTY; 1268 } 1269 1270 #ifdef DIAGNOSTIC 1271 panic("fdioctl: impossible"); 1272 #endif 1273 } 1274