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