1 /* $NetBSD: fd.c,v 1.6 1995/05/05 16:38:05 leo Exp $ */ 2 3 /* 4 * Copyright (c) 1995 Leo Weppelman. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Leo Weppelman. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * This file contains a driver for the Floppy Disk Controller (FDC) 35 * on the Atari TT. It uses the WD 1772 chip, modified for steprates. 36 * 37 * The ST floppy disk controller shares the access to the DMA circuitry 38 * with other devices. For this reason the floppy disk controller makes 39 * use of some special DMA accessing code. 40 * 41 * Interrupts from the FDC are in fact DMA interrupts which get their 42 * first level handling in 'dma.c' . If the floppy driver is currently 43 * using DMA the interrupt is signalled to 'fdcint'. 44 * 45 * TODO: 46 * - Test it with 2 drives (I don't have them) 47 * - Test it with an HD-drive (Don't have that either) 48 * - Finish ioctl's 49 */ 50 51 #include <sys/param.h> 52 #include <sys/systm.h> 53 #include <sys/kernel.h> 54 #include <sys/malloc.h> 55 #include <sys/buf.h> 56 #include <sys/device.h> 57 #include <sys/ioctl.h> 58 #include <sys/fcntl.h> 59 #include <sys/conf.h> 60 #include <sys/disklabel.h> 61 #include <sys/disk.h> 62 #include <sys/dkbad.h> 63 #include <atari/atari/device.h> 64 #include <machine/disklabel.h> 65 #include <machine/iomap.h> 66 #include <machine/mfp.h> 67 #include <machine/dma.h> 68 #include <machine/video.h> 69 #include <atari/dev/fdreg.h> 70 71 /* 72 * Be verbose for debugging 73 */ 74 /*#define FLP_DEBUG 1 */ 75 76 #define FDC_MAX_DMA_AD 0x1000000 /* No DMA possible beyond */ 77 78 /* Parameters for the disk drive. */ 79 #define SECTOR_SIZE 512 /* physical sector size in bytes */ 80 #define NR_DRIVES 2 /* maximum number of drives */ 81 #define NR_TYPES 3 /* number of diskette/drive combinations*/ 82 #define MAX_ERRORS 10 /* how often to try rd/wt before quitting*/ 83 #define STEP_DELAY 6000 /* 6ms (6000us) delay after stepping */ 84 85 86 #define INV_TRK 32000 /* Should fit in unsigned short */ 87 #define INV_PART NR_TYPES 88 89 /* 90 * Driver states 91 */ 92 #define FLP_IDLE 0x00 /* floppy is idle */ 93 #define FLP_MON 0x01 /* idle with motor on */ 94 #define FLP_STAT 0x02 /* determine floppy status */ 95 #define FLP_XFER 0x04 /* read/write data from floppy */ 96 97 /* 98 * Timer delay's 99 */ 100 #define FLP_MONDELAY (3 * hz) /* motor-on delay */ 101 #define FLP_XFERDELAY (2 * hz) /* timeout on transfer */ 102 103 104 #define b_block b_resid /* FIXME: this is not the place */ 105 106 /* 107 * Global data for all physical floppy devices 108 */ 109 static short selected = 0; /* drive/head currently selected*/ 110 static short motoron = 0; /* motor is spinning */ 111 static short nopens = 0; /* Number of opens executed */ 112 113 static short fd_state = FLP_IDLE; /* Current driver state */ 114 static int lock_stat= 0; /* dma locking status */ 115 static short fd_cmd = 0; /* command being executed */ 116 static char *fd_error= NULL; /* error from fd_xfer_ok() */ 117 118 /* 119 * Private per device data 120 */ 121 struct fd_softc { 122 struct dkdevice dkdev; 123 struct buf bufq; /* queue of buf's */ 124 int unit; /* unit for atari controlling hw*/ 125 int nheads; /* number of heads in use */ 126 int nsectors; /* number of sectors/track */ 127 int nblocks; /* number of blocks on disk */ 128 int curtrk; /* track head positioned on */ 129 short flags; /* misc flags */ 130 short part; /* Current open partition */ 131 int sector; /* logical sector for I/O */ 132 caddr_t io_data; /* KVA for data transfer */ 133 int io_bytes; /* bytes left for I/O */ 134 int io_dir; /* B_READ/B_WRITE */ 135 int errcnt; /* current error count */ 136 u_char *bounceb; /* Bounce buffer */ 137 138 }; 139 140 /* 141 * Flags in fd_softc: 142 */ 143 #define FLPF_NOTRESP 0x001 /* Unit not responding */ 144 #define FLPF_ISOPEN 0x002 /* Unit is open */ 145 #define FLPF_ISHD 0x004 /* Use High Density */ 146 #define FLPF_HAVELAB 0x008 /* We have a valid label */ 147 #define FLPF_BOUNCE 0x010 /* Now using the bounce buffer */ 148 #define FLPF_WRTPROT 0x020 /* Unit is write-protected */ 149 #define FLPF_EMPTY 0x040 /* Unit is empty */ 150 #define FLPF_INOPEN 0x080 /* Currently being opened */ 151 #define FLPF_GETSTAT 0x100 /* Getting unit status */ 152 153 struct fd_types { 154 int nheads; /* Heads in use */ 155 int nsectors; /* sectors per track */ 156 int nblocks; /* number of blocks */ 157 } fdtypes[NR_TYPES] = { 158 { 1, 9, 720 }, /* 360 Kb */ 159 { 2, 9, 1440 }, /* 720 Kb */ 160 { 1, 18, 2880 }, /* 1.44 Mb */ 161 }; 162 163 typedef void (*FPV)(); 164 165 /* 166 * Private drive functions.... 167 */ 168 static void fdstart __P((struct fd_softc *)); 169 static void fddone __P((struct fd_softc *)); 170 static void fdstatus __P((struct fd_softc *)); 171 static void fd_xfer __P((struct fd_softc *)); 172 static void fdcint __P((struct fd_softc *)); 173 static int fd_xfer_ok __P((struct fd_softc *)); 174 static void fdmotoroff __P((struct fd_softc *)); 175 static int fdminphys __P((struct buf *)); 176 static void fdtestdrv __P((struct fd_softc *)); 177 static int fdgetdisklabel __P((struct fd_softc *, dev_t)); 178 179 extern __inline__ u_char read_fdreg(u_short regno) 180 { 181 DMA->dma_mode = regno; 182 return(DMA->dma_data); 183 } 184 185 extern __inline__ void write_fdreg(u_short regno, u_short val) 186 { 187 DMA->dma_mode = regno; 188 DMA->dma_data = val; 189 } 190 191 extern __inline__ u_char read_dmastat(void) 192 { 193 DMA->dma_mode = FDC_CS | DMA_SCREG; 194 return(DMA->dma_stat); 195 } 196 197 /* 198 * Autoconfig stuff.... 199 */ 200 static int fdcmatch __P((struct device *, struct cfdata *, void *)); 201 static int fdcprint __P((void *, char *)); 202 static void fdcattach __P((struct device *, struct device *, void *)); 203 204 struct cfdriver fdccd = { 205 NULL, "fdc", (cfmatch_t)fdcmatch, fdcattach, DV_DULL, 206 sizeof(struct device), NULL, 0 }; 207 208 static int 209 fdcmatch(pdp, cfp, auxp) 210 struct device *pdp; 211 struct cfdata *cfp; 212 void *auxp; 213 { 214 if(strcmp("fdc", auxp) || cfp->cf_unit != 0) 215 return(0); 216 return(1); 217 } 218 219 static void 220 fdcattach(pdp, dp, auxp) 221 struct device *pdp, *dp; 222 void *auxp; 223 { 224 struct fd_softc fdsoftc; 225 int i, nfound = 0; 226 227 printf("\n"); 228 for(i = 0; i < NR_DRIVES; i++) { 229 230 /* 231 * Test if unit is present 232 */ 233 fdsoftc.unit = i; 234 fdsoftc.flags = 0; 235 st_dmagrab(fdcint, fdtestdrv, &fdsoftc, &lock_stat, 0); 236 st_dmafree(&fdsoftc, &lock_stat); 237 238 if(!(fdsoftc.flags & FLPF_NOTRESP)) { 239 nfound++; 240 config_found(dp, (void*)i, fdcprint); 241 } 242 } 243 244 if(nfound) { 245 246 /* 247 * enable disk related interrupts 248 */ 249 MFP->mf_ierb |= IB_DINT; 250 MFP->mf_iprb &= ~IB_DINT; 251 MFP->mf_imrb |= IB_DINT; 252 } 253 } 254 255 static int 256 fdcprint(auxp, pnp) 257 void *auxp; 258 char *pnp; 259 { 260 return(UNCONF); 261 } 262 263 static int fdmatch __P((struct device *, struct cfdata *, void *)); 264 static void fdattach __P((struct device *, struct device *, void *)); 265 void fdstrategy __P((struct buf *)); 266 struct dkdriver fddkdriver = { fdstrategy }; 267 268 struct cfdriver fdcd = { 269 NULL, "fd", (cfmatch_t)fdmatch, fdattach, DV_DISK, 270 sizeof(struct fd_softc), NULL, 0 }; 271 272 static int 273 fdmatch(pdp, cfp, auxp) 274 struct device *pdp; 275 struct cfdata *cfp; 276 void *auxp; 277 { 278 int unit = (int)auxp; 279 return(1); 280 } 281 282 static void 283 fdattach(pdp, dp, auxp) 284 struct device *pdp, *dp; 285 void *auxp; 286 { 287 struct fd_softc *sc; 288 289 sc = (struct fd_softc *)dp; 290 291 printf("\n"); 292 293 sc->dkdev.dk_driver = &fddkdriver; 294 } 295 296 fdioctl(dev, cmd, addr, flag, p) 297 dev_t dev; 298 u_long cmd; 299 int flag; 300 caddr_t addr; 301 struct proc *p; 302 { 303 struct fd_softc *sc; 304 void *data; 305 306 sc = getsoftc(fdcd, DISKUNIT(dev)); 307 308 if((sc->flags & FLPF_HAVELAB) == 0) 309 return(EBADF); 310 311 switch(cmd) { 312 case DIOCSBAD: 313 return(EINVAL); 314 case DIOCGDINFO: 315 *(struct disklabel *)addr = sc->dkdev.dk_label; 316 return(0); 317 case DIOCGPART: 318 ((struct partinfo *)addr)->disklab = 319 &sc->dkdev.dk_label; 320 ((struct partinfo *)addr)->part = 321 &sc->dkdev.dk_label.d_partitions[DISKPART(dev)]; 322 return(0); 323 #ifdef notyet /* XXX LWP */ 324 case DIOCSRETRIES: 325 case DIOCSSTEP: 326 case DIOCSDINFO: 327 case DIOCWDINFO: 328 case DIOCWLABEL: 329 #endif /* notyet */ 330 default: 331 return(ENOTTY); 332 } 333 } 334 335 /* 336 * Open the device. If this is the first open on both the floppy devices, 337 * intialize the controller. 338 * Note that partition info on the floppy device is used to distinguise 339 * between 780Kb and 360Kb floppy's. 340 * partition 0: 360Kb 341 * partition 1: 780Kb 342 */ 343 Fdopen(dev, flags, devtype, proc) 344 dev_t dev; 345 int flags, devtype; 346 struct proc *proc; 347 { 348 struct fd_softc *sc; 349 int sps; 350 351 #ifdef FLP_DEBUG 352 printf("Fdopen dev=0x%x\n", dev); 353 #endif 354 355 if(DISKPART(dev) >= NR_TYPES) 356 return(ENXIO); 357 358 if((sc = getsoftc(fdcd, DISKUNIT(dev))) == NULL) 359 return(ENXIO); 360 361 /* 362 * If no floppy currently open, reset the controller and select 363 * floppy type. 364 */ 365 if(!nopens) { 366 367 #ifdef FLP_DEBUG 368 printf("Fdopen device not yet open\n"); 369 #endif 370 nopens++; 371 write_fdreg(FDC_CS, IRUPT); 372 } 373 374 /* 375 * Sleep while other process is opening the device 376 */ 377 sps = splbio(); 378 while(sc->flags & FLPF_INOPEN) 379 tsleep((caddr_t)sc, PRIBIO, "Fdopen", 0); 380 splx(sps); 381 382 if(!(sc->flags & FLPF_ISOPEN)) { 383 /* 384 * Initialise some driver values. 385 */ 386 int part = DISKPART(dev); 387 void *addr; 388 389 sc->bufq.b_actf = NULL; 390 sc->unit = DISKUNIT(dev); 391 sc->part = part; 392 sc->nheads = fdtypes[part].nheads; 393 sc->nsectors = fdtypes[part].nsectors; 394 sc->nblocks = fdtypes[part].nblocks; 395 sc->curtrk = INV_TRK; 396 sc->sector = 0; 397 sc->errcnt = 0; 398 sc->bounceb = (u_char*)alloc_stmem(SECTOR_SIZE, &addr); 399 if(sc->bounceb == NULL) 400 return(ENOMEM); /* XXX */ 401 if(sc->nsectors > 9) /* XXX */ 402 sc->flags |= FLPF_ISHD; 403 404 /* 405 * Go get write protect + loaded status 406 */ 407 sc->flags |= FLPF_INOPEN|FLPF_GETSTAT; 408 sps = splbio(); 409 st_dmagrab(fdcint, fdstatus, sc, &lock_stat, 0); 410 while(sc->flags & FLPF_GETSTAT) 411 tsleep((caddr_t)sc, PRIBIO, "Fdopen", 0); 412 splx(sps); 413 wakeup((caddr_t)sc); 414 415 if((sc->flags & FLPF_WRTPROT) && (flags & FWRITE)) { 416 sc->flags = 0; 417 return(EPERM); 418 } 419 if(sc->flags & FLPF_EMPTY) { 420 sc->flags = 0; 421 return(ENXIO); 422 } 423 sc->flags &= ~(FLPF_INOPEN|FLPF_GETSTAT); 424 sc->flags |= FLPF_ISOPEN; 425 } 426 else { 427 /* 428 * Multiply opens are granted when accessing the same type of 429 * floppy (eq. the same partition). 430 */ 431 if(sc->part != DISKPART(dev)) 432 return(ENXIO); /* XXX temporarely out of business */ 433 } 434 fdgetdisklabel(sc, dev); 435 #ifdef FLP_DEBUG 436 printf("Fdopen open succeeded on type %d\n", sc->part); 437 #endif 438 } 439 440 fdclose(dev, flags, devtype, proc) 441 dev_t dev; 442 int flags, devtype; 443 struct proc *proc; 444 { 445 struct fd_softc *sc; 446 447 sc = getsoftc(fdcd, DISKUNIT(dev)); 448 free_stmem(sc->bounceb); 449 sc->flags = 0; 450 nopens--; 451 452 #ifdef FLP_DEBUG 453 printf("Closed floppy device -- nopens: %d\n", nopens); 454 #endif 455 return(0); 456 } 457 458 void 459 fdstrategy(bp) 460 struct buf *bp; 461 { 462 struct fd_softc *sc; 463 int sps, nblocks; 464 465 sc = getsoftc(fdcd, DISKUNIT(bp->b_dev)); 466 467 #ifdef FLP_DEBUG 468 printf("fdstrategy: 0x%x\n", bp); 469 #endif 470 471 /* 472 * check for valid partition and bounds 473 */ 474 nblocks = (bp->b_bcount + SECTOR_SIZE - 1) / SECTOR_SIZE; 475 if((bp->b_blkno < 0) || ((bp->b_blkno + nblocks) >= sc->nblocks)) { 476 if((bp->b_blkno == sc->nblocks) && (bp->b_flags & B_READ)) { 477 /* 478 * Read 1 block beyond, return EOF 479 */ 480 bp->b_resid = bp->b_bcount; 481 goto done; 482 } 483 /* 484 * Try to limit the size of the transaction, adjust count 485 * if we succeed. 486 */ 487 nblocks = sc->nblocks - bp->b_blkno; 488 if((nblocks <= 0) || (bp->b_blkno < 0)) { 489 bp->b_error = EINVAL; 490 bp->b_flags |= B_ERROR; 491 goto done; 492 } 493 bp->b_bcount = nblocks * SECTOR_SIZE; 494 } 495 if(bp->b_bcount == 0) 496 goto done; 497 498 /* 499 * Set order info for disksort 500 */ 501 bp->b_block = bp->b_blkno / (sc->nsectors * sc->nheads); 502 503 /* 504 * queue the buf and kick the low level code 505 */ 506 sps = splbio(); 507 disksort(&sc->bufq, bp); 508 if(!lock_stat) { 509 if(fd_state & FLP_MON) 510 untimeout((FPV)fdmotoroff, (void*)sc); 511 fd_state = FLP_IDLE; 512 st_dmagrab(fdcint, fdstart, sc, &lock_stat, 0); 513 } 514 splx(sps); 515 516 return; 517 done: 518 bp->b_resid = bp->b_bcount; 519 biodone(bp); 520 } 521 522 /* 523 * no dumps to floppy disks thank you. 524 */ 525 int 526 fddump(dev_t dev) 527 { 528 return(ENXIO); 529 } 530 531 /* 532 * no dumps to floppy disks thank you. 533 */ 534 int 535 fdsize(dev) 536 dev_t dev; 537 { 538 return(-1); 539 } 540 541 int 542 fdread(dev, uio) 543 dev_t dev; 544 struct uio *uio; 545 { 546 return(physio(cdevsw[major(dev)].d_strategy, (struct buf *)NULL, 547 dev, B_READ, fdminphys, uio)); 548 } 549 550 int 551 fdwrite(dev, uio) 552 dev_t dev; 553 struct uio *uio; 554 { 555 return(physio(cdevsw[major(dev)].d_strategy, (struct buf *)NULL, 556 dev, B_WRITE, fdminphys, uio)); 557 } 558 559 /* 560 * Called through DMA-dispatcher, get status. 561 */ 562 static void 563 fdstatus(sc) 564 struct fd_softc *sc; 565 { 566 #ifdef FLP_DEBUG 567 printf("fdstatus\n"); 568 #endif 569 sc->errcnt = 0; 570 fd_state = FLP_STAT; 571 572 /* 573 * Make sure the floppy controller is the correct density mode 574 */ 575 if(sc->flags & FLPF_ISHD) 576 DMA->dma_drvmode |= (FDC_HDSET|FDC_HDSIG); 577 else DMA->dma_drvmode &= ~(FDC_HDSET|FDC_HDSIG); 578 fd_xfer(sc); 579 } 580 581 /* 582 * Called through the dma-dispatcher. So we know we are the only ones 583 * messing with the floppy-controler. 584 * Initialize some fields in the fdsoftc for the state-machine and get 585 * it going. 586 */ 587 static void 588 fdstart(sc) 589 struct fd_softc *sc; 590 { 591 struct buf *bp; 592 593 bp = sc->bufq.b_actf; 594 sc->sector = bp->b_blkno; /* Start sector for I/O */ 595 sc->io_data = bp->b_data; /* KVA base for I/O */ 596 sc->io_bytes = bp->b_bcount; /* Transfer size in bytes */ 597 sc->io_dir = bp->b_flags & B_READ;/* Direction of transfer */ 598 sc->errcnt = 0; /* No errors yet */ 599 fd_state = FLP_XFER; /* Yes, we're going to transfer */ 600 601 /* 602 * Make sure the floppy controller is the correct density mode 603 */ 604 if(sc->flags & FLPF_ISHD) 605 DMA->dma_drvmode |= (FDC_HDSET|FDC_HDSIG); 606 else DMA->dma_drvmode &= ~(FDC_HDSET|FDC_HDSIG); 607 fd_xfer(sc); 608 } 609 610 /* 611 * The current transaction is finished (for good or bad). Let go of 612 * the the dma-resources. Call biodone() to finish the transaction. 613 * Find a new transaction to work on. 614 */ 615 static void 616 fddone(sc) 617 register struct fd_softc *sc; 618 { 619 struct buf *bp, *dp; 620 struct fd_softc *sc1; 621 int i, sps; 622 623 /* 624 * Lower clock frequency of FDC (better for some old ones). 625 */ 626 DMA->dma_drvmode &= ~(FDC_HDSET|FDC_HDSIG); 627 628 /* 629 * Give others a chance to use the dma. 630 */ 631 st_dmafree(sc, &lock_stat); 632 633 634 if(fd_state != FLP_STAT) { 635 /* 636 * Finish current transaction. 637 */ 638 sps = splbio(); 639 dp = &sc->bufq; 640 bp = dp->b_actf; 641 if(bp == NULL) 642 panic("fddone"); 643 dp->b_actf = bp->b_actf; 644 splx(sps); 645 646 #ifdef FLP_DEBUG 647 printf("fddone: unit: %d, buf: %x, resid: %d\n",sc->unit,bp, 648 sc->io_bytes); 649 #endif 650 bp->b_resid = sc->io_bytes; 651 biodone(bp); 652 } 653 fd_state = FLP_MON; 654 655 if(lock_stat) 656 return; /* XXX Is this possible? */ 657 658 /* 659 * Find a new transaction on round-robin basis. 660 */ 661 for(i = sc->unit + 1; ;i++) { 662 if(i >= fdcd.cd_ndevs) 663 i = 0; 664 if((sc1 = fdcd.cd_devs[i]) == NULL) 665 continue; 666 if(sc1->bufq.b_actf) 667 break; 668 if(i == sc->unit) { 669 timeout((FPV)fdmotoroff, (void*)sc, FLP_MONDELAY); 670 #ifdef FLP_DEBUG 671 printf("fddone: Nothing to do\n"); 672 #endif 673 return; /* No work */ 674 } 675 } 676 fd_state = FLP_IDLE; 677 #ifdef FLP_DEBUG 678 printf("fddone: Staring job on unit %d\n", sc1->unit); 679 #endif 680 st_dmagrab(fdcint, fdstart, sc1, &lock_stat, 0); 681 } 682 683 /**************************************************************************** 684 * The following functions assume to be running as a result of a * 685 * disk-interrupt (e.q. spl = splbio). * 686 * They form the finit-state machine, the actual driver. * 687 * * 688 * fdstart()/ --> fd_xfer() -> activate hardware * 689 * fdopen() ^ * 690 * | * 691 * +-- not ready -<------------+ * 692 * | * 693 * fdmotoroff()/ --> fdcint() -> fd_xfer_ok() ---+ * 694 * h/w interrupt | * 695 * \|/ * 696 * finished ---> fdone() * 697 * * 698 ****************************************************************************/ 699 static void 700 fd_xfer(sc) 701 struct fd_softc *sc; 702 { 703 register int head = 0; 704 register int track, sector, hbit; 705 int i; 706 u_long phys_addr; 707 708 switch(fd_state) { 709 case FLP_XFER: 710 /* 711 * Calculate head/track values 712 */ 713 track = sc->sector / sc->nsectors; 714 head = track % sc->nheads; 715 track = track / sc->nheads; 716 #ifdef FLP_DEBUG 717 printf("fd_xfer: sector:%d,head:%d,track:%d\n", sc->sector,head, 718 track); 719 #endif 720 break; 721 722 case FLP_STAT: 723 /* 724 * FLP_STAT only wants to recalibrate 725 */ 726 sc->curtrk = INV_TRK; 727 break; 728 default: 729 panic("fd_xfer: wrong state (0x%x)", fd_state); 730 } 731 732 /* 733 * Determine if the controller should check spin-up. 734 */ 735 hbit = motoron ? HBIT : 0; 736 motoron = 1; 737 738 /* 739 * Select the right unit and head. 740 */ 741 i = (sc->unit ? PA_FLOP1 : PA_FLOP0) | head; 742 if(i != selected) { 743 selected = i; 744 SOUND->sd_selr = YM_IOA; 745 SOUND->sd_wdat = (SOUND->sd_rdat & 0xF8) | (i ^ 0x07); 746 } 747 748 if(sc->curtrk == INV_TRK) { 749 /* 750 * Recalibrate, since we lost track of head positioning. 751 * The floppy disk controller has no way of determining its 752 * absolute arm position (track). Instead, it steps the 753 * arm a track at a time and keeps track of where it 754 * thinks it is (in software). However, after a SEEK, the 755 * hardware reads information from the diskette telling 756 * where the arm actually is. If the arm is in the wrong place, 757 * a recalibration is done, which forces the arm to track 0. 758 * This way the controller can get back into sync with reality. 759 */ 760 write_fdreg(FDC_CS, RESTORE|VBIT|hbit); 761 fd_cmd = RESTORE; 762 timeout((FPV)fdmotoroff, (void*)sc, FLP_XFERDELAY); 763 764 #ifdef FLP_DEBUG 765 printf("fd_xfer:Recalibrating drive %d\n", sc->unit); 766 #endif 767 return; 768 } 769 770 write_fdreg(FDC_TR, sc->curtrk); 771 772 /* 773 * Issue a SEEK command on the indicated drive unless the arm is 774 * already positioned on the correct track. 775 */ 776 if(track != sc->curtrk) { 777 sc->curtrk = track; /* be optimistic */ 778 write_fdreg(FDC_DR, track); 779 write_fdreg(FDC_CS, SEEK|RATE6|VBIT|hbit); 780 timeout((FPV)fdmotoroff, (void*)sc, FLP_XFERDELAY); 781 fd_cmd = SEEK; 782 #ifdef FLP_DEBUG 783 printf("fd_xfer:Seek to track %d on drive %d\n",track,sc->unit); 784 #endif 785 return; 786 } 787 788 /* 789 * The drive is now on the proper track. Read or write 1 block. 790 */ 791 sector = sc->sector % sc->nsectors; 792 sector++; /* start numbering at 1 */ 793 794 write_fdreg(FDC_SR, sector); 795 796 phys_addr = (u_long)kvtop(sc->io_data); 797 if(phys_addr >= FDC_MAX_DMA_AD) { 798 /* 799 * We _must_ bounce this address 800 */ 801 phys_addr = (u_long)kvtop(sc->bounceb); 802 if(sc->io_dir == B_WRITE) 803 bcopy(sc->io_data, sc->bounceb, SECTOR_SIZE); 804 sc->flags |= FLPF_BOUNCE; 805 } 806 st_dmaaddr((caddr_t)phys_addr); /* DMA address setup */ 807 808 #ifdef FLP_DEBUG 809 printf("fd_xfer:Start io (io_addr:%x)\n", kvtop(sc->io_data)); 810 #endif 811 812 if(sc->io_dir == B_READ) { 813 /* Issue the command */ 814 st_dmacomm(DMA_FDC | DMA_SCREG, 1); 815 write_fdreg(FDC_CS, F_READ|hbit); 816 fd_cmd = F_READ; 817 } 818 else { 819 /* Issue the command */ 820 st_dmacomm(DMA_WRBIT | DMA_FDC | DMA_SCREG, 1); 821 write_fdreg(DMA_WRBIT | FDC_CS, F_WRITE|hbit|EBIT|PBIT); 822 fd_cmd = F_WRITE; 823 } 824 timeout((FPV)fdmotoroff, (void*)sc, FLP_XFERDELAY); 825 } 826 827 /* return values of fd_xfer_ok(): */ 828 #define X_OK 0 829 #define X_AGAIN 1 830 #define X_ERROR 2 831 #define X_FAIL 3 832 833 /* 834 * Hardware interrupt function. 835 */ 836 static void 837 fdcint(sc) 838 struct fd_softc *sc; 839 { 840 struct buf *bp; 841 842 #ifdef FLP_DEBUG 843 printf("fdcint: unit = %d\n", sc->unit); 844 #endif 845 846 /* 847 * Cancel timeout (we made it, didn't we) 848 */ 849 untimeout((FPV)fdmotoroff, (void*)sc); 850 851 switch(fd_xfer_ok(sc)) { 852 case X_ERROR : 853 if(++(sc->errcnt) < MAX_ERRORS) { 854 /* 855 * Command failed but still retries left. 856 */ 857 break; 858 } 859 /* FALL THROUGH */ 860 case X_FAIL : 861 /* 862 * Non recoverable error. Fall back to motor-on 863 * idle-state. 864 */ 865 if(fd_state == FLP_STAT) { 866 sc->flags |= FLPF_EMPTY; 867 sc->flags &= ~FLPF_GETSTAT; 868 wakeup((caddr_t)sc); 869 fddone(sc); 870 return; 871 } 872 873 bp = sc->bufq.b_actf; 874 875 bp->b_error = EIO; 876 bp->b_flags |= B_ERROR; 877 fd_state = FLP_MON; 878 if(fd_error != NULL) { 879 printf("Floppy error: %s\n", fd_error); 880 fd_error = NULL; 881 } 882 883 break; 884 case X_AGAIN: 885 /* 886 * Start next part of state machine. 887 */ 888 break; 889 case X_OK: 890 /* 891 * Command ok and finished. Reset error-counter. 892 * If there are no more bytes to transfer fall back 893 * to motor-on idle state. 894 */ 895 sc->errcnt = 0; 896 897 if(fd_state == FLP_STAT) { 898 sc->flags &= ~FLPF_GETSTAT; 899 wakeup((caddr_t)sc); 900 fddone(sc); 901 return; 902 } 903 904 if((sc->flags & FLPF_BOUNCE) && (sc->io_dir == B_READ)) 905 bcopy(sc->bounceb, sc->io_data, SECTOR_SIZE); 906 sc->flags &= ~FLPF_BOUNCE; 907 908 sc->sector++; 909 sc->io_data += SECTOR_SIZE; 910 sc->io_bytes -= SECTOR_SIZE; 911 if(sc->io_bytes <= 0) 912 fd_state = FLP_MON; 913 } 914 if(fd_state == FLP_MON) 915 fddone(sc); 916 else fd_xfer(sc); 917 } 918 919 /* 920 * Determine status of last command. Should only be called through 921 * 'fdcint()'. 922 * Returns: 923 * X_ERROR : Error on command; might succeed next time. 924 * X_FAIL : Error on command; will never succeed. 925 * X_AGAIN : Part of a command succeeded, call 'fd_xfer()' to complete. 926 * X_OK : Command succeeded and is complete. 927 * 928 * This function only affects sc->curtrk. 929 */ 930 static int 931 fd_xfer_ok(sc) 932 register struct fd_softc *sc; 933 { 934 register int status; 935 936 #ifdef FLP_DEBUG 937 printf("fd_xfer_ok: cmd: 0x%x, state: 0x%x\n", fd_cmd, fd_state); 938 #endif 939 switch(fd_cmd) { 940 case IRUPT: 941 /* 942 * Timeout. Force a recalibrate before we try again. 943 */ 944 fd_error = "Timeout"; 945 sc->curtrk = INV_TRK; 946 return(X_ERROR); 947 case F_READ: 948 /* 949 * Test for DMA error 950 */ 951 status = read_dmastat(); 952 if(!(status & DMAOK)) { 953 fd_error = "Dma error"; 954 return(X_ERROR); 955 } 956 /* 957 * Get controller status and check for errors. 958 */ 959 status = read_fdreg(FDC_CS); 960 if(status & (RNF | CRCERR | LD_T00)) { 961 fd_error = "Read error"; 962 if(status & RNF) 963 sc->curtrk = INV_TRK; 964 return(X_ERROR); 965 } 966 break; 967 case F_WRITE: 968 /* 969 * Test for DMA error 970 */ 971 status = read_dmastat(); 972 if(!(status & DMAOK)) { 973 fd_error = "Dma error"; 974 return(X_ERROR); 975 } 976 /* 977 * Get controller status and check for errors. 978 */ 979 status = read_fdreg(FDC_CS); 980 if(status & WRI_PRO) { 981 fd_error = "Write protected"; 982 return(X_FAIL); 983 } 984 if(status & (RNF | CRCERR | LD_T00)) { 985 fd_error = "Write error"; 986 sc->curtrk = INV_TRK; 987 return(X_ERROR); 988 } 989 break; 990 case SEEK: 991 status = read_fdreg(FDC_CS); 992 if(status & (RNF | CRCERR)) { 993 fd_error = "Seek error"; 994 sc->curtrk = INV_TRK; 995 return(X_ERROR); 996 } 997 return(X_AGAIN); 998 case RESTORE: 999 /* 1000 * Determine if the recalibration succeeded. 1001 */ 1002 status = read_fdreg(FDC_CS); 1003 if(status & RNF) { 1004 fd_error = "Recalibrate error"; 1005 /* reset controller */ 1006 write_fdreg(FDC_CS, IRUPT); 1007 sc->curtrk = INV_TRK; 1008 return(X_ERROR); 1009 } 1010 sc->curtrk = 0; 1011 if(fd_state == FLP_STAT) { 1012 if(status & WRI_PRO) 1013 sc->flags |= FLPF_WRTPROT; 1014 break; 1015 } 1016 return(X_AGAIN); 1017 default: 1018 fd_error = "Driver error: fd_xfer_ok : Unknown state"; 1019 return(X_FAIL); 1020 } 1021 return(X_OK); 1022 } 1023 1024 /* 1025 * All timeouts will call this function. 1026 */ 1027 static void 1028 fdmotoroff(sc) 1029 struct fd_softc *sc; 1030 { 1031 int sps, wrbit; 1032 1033 /* 1034 * Get at harware interrupt level 1035 */ 1036 sps = splbio(); 1037 1038 #if FLP_DEBUG 1039 printf("fdmotoroff, state = 0x%x\n", fd_state); 1040 #endif 1041 1042 switch(fd_state) { 1043 case FLP_STAT : 1044 case FLP_XFER : 1045 /* 1046 * Timeout during a transfer; cancel transaction 1047 * set command to 'IRUPT'. 1048 * A drive-interrupt is simulated to trigger the state 1049 * machine. 1050 */ 1051 /* 1052 * Cancel current transaction 1053 */ 1054 wrbit = (fd_cmd == F_WRITE) ? DMA_WRBIT : 0; 1055 fd_cmd = IRUPT; 1056 write_fdreg(FDC_CS, wrbit|IRUPT); 1057 1058 /* 1059 * Simulate floppy interrupt. 1060 */ 1061 fdcint(sc); 1062 return; 1063 case FLP_MON : 1064 /* 1065 * Turn motor off. 1066 */ 1067 if(selected) { 1068 SOUND->sd_selr = YM_IOA; 1069 SOUND->sd_wdat = SOUND->sd_rdat | 0x07; 1070 motoron = selected = 0; 1071 } 1072 fd_state = FLP_IDLE; 1073 break; 1074 } 1075 splx(sps); 1076 } 1077 1078 /* 1079 * min byte count to whats left of the track in question 1080 */ 1081 static int 1082 fdminphys(bp) 1083 struct buf *bp; 1084 { 1085 struct fd_softc *sc; 1086 int sec, toff, tsz; 1087 1088 if((sc = getsoftc(fdcd, DISKUNIT(bp->b_dev))) == NULL) 1089 return(ENXIO); 1090 1091 sec = bp->b_blkno % (sc->nsectors * sc->nheads); 1092 toff = sec * SECTOR_SIZE; 1093 tsz = sc->nsectors * sc->nheads * SECTOR_SIZE; 1094 1095 #ifdef FLP_DEBUG 1096 printf("fdminphys: before %d", bp->b_bcount); 1097 #endif 1098 1099 bp->b_bcount = min(bp->b_bcount, tsz - toff); 1100 1101 #ifdef FLP_DEBUG 1102 printf(" after %d\n", bp->b_bcount); 1103 #endif 1104 1105 return(bp->b_bcount); 1106 } 1107 1108 /* 1109 * Used to find out wich drives are actually connected. We do this by issueing 1110 * is 'RESTORE' command and check if the 'track-0' bit is set. This also works 1111 * if the drive is present but no floppy is inserted. 1112 */ 1113 static void 1114 fdtestdrv(fdsoftc) 1115 struct fd_softc *fdsoftc; 1116 { 1117 int i, status; 1118 1119 /* 1120 * Select the right unit and head. 1121 */ 1122 i = fdsoftc->unit ? PA_FLOP1 : PA_FLOP0; 1123 if(i != selected) { 1124 selected = i; 1125 SOUND->sd_selr = YM_IOA; 1126 SOUND->sd_wdat = (SOUND->sd_rdat & 0xF8) | (i ^ 0x07); 1127 } 1128 1129 write_fdreg(FDC_CS, RESTORE|VBIT|HBIT); 1130 1131 /* 1132 * Wait for about 2 seconds. 1133 */ 1134 delay(2000000); 1135 1136 status = read_fdreg(FDC_CS); 1137 if(status & (RNF|BUSY)) 1138 write_fdreg(FDC_CS, IRUPT); /* reset controller */ 1139 1140 if(!(status & LD_T00)) 1141 fdsoftc->flags |= FLPF_NOTRESP; 1142 } 1143 1144 /* 1145 * Build disk label. For now we only create a label from what we know 1146 * from 'sc'. 1147 */ 1148 static int 1149 fdgetdisklabel(sc, dev) 1150 struct fd_softc *sc; 1151 dev_t dev; 1152 { 1153 struct disklabel *lp, *dlp; 1154 int part; 1155 1156 /* 1157 * If we already got one, get out. 1158 */ 1159 if(sc->flags & FLPF_HAVELAB) 1160 return(0); 1161 1162 #ifdef FLP_DEBUG 1163 printf("fdgetdisklabel()\n"); 1164 #endif 1165 1166 part = DISKPART(dev); 1167 lp = &sc->dkdev.dk_label; 1168 bzero(lp, sizeof(struct disklabel)); 1169 1170 lp->d_secsize = SECTOR_SIZE; 1171 lp->d_ntracks = sc->nheads; 1172 lp->d_nsectors = sc->nsectors; 1173 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 1174 lp->d_ncylinders = sc->nblocks / lp->d_secpercyl; 1175 lp->d_secperunit = sc->nblocks; 1176 1177 lp->d_type = DTYPE_FLOPPY; 1178 lp->d_rpm = 300; /* good guess I suppose. */ 1179 lp->d_interleave = 1; /* FIXME: is this OK? */ 1180 lp->d_bbsize = 0; 1181 lp->d_sbsize = 0; 1182 lp->d_npartitions = part + 1; 1183 lp->d_trkseek = STEP_DELAY; 1184 lp->d_magic = DISKMAGIC; 1185 lp->d_magic2 = DISKMAGIC; 1186 lp->d_checksum = dkcksum(lp); 1187 lp->d_partitions[part].p_size = lp->d_secperunit; 1188 lp->d_partitions[part].p_fstype = FS_UNUSED; 1189 lp->d_partitions[part].p_fsize = 1024; 1190 lp->d_partitions[part].p_frag = 8; 1191 sc->flags |= FLPF_HAVELAB; 1192 1193 return(0); 1194 } 1195