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