1 /* 2 * Copyright (c) 1994 Christian E. Hopps 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by Christian E. Hopps. 16 * 4. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 * 30 * $Id: fd.c,v 1.11 1994/07/18 01:37:48 chopps Exp $ 31 */ 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/kernel.h> 35 #include <sys/malloc.h> 36 #include <sys/buf.h> 37 #include <sys/device.h> 38 #include <sys/ioctl.h> 39 #include <sys/fcntl.h> 40 #include <sys/conf.h> 41 #include <sys/disklabel.h> 42 #include <sys/disk.h> 43 #include <sys/dkbad.h> 44 #include <amiga/amiga/device.h> 45 #include <amiga/amiga/custom.h> 46 #include <amiga/amiga/cia.h> 47 #include <amiga/amiga/cc.h> 48 49 enum fdc_bits { FDB_CHANGED = 2, FDB_PROTECT, FDB_CYLZERO, FDB_READY }; 50 /* 51 * partitions in fd represent different format floppies 52 * partition a is 0 etc.. 53 */ 54 enum fd_parttypes { 55 FDAMIGAPART = 0, 56 #ifdef not_yet 57 FDMSDOSPART, 58 #endif 59 FDMAXPARTS 60 }; 61 62 #define FDBBSIZE (8192) 63 #define FDSBSIZE (8192) 64 65 #define b_cylin b_resid 66 #define FDUNIT(dev) DISKUNIT(dev) 67 #define FDPART(dev) DISKPART(dev) 68 #define FDMAKEDEV(m, u, p) MAKEDISKDEV((m), (u), (p)) 69 70 #define FDNHEADS (2) /* amiga drives always have 2 heads */ 71 #define FDSECSIZE (512) /* amiga drives always have 512 byte sectors */ 72 #define FDSECLWORDS (128) 73 74 #define FDSETTLEDELAY (18000) /* usec delay after seeking after switch dir */ 75 #define FDSTEPDELAY (3500) /* usec delay after steping */ 76 #define FDPRESIDEDELAY (1000) /* usec delay before writing can occur */ 77 #define FDWRITEDELAY (1300) /* usec delay after write */ 78 79 #define FDSTEPOUT (1) /* decrease track step */ 80 #define FDSTEPIN (0) /* increase track step */ 81 82 #define FDCUNITMASK (0x78) /* mask for all units (bits 6-3) */ 83 84 #define FDRETRIES (2) /* default number of retries */ 85 #define FDMAXUNITS (4) /* maximum number of supported units */ 86 87 #define DISKLEN_READ (0) /* fake mask for reading */ 88 #define DISKLEN_WRITE (1 << 14) /* bit for writing */ 89 #define DISKLEN_DMAEN (1 << 15) /* dma go */ 90 #define DMABUFSZ ((DISKLEN_WRITE - 1) * 2) /* largest dma possible */ 91 92 #define FDMFMSYNC (0x4489) 93 94 /* 95 * floppy device type 96 */ 97 struct fdtype { 98 u_int driveid; /* drive identification (from drive) */ 99 u_int ncylinders; /* number of cylinders on drive */ 100 u_int amiga_nsectors; /* number of sectors per amiga track */ 101 u_int msdos_nsectors; /* number of sectors per msdos track */ 102 u_int nreadw; /* number of words (short) read per track */ 103 u_int nwritew; /* number of words (short) written per track */ 104 u_int gap; /* track gap size in long words */ 105 u_int precomp[2]; /* 1st and 2nd precomp values */ 106 char *desc; /* description of drive type (useq) */ 107 }; 108 109 /* 110 * floppy disk device data 111 */ 112 struct fd_softc { 113 struct dkdevice dkdev; 114 struct buf bufq; /* queue of buf's */ 115 struct fdtype *type; 116 void *cachep; /* cached track data (write through) */ 117 int cachetrk; /* cahced track -1 for none */ 118 int hwunit; /* unit for amiga controlling hw */ 119 int unitmask; /* mask for cia select deslect */ 120 int pstepdir; /* previous step direction */ 121 int curcyl; /* current curcyl head positioned on */ 122 int flags; /* misc flags */ 123 int wlabel; 124 int stepdelay; /* useq to delay after seek user setable */ 125 int nsectors; /* number of sectors per track */ 126 int openpart; /* which partition [ab] == [12] is open */ 127 short retries; /* number of times to retry failed io */ 128 short retried; /* number of times current io retried */ 129 }; 130 131 /* fd_softc->flags */ 132 #define FDF_MOTORON (0x01) /* motor is running */ 133 #define FDF_MOTOROFF (0x02) /* motor is waiting to be turned off */ 134 #define FDF_WMOTOROFF (0x04) /* unit wants a wakeup after off */ 135 #define FDF_DIRTY (0x08) /* track cache needs write */ 136 #define FDF_WRITEWAIT (0x10) /* need to head select delay on next setpos */ 137 #define FDF_HAVELABEL (0x20) /* label is valid */ 138 #define FDF_JUSTFLUSH (0x40) /* don't bother caching track. */ 139 #define FDF_NOTRACK0 (0x80) /* was not able to recalibrate drive */ 140 141 int fdc_wantwakeup; 142 int fdc_side; 143 void *fdc_dmap; 144 struct fd_softc *fdc_indma; 145 146 struct fdcargs { 147 struct fdtype *type; 148 int unit; 149 }; 150 151 int fdmatch __P((struct device *, struct cfdata *, void *)); 152 int fdcmatch __P((struct device *, struct cfdata *, void *)); 153 int fdcprint __P((void *, char *)); 154 void fdcattach __P((struct device *, struct device *, void *)); 155 void fdattach __P((struct device *, struct device *, void *)); 156 157 void fdstart __P((struct fd_softc *)); 158 void fddone __P((struct fd_softc *)); 159 void fdfindwork __P((int)); 160 void fddmastart __P((struct fd_softc *, int)); 161 void fddmadone __P((struct fd_softc *, int)); 162 void fdsetpos __P((struct fd_softc *, int, int)); 163 void fdmotoroff __P((void *)); 164 void fdmotorwait __P((void *)); 165 int fdminphys __P((struct buf *)); 166 void fdcachetoraw __P((struct fd_softc *)); 167 int fdrawtocache __P((struct fd_softc *)); 168 int fdloaddisk __P((struct fd_softc *)); 169 u_long *mfmblkencode __P((u_long *, u_long *, u_long *, int)); 170 u_long *mfmblkdecode __P((u_long *, u_long *, u_long *, int)); 171 struct fdtype * fdcgetfdtype __P((int)); 172 173 void fdstrategy __P((struct buf *)); 174 175 struct dkdriver fddkdriver = { fdstrategy }; 176 177 /* 178 * read size is (nsectors + 1) * mfm secsize + gap bytes + 2 shorts 179 * write size is nsectors * mfm secsize + gap bytes + 3 shorts 180 * the extra shorts are to deal with a dma hw bug in the controller 181 * they are probably too much (I belive the bug is 1 short on write and 182 * 3 bits on read) but there is no need to be cheap here. 183 */ 184 #define MAXTRKSZ (22 * FDSECSIZE) 185 struct fdtype fdtype[] = { 186 { 0x00000000, 80, 11, 9, 7358, 6815, 414, { 80, 161 }, "3.5dd" }, 187 { 0x55555555, 40, 11, 9, 7358, 6815, 414, { 80, 161 }, "5.25dd" }, 188 { 0xAAAAAAAA, 80, 22, 18, 14716, 13630, 828, { 80, 161 }, "3.5hd" } 189 }; 190 int nfdtype = sizeof(fdtype) / sizeof(*fdtype); 191 192 struct cfdriver fdcd = { 193 NULL, "fd", fdmatch, fdattach, DV_DISK, 194 sizeof(struct fd_softc), NULL, 0 }; 195 196 struct cfdriver fdccd = { 197 NULL, "fdc", fdcmatch, fdcattach, DV_DULL, 198 sizeof(struct device), NULL, 0 }; 199 200 /* 201 * all hw access through macros, this helps to hide the active low 202 * properties 203 */ 204 205 #define FDUNITMASK(unit) (1 << (3 + (unit))) 206 207 /* 208 * select units using mask 209 */ 210 #define FDSELECT(um) do { ciab.prb &= ~(um); } while (0) 211 212 /* 213 * deselect units using mask 214 */ 215 #define FDDESELECT(um) do { ciab.prb |= (um); delay(1); } while (0) 216 217 /* 218 * test hw condition bits 219 */ 220 #define FDTESTC(bit) ((ciaa.pra & (1 << (bit))) == 0) 221 222 /* 223 * set motor for select units, true motor on else off 224 */ 225 #define FDSETMOTOR(on) do { \ 226 if (on) ciab.prb &= ~CIAB_PRB_MTR; else ciab.prb |= CIAB_PRB_MTR; \ 227 } while (0) 228 229 /* 230 * set head for select units 231 */ 232 #define FDSETHEAD(head) do { \ 233 if (head) ciab.prb &= ~CIAB_PRB_SIDE; else ciab.prb |= CIAB_PRB_SIDE; \ 234 delay(1); } while (0) 235 236 /* 237 * select direction, true towards spindle else outwards 238 */ 239 #define FDSETDIR(in) do { \ 240 if (in) ciab.prb &= ~CIAB_PRB_DIR; else ciab.prb |= CIAB_PRB_DIR; \ 241 delay(1); } while (0) 242 243 /* 244 * step the selected units 245 */ 246 #define FDSTEP do { \ 247 ciab.prb &= ~CIAB_PRB_STEP; ciab.prb |= CIAB_PRB_STEP; \ 248 } while (0) 249 250 #define FDDMASTART(len, towrite) do { \ 251 int dmasz = (len) | ((towrite) ? DISKLEN_WRITE : 0) | DISKLEN_DMAEN; \ 252 custom.dsklen = dmasz; custom.dsklen = dmasz; } while (0) 253 254 #define FDDMASTOP do { custom.dsklen = 0; } while (0) 255 256 257 int 258 fdcmatch(pdp, cfp, auxp) 259 struct device *pdp; 260 struct cfdata *cfp; 261 void *auxp; 262 { 263 if (matchname("fdc", auxp) == 0 || cfp->cf_unit != 0) 264 return(0); 265 if ((fdc_dmap = alloc_chipmem(DMABUFSZ)) == NULL) { 266 printf("fdc: unable to allocate dma buffer\n"); 267 return(0); 268 } 269 return(1); 270 } 271 272 void 273 fdcattach(pdp, dp, auxp) 274 struct device *pdp, *dp; 275 void *auxp; 276 { 277 struct fdcargs args; 278 279 printf(": dmabuf pa 0x%x\n", kvtop(fdc_dmap)); 280 args.unit = 0; 281 args.type = fdcgetfdtype(args.unit); 282 283 fdc_side = -1; 284 config_found(dp, &args, fdcprint); 285 for (args.unit++; args.unit < FDMAXUNITS; args.unit++) { 286 if ((args.type = fdcgetfdtype(args.unit)) == NULL) 287 continue; 288 config_found(dp, &args, fdcprint); 289 } 290 } 291 292 int 293 fdcprint(auxp, pnp) 294 void *auxp; 295 char *pnp; 296 { 297 return(UNCONF); 298 } 299 300 /*ARGSUSED*/ 301 int 302 fdmatch(pdp, cfp, auxp) 303 struct device *pdp; 304 struct cfdata *cfp; 305 void *auxp; 306 { 307 #define cf_unit cf_loc[0] 308 struct fdcargs *fdap; 309 310 fdap = auxp; 311 if (cfp->cf_unit == fdap->unit || cfp->cf_unit == -1) 312 return(1); 313 return(0); 314 #undef cf_unit 315 } 316 317 void 318 fdattach(pdp, dp, auxp) 319 struct device *pdp, *dp; 320 void *auxp; 321 { 322 struct fdcargs *ap; 323 struct fd_softc *sc; 324 325 ap = auxp; 326 sc = (struct fd_softc *)dp; 327 328 sc->curcyl = sc->cachetrk = -1; 329 sc->openpart = -1; 330 sc->type = ap->type; 331 sc->hwunit = ap->unit; 332 sc->unitmask = 1 << (3 + ap->unit); 333 sc->retries = FDRETRIES; 334 sc->dkdev.dk_driver = &fddkdriver; 335 sc->stepdelay = FDSTEPDELAY; 336 printf(": %s %d cyl, %d head, %d sec [%d sec], 512 bytes/sec\n", 337 sc->type->desc, sc->type->ncylinders, FDNHEADS, 338 sc->type->amiga_nsectors, sc->type->msdos_nsectors); 339 340 /* 341 * calibrate the drive 342 */ 343 fdsetpos(sc, 0, 0); 344 fdsetpos(sc, sc->type->ncylinders, 0); 345 fdsetpos(sc, 0, 0); 346 fdmotoroff(sc); 347 348 /* 349 * enable disk related interrupts 350 */ 351 custom.dmacon = DMAF_SETCLR | DMAF_DISK; 352 /* XXX why softint */ 353 custom.intena = INTF_SETCLR |INTF_SOFTINT | INTF_DSKBLK; 354 ciaa.icr = CIA_ICR_IR_SC | CIA_ICR_FLG; 355 } 356 357 /*ARGSUSED*/ 358 int 359 Fdopen(dev, flags, devtype, p) 360 dev_t dev; 361 int flags, devtype; 362 struct proc *p; 363 { 364 struct fd_softc *sc; 365 int wasopen, fwork, error, s; 366 367 error = 0; 368 369 if (FDPART(dev) >= FDMAXPARTS) 370 return(ENXIO); 371 372 if ((sc = getsoftc(fdcd, FDUNIT(dev))) == NULL) 373 return(ENXIO); 374 if (sc->flags & FDF_NOTRACK0) 375 return(ENXIO); 376 if (sc->cachep == NULL) 377 sc->cachep = malloc(MAXTRKSZ, M_DEVBUF, M_WAITOK); 378 379 s = splbio(); 380 /* 381 * if we are sleeping in fdclose(); waiting for a chance to 382 * shut the motor off, do a sleep here also. 383 */ 384 while (sc->flags & FDF_WMOTOROFF) 385 tsleep(fdmotoroff, PRIBIO, "Fdopen", 0); 386 387 fwork = 0; 388 /* 389 * if not open let user open request type, otherwise 390 * ensure they are trying to open same type. 391 */ 392 if (sc->openpart == FDPART(dev)) 393 wasopen = 1; 394 else if (sc->openpart == -1) { 395 sc->openpart = FDPART(dev); 396 wasopen = 0; 397 } else { 398 wasopen = 1; 399 error = EPERM; 400 goto done; 401 } 402 403 /* 404 * wait for current io to complete if any 405 */ 406 if (fdc_indma) { 407 fwork = 1; 408 fdc_wantwakeup++; 409 tsleep(Fdopen, PRIBIO, "Fdopen", 0); 410 } 411 if (error = fdloaddisk(sc)) 412 goto done; 413 if (error = fdgetdisklabel(sc, dev)) 414 goto done; 415 #ifdef FDDEBUG 416 printf(" open successful\n"); 417 #endif 418 done: 419 /* 420 * if we requested that fddone()->fdfindwork() wake us, allow it to 421 * complete its job now 422 */ 423 if (fwork) 424 fdfindwork(FDUNIT(dev)); 425 splx(s); 426 427 /* 428 * if we were not open and we marked us so reverse that. 429 */ 430 if (error && wasopen == 0) 431 sc->openpart = 0; 432 return(error); 433 } 434 435 /*ARGSUSED*/ 436 int 437 fdclose(dev, flags, devtype, p) 438 dev_t dev; 439 int flags, devtype; 440 struct proc *p; 441 { 442 struct fd_softc *sc; 443 int s; 444 445 #ifdef FDDEBUG 446 printf("fdclose()\n"); 447 #endif 448 sc = getsoftc(fdcd, FDUNIT(dev)); 449 s = splbio(); 450 if (sc->flags & FDF_MOTORON) { 451 sc->flags |= FDF_WMOTOROFF; 452 tsleep(fdmotoroff, PRIBIO, "fdclose", 0); 453 sc->flags &= ~FDF_WMOTOROFF; 454 wakeup(fdmotoroff); 455 } 456 sc->openpart = -1; 457 splx(s); 458 return(0); 459 } 460 461 int 462 fdioctl(dev, cmd, addr, flag, p) 463 dev_t dev; 464 int cmd, flag; 465 caddr_t addr; 466 struct proc *p; 467 { 468 struct fd_softc *sc; 469 void *data; 470 int error, wlab; 471 472 sc = getsoftc(fdcd, FDUNIT(dev)); 473 474 if ((sc->flags & FDF_HAVELABEL) == 0) 475 return(EBADF); 476 477 switch (cmd) { 478 case DIOCSBAD: 479 return(EINVAL); 480 case DIOCSRETRIES: 481 if (*(int *)addr < 0) 482 return(EINVAL); 483 sc->retries = *(int *)addr; 484 return(0); 485 case DIOCSSTEP: 486 if (*(int *)addr < FDSTEPDELAY) 487 return(EINVAL); 488 sc->dkdev.dk_label.d_trkseek = sc->stepdelay = *(int *)addr; 489 return(0); 490 case DIOCGDINFO: 491 *(struct disklabel *)addr = sc->dkdev.dk_label; 492 return(0); 493 case DIOCGPART: 494 ((struct partinfo *)addr)->disklab = &sc->dkdev.dk_label; 495 ((struct partinfo *)addr)->part = 496 &sc->dkdev.dk_label.d_partitions[FDPART(dev)]; 497 return(0); 498 case DIOCSDINFO: 499 if ((flag & FWRITE) == 0) 500 return(EBADF); 501 return(fdsetdisklabel(sc, (struct disklabel *)addr)); 502 case DIOCWDINFO: 503 if ((flag & FWRITE) == 0) 504 return(EBADF); 505 if (error = fdsetdisklabel(sc, (struct disklabel *)addr)) 506 return(error); 507 wlab = sc->wlabel; 508 sc->wlabel = 1; 509 error = fdputdisklabel(sc, dev); 510 sc->wlabel = wlab; 511 return(error); 512 case DIOCWLABEL: 513 if ((flag & FWRITE) == 0) 514 return(EBADF); 515 sc->wlabel = *(int *)addr; 516 return(0); 517 default: 518 return(ENOTTY); 519 } 520 } 521 522 /* 523 * no dumps to floppy disks thank you. 524 */ 525 int 526 fdsize(dev) 527 dev_t dev; 528 { 529 return(-1); 530 } 531 532 int 533 fdread(dev, uio) 534 dev_t dev; 535 struct uio *uio; 536 { 537 return (physio(cdevsw[major(dev)].d_strategy, (struct buf *)NULL, 538 dev, B_READ, fdminphys, uio)); 539 } 540 541 int 542 fdwrite(dev, uio) 543 dev_t dev; 544 struct uio *uio; 545 { 546 return (physio(cdevsw[major(dev)].d_strategy, (struct buf *)NULL, 547 dev, B_WRITE, fdminphys, uio)); 548 } 549 550 551 int 552 fdintr() 553 { 554 int s; 555 556 s = splbio(); 557 if (fdc_indma) 558 fddmadone(fdc_indma, 0); 559 splx(s); 560 } 561 562 void 563 fdstrategy(bp) 564 struct buf *bp; 565 { 566 struct disklabel *lp; 567 struct fd_softc *sc; 568 struct buf *dp; 569 int unit, part, s; 570 571 unit = FDUNIT(bp->b_dev); 572 part = FDPART(bp->b_dev); 573 sc = getsoftc(fdcd, unit); 574 575 #ifdef FDDEBUG 576 printf("fdstrategy: 0x%x\n", bp); 577 #endif 578 /* 579 * check for valid partition and bounds 580 */ 581 lp = &sc->dkdev.dk_label; 582 if ((sc->flags & FDF_HAVELABEL) == 0) { 583 bp->b_error = EIO; 584 goto bad; 585 } 586 if (bounds_check_with_label(bp, lp, sc->wlabel) <= 0) 587 goto done; 588 589 /* 590 * trans count of zero or bounds check indicates io is done 591 * we are done. 592 */ 593 if (bp->b_bcount == 0) 594 goto done; 595 596 /* 597 * queue the buf and kick the low level code 598 */ 599 s = splbio(); 600 dp = &sc->bufq; 601 disksort(dp, bp); 602 fdstart(sc); 603 splx(s); 604 return; 605 bad: 606 bp->b_flags |= B_ERROR; 607 done: 608 bp->b_resid = bp->b_bcount; 609 biodone(bp); 610 } 611 612 /* 613 * make sure disk is loaded and label is up-to-date. 614 */ 615 int 616 fdloaddisk(sc) 617 struct fd_softc *sc; 618 { 619 /* 620 * if diskchange is low step drive to 0 then up one then to zero. 621 */ 622 fdsetpos(sc, 0, 0); 623 if (FDTESTC(FDB_CHANGED)) { 624 sc->cachetrk = -1; /* invalidate the cache */ 625 sc->flags &= ~FDF_HAVELABEL; 626 fdsetpos(sc, FDNHEADS, 0); 627 fdsetpos(sc, 0, 0); 628 if (FDTESTC(FDB_CHANGED)) { 629 fdmotoroff(sc); 630 return(ENXIO); 631 } 632 } 633 fdmotoroff(sc); 634 sc->type = fdcgetfdtype(sc->hwunit); 635 if (sc->type == NULL) 636 return(ENXIO); 637 #ifdef not_yet 638 if (sc->openpart == FDMSDOSPART) 639 sc->nsectors = sc->type->msdos_nsectors; 640 else 641 #endif 642 sc->nsectors = sc->type->amiga_nsectors; 643 return(0); 644 } 645 646 /* 647 * read disk label, if present otherwise create one 648 * return a new label if raw part and none found, otherwise err. 649 */ 650 int 651 fdgetdisklabel(sc, dev) 652 struct fd_softc *sc; 653 dev_t dev; 654 { 655 struct disklabel *lp, *dlp; 656 struct cpu_disklabel *clp; 657 struct buf *bp; 658 int error, part; 659 660 if (sc->flags & FDF_HAVELABEL) 661 return(0); 662 #ifdef FDDEBUG 663 printf("fdgetdisklabel()\n"); 664 #endif 665 part = FDPART(dev); 666 lp = &sc->dkdev.dk_label; 667 clp = &sc->dkdev.dk_cpulabel; 668 bzero(lp, sizeof(struct disklabel)); 669 bzero(clp, sizeof(struct cpu_disklabel)); 670 671 lp->d_secsize = FDSECSIZE; 672 lp->d_ntracks = FDNHEADS; 673 lp->d_ncylinders = sc->type->ncylinders; 674 lp->d_nsectors = sc->nsectors; 675 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 676 lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders; 677 lp->d_npartitions = part + 1; 678 lp->d_partitions[part].p_size = lp->d_secperunit; 679 lp->d_partitions[part].p_fstype = FS_UNUSED; 680 lp->d_partitions[part].p_fsize = 1024; 681 lp->d_partitions[part].p_frag = 8; 682 683 sc->flags |= FDF_HAVELABEL; 684 685 bp = (void *)geteblk((int)lp->d_secsize); 686 bp->b_dev = dev; 687 bp->b_blkno = 0; 688 bp->b_cylin = 0; 689 bp->b_bcount = FDSECSIZE; 690 bp->b_flags = B_BUSY | B_READ; 691 fdstrategy(bp); 692 if (error = biowait(bp)) 693 goto nolabel; 694 dlp = (struct disklabel *)(bp->b_data + LABELOFFSET); 695 if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC || 696 dkcksum(dlp)) { 697 error = EINVAL; 698 goto nolabel; 699 } 700 bcopy(dlp, lp, sizeof(struct disklabel)); 701 if (lp->d_trkseek > FDSTEPDELAY) 702 sc->stepdelay = lp->d_trkseek; 703 brelse(bp); 704 return(0); 705 nolabel: 706 bzero(lp, sizeof(struct disklabel)); 707 lp->d_secsize = FDSECSIZE; 708 lp->d_ntracks = FDNHEADS; 709 lp->d_ncylinders = sc->type->ncylinders; 710 lp->d_nsectors = sc->nsectors; 711 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 712 lp->d_type = DTYPE_FLOPPY; 713 lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders; 714 lp->d_rpm = 300; /* good guess I suppose. */ 715 lp->d_interleave = 1; /* should change when adding msdos */ 716 sc->stepdelay = lp->d_trkseek = FDSTEPDELAY; 717 lp->d_bbsize = 0; 718 lp->d_sbsize = 0; 719 lp->d_partitions[part].p_size = lp->d_secperunit; 720 lp->d_partitions[part].p_fstype = FS_UNUSED; 721 lp->d_partitions[part].p_fsize = 1024; 722 lp->d_partitions[part].p_frag = 8; 723 lp->d_npartitions = part + 1; 724 lp->d_magic = lp->d_magic2 = DISKMAGIC; 725 lp->d_checksum = dkcksum(lp); 726 brelse(bp); 727 return(0); 728 } 729 730 /* 731 * set the incore copy of this units disklabel 732 */ 733 int 734 fdsetdisklabel(sc, lp) 735 struct fd_softc *sc; 736 struct disklabel *lp; 737 { 738 struct disklabel *clp; 739 struct partition *pp; 740 741 /* 742 * must have at least opened raw unit to fetch the 743 * raw_part stuff. 744 */ 745 if ((sc->flags & FDF_HAVELABEL) == 0) 746 return(EINVAL); 747 clp = &sc->dkdev.dk_label; 748 /* 749 * make sure things check out and we only have one valid 750 * partition 751 */ 752 #ifdef FDDEBUG 753 printf("fdsetdisklabel\n"); 754 #endif 755 if (lp->d_secsize != FDSECSIZE || 756 lp->d_nsectors != clp->d_nsectors || 757 lp->d_ntracks != FDNHEADS || 758 lp->d_ncylinders != clp->d_ncylinders || 759 lp->d_secpercyl != clp->d_secpercyl || 760 lp->d_secperunit != clp->d_secperunit || 761 lp->d_magic != DISKMAGIC || 762 lp->d_magic2 != DISKMAGIC || 763 lp->d_npartitions == 0 || 764 lp->d_npartitions > FDMAXPARTS || 765 (lp->d_partitions[0].p_offset && lp->d_partitions[1].p_offset) || 766 dkcksum(lp)) 767 return(EINVAL); 768 /* 769 * if any partitions are present make sure they 770 * represent the currently open type 771 */ 772 if ((pp = &lp->d_partitions[0])->p_size) { 773 if ((pp = &lp->d_partitions[1])->p_size == 0) 774 goto done; 775 else if (sc->openpart != 1) 776 return(EINVAL); 777 } else if (sc->openpart != 0) 778 return(EINVAL); 779 /* 780 * make sure selected partition is within bounds 781 * XXX on the second check, its to handle a bug in 782 * XXX the cluster routines as they require mutliples 783 * XXX of CLBYTES currently 784 */ 785 if ((pp->p_offset + pp->p_size >= lp->d_secperunit) || 786 (pp->p_frag * pp->p_fsize % CLBYTES)) 787 return(EINVAL); 788 done: 789 bcopy(lp, clp, sizeof(struct disklabel)); 790 return(0); 791 } 792 793 /* 794 * write out the incore copy of this units disklabel 795 */ 796 int 797 fdputdisklabel(sc, dev) 798 struct fd_softc *sc; 799 dev_t dev; 800 { 801 struct disklabel *lp, *dlp; 802 struct buf *bp; 803 int error; 804 805 if ((sc->flags & FDF_HAVELABEL) == 0) 806 return(EBADF); 807 #ifdef FDDEBUG 808 printf("fdputdisklabel\n"); 809 #endif 810 /* 811 * get buf and read in sector 0 812 */ 813 lp = &sc->dkdev.dk_label; 814 bp = (void *)geteblk((int)lp->d_secsize); 815 bp->b_dev = FDMAKEDEV(major(dev), FDUNIT(dev), RAW_PART); 816 bp->b_blkno = 0; 817 bp->b_cylin = 0; 818 bp->b_bcount = FDSECSIZE; 819 bp->b_flags = B_BUSY | B_READ; 820 fdstrategy(bp); 821 if (error = biowait(bp)) 822 goto done; 823 /* 824 * copy disklabel to buf and write it out syncronous 825 */ 826 dlp = (struct disklabel *)(bp->b_data + LABELOFFSET); 827 bcopy(lp, dlp, sizeof(struct disklabel)); 828 bp->b_blkno = 0; 829 bp->b_cylin = 0; 830 bp->b_flags = B_WRITE; 831 fdstrategy(bp); 832 error = biowait(bp); 833 done: 834 brelse(bp); 835 return(error); 836 } 837 838 /* 839 * figure out drive type or NULL if none. 840 */ 841 struct fdtype * 842 fdcgetfdtype(unit) 843 int unit; 844 { 845 struct fdtype *ftp; 846 u_long id, idb; 847 int cnt, umask; 848 849 id = 0; 850 umask = 1 << (3 + unit); 851 852 FDDESELECT(FDCUNITMASK); 853 854 FDSETMOTOR(1); 855 delay(1); 856 FDSELECT(umask); 857 delay(1); 858 FDDESELECT(umask); 859 860 FDSETMOTOR(0); 861 delay(1); 862 FDSELECT(umask); 863 delay(1); 864 FDDESELECT(umask); 865 866 for (idb = 0x80000000; idb; idb >>= 1) { 867 FDSELECT(umask); 868 delay(1); 869 if (FDTESTC(FDB_READY) == 0) 870 id |= idb; 871 FDDESELECT(umask); 872 delay(1); 873 } 874 #ifdef FDDEBUG 875 printf("fdcgettype unit %d id 0x%x\n", unit, id); 876 #endif 877 878 for (cnt = 0, ftp = fdtype; cnt < nfdtype; ftp++, cnt++) 879 if (ftp->driveid == id) 880 return(ftp); 881 /* 882 * 3.5dd's at unit 0 do not always return id. 883 */ 884 if (unit == 0) 885 return(fdtype); 886 return(NULL); 887 } 888 889 /* 890 * turn motor off if possible otherwise mark as needed and will be done 891 * later. 892 */ 893 void 894 fdmotoroff(arg) 895 void *arg; 896 { 897 struct fd_softc *sc; 898 int unitmask, s; 899 900 sc = arg; 901 s = splbio(); 902 903 #ifdef FDDEBUG 904 printf("fdmotoroff: unit %d\n", sc->hwunit); 905 #endif 906 if ((sc->flags & FDF_MOTORON) == 0) 907 goto done; 908 /* 909 * if we have a timeout on a dma operation let fddmadone() 910 * deal with it. 911 */ 912 if (fdc_indma == sc) { 913 fddmadone(sc, 1); 914 goto done; 915 } 916 #ifdef FDDEBUG 917 printf(" motor was on, turning off\n"); 918 #endif 919 920 /* 921 * flush cache if needed 922 */ 923 if (sc->flags & FDF_DIRTY) { 924 sc->flags |= FDF_JUSTFLUSH | FDF_MOTOROFF; 925 #ifdef FDDEBUG 926 printf(" flushing dirty buffer first\n"); 927 #endif 928 /* 929 * if dma'ing done for now, fddone() will call us again 930 */ 931 if (fdc_indma) 932 goto done; 933 fddmastart(sc, sc->cachetrk); 934 goto done; 935 } 936 937 /* 938 * if controller is busy just schedule us to be called back 939 */ 940 if (fdc_indma) { 941 /* 942 * someone else has the controller now 943 * just set flag and let fddone() call us again. 944 */ 945 sc->flags |= FDF_MOTOROFF; 946 goto done; 947 } 948 949 #ifdef FDDEBUG 950 printf(" hw turing unit off\n"); 951 #endif 952 953 sc->flags &= ~(FDF_MOTORON | FDF_MOTOROFF); 954 FDDESELECT(FDCUNITMASK); 955 FDSETMOTOR(0); 956 delay(1); 957 FDSELECT(sc->unitmask); 958 delay(4); 959 FDDESELECT(sc->unitmask); 960 delay(1); 961 if (sc->flags & FDF_WMOTOROFF) 962 wakeup(fdmotoroff); 963 done: 964 splx(s); 965 } 966 967 /* 968 * select drive seek to track exit with motor on. 969 * fdsetpos(x, 0, 0) does calibrates the drive. 970 */ 971 void 972 fdsetpos(sc, trk, towrite) 973 struct fd_softc *sc; 974 int trk, towrite; 975 { 976 int nstep, sdir, ondly, ncyl, nside; 977 978 FDDESELECT(FDCUNITMASK); 979 FDSETMOTOR(1); 980 delay(1); 981 FDSELECT(sc->unitmask); 982 delay(1); 983 if ((sc->flags & FDF_MOTORON) == 0) { 984 ondly = 0; 985 while (FDTESTC(FDB_READY) == 0) { 986 delay(1000); 987 if (++ondly >= 1000) 988 break; 989 } 990 } 991 sc->flags |= FDF_MOTORON; 992 993 ncyl = trk / FDNHEADS; 994 nside = trk % FDNHEADS; 995 996 if (sc->curcyl == ncyl && fdc_side == nside) 997 return; 998 999 if (towrite) 1000 sc->flags |= FDF_WRITEWAIT; 1001 1002 #ifdef FDDEBUG 1003 printf("fdsetpos: cyl %d head %d towrite %d\n", trk / FDNHEADS, 1004 trk % FDNHEADS, towrite); 1005 #endif 1006 nstep = ncyl - sc->curcyl; 1007 if (nstep) { 1008 /* 1009 * figure direction 1010 */ 1011 if (nstep > 0 && ncyl != 0) { 1012 sdir = FDSTEPIN; 1013 FDSETDIR(1); 1014 } else { 1015 nstep = -nstep; 1016 sdir = FDSTEPOUT; 1017 FDSETDIR(0); 1018 } 1019 if (ncyl == 0) { 1020 /* 1021 * either just want cylinder 0 or doing 1022 * a calibrate. 1023 */ 1024 nstep = 256; 1025 while (FDTESTC(FDB_CYLZERO) == 0 && nstep--) { 1026 FDSTEP; 1027 delay(sc->stepdelay); 1028 } 1029 if (nstep < 0) 1030 sc->flags |= FDF_NOTRACK0; 1031 } else { 1032 /* 1033 * step the needed amount amount. 1034 */ 1035 while (nstep--) { 1036 FDSTEP; 1037 delay(sc->stepdelay); 1038 } 1039 } 1040 /* 1041 * if switched directions 1042 * allow drive to settle. 1043 */ 1044 if (sc->pstepdir != sdir) 1045 delay(FDSETTLEDELAY); 1046 sc->pstepdir = sdir; 1047 sc->curcyl = ncyl; 1048 } 1049 if (nside == fdc_side) 1050 return; 1051 /* 1052 * select side 1053 */ 1054 fdc_side = nside; 1055 FDSETHEAD(nside); 1056 delay(FDPRESIDEDELAY); 1057 } 1058 1059 void 1060 fdselunit(sc) 1061 struct fd_softc *sc; 1062 { 1063 FDDESELECT(FDCUNITMASK); /* deselect all */ 1064 FDSETMOTOR(sc->flags & FDF_MOTORON); /* set motor to unit's state */ 1065 delay(1); 1066 FDSELECT(sc->unitmask); /* select unit */ 1067 delay(1); 1068 } 1069 1070 /* 1071 * process next buf on device queue. 1072 * normall sequence of events: 1073 * fdstart() -> fddmastart(); 1074 * fdintr() -> fddmadone() -> fddone(); 1075 * if the track is in the cache then fdstart() will short-circuit 1076 * to fddone() else if the track cache is dirty it will flush. If 1077 * the buf is not an entire track it will cache the requested track. 1078 */ 1079 void 1080 fdstart(sc) 1081 struct fd_softc *sc; 1082 { 1083 int trk, error, write; 1084 struct buf *bp, *dp; 1085 1086 #ifdef FDDEBUG 1087 printf("fdstart: unit %d\n", sc->hwunit); 1088 #endif 1089 1090 /* 1091 * if dma'ing just return. we must have been called from fdstartegy. 1092 */ 1093 if (fdc_indma) 1094 return; 1095 1096 /* 1097 * get next buf if there. 1098 */ 1099 dp = &sc->bufq; 1100 if ((bp = dp->b_actf) == NULL) { 1101 #ifdef FDDEBUG 1102 printf(" nothing to do\n"); 1103 #endif 1104 return; 1105 } 1106 1107 /* 1108 * make sure same disk is loaded 1109 */ 1110 fdselunit(sc); 1111 if (FDTESTC(FDB_CHANGED)) { 1112 /* 1113 * disk missing, invalidate all future io on 1114 * this unit until re-open()'ed also invalidate 1115 * all current io 1116 */ 1117 #ifdef FDDEBUG 1118 printf(" disk was removed invalidating all io\n"); 1119 #endif 1120 sc->flags &= ~FDF_HAVELABEL; 1121 for (;;) { 1122 bp->b_flags |= B_ERROR; 1123 bp->b_error = EIO; 1124 if (bp->b_actf == NULL) 1125 break; 1126 biodone(bp); 1127 bp = bp->b_actf; 1128 } 1129 /* 1130 * do fddone() on last buf to allow other units to start. 1131 */ 1132 dp->b_actf = bp; 1133 fddone(sc); 1134 return; 1135 } 1136 1137 /* 1138 * we have a valid buf, setup our local version 1139 * we use this count to allow reading over multiple tracks. 1140 * into a single buffer 1141 */ 1142 dp->b_bcount = bp->b_bcount; 1143 dp->b_blkno = bp->b_blkno; 1144 dp->b_data = bp->b_data; 1145 dp->b_flags = bp->b_flags; 1146 dp->b_resid = 0; 1147 1148 if (bp->b_flags & B_READ) 1149 write = 0; 1150 else if (FDTESTC(FDB_PROTECT) == 0) 1151 write = 1; 1152 else { 1153 error = EPERM; 1154 goto bad; 1155 } 1156 1157 /* 1158 * figure trk given blkno 1159 */ 1160 trk = bp->b_blkno / sc->nsectors; 1161 1162 /* 1163 * check to see if same as currently cached track 1164 * if so we need to do no dma read. 1165 */ 1166 if (trk == sc->cachetrk) { 1167 fddone(sc); 1168 return; 1169 } 1170 1171 /* 1172 * if we will be overwriting the entire cache, don't bother to 1173 * fetch it. 1174 */ 1175 if (bp->b_bcount == (sc->nsectors * FDSECSIZE) && write && 1176 bp->b_blkno % sc->nsectors == 0) { 1177 if (sc->flags & FDF_DIRTY) 1178 sc->flags |= FDF_JUSTFLUSH; 1179 else { 1180 sc->cachetrk = trk; 1181 fddone(sc); 1182 return; 1183 } 1184 } 1185 1186 /* 1187 * start dma read of `trk' 1188 */ 1189 fddmastart(sc, trk); 1190 return; 1191 bad: 1192 bp->b_flags |= B_ERROR; 1193 bp->b_error = error; 1194 fddone(sc); 1195 } 1196 1197 /* 1198 * continue a started operation on next track. always begin at 1199 * sector 0 on the next track. 1200 */ 1201 void 1202 fdcont(sc) 1203 struct fd_softc *sc; 1204 { 1205 struct buf *dp, *bp; 1206 int trk, write; 1207 1208 dp = &sc->bufq; 1209 bp = dp->b_actf; 1210 dp->b_data += (dp->b_bcount - bp->b_resid); 1211 dp->b_blkno += (dp->b_bcount - bp->b_resid) / FDSECSIZE; 1212 dp->b_bcount = bp->b_resid; 1213 1214 /* 1215 * figure trk given blkno 1216 */ 1217 trk = dp->b_blkno / sc->nsectors; 1218 #ifdef DEBUG 1219 if (trk != sc->cachetrk + 1 || dp->b_blkno % sc->nsectors != 0) 1220 panic("fdcont: confused"); 1221 #endif 1222 if (dp->b_flags & B_READ) 1223 write = 0; 1224 else 1225 write = 1; 1226 /* 1227 * if we will be overwriting the entire cache, don't bother to 1228 * fetch it. 1229 */ 1230 if (dp->b_bcount == (sc->nsectors * FDSECSIZE) && write) { 1231 if (sc->flags & FDF_DIRTY) 1232 sc->flags |= FDF_JUSTFLUSH; 1233 else { 1234 sc->cachetrk = trk; 1235 fddone(sc); 1236 return; 1237 } 1238 } 1239 /* 1240 * start dma read of `trk' 1241 */ 1242 fddmastart(sc, trk); 1243 return; 1244 } 1245 1246 void 1247 fddmastart(sc, trk) 1248 struct fd_softc *sc; 1249 int trk; 1250 { 1251 int adkmask, ndmaw, write, dmatrk; 1252 1253 #ifdef FDDEBUG 1254 printf("fddmastart: unit %d cyl %d head %d", sc->hwunit, 1255 trk / FDNHEADS, trk % FDNHEADS); 1256 #endif 1257 /* 1258 * flush the cached track if dirty else read requested track. 1259 */ 1260 if (sc->flags & FDF_DIRTY) { 1261 fdcachetoraw(sc); 1262 ndmaw = sc->type->nwritew; 1263 dmatrk = sc->cachetrk; 1264 write = 1; 1265 } else { 1266 ndmaw = sc->type->nreadw; 1267 dmatrk = trk; 1268 write = 0; 1269 } 1270 1271 #ifdef FDDEBUG 1272 printf(" %s", write ? " flushing cache\n" : " loading cache\n"); 1273 #endif 1274 sc->cachetrk = trk; 1275 fdc_indma = sc; 1276 fdsetpos(sc, dmatrk, write); 1277 1278 /* 1279 * setup dma stuff 1280 */ 1281 if (write == 0) { 1282 custom.adkcon = ADKF_MSBSYNC; 1283 custom.adkcon = ADKF_SETCLR | ADKF_WORDSYNC | ADKF_FAST; 1284 custom.dsksync = FDMFMSYNC; 1285 } else { 1286 custom.adkcon = ADKF_PRECOMP1 | ADKF_PRECOMP0 | ADKF_WORDSYNC | 1287 ADKF_MSBSYNC; 1288 adkmask = ADKF_SETCLR | ADKF_FAST | ADKF_MFMPREC; 1289 if (dmatrk >= sc->type->precomp[0]) 1290 adkmask |= ADKF_PRECOMP0; 1291 if (dmatrk >= sc->type->precomp[1]) 1292 adkmask |= ADKF_PRECOMP1; 1293 custom.adkcon = adkmask; 1294 } 1295 custom.dskpt = (u_char *)kvtop(fdc_dmap); 1296 FDDMASTART(ndmaw, write); 1297 1298 #ifdef FDDEBUG 1299 printf(" dma started\n"); 1300 #endif 1301 } 1302 1303 /* 1304 * recalibrate the drive 1305 */ 1306 void 1307 fdcalibrate(arg) 1308 void *arg; 1309 { 1310 struct fd_softc *sc; 1311 static int loopcnt; 1312 1313 sc = arg; 1314 1315 if (loopcnt == 0) { 1316 /* 1317 * seek cyl 0 1318 */ 1319 fdc_indma = sc; 1320 sc->stepdelay += 900; 1321 if (sc->cachetrk > 1) 1322 fdsetpos(sc, sc->cachetrk % FDNHEADS, 0); 1323 sc->stepdelay -= 900; 1324 } 1325 if (loopcnt++ & 1) 1326 fdsetpos(sc, sc->cachetrk, 0); 1327 else 1328 fdsetpos(sc, sc->cachetrk + FDNHEADS, 0); 1329 /* 1330 * trk++, trk, trk++, trk, trk++, trk, trk++, trk and dma 1331 */ 1332 if (loopcnt < 8) 1333 timeout(fdcalibrate, sc, hz / 8); 1334 else { 1335 loopcnt = 0; 1336 fdc_indma = NULL; 1337 timeout(fdmotoroff, sc, 3 * hz / 2); 1338 fddmastart(sc, sc->cachetrk); 1339 } 1340 } 1341 1342 void 1343 fddmadone(sc, timeo) 1344 struct fd_softc *sc; 1345 int timeo; 1346 { 1347 #ifdef FDDEBUG 1348 printf("fddmadone: unit %d, timeo %d\n", sc->hwunit, timeo); 1349 #endif 1350 fdc_indma = NULL; 1351 untimeout(fdmotoroff, sc); 1352 FDDMASTOP; 1353 1354 /* 1355 * guarantee the drive has been at current head and cyl 1356 * for at least FDWRITEDELAY after a write. 1357 */ 1358 if (sc->flags & FDF_WRITEWAIT) { 1359 delay(FDWRITEDELAY); 1360 sc->flags &= ~FDF_WRITEWAIT; 1361 } 1362 1363 if ((sc->flags & FDF_MOTOROFF) == 0) { 1364 /* 1365 * motor runs for 1.5 seconds after last dma 1366 */ 1367 timeout(fdmotoroff, sc, 3 * hz / 2); 1368 } 1369 if (sc->flags & FDF_DIRTY) { 1370 /* 1371 * if buffer dirty, the last dma cleaned it 1372 */ 1373 sc->flags &= ~FDF_DIRTY; 1374 if (timeo) 1375 printf("%s: write of track cache timed out.\n", 1376 sc->dkdev.dk_dev.dv_xname); 1377 if (sc->flags & FDF_JUSTFLUSH) { 1378 sc->flags &= ~FDF_JUSTFLUSH; 1379 /* 1380 * we are done dma'ing 1381 */ 1382 fddone(sc); 1383 return; 1384 } 1385 /* 1386 * load the cache 1387 */ 1388 fddmastart(sc, sc->cachetrk); 1389 return; 1390 } 1391 #ifdef FDDEBUG 1392 else if (sc->flags & FDF_MOTOROFF) 1393 panic("fddmadone: FDF_MOTOROFF with no FDF_DIRTY"); 1394 #endif 1395 1396 /* 1397 * cache loaded decode it into cache buffer 1398 */ 1399 if (timeo == 0 && fdrawtocache(sc) == 0) 1400 sc->retried = 0; 1401 else { 1402 #ifdef FDDEBUG 1403 if (timeo) 1404 printf("%s: fddmadone: cache load timed out.\n", 1405 sc->dkdev.dk_dev.dv_xname); 1406 #endif 1407 if (sc->retried >= sc->retries) { 1408 sc->retried = 0; 1409 sc->cachetrk = -1; 1410 } else { 1411 sc->retried++; 1412 /* 1413 * this will be restarted at end of calibrate loop. 1414 */ 1415 untimeout(fdmotoroff, sc); 1416 fdcalibrate(sc); 1417 return; 1418 } 1419 } 1420 fddone(sc); 1421 } 1422 1423 void 1424 fddone(sc) 1425 struct fd_softc *sc; 1426 { 1427 struct buf *dp, *bp; 1428 char *data; 1429 int sz, blk; 1430 1431 #ifdef FDDEBUG 1432 printf("fddone: unit %d\n", sc->hwunit); 1433 #endif 1434 /* 1435 * check to see if unit is just flushing the cache, 1436 * that is we have no io queued. 1437 */ 1438 if (sc->flags & FDF_MOTOROFF) 1439 goto nobuf; 1440 1441 dp = &sc->bufq; 1442 if ((bp = dp->b_actf) == NULL) 1443 panic ("fddone"); 1444 /* 1445 * check for an error that may have occured 1446 * while getting the track. 1447 */ 1448 if (sc->cachetrk == -1) { 1449 sc->retried = 0; 1450 bp->b_flags |= B_ERROR; 1451 bp->b_error = EIO; 1452 } else if ((bp->b_flags & B_ERROR) == 0) { 1453 data = sc->cachep; 1454 /* 1455 * get offset of data in track cache and limit 1456 * the copy size to not exceed the cache's end. 1457 */ 1458 data += (dp->b_blkno % sc->nsectors) * FDSECSIZE; 1459 sz = sc->nsectors - dp->b_blkno % sc->nsectors; 1460 sz *= FDSECSIZE; 1461 sz = min(dp->b_bcount, sz); 1462 if (bp->b_flags & B_READ) 1463 bcopy(data, dp->b_data, sz); 1464 else { 1465 bcopy(dp->b_data, data, sz); 1466 sc->flags |= FDF_DIRTY; 1467 } 1468 bp->b_resid = dp->b_bcount - sz; 1469 if (bp->b_resid == 0) { 1470 bp->b_error = 0; 1471 } else { 1472 /* 1473 * not done yet need to read next track 1474 */ 1475 fdcont(sc); 1476 return; 1477 } 1478 } 1479 /* 1480 * remove from queue. 1481 */ 1482 dp->b_actf = bp->b_actf; 1483 biodone(bp); 1484 nobuf: 1485 fdfindwork(sc->dkdev.dk_dev.dv_unit); 1486 } 1487 1488 void 1489 fdfindwork(unit) 1490 int unit; 1491 { 1492 struct fd_softc *ssc, *sc; 1493 int i, last; 1494 1495 /* 1496 * first see if we have any Fdopen()'s waiting 1497 */ 1498 if (fdc_wantwakeup) { 1499 wakeup(Fdopen); 1500 fdc_wantwakeup--; 1501 return; 1502 } 1503 1504 /* 1505 * start next available unit, linear search from the next unit 1506 * wrapping and finally this unit. 1507 */ 1508 last = 0; 1509 ssc = NULL; 1510 for (i = unit + 1; last == 0; i++) { 1511 if (i == unit) 1512 last = 1; 1513 if (i >= fdcd.cd_ndevs) { 1514 i = -1; 1515 continue; 1516 } 1517 if ((sc = fdcd.cd_devs[i]) == NULL) 1518 continue; 1519 1520 /* 1521 * if unit has requested to be turned off 1522 * and it has no buf's queued do it now 1523 */ 1524 if (sc->flags & FDF_MOTOROFF) { 1525 if (sc->bufq.b_actf == NULL) 1526 fdmotoroff(sc); 1527 else { 1528 /* 1529 * we gained a buf request while 1530 * we waited, forget the motoroff 1531 */ 1532 sc->flags &= ~FDF_MOTOROFF; 1533 } 1534 /* 1535 * if we now have dma unit must have needed 1536 * flushing, quit 1537 */ 1538 if (fdc_indma) 1539 return; 1540 } 1541 /* 1542 * if we have no start unit and the current unit has 1543 * io waiting choose this unit to start. 1544 */ 1545 if (ssc == NULL && sc->bufq.b_actf) 1546 ssc = sc; 1547 } 1548 if (ssc) 1549 fdstart(ssc); 1550 } 1551 1552 /* 1553 * min byte count to whats left of the track in question 1554 */ 1555 int 1556 fdminphys(bp) 1557 struct buf *bp; 1558 { 1559 struct fd_softc *sc; 1560 int trk, sec, toff, tsz; 1561 1562 if ((sc = getsoftc(fdcd, FDUNIT(bp->b_dev))) == NULL) 1563 return(ENXIO); 1564 1565 trk = bp->b_blkno / sc->nsectors; 1566 sec = bp->b_blkno % sc->nsectors; 1567 1568 toff = sec * FDSECSIZE; 1569 tsz = sc->nsectors * FDSECSIZE; 1570 #ifdef FDDEBUG 1571 printf("fdminphys: before %d", bp->b_bcount); 1572 #endif 1573 bp->b_bcount = min(bp->b_bcount, tsz - toff); 1574 #ifdef FDDEBUG 1575 printf(" after %d\n", bp->b_bcount); 1576 #endif 1577 return(bp->b_bcount); 1578 } 1579 1580 /* 1581 * encode the track cache into raw MFM ready for dma 1582 * when we go to multiple disk formats, this will call type dependent 1583 * functions 1584 */ 1585 void 1586 fdcachetoraw(sc) 1587 struct fd_softc *sc; 1588 { 1589 static u_long mfmnull[4]; 1590 u_long *rp, *crp, *dp, hcksum, dcksum, info, zero; 1591 int sec, i; 1592 1593 rp = fdc_dmap; 1594 1595 /* 1596 * not yet one sector (- 1 long) gap. 1597 * for now use previous drivers values 1598 */ 1599 for (i = 0; i < sc->type->gap; i++) 1600 *rp++ = 0xaaaaaaaa; 1601 /* 1602 * process sectors 1603 */ 1604 dp = sc->cachep; 1605 zero = 0; 1606 info = 0xff000000 | (sc->cachetrk << 16) | sc->nsectors; 1607 for (sec = 0; sec < sc->nsectors; sec++, info += (1 << 8) - 1) { 1608 hcksum = dcksum = 0; 1609 /* 1610 * sector format 1611 * offset description 1612 *----------------------------------- 1613 * 0 null 1614 * 1 sync 1615 * oddbits evenbits 1616 *---------------------- 1617 * 2 3 [0xff]b [trk]b [sec]b [togap]b 1618 * 4-7 8-11 null 1619 * 12 13 header cksum [2-11] 1620 * 14 15 data cksum [16-271] 1621 * 16-143 144-271 data 1622 */ 1623 *rp = 0xaaaaaaaa; 1624 if (*(rp - 1) & 0x1) 1625 *rp &= 0x7fffffff; /* clock bit correction */ 1626 rp++; 1627 *rp++ = (FDMFMSYNC << 16) | FDMFMSYNC; 1628 rp = mfmblkencode(&info, rp, &hcksum, 1); 1629 rp = mfmblkencode(mfmnull, rp, &hcksum, 4); 1630 rp = mfmblkencode(&hcksum, rp, NULL, 1); 1631 1632 crp = rp; 1633 rp = mfmblkencode(dp, rp + 2, &dcksum, FDSECLWORDS); 1634 dp += FDSECLWORDS; 1635 crp = mfmblkencode(&dcksum, crp, NULL, 1); 1636 if (*(crp - 1) & 0x1) 1637 *crp &= 0x7fffffff; /* clock bit correction */ 1638 else if ((*crp & 0x40000000) == 0) 1639 *crp |= 0x80000000; 1640 } 1641 *rp = 0xaaa80000; 1642 if (*(rp - 1) & 0x1) 1643 *rp &= 0x7fffffff; 1644 } 1645 1646 u_long * 1647 fdfindsync(rp, ep) 1648 u_long *rp, *ep; 1649 { 1650 u_short *sp; 1651 1652 sp = (u_short *)rp; 1653 while ((u_long *)sp < ep && *sp != FDMFMSYNC) 1654 sp++; 1655 while ((u_long *)sp < ep && *sp == FDMFMSYNC) 1656 sp++; 1657 if ((u_long *)sp < ep) 1658 return((u_long *)sp); 1659 return(NULL); 1660 } 1661 1662 /* 1663 * decode raw MFM from dma into units track cache. 1664 * when we go to multiple disk formats, this will call type dependent 1665 * functions 1666 */ 1667 int 1668 fdrawtocache(sc) 1669 struct fd_softc *sc; 1670 { 1671 u_long mfmnull[4]; 1672 u_long *dp, *rp, *erp, *crp, *srp, hcksum, dcksum, info, cktmp; 1673 int cnt, doagain; 1674 1675 doagain = 1; 1676 srp = rp = fdc_dmap; 1677 erp = (u_long *)((u_short *)rp + sc->type->nreadw); 1678 cnt = 0; 1679 again: 1680 if (doagain == 0 || (rp = srp = fdfindsync(srp, erp)) == NULL) { 1681 #ifdef DIAGNOSTIC 1682 printf("%s: corrupted track (%d) data.\n", 1683 sc->dkdev.dk_dev.dv_xname, sc->cachetrk); 1684 #endif 1685 return(-1); 1686 } 1687 1688 /* 1689 * process sectors 1690 */ 1691 for (; cnt < sc->nsectors; cnt++) { 1692 hcksum = dcksum = 0; 1693 rp = mfmblkdecode(rp, &info, &hcksum, 1); 1694 rp = mfmblkdecode(rp, mfmnull, &hcksum, 4); 1695 rp = mfmblkdecode(rp, &cktmp, NULL, 1); 1696 if (cktmp != hcksum) { 1697 #ifdef FDDEBUG 1698 printf(" info 0x%x hchksum 0x%x trkhcksum 0x%x\n", 1699 info, hcksum, cktmp); 1700 #endif 1701 goto again; 1702 } 1703 if (((info >> 16) & 0xff) != sc->cachetrk) { 1704 #ifdef DEBUG 1705 printf("%s: incorrect track found: 0x%0x %d\n", 1706 sc->dkdev.dk_dev.dv_xname, info, sc->cachetrk); 1707 #endif 1708 goto again; 1709 } 1710 #ifdef FDDEBUG 1711 printf(" info 0x%x\n", info); 1712 #endif 1713 1714 rp = mfmblkdecode(rp, &cktmp, NULL, 1); 1715 dp = sc->cachep; 1716 dp += FDSECLWORDS * ((info >> 8) & 0xff); 1717 crp = mfmblkdecode(rp, dp, &dcksum, FDSECLWORDS); 1718 if (cktmp != dcksum) { 1719 #ifdef FDDEBUG 1720 printf(" info 0x%x dchksum 0x%x trkdcksum 0x%x\n", 1721 info, dcksum, cktmp); 1722 #endif 1723 goto again; 1724 } 1725 1726 /* 1727 * if we are at gap then we can no longer be sure 1728 * of correct sync marks 1729 */ 1730 if ((info && 0xff) == 1) 1731 doagain = 1; 1732 else 1733 doagain = 0; 1734 srp = rp = fdfindsync(crp, erp); 1735 } 1736 return(0); 1737 } 1738 1739 /* 1740 * encode len longwords of `dp' data in amiga mfm block format (`rp') 1741 * this format specified that the odd bits are at current pos and even 1742 * bits at len + current pos 1743 */ 1744 u_long * 1745 mfmblkencode(dp, rp, cp, len) 1746 u_long *dp, *rp, *cp; 1747 int len; 1748 { 1749 u_long *sdp, *edp, d, dtmp, correct; 1750 int i; 1751 1752 sdp = dp; 1753 edp = dp + len; 1754 1755 if (*(rp - 1) & 0x1) 1756 correct = 1; 1757 else 1758 correct = 0; 1759 /* 1760 * do odd bits 1761 */ 1762 while (dp < edp) { 1763 d = (*dp >> 1) & 0x55555555; /* remove clock bits */ 1764 dtmp = d ^ 0x55555555; 1765 d |= ((dtmp >> 1) | 0x80000000) & (dtmp << 1); 1766 /* 1767 * correct upper clock bit if needed 1768 */ 1769 if (correct) 1770 d &= 0x7fffffff; 1771 if (d & 0x1) 1772 correct = 1; 1773 else 1774 correct = 0; 1775 /* 1776 * do checksums and store in raw buffer 1777 */ 1778 if (cp) 1779 *cp ^= d; 1780 *rp++ = d; 1781 dp++; 1782 } 1783 /* 1784 * do even bits 1785 */ 1786 dp = sdp; 1787 while (dp < edp) { 1788 d = *dp & 0x55555555; /* remove clock bits */ 1789 dtmp = d ^ 0x55555555; 1790 d |= ((dtmp >> 1) | 0x80000000) & (dtmp << 1); 1791 /* 1792 * correct upper clock bit if needed 1793 */ 1794 if (correct) 1795 d &= 0x7fffffff; 1796 if (d & 0x1) 1797 correct = 1; 1798 else 1799 correct = 0; 1800 /* 1801 * do checksums and store in raw buffer 1802 */ 1803 if (cp) 1804 *cp ^= d; 1805 *rp++ = d; 1806 dp++; 1807 } 1808 if (cp) 1809 *cp &= 0x55555555; 1810 return(rp); 1811 } 1812 1813 /* 1814 * decode len longwords of `dp' data in amiga mfm block format (`rp') 1815 * this format specified that the odd bits are at current pos and even 1816 * bits at len + current pos 1817 */ 1818 u_long * 1819 mfmblkdecode(rp, dp, cp, len) 1820 u_long *rp, *dp, *cp; 1821 int len; 1822 { 1823 u_long o, e; 1824 int cnt; 1825 1826 cnt = len; 1827 while (cnt--) { 1828 o = *rp; 1829 e = *(rp + len); 1830 if (cp) { 1831 *cp ^= o; 1832 *cp ^= e; 1833 } 1834 o &= 0x55555555; 1835 e &= 0x55555555; 1836 *dp++ = (o << 1) | e; 1837 rp++; 1838 } 1839 if (cp) 1840 *cp &= 0x55555555; 1841 return(rp + len); 1842 } 1843