1 /* $NetBSD: fd.c,v 1.3 1995/04/16 14:56:25 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_DELAY 64 /* for dma[rw]dat() */ 77 #define FDC_MAX_DMA_AD 0x1000000 /* No DMA possible beyond */ 78 79 /* Parameters for the disk drive. */ 80 #define SECTOR_SIZE 512 /* physical sector size in bytes */ 81 #define NR_DRIVES 2 /* maximum number of drives */ 82 #define NR_TYPES 3 /* number of diskette/drive combinations*/ 83 #define MAX_ERRORS 10 /* how often to try rd/wt before quitting*/ 84 #define STEP_DELAY 6000 /* 6ms (6000us) delay after stepping */ 85 86 87 #define INV_TRK 32000 /* Should fit in unsigned short */ 88 #define INV_PART NR_TYPES 89 90 /* 91 * Driver states 92 */ 93 #define FLP_IDLE 0x00 /* floppy is idle */ 94 #define FLP_MON 0x01 /* idle with motor on */ 95 #define FLP_STAT 0x02 /* determine floppy status */ 96 #define FLP_XFER 0x04 /* read/write data from floppy */ 97 98 /* 99 * Timer delay's 100 */ 101 #define FLP_MONDELAY (3 * hz) /* motor-on delay */ 102 #define FLP_XFERDELAY (2 * hz) /* timeout on transfer */ 103 104 105 #define b_block b_resid /* FIXME: this is not the place */ 106 107 /* 108 * Global data for all physical floppy devices 109 */ 110 static short selected = 0; /* drive/head currently selected*/ 111 static short motoron = 0; /* motor is spinning */ 112 static short nopens = 0; /* Number of opens executed */ 113 114 static short fd_state = FLP_IDLE;/* Current driver state */ 115 static short fd_in_dma= 0; /* 1: dmagrab() called */ 116 static short fd_cmd = 0; /* command being executed */ 117 static char *fd_error= NULL; /* error from fd_xfer_ok() */ 118 119 /* 120 * Private per device data 121 */ 122 struct fd_softc { 123 struct dkdevice dkdev; 124 struct buf bufq; /* queue of buf's */ 125 int unit; /* unit for atari controlling hw*/ 126 int nheads; /* number of heads in use */ 127 int nsectors; /* number of sectors/track */ 128 int nblocks; /* number of blocks on disk */ 129 int curtrk; /* track head positioned on */ 130 short flags; /* misc flags */ 131 short part; /* Current open partition */ 132 int sector; /* logical sector for I/O */ 133 caddr_t io_data; /* KVA for data transfer */ 134 int io_bytes; /* bytes left for I/O */ 135 int io_dir; /* B_READ/B_WRITE */ 136 int errcnt; /* current error count */ 137 u_char *bounceb; /* Bounce buffer */ 138 139 }; 140 141 /* 142 * Flags in fd_softc: 143 */ 144 #define FLPF_NOTRESP 0x01 /* Unit not responding */ 145 #define FLPF_ISOPEN 0x02 /* Unit is open */ 146 #define FLPF_ISHD 0x04 /* Use High Density */ 147 #define FLPF_HAVELAB 0x08 /* We have a valid label */ 148 #define FLPF_BOUNCE 0x10 /* Now using the bounce buffer */ 149 150 struct fd_types { 151 int nheads; /* Heads in use */ 152 int nsectors; /* sectors per track */ 153 int nblocks; /* number of blocks */ 154 } fdtypes[NR_TYPES] = { 155 { 1, 9, 720 }, /* 360 Kb */ 156 { 2, 9, 1440 }, /* 720 Kb */ 157 { 1, 18, 2880 }, /* 1.44 Mb */ 158 }; 159 160 typedef void (*FPV)(); 161 162 /* 163 * Private drive functions.... 164 */ 165 static void fdstart __P((struct fd_softc *)); 166 static void fddone __P((struct fd_softc *)); 167 static void fd_xfer __P((struct fd_softc *)); 168 static int fdcint __P((struct fd_softc *)); 169 static int fd_xfer_ok __P((struct fd_softc *)); 170 static void fdmotoroff __P((struct fd_softc *)); 171 static int fdminphys __P((struct buf *)); 172 static void fdtestdrv __P((struct fd_softc *)); 173 static int fdgetdisklabel __P((struct fd_softc *, dev_t)); 174 175 /* 176 * Autoconfig stuff.... 177 */ 178 static int fdcmatch __P((struct device *, struct cfdata *, void *)); 179 static int fdcprint __P((void *, char *)); 180 static void fdcattach __P((struct device *, struct device *, void *)); 181 182 struct cfdriver fdccd = { 183 NULL, "fdc", (cfmatch_t)fdcmatch, fdcattach, DV_DULL, 184 sizeof(struct device), NULL, 0 }; 185 186 static int 187 fdcmatch(pdp, cfp, auxp) 188 struct device *pdp; 189 struct cfdata *cfp; 190 void *auxp; 191 { 192 if(strcmp("fdc", auxp) || cfp->cf_unit != 0) 193 return(0); 194 return(1); 195 } 196 197 static void 198 fdcattach(pdp, dp, auxp) 199 struct device *pdp, *dp; 200 void *auxp; 201 { 202 struct fd_softc fdsoftc; 203 int i, nfound = 0; 204 205 printf("\n"); 206 for(i = 0; i < NR_DRIVES; i++) { 207 208 /* 209 * Test if unit is present 210 */ 211 fdsoftc.unit = i; 212 fdsoftc.flags = 0; 213 dmagrab(fdcint, fdtestdrv, &fdsoftc); 214 dmafree(); 215 216 if(!(fdsoftc.flags & FLPF_NOTRESP)) { 217 nfound++; 218 config_found(dp, (void*)i, fdcprint); 219 } 220 } 221 222 if(nfound) { 223 /* 224 * enable disk related interrupts 225 */ 226 MFP->mf_ierb |= IB_DINT; 227 MFP->mf_iprb &= ~IB_DINT; 228 MFP->mf_imrb |= IB_DINT; 229 } 230 } 231 232 static int 233 fdcprint(auxp, pnp) 234 void *auxp; 235 char *pnp; 236 { 237 return(UNCONF); 238 } 239 240 static int fdmatch __P((struct device *, struct cfdata *, void *)); 241 static void fdattach __P((struct device *, struct device *, void *)); 242 void fdstrategy __P((struct buf *)); 243 struct dkdriver fddkdriver = { fdstrategy }; 244 245 struct cfdriver fdcd = { 246 NULL, "fd", (cfmatch_t)fdmatch, fdattach, DV_DISK, 247 sizeof(struct fd_softc), NULL, 0 }; 248 249 static int 250 fdmatch(pdp, cfp, auxp) 251 struct device *pdp; 252 struct cfdata *cfp; 253 void *auxp; 254 { 255 int unit = (int)auxp; 256 return(1); 257 } 258 259 static void 260 fdattach(pdp, dp, auxp) 261 struct device *pdp, *dp; 262 void *auxp; 263 { 264 struct fd_softc *sc; 265 266 sc = (struct fd_softc *)dp; 267 268 printf("\n"); 269 270 sc->dkdev.dk_driver = &fddkdriver; 271 } 272 273 fdioctl(dev, cmd, addr, flag, p) 274 dev_t dev; 275 u_long cmd; 276 int flag; 277 caddr_t addr; 278 struct proc *p; 279 { 280 struct fd_softc *sc; 281 void *data; 282 283 sc = getsoftc(fdcd, DISKUNIT(dev)); 284 285 if((sc->flags & FLPF_HAVELAB) == 0) 286 return(EBADF); 287 288 switch(cmd) { 289 case DIOCSBAD: 290 return(EINVAL); 291 case DIOCGDINFO: 292 *(struct disklabel *)addr = sc->dkdev.dk_label; 293 return(0); 294 case DIOCGPART: 295 ((struct partinfo *)addr)->disklab = 296 &sc->dkdev.dk_label; 297 ((struct partinfo *)addr)->part = 298 &sc->dkdev.dk_label.d_partitions[DISKPART(dev)]; 299 return(0); 300 #ifdef notyet /* XXX LWP */ 301 case DIOCSRETRIES: 302 case DIOCSSTEP: 303 case DIOCSDINFO: 304 case DIOCWDINFO: 305 case DIOCWLABEL: 306 #endif /* notyet */ 307 default: 308 return(ENOTTY); 309 } 310 } 311 312 /* 313 * Open the device. If this is the first open on both the floppy devices, 314 * intialize the controller. 315 * Note that partition info on the floppy device is used to distinguise 316 * between 780Kb and 360Kb floppy's. 317 * partition 0: 360Kb 318 * partition 1: 780Kb 319 */ 320 Fdopen(dev, flags, devtype, proc) 321 dev_t dev; 322 int flags, devtype; 323 struct proc *proc; 324 { 325 struct fd_softc *sc; 326 int sps; 327 328 #ifdef FLP_DEBUG 329 printf("Fdopen dev=0x%x\n", dev); 330 #endif 331 332 if(DISKPART(dev) >= NR_TYPES) 333 return(ENXIO); 334 335 if((sc = getsoftc(fdcd, DISKUNIT(dev))) == NULL) 336 return(ENXIO); 337 338 /* 339 * If no floppy currently open, reset the controller and select 340 * floppy type. 341 */ 342 if(!nopens) { 343 344 #ifdef FLP_DEBUG 345 printf("Fdopen device not yet open\n"); 346 #endif 347 nopens++; 348 dmawdat(FDC_CS, IRUPT, FDC_DELAY); 349 } 350 351 if(!(sc->flags & FLPF_ISOPEN)) { 352 /* 353 * Initialise some driver values. 354 */ 355 int part = DISKPART(dev); 356 void *addr; 357 358 sc->bufq.b_actf = NULL; 359 sc->unit = DISKUNIT(dev); 360 sc->part = part; 361 sc->nheads = fdtypes[part].nheads; 362 sc->nsectors = fdtypes[part].nsectors; 363 sc->nblocks = fdtypes[part].nblocks; 364 sc->curtrk = INV_TRK; 365 sc->sector = 0; 366 sc->errcnt = 0; 367 sc->bounceb = (u_char*)alloc_stmem(SECTOR_SIZE, &addr); 368 if(sc->bounceb == NULL) 369 return(ENOMEM); /* XXX */ 370 if(sc->nsectors > 9) /* XXX */ 371 sc->flags |= FLPF_ISHD; 372 373 sc->flags = FLPF_ISOPEN; 374 } 375 else { 376 /* 377 * Multiply opens are granted when accessing the same type of 378 * floppy (eq. the same partition). 379 */ 380 if(sc->part != DISKPART(dev)) 381 return(ENXIO); /* XXX temporarely out of business */ 382 } 383 fdgetdisklabel(sc, dev); 384 #ifdef FLP_DEBUG 385 printf("Fdopen open succeeded on type %d\n", sc->part); 386 #endif 387 } 388 389 fdclose(dev, flags, devtype, proc) 390 dev_t dev; 391 int flags, devtype; 392 struct proc *proc; 393 { 394 struct fd_softc *sc; 395 396 sc = getsoftc(fdcd, DISKUNIT(dev)); 397 free_stmem(sc->bounceb); 398 sc->flags = 0; 399 nopens--; 400 401 #ifdef FLP_DEBUG 402 printf("Closed floppy device -- nopens: %d\n", nopens); 403 #endif 404 } 405 406 void 407 fdstrategy(bp) 408 struct buf *bp; 409 { 410 struct fd_softc *sc; 411 int sps, nblocks; 412 413 sc = getsoftc(fdcd, DISKUNIT(bp->b_dev)); 414 415 #ifdef FLP_DEBUG 416 printf("fdstrategy: 0x%x\n", bp); 417 #endif 418 419 /* 420 * check for valid partition and bounds 421 */ 422 nblocks = (bp->b_bcount + SECTOR_SIZE - 1) / SECTOR_SIZE; 423 if((bp->b_blkno < 0) || ((bp->b_blkno + nblocks) >= sc->nblocks)) { 424 if((bp->b_blkno == sc->nblocks) && (bp->b_flags & B_READ)) { 425 /* 426 * Read 1 block beyond, return EOF 427 */ 428 bp->b_resid = bp->b_bcount; 429 goto done; 430 } 431 /* 432 * Try to limit the size of the transaction, adjust count 433 * if we succeed. 434 */ 435 nblocks = sc->nblocks - bp->b_blkno; 436 if((nblocks <= 0) || (bp->b_blkno < 0)) { 437 bp->b_error = EINVAL; 438 bp->b_flags |= B_ERROR; 439 goto done; 440 } 441 bp->b_bcount = nblocks * SECTOR_SIZE; 442 } 443 if(bp->b_bcount == 0) 444 goto done; 445 446 /* 447 * Set order info for disksort 448 */ 449 bp->b_block = bp->b_blkno / (sc->nsectors * sc->nheads); 450 451 /* 452 * queue the buf and kick the low level code 453 */ 454 sps = splbio(); 455 disksort(&sc->bufq, bp); 456 if(!fd_in_dma) { 457 if(fd_state & FLP_MON) 458 untimeout((FPV)fdmotoroff, (void*)sc); 459 fd_state = FLP_IDLE; 460 fd_in_dma = 1; dmagrab(fdcint, fdstart, sc); 461 } 462 splx(sps); 463 464 return; 465 done: 466 bp->b_resid = bp->b_bcount; 467 biodone(bp); 468 } 469 470 /* 471 * no dumps to floppy disks thank you. 472 */ 473 int 474 fddump(dev_t dev) 475 { 476 return(ENXIO); 477 } 478 479 /* 480 * no dumps to floppy disks thank you. 481 */ 482 int 483 fdsize(dev) 484 dev_t dev; 485 { 486 return(-1); 487 } 488 489 int 490 fdread(dev, uio) 491 dev_t dev; 492 struct uio *uio; 493 { 494 return(physio(cdevsw[major(dev)].d_strategy, (struct buf *)NULL, 495 dev, B_READ, fdminphys, uio)); 496 } 497 498 int 499 fdwrite(dev, uio) 500 dev_t dev; 501 struct uio *uio; 502 { 503 return(physio(cdevsw[major(dev)].d_strategy, (struct buf *)NULL, 504 dev, B_WRITE, fdminphys, uio)); 505 } 506 507 /* 508 * Called through the dma-dispatcher. So we know we are the only ones 509 * messing with the floppy-controler. 510 * Initialize some fields in the fdsoftc for the state-machine and get 511 * it going. 512 */ 513 static void 514 fdstart(sc) 515 struct fd_softc *sc; 516 { 517 struct buf *bp; 518 519 bp = sc->bufq.b_actf; 520 sc->sector = bp->b_blkno; /* Start sector for I/O */ 521 sc->io_data = bp->b_data; /* KVA base for I/O */ 522 sc->io_bytes = bp->b_bcount; /* Transfer size in bytes */ 523 sc->io_dir = bp->b_flags & B_READ;/* Direction of transfer */ 524 sc->errcnt = 0; /* No errors yet */ 525 fd_state = FLP_XFER; /* Yes, we're going to transfer */ 526 527 /* 528 * Make sure the floppy controller is the correct density mode 529 */ 530 if(sc->flags & FLPF_ISHD) 531 DMA->dma_drvmode |= (FDC_HDSET|FDC_HDSIG); 532 else DMA->dma_drvmode &= ~(FDC_HDSET|FDC_HDSIG); 533 fd_xfer(sc); 534 } 535 536 /* 537 * The current transaction is finished (for good or bad). Let go of 538 * the the dma-resources. Call biodone() to finish the transaction. 539 * Find a new transaction to work on. 540 */ 541 static void 542 fddone(sc) 543 register struct fd_softc *sc; 544 { 545 struct buf *bp, *dp; 546 struct fd_softc *sc1; 547 int i; 548 549 /* 550 * Lower clock frequency of FDC (better for some old ones). 551 */ 552 DMA->dma_drvmode &= ~(FDC_HDSET|FDC_HDSIG); 553 554 dp = &sc->bufq; 555 bp = dp->b_actf; 556 if(bp == NULL) 557 panic("fddone"); 558 dp->b_actf = bp->b_actf; 559 560 #ifdef FLP_DEBUG 561 printf("fddone: unit: %d, buf: %x, resid: %d\n",sc->unit,bp, 562 sc->io_bytes); 563 #endif 564 /* 565 * Give others a chance to use the dma. 566 */ 567 fd_in_dma = 0; dmafree(); 568 569 /* 570 * Finish current transaction. 571 */ 572 bp->b_resid = sc->io_bytes; 573 biodone(bp); 574 575 if(fd_in_dma) 576 return; /* XXX Is this possible? */ 577 578 /* 579 * Find a new transaction on round-robin basis. 580 */ 581 for(i = sc->unit + 1; ;i++) { 582 if(i >= fdcd.cd_ndevs) 583 i = 0; 584 if((sc1 = fdcd.cd_devs[i]) == NULL) 585 continue; 586 if(sc1->bufq.b_actf) 587 break; 588 if(i == sc->unit) { 589 timeout((FPV)fdmotoroff, (void*)sc, FLP_MONDELAY); 590 #ifdef FLP_DEBUG 591 printf("fddone: Nothing to do\n"); 592 #endif 593 return; /* No work */ 594 } 595 } 596 fd_state = FLP_IDLE; 597 #ifdef FLP_DEBUG 598 printf("fddone: Staring job on unit %d\n", sc1->unit); 599 #endif 600 fd_in_dma = 1; dmagrab(fdcint, fdstart, sc1); 601 } 602 603 /**************************************************************************** 604 * The following functions assume to be running as a result of a * 605 * disk-interrupt (e.q. spl = splbio). * 606 * They form the finit-state machine, the actual driver. * 607 * * 608 * fdstart()/ --> fd_xfer() -> activate hardware * 609 * fdopen() ^ * 610 * | * 611 * +-- not ready -<------------+ * 612 * | * 613 * fdmotoroff()/ --> fdcint() -> fd_xfer_ok() ---+ * 614 * h/w interrupt | * 615 * \|/ * 616 * finished ---> fdone() * 617 * * 618 ****************************************************************************/ 619 static void 620 fd_xfer(sc) 621 struct fd_softc *sc; 622 { 623 register int head = 0; 624 register int track, sector, hbit; 625 int i; 626 u_long phys_addr; 627 628 if(fd_state != FLP_XFER) 629 panic("fd_xfer: wrong state (0x%x)", fd_state); 630 631 /* 632 * Calculate head/track values 633 */ 634 track = sc->sector / sc->nsectors; 635 head = track % sc->nheads; 636 track = track / sc->nheads; 637 #ifdef FLP_DEBUG 638 printf("fd_xfer: sector:%d,head:%d,track:%d\n", sc->sector,head,track); 639 #endif 640 641 /* 642 * Determine if the controller should check spin-up. 643 */ 644 hbit = motoron ? HBIT : 0; 645 motoron = 1; 646 647 /* 648 * Select the right unit and head. 649 */ 650 i = (sc->unit ? PA_FLOP1 : PA_FLOP0) | head; 651 if(i != selected) { 652 selected = i; 653 SOUND->sd_selr = YM_IOA; 654 SOUND->sd_wdat = (SOUND->sd_rdat & 0xF8) | (i ^ 0x07); 655 } 656 657 if(sc->curtrk == INV_TRK) { 658 /* 659 * Recalibrate, since we lost track of head positioning. 660 * The floppy disk controller has no way of determining its 661 * absolute arm position (track). Instead, it steps the 662 * arm a track at a time and keeps track of where it 663 * thinks it is (in software). However, after a SEEK, the 664 * hardware reads information from the diskette telling 665 * where the arm actually is. If the arm is in the wrong place, 666 * a recalibration is done, which forces the arm to track 0. 667 * This way the controller can get back into sync with reality. 668 */ 669 dmawdat(FDC_CS, RESTORE|VBIT|hbit, FDC_DELAY); 670 fd_cmd = RESTORE; 671 timeout((FPV)fdmotoroff, (void*)sc, FLP_XFERDELAY); 672 673 #ifdef FLP_DEBUG 674 printf("fd_xfer:Recalibrating drive %d\n", sc->unit); 675 #endif 676 return; 677 } 678 679 dmawdat(FDC_TR, sc->curtrk, FDC_DELAY); 680 681 /* 682 * Issue a SEEK command on the indicated drive unless the arm is 683 * already positioned on the correct track. 684 */ 685 if(track != sc->curtrk) { 686 sc->curtrk = track; /* be optimistic */ 687 dmawdat(FDC_DR, track, FDC_DELAY); 688 dmawdat(FDC_CS, SEEK|RATE6|VBIT|hbit, FDC_DELAY); 689 timeout((FPV)fdmotoroff, (void*)sc, FLP_XFERDELAY); 690 fd_cmd = SEEK; 691 #ifdef FLP_DEBUG 692 printf("fd_xfer:Seek to track %d on drive %d\n",track,sc->unit); 693 #endif 694 return; 695 } 696 697 /* 698 * The drive is now on the proper track. Read or write 1 block. 699 */ 700 sector = sc->sector % sc->nsectors; 701 sector++; /* start numbering at 1 */ 702 703 dmawdat(FDC_SR, sector, FDC_DELAY); 704 705 phys_addr = (u_long)kvtop(sc->io_data); 706 if(phys_addr >= FDC_MAX_DMA_AD) { 707 /* 708 * We _must_ bounce this address 709 */ 710 phys_addr = (u_long)kvtop(sc->bounceb); 711 if(sc->io_dir == B_WRITE) 712 bcopy(sc->io_data, sc->bounceb, SECTOR_SIZE); 713 sc->flags |= FLPF_BOUNCE; 714 } 715 dmaaddr(phys_addr); /* DMA address setup */ 716 717 #ifdef FLP_DEBUG 718 printf("fd_xfer:Start io (io_addr:%x)\n", kvtop(sc->io_data)); 719 #endif 720 721 if(sc->io_dir == B_READ) { 722 /* Issue the command */ 723 dmacomm(FDC | SCREG, 1, 0); 724 dmawdat(FDC_CS, F_READ|hbit, FDC_DELAY); 725 fd_cmd = F_READ; 726 } 727 else { 728 /* Issue the command */ 729 dmacomm(WRBIT | FDC | SCREG, 1, FDC_DELAY); 730 dmawdat(WRBIT | FDC_CS, F_WRITE|hbit|EBIT|PBIT, FDC_DELAY); 731 fd_cmd = F_WRITE; 732 } 733 timeout((FPV)fdmotoroff, (void*)sc, FLP_XFERDELAY); 734 } 735 736 /* return values of fd_xfer_ok(): */ 737 #define X_OK 0 738 #define X_AGAIN 1 739 #define X_ERROR 2 740 #define X_FAIL 3 741 742 /* 743 * Hardware interrupt function. 744 */ 745 static int 746 fdcint(sc) 747 struct fd_softc *sc; 748 { 749 struct buf *bp; 750 751 #ifdef FLP_DEBUG 752 printf("fdcint: unit = %d\n", sc->unit); 753 #endif 754 755 /* 756 * Cancel timeout (we made it, didn't we) 757 */ 758 untimeout((FPV)fdmotoroff, (void*)sc); 759 760 switch(fd_xfer_ok(sc)) { 761 case X_ERROR : 762 if(++(sc->errcnt) < MAX_ERRORS) { 763 /* 764 * Command failed but still retries left. 765 */ 766 break; 767 } 768 /* FALL THROUGH */ 769 case X_FAIL : 770 /* 771 * Non recoverable error. Fall back to motor-on 772 * idle-state. 773 */ 774 bp = sc->bufq.b_actf; 775 776 bp->b_error = EIO; 777 bp->b_flags |= B_ERROR; 778 fd_state = FLP_MON; 779 if(fd_error != NULL) { 780 printf("Floppy error: %s\n", fd_error); 781 fd_error = NULL; 782 } 783 784 break; 785 case X_AGAIN: 786 /* 787 * Start next part of state machine. 788 */ 789 break; 790 case X_OK: 791 /* 792 * Command ok and finished. Reset error-counter. 793 * If there are no more bytes to transfer fall back 794 * to motor-on idle state. 795 */ 796 sc->errcnt = 0; 797 if((sc->flags & FLPF_BOUNCE) && (sc->io_dir == B_READ)) 798 bcopy(sc->bounceb, sc->io_data, SECTOR_SIZE); 799 sc->flags &= ~FLPF_BOUNCE; 800 801 sc->sector++; 802 sc->io_data += SECTOR_SIZE; 803 sc->io_bytes -= SECTOR_SIZE; 804 if(sc->io_bytes <= 0) 805 fd_state = FLP_MON; 806 } 807 if(fd_state == FLP_MON) 808 fddone(sc); 809 else fd_xfer(sc); 810 } 811 812 /* 813 * Determine status of last command. Should only be called through 814 * 'fdcint()'. 815 * Returns: 816 * X_ERROR : Error on command; might succeed next time. 817 * X_FAIL : Error on command; will never succeed. 818 * X_AGAIN : Part of a command succeeded, call 'fd_xfer()' to complete. 819 * X_OK : Command succeeded and is complete. 820 * 821 * This function only affects sc->curtrk. 822 */ 823 static int 824 fd_xfer_ok(sc) 825 register struct fd_softc *sc; 826 { 827 register int status; 828 829 switch(fd_cmd) { 830 case IRUPT: 831 /* 832 * Timeout. Force a recalibrate before we try again. 833 */ 834 fd_error = "Timeout"; 835 sc->curtrk = INV_TRK; 836 return(X_ERROR); 837 case F_READ: 838 /* 839 * Test for DMA error 840 */ 841 status = dmastat(FDC_CS | SCREG, 0); 842 if(!(status & DMAOK)) { 843 fd_error = "Dma error"; 844 return(X_ERROR); 845 } 846 /* 847 * Get controller status and check for errors. 848 */ 849 status = dmardat(FDC_CS, FDC_DELAY); 850 if(status & (RNF | CRCERR | LD_T00)) { 851 fd_error = "Read error"; 852 if(status & RNF) 853 sc->curtrk = INV_TRK; 854 return(X_ERROR); 855 } 856 break; 857 case F_WRITE: 858 /* 859 * Get controller status and check for errors. 860 */ 861 status = dmardat(WRBIT | FDC_CS, FDC_DELAY); 862 if(status & WRI_PRO) { 863 fd_error = "Write protected"; 864 return(X_FAIL); 865 } 866 if(status & (RNF | CRCERR | LD_T00)) { 867 fd_error = "Write error"; 868 sc->curtrk = INV_TRK; 869 return(X_ERROR); 870 } 871 break; 872 case SEEK: 873 status = dmardat(FDC_CS, FDC_DELAY); 874 if(status & (RNF | CRCERR)) { 875 fd_error = "Seek error"; 876 sc->curtrk = INV_TRK; 877 return(X_ERROR); 878 } 879 return(X_AGAIN); 880 case RESTORE: 881 /* 882 * Determine if the recalibration succeeded. 883 */ 884 status = dmardat(FDC_CS, FDC_DELAY); 885 if(status & RNF) { 886 fd_error = "Recalibrate error"; 887 /* reset controller */ 888 dmawdat(FDC_CS, IRUPT, FDC_DELAY); 889 sc->curtrk = INV_TRK; 890 return(X_ERROR); 891 } 892 sc->curtrk = 0; 893 return(X_AGAIN); 894 default: 895 fd_error = "Driver error: fd_xfer_ok : Unknown state"; 896 return(X_FAIL); 897 } 898 return(X_OK); 899 } 900 901 /* 902 * All timeouts will call this function. 903 */ 904 static void 905 fdmotoroff(sc) 906 struct fd_softc *sc; 907 { 908 int sps, wrbit; 909 910 /* 911 * Get at harware interrupt level 912 */ 913 sps = splbio(); 914 915 #if FLP_DEBUG 916 printf("fdmotoroff, state = 0x%x\n", fd_state); 917 #endif 918 919 switch(fd_state) { 920 case FLP_XFER : 921 /* 922 * Timeout during a transfer; cancel transaction 923 * set command to 'IRUPT'. 924 * A drive-interrupt is simulated to trigger the state 925 * machine. 926 */ 927 /* 928 * Cancel current transaction 929 */ 930 wrbit = (fd_cmd == F_WRITE) ? WRBIT : 0; 931 fd_cmd = IRUPT; 932 dmawdat(FDC_CS, wrbit|IRUPT, FDC_DELAY); 933 934 /* 935 * Simulate floppy interrupt. 936 */ 937 fdcint(sc); 938 return; 939 case FLP_MON : 940 /* 941 * Turn motor off. 942 */ 943 if(selected) { 944 SOUND->sd_selr = YM_IOA; 945 SOUND->sd_wdat = SOUND->sd_rdat | 0x07; 946 motoron = selected = 0; 947 } 948 fd_state = FLP_IDLE; 949 break; 950 } 951 splx(sps); 952 } 953 954 /* 955 * min byte count to whats left of the track in question 956 */ 957 static int 958 fdminphys(bp) 959 struct buf *bp; 960 { 961 struct fd_softc *sc; 962 int sec, toff, tsz; 963 964 if((sc = getsoftc(fdcd, DISKUNIT(bp->b_dev))) == NULL) 965 return(ENXIO); 966 967 sec = bp->b_blkno % (sc->nsectors * sc->nheads); 968 toff = sec * SECTOR_SIZE; 969 tsz = sc->nsectors * sc->nheads * SECTOR_SIZE; 970 971 #ifdef FLP_DEBUG 972 printf("fdminphys: before %d", bp->b_bcount); 973 #endif 974 975 bp->b_bcount = min(bp->b_bcount, tsz - toff); 976 977 #ifdef FLP_DEBUG 978 printf(" after %d\n", bp->b_bcount); 979 #endif 980 981 return(bp->b_bcount); 982 } 983 984 /* 985 * Used to find out wich drives are actually connected. We do this by issueing 986 * is 'RESTORE' command and check if the 'track-0' bit is set. This also works 987 * if the drive is present but no floppy is inserted. 988 */ 989 static void 990 fdtestdrv(fdsoftc) 991 struct fd_softc *fdsoftc; 992 { 993 int i, status; 994 995 /* 996 * Select the right unit and head. 997 */ 998 i = fdsoftc->unit ? PA_FLOP1 : PA_FLOP0; 999 if(i != selected) { 1000 selected = i; 1001 SOUND->sd_selr = YM_IOA; 1002 SOUND->sd_wdat = (SOUND->sd_rdat & 0xF8) | (i ^ 0x07); 1003 } 1004 1005 dmawdat(FDC_CS, RESTORE|VBIT|HBIT, FDC_DELAY); 1006 1007 /* 1008 * Wait for about 2 seconds. 1009 */ 1010 delay(2000000); 1011 1012 status = dmardat(FDC_CS, FDC_DELAY); 1013 if(status & (RNF|BUSY)) 1014 dmawdat(FDC_CS, IRUPT, FDC_DELAY); /* reset controller */ 1015 1016 if(!(status & LD_T00)) 1017 fdsoftc->flags |= FLPF_NOTRESP; 1018 } 1019 1020 /* 1021 * Build disk label. For now we only create a label from what we know 1022 * from 'sc'. 1023 */ 1024 static int 1025 fdgetdisklabel(sc, dev) 1026 struct fd_softc *sc; 1027 dev_t dev; 1028 { 1029 struct disklabel *lp, *dlp; 1030 int part; 1031 1032 /* 1033 * If we already got one, get out. 1034 */ 1035 if(sc->flags & FLPF_HAVELAB) 1036 return(0); 1037 1038 #ifdef FLP_DEBUG 1039 printf("fdgetdisklabel()\n"); 1040 #endif 1041 1042 part = DISKPART(dev); 1043 lp = &sc->dkdev.dk_label; 1044 bzero(lp, sizeof(struct disklabel)); 1045 1046 lp->d_secsize = SECTOR_SIZE; 1047 lp->d_ntracks = sc->nheads; 1048 lp->d_nsectors = sc->nsectors; 1049 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 1050 lp->d_ncylinders = sc->nblocks / lp->d_secpercyl; 1051 lp->d_secperunit = sc->nblocks; 1052 1053 lp->d_type = DTYPE_FLOPPY; 1054 lp->d_rpm = 300; /* good guess I suppose. */ 1055 lp->d_interleave = 1; /* FIXME: is this OK? */ 1056 lp->d_bbsize = 0; 1057 lp->d_sbsize = 0; 1058 lp->d_npartitions = part + 1; 1059 lp->d_trkseek = STEP_DELAY; 1060 lp->d_magic = DISKMAGIC; 1061 lp->d_magic2 = DISKMAGIC; 1062 lp->d_checksum = dkcksum(lp); 1063 lp->d_partitions[part].p_size = lp->d_secperunit; 1064 lp->d_partitions[part].p_fstype = FS_UNUSED; 1065 lp->d_partitions[part].p_fsize = 1024; 1066 lp->d_partitions[part].p_frag = 8; 1067 sc->flags |= FLPF_HAVELAB; 1068 1069 return(0); 1070 } 1071