1 /* $NetBSD: fd.c,v 1.14 1994/12/13 21:17:23 mycroft Exp $ */ 2 3 /* 4 * Copyright (c) 1994 Christian E. Hopps 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 Christian E. Hopps. 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 #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", (cfmatch_t)fdmatch, fdattach, DV_DISK, 194 sizeof(struct fd_softc), NULL, 0 }; 195 196 struct cfdriver fdccd = { 197 NULL, "fdc", (cfmatch_t)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 u_long cmd; 465 caddr_t addr; 466 int flag; 467 struct proc *p; 468 { 469 struct fd_softc *sc; 470 void *data; 471 int error, wlab; 472 473 sc = getsoftc(fdcd, FDUNIT(dev)); 474 475 if ((sc->flags & FDF_HAVELABEL) == 0) 476 return(EBADF); 477 478 switch (cmd) { 479 case DIOCSBAD: 480 return(EINVAL); 481 case DIOCSRETRIES: 482 if (*(int *)addr < 0) 483 return(EINVAL); 484 sc->retries = *(int *)addr; 485 return(0); 486 case DIOCSSTEP: 487 if (*(int *)addr < FDSTEPDELAY) 488 return(EINVAL); 489 sc->dkdev.dk_label.d_trkseek = sc->stepdelay = *(int *)addr; 490 return(0); 491 case DIOCGDINFO: 492 *(struct disklabel *)addr = sc->dkdev.dk_label; 493 return(0); 494 case DIOCGPART: 495 ((struct partinfo *)addr)->disklab = &sc->dkdev.dk_label; 496 ((struct partinfo *)addr)->part = 497 &sc->dkdev.dk_label.d_partitions[FDPART(dev)]; 498 return(0); 499 case DIOCSDINFO: 500 if ((flag & FWRITE) == 0) 501 return(EBADF); 502 return(fdsetdisklabel(sc, (struct disklabel *)addr)); 503 case DIOCWDINFO: 504 if ((flag & FWRITE) == 0) 505 return(EBADF); 506 if (error = fdsetdisklabel(sc, (struct disklabel *)addr)) 507 return(error); 508 wlab = sc->wlabel; 509 sc->wlabel = 1; 510 error = fdputdisklabel(sc, dev); 511 sc->wlabel = wlab; 512 return(error); 513 case DIOCWLABEL: 514 if ((flag & FWRITE) == 0) 515 return(EBADF); 516 sc->wlabel = *(int *)addr; 517 return(0); 518 default: 519 return(ENOTTY); 520 } 521 } 522 523 /* 524 * no dumps to floppy disks thank you. 525 */ 526 int 527 fdsize(dev) 528 dev_t dev; 529 { 530 return(-1); 531 } 532 533 int 534 fdread(dev, uio) 535 dev_t dev; 536 struct uio *uio; 537 { 538 return (physio(cdevsw[major(dev)].d_strategy, (struct buf *)NULL, 539 dev, B_READ, fdminphys, uio)); 540 } 541 542 int 543 fdwrite(dev, uio) 544 dev_t dev; 545 struct uio *uio; 546 { 547 return (physio(cdevsw[major(dev)].d_strategy, (struct buf *)NULL, 548 dev, B_WRITE, fdminphys, uio)); 549 } 550 551 552 int 553 fdintr() 554 { 555 int s; 556 557 s = splbio(); 558 if (fdc_indma) 559 fddmadone(fdc_indma, 0); 560 splx(s); 561 } 562 563 void 564 fdstrategy(bp) 565 struct buf *bp; 566 { 567 struct disklabel *lp; 568 struct fd_softc *sc; 569 struct buf *dp; 570 int unit, part, s; 571 572 unit = FDUNIT(bp->b_dev); 573 part = FDPART(bp->b_dev); 574 sc = getsoftc(fdcd, unit); 575 576 #ifdef FDDEBUG 577 printf("fdstrategy: 0x%x\n", bp); 578 #endif 579 /* 580 * check for valid partition and bounds 581 */ 582 lp = &sc->dkdev.dk_label; 583 if ((sc->flags & FDF_HAVELABEL) == 0) { 584 bp->b_error = EIO; 585 goto bad; 586 } 587 if (bounds_check_with_label(bp, lp, sc->wlabel) <= 0) 588 goto done; 589 590 /* 591 * trans count of zero or bounds check indicates io is done 592 * we are done. 593 */ 594 if (bp->b_bcount == 0) 595 goto done; 596 597 /* 598 * queue the buf and kick the low level code 599 */ 600 s = splbio(); 601 dp = &sc->bufq; 602 disksort(dp, bp); 603 fdstart(sc); 604 splx(s); 605 return; 606 bad: 607 bp->b_flags |= B_ERROR; 608 done: 609 bp->b_resid = bp->b_bcount; 610 biodone(bp); 611 } 612 613 /* 614 * make sure disk is loaded and label is up-to-date. 615 */ 616 int 617 fdloaddisk(sc) 618 struct fd_softc *sc; 619 { 620 /* 621 * if diskchange is low step drive to 0 then up one then to zero. 622 */ 623 fdsetpos(sc, 0, 0); 624 if (FDTESTC(FDB_CHANGED)) { 625 sc->cachetrk = -1; /* invalidate the cache */ 626 sc->flags &= ~FDF_HAVELABEL; 627 fdsetpos(sc, FDNHEADS, 0); 628 fdsetpos(sc, 0, 0); 629 if (FDTESTC(FDB_CHANGED)) { 630 fdmotoroff(sc); 631 return(ENXIO); 632 } 633 } 634 fdmotoroff(sc); 635 sc->type = fdcgetfdtype(sc->hwunit); 636 if (sc->type == NULL) 637 return(ENXIO); 638 #ifdef not_yet 639 if (sc->openpart == FDMSDOSPART) 640 sc->nsectors = sc->type->msdos_nsectors; 641 else 642 #endif 643 sc->nsectors = sc->type->amiga_nsectors; 644 return(0); 645 } 646 647 /* 648 * read disk label, if present otherwise create one 649 * return a new label if raw part and none found, otherwise err. 650 */ 651 int 652 fdgetdisklabel(sc, dev) 653 struct fd_softc *sc; 654 dev_t dev; 655 { 656 struct disklabel *lp, *dlp; 657 struct cpu_disklabel *clp; 658 struct buf *bp; 659 int error, part; 660 661 if (sc->flags & FDF_HAVELABEL) 662 return(0); 663 #ifdef FDDEBUG 664 printf("fdgetdisklabel()\n"); 665 #endif 666 part = FDPART(dev); 667 lp = &sc->dkdev.dk_label; 668 clp = &sc->dkdev.dk_cpulabel; 669 bzero(lp, sizeof(struct disklabel)); 670 bzero(clp, sizeof(struct cpu_disklabel)); 671 672 lp->d_secsize = FDSECSIZE; 673 lp->d_ntracks = FDNHEADS; 674 lp->d_ncylinders = sc->type->ncylinders; 675 lp->d_nsectors = sc->nsectors; 676 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 677 lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders; 678 lp->d_npartitions = part + 1; 679 lp->d_partitions[part].p_size = lp->d_secperunit; 680 lp->d_partitions[part].p_fstype = FS_UNUSED; 681 lp->d_partitions[part].p_fsize = 1024; 682 lp->d_partitions[part].p_frag = 8; 683 684 sc->flags |= FDF_HAVELABEL; 685 686 bp = (void *)geteblk((int)lp->d_secsize); 687 bp->b_dev = dev; 688 bp->b_blkno = 0; 689 bp->b_cylin = 0; 690 bp->b_bcount = FDSECSIZE; 691 bp->b_flags = B_BUSY | B_READ; 692 fdstrategy(bp); 693 if (error = biowait(bp)) 694 goto nolabel; 695 dlp = (struct disklabel *)(bp->b_data + LABELOFFSET); 696 if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC || 697 dkcksum(dlp)) { 698 error = EINVAL; 699 goto nolabel; 700 } 701 bcopy(dlp, lp, sizeof(struct disklabel)); 702 if (lp->d_trkseek > FDSTEPDELAY) 703 sc->stepdelay = lp->d_trkseek; 704 brelse(bp); 705 return(0); 706 nolabel: 707 bzero(lp, sizeof(struct disklabel)); 708 lp->d_secsize = FDSECSIZE; 709 lp->d_ntracks = FDNHEADS; 710 lp->d_ncylinders = sc->type->ncylinders; 711 lp->d_nsectors = sc->nsectors; 712 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 713 lp->d_type = DTYPE_FLOPPY; 714 lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders; 715 lp->d_rpm = 300; /* good guess I suppose. */ 716 lp->d_interleave = 1; /* should change when adding msdos */ 717 sc->stepdelay = lp->d_trkseek = FDSTEPDELAY; 718 lp->d_bbsize = 0; 719 lp->d_sbsize = 0; 720 lp->d_partitions[part].p_size = lp->d_secperunit; 721 lp->d_partitions[part].p_fstype = FS_UNUSED; 722 lp->d_partitions[part].p_fsize = 1024; 723 lp->d_partitions[part].p_frag = 8; 724 lp->d_npartitions = part + 1; 725 lp->d_magic = lp->d_magic2 = DISKMAGIC; 726 lp->d_checksum = dkcksum(lp); 727 brelse(bp); 728 return(0); 729 } 730 731 /* 732 * set the incore copy of this units disklabel 733 */ 734 int 735 fdsetdisklabel(sc, lp) 736 struct fd_softc *sc; 737 struct disklabel *lp; 738 { 739 struct disklabel *clp; 740 struct partition *pp; 741 742 /* 743 * must have at least opened raw unit to fetch the 744 * raw_part stuff. 745 */ 746 if ((sc->flags & FDF_HAVELABEL) == 0) 747 return(EINVAL); 748 clp = &sc->dkdev.dk_label; 749 /* 750 * make sure things check out and we only have one valid 751 * partition 752 */ 753 #ifdef FDDEBUG 754 printf("fdsetdisklabel\n"); 755 #endif 756 if (lp->d_secsize != FDSECSIZE || 757 lp->d_nsectors != clp->d_nsectors || 758 lp->d_ntracks != FDNHEADS || 759 lp->d_ncylinders != clp->d_ncylinders || 760 lp->d_secpercyl != clp->d_secpercyl || 761 lp->d_secperunit != clp->d_secperunit || 762 lp->d_magic != DISKMAGIC || 763 lp->d_magic2 != DISKMAGIC || 764 lp->d_npartitions == 0 || 765 lp->d_npartitions > FDMAXPARTS || 766 (lp->d_partitions[0].p_offset && lp->d_partitions[1].p_offset) || 767 dkcksum(lp)) 768 return(EINVAL); 769 /* 770 * if any partitions are present make sure they 771 * represent the currently open type 772 */ 773 if ((pp = &lp->d_partitions[0])->p_size) { 774 if ((pp = &lp->d_partitions[1])->p_size == 0) 775 goto done; 776 else if (sc->openpart != 1) 777 return(EINVAL); 778 } else if (sc->openpart != 0) 779 return(EINVAL); 780 /* 781 * make sure selected partition is within bounds 782 * XXX on the second check, its to handle a bug in 783 * XXX the cluster routines as they require mutliples 784 * XXX of CLBYTES currently 785 */ 786 if ((pp->p_offset + pp->p_size >= lp->d_secperunit) || 787 (pp->p_frag * pp->p_fsize % CLBYTES)) 788 return(EINVAL); 789 done: 790 bcopy(lp, clp, sizeof(struct disklabel)); 791 return(0); 792 } 793 794 /* 795 * write out the incore copy of this units disklabel 796 */ 797 int 798 fdputdisklabel(sc, dev) 799 struct fd_softc *sc; 800 dev_t dev; 801 { 802 struct disklabel *lp, *dlp; 803 struct buf *bp; 804 int error; 805 806 if ((sc->flags & FDF_HAVELABEL) == 0) 807 return(EBADF); 808 #ifdef FDDEBUG 809 printf("fdputdisklabel\n"); 810 #endif 811 /* 812 * get buf and read in sector 0 813 */ 814 lp = &sc->dkdev.dk_label; 815 bp = (void *)geteblk((int)lp->d_secsize); 816 bp->b_dev = FDMAKEDEV(major(dev), FDUNIT(dev), RAW_PART); 817 bp->b_blkno = 0; 818 bp->b_cylin = 0; 819 bp->b_bcount = FDSECSIZE; 820 bp->b_flags = B_BUSY | B_READ; 821 fdstrategy(bp); 822 if (error = biowait(bp)) 823 goto done; 824 /* 825 * copy disklabel to buf and write it out syncronous 826 */ 827 dlp = (struct disklabel *)(bp->b_data + LABELOFFSET); 828 bcopy(lp, dlp, sizeof(struct disklabel)); 829 bp->b_blkno = 0; 830 bp->b_cylin = 0; 831 bp->b_flags = B_WRITE; 832 fdstrategy(bp); 833 error = biowait(bp); 834 done: 835 brelse(bp); 836 return(error); 837 } 838 839 /* 840 * figure out drive type or NULL if none. 841 */ 842 struct fdtype * 843 fdcgetfdtype(unit) 844 int unit; 845 { 846 struct fdtype *ftp; 847 u_long id, idb; 848 int cnt, umask; 849 850 id = 0; 851 umask = 1 << (3 + unit); 852 853 FDDESELECT(FDCUNITMASK); 854 855 FDSETMOTOR(1); 856 delay(1); 857 FDSELECT(umask); 858 delay(1); 859 FDDESELECT(umask); 860 861 FDSETMOTOR(0); 862 delay(1); 863 FDSELECT(umask); 864 delay(1); 865 FDDESELECT(umask); 866 867 for (idb = 0x80000000; idb; idb >>= 1) { 868 FDSELECT(umask); 869 delay(1); 870 if (FDTESTC(FDB_READY) == 0) 871 id |= idb; 872 FDDESELECT(umask); 873 delay(1); 874 } 875 #ifdef FDDEBUG 876 printf("fdcgettype unit %d id 0x%x\n", unit, id); 877 #endif 878 879 for (cnt = 0, ftp = fdtype; cnt < nfdtype; ftp++, cnt++) 880 if (ftp->driveid == id) 881 return(ftp); 882 /* 883 * 3.5dd's at unit 0 do not always return id. 884 */ 885 if (unit == 0) 886 return(fdtype); 887 return(NULL); 888 } 889 890 /* 891 * turn motor off if possible otherwise mark as needed and will be done 892 * later. 893 */ 894 void 895 fdmotoroff(arg) 896 void *arg; 897 { 898 struct fd_softc *sc; 899 int unitmask, s; 900 901 sc = arg; 902 s = splbio(); 903 904 #ifdef FDDEBUG 905 printf("fdmotoroff: unit %d\n", sc->hwunit); 906 #endif 907 if ((sc->flags & FDF_MOTORON) == 0) 908 goto done; 909 /* 910 * if we have a timeout on a dma operation let fddmadone() 911 * deal with it. 912 */ 913 if (fdc_indma == sc) { 914 fddmadone(sc, 1); 915 goto done; 916 } 917 #ifdef FDDEBUG 918 printf(" motor was on, turning off\n"); 919 #endif 920 921 /* 922 * flush cache if needed 923 */ 924 if (sc->flags & FDF_DIRTY) { 925 sc->flags |= FDF_JUSTFLUSH | FDF_MOTOROFF; 926 #ifdef FDDEBUG 927 printf(" flushing dirty buffer first\n"); 928 #endif 929 /* 930 * if dma'ing done for now, fddone() will call us again 931 */ 932 if (fdc_indma) 933 goto done; 934 fddmastart(sc, sc->cachetrk); 935 goto done; 936 } 937 938 /* 939 * if controller is busy just schedule us to be called back 940 */ 941 if (fdc_indma) { 942 /* 943 * someone else has the controller now 944 * just set flag and let fddone() call us again. 945 */ 946 sc->flags |= FDF_MOTOROFF; 947 goto done; 948 } 949 950 #ifdef FDDEBUG 951 printf(" hw turing unit off\n"); 952 #endif 953 954 sc->flags &= ~(FDF_MOTORON | FDF_MOTOROFF); 955 FDDESELECT(FDCUNITMASK); 956 FDSETMOTOR(0); 957 delay(1); 958 FDSELECT(sc->unitmask); 959 delay(4); 960 FDDESELECT(sc->unitmask); 961 delay(1); 962 if (sc->flags & FDF_WMOTOROFF) 963 wakeup(fdmotoroff); 964 done: 965 splx(s); 966 } 967 968 /* 969 * select drive seek to track exit with motor on. 970 * fdsetpos(x, 0, 0) does calibrates the drive. 971 */ 972 void 973 fdsetpos(sc, trk, towrite) 974 struct fd_softc *sc; 975 int trk, towrite; 976 { 977 int nstep, sdir, ondly, ncyl, nside; 978 979 FDDESELECT(FDCUNITMASK); 980 FDSETMOTOR(1); 981 delay(1); 982 FDSELECT(sc->unitmask); 983 delay(1); 984 if ((sc->flags & FDF_MOTORON) == 0) { 985 ondly = 0; 986 while (FDTESTC(FDB_READY) == 0) { 987 delay(1000); 988 if (++ondly >= 1000) 989 break; 990 } 991 } 992 sc->flags |= FDF_MOTORON; 993 994 ncyl = trk / FDNHEADS; 995 nside = trk % FDNHEADS; 996 997 if (sc->curcyl == ncyl && fdc_side == nside) 998 return; 999 1000 if (towrite) 1001 sc->flags |= FDF_WRITEWAIT; 1002 1003 #ifdef FDDEBUG 1004 printf("fdsetpos: cyl %d head %d towrite %d\n", trk / FDNHEADS, 1005 trk % FDNHEADS, towrite); 1006 #endif 1007 nstep = ncyl - sc->curcyl; 1008 if (nstep) { 1009 /* 1010 * figure direction 1011 */ 1012 if (nstep > 0 && ncyl != 0) { 1013 sdir = FDSTEPIN; 1014 FDSETDIR(1); 1015 } else { 1016 nstep = -nstep; 1017 sdir = FDSTEPOUT; 1018 FDSETDIR(0); 1019 } 1020 if (ncyl == 0) { 1021 /* 1022 * either just want cylinder 0 or doing 1023 * a calibrate. 1024 */ 1025 nstep = 256; 1026 while (FDTESTC(FDB_CYLZERO) == 0 && nstep--) { 1027 FDSTEP; 1028 delay(sc->stepdelay); 1029 } 1030 if (nstep < 0) 1031 sc->flags |= FDF_NOTRACK0; 1032 } else { 1033 /* 1034 * step the needed amount amount. 1035 */ 1036 while (nstep--) { 1037 FDSTEP; 1038 delay(sc->stepdelay); 1039 } 1040 } 1041 /* 1042 * if switched directions 1043 * allow drive to settle. 1044 */ 1045 if (sc->pstepdir != sdir) 1046 delay(FDSETTLEDELAY); 1047 sc->pstepdir = sdir; 1048 sc->curcyl = ncyl; 1049 } 1050 if (nside == fdc_side) 1051 return; 1052 /* 1053 * select side 1054 */ 1055 fdc_side = nside; 1056 FDSETHEAD(nside); 1057 delay(FDPRESIDEDELAY); 1058 } 1059 1060 void 1061 fdselunit(sc) 1062 struct fd_softc *sc; 1063 { 1064 FDDESELECT(FDCUNITMASK); /* deselect all */ 1065 FDSETMOTOR(sc->flags & FDF_MOTORON); /* set motor to unit's state */ 1066 delay(1); 1067 FDSELECT(sc->unitmask); /* select unit */ 1068 delay(1); 1069 } 1070 1071 /* 1072 * process next buf on device queue. 1073 * normall sequence of events: 1074 * fdstart() -> fddmastart(); 1075 * fdintr() -> fddmadone() -> fddone(); 1076 * if the track is in the cache then fdstart() will short-circuit 1077 * to fddone() else if the track cache is dirty it will flush. If 1078 * the buf is not an entire track it will cache the requested track. 1079 */ 1080 void 1081 fdstart(sc) 1082 struct fd_softc *sc; 1083 { 1084 int trk, error, write; 1085 struct buf *bp, *dp; 1086 1087 #ifdef FDDEBUG 1088 printf("fdstart: unit %d\n", sc->hwunit); 1089 #endif 1090 1091 /* 1092 * if dma'ing just return. we must have been called from fdstartegy. 1093 */ 1094 if (fdc_indma) 1095 return; 1096 1097 /* 1098 * get next buf if there. 1099 */ 1100 dp = &sc->bufq; 1101 if ((bp = dp->b_actf) == NULL) { 1102 #ifdef FDDEBUG 1103 printf(" nothing to do\n"); 1104 #endif 1105 return; 1106 } 1107 1108 /* 1109 * make sure same disk is loaded 1110 */ 1111 fdselunit(sc); 1112 if (FDTESTC(FDB_CHANGED)) { 1113 /* 1114 * disk missing, invalidate all future io on 1115 * this unit until re-open()'ed also invalidate 1116 * all current io 1117 */ 1118 #ifdef FDDEBUG 1119 printf(" disk was removed invalidating all io\n"); 1120 #endif 1121 sc->flags &= ~FDF_HAVELABEL; 1122 for (;;) { 1123 bp->b_flags |= B_ERROR; 1124 bp->b_error = EIO; 1125 if (bp->b_actf == NULL) 1126 break; 1127 biodone(bp); 1128 bp = bp->b_actf; 1129 } 1130 /* 1131 * do fddone() on last buf to allow other units to start. 1132 */ 1133 dp->b_actf = bp; 1134 fddone(sc); 1135 return; 1136 } 1137 1138 /* 1139 * we have a valid buf, setup our local version 1140 * we use this count to allow reading over multiple tracks. 1141 * into a single buffer 1142 */ 1143 dp->b_bcount = bp->b_bcount; 1144 dp->b_blkno = bp->b_blkno; 1145 dp->b_data = bp->b_data; 1146 dp->b_flags = bp->b_flags; 1147 dp->b_resid = 0; 1148 1149 if (bp->b_flags & B_READ) 1150 write = 0; 1151 else if (FDTESTC(FDB_PROTECT) == 0) 1152 write = 1; 1153 else { 1154 error = EPERM; 1155 goto bad; 1156 } 1157 1158 /* 1159 * figure trk given blkno 1160 */ 1161 trk = bp->b_blkno / sc->nsectors; 1162 1163 /* 1164 * check to see if same as currently cached track 1165 * if so we need to do no dma read. 1166 */ 1167 if (trk == sc->cachetrk) { 1168 fddone(sc); 1169 return; 1170 } 1171 1172 /* 1173 * if we will be overwriting the entire cache, don't bother to 1174 * fetch it. 1175 */ 1176 if (bp->b_bcount == (sc->nsectors * FDSECSIZE) && write && 1177 bp->b_blkno % sc->nsectors == 0) { 1178 if (sc->flags & FDF_DIRTY) 1179 sc->flags |= FDF_JUSTFLUSH; 1180 else { 1181 sc->cachetrk = trk; 1182 fddone(sc); 1183 return; 1184 } 1185 } 1186 1187 /* 1188 * start dma read of `trk' 1189 */ 1190 fddmastart(sc, trk); 1191 return; 1192 bad: 1193 bp->b_flags |= B_ERROR; 1194 bp->b_error = error; 1195 fddone(sc); 1196 } 1197 1198 /* 1199 * continue a started operation on next track. always begin at 1200 * sector 0 on the next track. 1201 */ 1202 void 1203 fdcont(sc) 1204 struct fd_softc *sc; 1205 { 1206 struct buf *dp, *bp; 1207 int trk, write; 1208 1209 dp = &sc->bufq; 1210 bp = dp->b_actf; 1211 dp->b_data += (dp->b_bcount - bp->b_resid); 1212 dp->b_blkno += (dp->b_bcount - bp->b_resid) / FDSECSIZE; 1213 dp->b_bcount = bp->b_resid; 1214 1215 /* 1216 * figure trk given blkno 1217 */ 1218 trk = dp->b_blkno / sc->nsectors; 1219 #ifdef DEBUG 1220 if (trk != sc->cachetrk + 1 || dp->b_blkno % sc->nsectors != 0) 1221 panic("fdcont: confused"); 1222 #endif 1223 if (dp->b_flags & B_READ) 1224 write = 0; 1225 else 1226 write = 1; 1227 /* 1228 * if we will be overwriting the entire cache, don't bother to 1229 * fetch it. 1230 */ 1231 if (dp->b_bcount == (sc->nsectors * FDSECSIZE) && write) { 1232 if (sc->flags & FDF_DIRTY) 1233 sc->flags |= FDF_JUSTFLUSH; 1234 else { 1235 sc->cachetrk = trk; 1236 fddone(sc); 1237 return; 1238 } 1239 } 1240 /* 1241 * start dma read of `trk' 1242 */ 1243 fddmastart(sc, trk); 1244 return; 1245 } 1246 1247 void 1248 fddmastart(sc, trk) 1249 struct fd_softc *sc; 1250 int trk; 1251 { 1252 int adkmask, ndmaw, write, dmatrk; 1253 1254 #ifdef FDDEBUG 1255 printf("fddmastart: unit %d cyl %d head %d", sc->hwunit, 1256 trk / FDNHEADS, trk % FDNHEADS); 1257 #endif 1258 /* 1259 * flush the cached track if dirty else read requested track. 1260 */ 1261 if (sc->flags & FDF_DIRTY) { 1262 fdcachetoraw(sc); 1263 ndmaw = sc->type->nwritew; 1264 dmatrk = sc->cachetrk; 1265 write = 1; 1266 } else { 1267 ndmaw = sc->type->nreadw; 1268 dmatrk = trk; 1269 write = 0; 1270 } 1271 1272 #ifdef FDDEBUG 1273 printf(" %s", write ? " flushing cache\n" : " loading cache\n"); 1274 #endif 1275 sc->cachetrk = trk; 1276 fdc_indma = sc; 1277 fdsetpos(sc, dmatrk, write); 1278 1279 /* 1280 * setup dma stuff 1281 */ 1282 if (write == 0) { 1283 custom.adkcon = ADKF_MSBSYNC; 1284 custom.adkcon = ADKF_SETCLR | ADKF_WORDSYNC | ADKF_FAST; 1285 custom.dsksync = FDMFMSYNC; 1286 } else { 1287 custom.adkcon = ADKF_PRECOMP1 | ADKF_PRECOMP0 | ADKF_WORDSYNC | 1288 ADKF_MSBSYNC; 1289 adkmask = ADKF_SETCLR | ADKF_FAST | ADKF_MFMPREC; 1290 if (dmatrk >= sc->type->precomp[0]) 1291 adkmask |= ADKF_PRECOMP0; 1292 if (dmatrk >= sc->type->precomp[1]) 1293 adkmask |= ADKF_PRECOMP1; 1294 custom.adkcon = adkmask; 1295 } 1296 custom.dskpt = (u_char *)kvtop(fdc_dmap); 1297 FDDMASTART(ndmaw, write); 1298 1299 #ifdef FDDEBUG 1300 printf(" dma started\n"); 1301 #endif 1302 } 1303 1304 /* 1305 * recalibrate the drive 1306 */ 1307 void 1308 fdcalibrate(arg) 1309 void *arg; 1310 { 1311 struct fd_softc *sc; 1312 static int loopcnt; 1313 1314 sc = arg; 1315 1316 if (loopcnt == 0) { 1317 /* 1318 * seek cyl 0 1319 */ 1320 fdc_indma = sc; 1321 sc->stepdelay += 900; 1322 if (sc->cachetrk > 1) 1323 fdsetpos(sc, sc->cachetrk % FDNHEADS, 0); 1324 sc->stepdelay -= 900; 1325 } 1326 if (loopcnt++ & 1) 1327 fdsetpos(sc, sc->cachetrk, 0); 1328 else 1329 fdsetpos(sc, sc->cachetrk + FDNHEADS, 0); 1330 /* 1331 * trk++, trk, trk++, trk, trk++, trk, trk++, trk and dma 1332 */ 1333 if (loopcnt < 8) 1334 timeout(fdcalibrate, sc, hz / 8); 1335 else { 1336 loopcnt = 0; 1337 fdc_indma = NULL; 1338 timeout(fdmotoroff, sc, 3 * hz / 2); 1339 fddmastart(sc, sc->cachetrk); 1340 } 1341 } 1342 1343 void 1344 fddmadone(sc, timeo) 1345 struct fd_softc *sc; 1346 int timeo; 1347 { 1348 #ifdef FDDEBUG 1349 printf("fddmadone: unit %d, timeo %d\n", sc->hwunit, timeo); 1350 #endif 1351 fdc_indma = NULL; 1352 untimeout(fdmotoroff, sc); 1353 FDDMASTOP; 1354 1355 /* 1356 * guarantee the drive has been at current head and cyl 1357 * for at least FDWRITEDELAY after a write. 1358 */ 1359 if (sc->flags & FDF_WRITEWAIT) { 1360 delay(FDWRITEDELAY); 1361 sc->flags &= ~FDF_WRITEWAIT; 1362 } 1363 1364 if ((sc->flags & FDF_MOTOROFF) == 0) { 1365 /* 1366 * motor runs for 1.5 seconds after last dma 1367 */ 1368 timeout(fdmotoroff, sc, 3 * hz / 2); 1369 } 1370 if (sc->flags & FDF_DIRTY) { 1371 /* 1372 * if buffer dirty, the last dma cleaned it 1373 */ 1374 sc->flags &= ~FDF_DIRTY; 1375 if (timeo) 1376 printf("%s: write of track cache timed out.\n", 1377 sc->dkdev.dk_dev.dv_xname); 1378 if (sc->flags & FDF_JUSTFLUSH) { 1379 sc->flags &= ~FDF_JUSTFLUSH; 1380 /* 1381 * we are done dma'ing 1382 */ 1383 fddone(sc); 1384 return; 1385 } 1386 /* 1387 * load the cache 1388 */ 1389 fddmastart(sc, sc->cachetrk); 1390 return; 1391 } 1392 #ifdef FDDEBUG 1393 else if (sc->flags & FDF_MOTOROFF) 1394 panic("fddmadone: FDF_MOTOROFF with no FDF_DIRTY"); 1395 #endif 1396 1397 /* 1398 * cache loaded decode it into cache buffer 1399 */ 1400 if (timeo == 0 && fdrawtocache(sc) == 0) 1401 sc->retried = 0; 1402 else { 1403 #ifdef FDDEBUG 1404 if (timeo) 1405 printf("%s: fddmadone: cache load timed out.\n", 1406 sc->dkdev.dk_dev.dv_xname); 1407 #endif 1408 if (sc->retried >= sc->retries) { 1409 sc->retried = 0; 1410 sc->cachetrk = -1; 1411 } else { 1412 sc->retried++; 1413 /* 1414 * this will be restarted at end of calibrate loop. 1415 */ 1416 untimeout(fdmotoroff, sc); 1417 fdcalibrate(sc); 1418 return; 1419 } 1420 } 1421 fddone(sc); 1422 } 1423 1424 void 1425 fddone(sc) 1426 struct fd_softc *sc; 1427 { 1428 struct buf *dp, *bp; 1429 char *data; 1430 int sz, blk; 1431 1432 #ifdef FDDEBUG 1433 printf("fddone: unit %d\n", sc->hwunit); 1434 #endif 1435 /* 1436 * check to see if unit is just flushing the cache, 1437 * that is we have no io queued. 1438 */ 1439 if (sc->flags & FDF_MOTOROFF) 1440 goto nobuf; 1441 1442 dp = &sc->bufq; 1443 if ((bp = dp->b_actf) == NULL) 1444 panic ("fddone"); 1445 /* 1446 * check for an error that may have occured 1447 * while getting the track. 1448 */ 1449 if (sc->cachetrk == -1) { 1450 sc->retried = 0; 1451 bp->b_flags |= B_ERROR; 1452 bp->b_error = EIO; 1453 } else if ((bp->b_flags & B_ERROR) == 0) { 1454 data = sc->cachep; 1455 /* 1456 * get offset of data in track cache and limit 1457 * the copy size to not exceed the cache's end. 1458 */ 1459 data += (dp->b_blkno % sc->nsectors) * FDSECSIZE; 1460 sz = sc->nsectors - dp->b_blkno % sc->nsectors; 1461 sz *= FDSECSIZE; 1462 sz = min(dp->b_bcount, sz); 1463 if (bp->b_flags & B_READ) 1464 bcopy(data, dp->b_data, sz); 1465 else { 1466 bcopy(dp->b_data, data, sz); 1467 sc->flags |= FDF_DIRTY; 1468 } 1469 bp->b_resid = dp->b_bcount - sz; 1470 if (bp->b_resid == 0) { 1471 bp->b_error = 0; 1472 } else { 1473 /* 1474 * not done yet need to read next track 1475 */ 1476 fdcont(sc); 1477 return; 1478 } 1479 } 1480 /* 1481 * remove from queue. 1482 */ 1483 dp->b_actf = bp->b_actf; 1484 biodone(bp); 1485 nobuf: 1486 fdfindwork(sc->dkdev.dk_dev.dv_unit); 1487 } 1488 1489 void 1490 fdfindwork(unit) 1491 int unit; 1492 { 1493 struct fd_softc *ssc, *sc; 1494 int i, last; 1495 1496 /* 1497 * first see if we have any Fdopen()'s waiting 1498 */ 1499 if (fdc_wantwakeup) { 1500 wakeup(Fdopen); 1501 fdc_wantwakeup--; 1502 return; 1503 } 1504 1505 /* 1506 * start next available unit, linear search from the next unit 1507 * wrapping and finally this unit. 1508 */ 1509 last = 0; 1510 ssc = NULL; 1511 for (i = unit + 1; last == 0; i++) { 1512 if (i == unit) 1513 last = 1; 1514 if (i >= fdcd.cd_ndevs) { 1515 i = -1; 1516 continue; 1517 } 1518 if ((sc = fdcd.cd_devs[i]) == NULL) 1519 continue; 1520 1521 /* 1522 * if unit has requested to be turned off 1523 * and it has no buf's queued do it now 1524 */ 1525 if (sc->flags & FDF_MOTOROFF) { 1526 if (sc->bufq.b_actf == NULL) 1527 fdmotoroff(sc); 1528 else { 1529 /* 1530 * we gained a buf request while 1531 * we waited, forget the motoroff 1532 */ 1533 sc->flags &= ~FDF_MOTOROFF; 1534 } 1535 /* 1536 * if we now have dma unit must have needed 1537 * flushing, quit 1538 */ 1539 if (fdc_indma) 1540 return; 1541 } 1542 /* 1543 * if we have no start unit and the current unit has 1544 * io waiting choose this unit to start. 1545 */ 1546 if (ssc == NULL && sc->bufq.b_actf) 1547 ssc = sc; 1548 } 1549 if (ssc) 1550 fdstart(ssc); 1551 } 1552 1553 /* 1554 * min byte count to whats left of the track in question 1555 */ 1556 int 1557 fdminphys(bp) 1558 struct buf *bp; 1559 { 1560 struct fd_softc *sc; 1561 int trk, sec, toff, tsz; 1562 1563 if ((sc = getsoftc(fdcd, FDUNIT(bp->b_dev))) == NULL) 1564 return(ENXIO); 1565 1566 trk = bp->b_blkno / sc->nsectors; 1567 sec = bp->b_blkno % sc->nsectors; 1568 1569 toff = sec * FDSECSIZE; 1570 tsz = sc->nsectors * FDSECSIZE; 1571 #ifdef FDDEBUG 1572 printf("fdminphys: before %d", bp->b_bcount); 1573 #endif 1574 bp->b_bcount = min(bp->b_bcount, tsz - toff); 1575 #ifdef FDDEBUG 1576 printf(" after %d\n", bp->b_bcount); 1577 #endif 1578 return(bp->b_bcount); 1579 } 1580 1581 /* 1582 * encode the track cache into raw MFM ready for dma 1583 * when we go to multiple disk formats, this will call type dependent 1584 * functions 1585 */ 1586 void 1587 fdcachetoraw(sc) 1588 struct fd_softc *sc; 1589 { 1590 static u_long mfmnull[4]; 1591 u_long *rp, *crp, *dp, hcksum, dcksum, info, zero; 1592 int sec, i; 1593 1594 rp = fdc_dmap; 1595 1596 /* 1597 * not yet one sector (- 1 long) gap. 1598 * for now use previous drivers values 1599 */ 1600 for (i = 0; i < sc->type->gap; i++) 1601 *rp++ = 0xaaaaaaaa; 1602 /* 1603 * process sectors 1604 */ 1605 dp = sc->cachep; 1606 zero = 0; 1607 info = 0xff000000 | (sc->cachetrk << 16) | sc->nsectors; 1608 for (sec = 0; sec < sc->nsectors; sec++, info += (1 << 8) - 1) { 1609 hcksum = dcksum = 0; 1610 /* 1611 * sector format 1612 * offset description 1613 *----------------------------------- 1614 * 0 null 1615 * 1 sync 1616 * oddbits evenbits 1617 *---------------------- 1618 * 2 3 [0xff]b [trk]b [sec]b [togap]b 1619 * 4-7 8-11 null 1620 * 12 13 header cksum [2-11] 1621 * 14 15 data cksum [16-271] 1622 * 16-143 144-271 data 1623 */ 1624 *rp = 0xaaaaaaaa; 1625 if (*(rp - 1) & 0x1) 1626 *rp &= 0x7fffffff; /* clock bit correction */ 1627 rp++; 1628 *rp++ = (FDMFMSYNC << 16) | FDMFMSYNC; 1629 rp = mfmblkencode(&info, rp, &hcksum, 1); 1630 rp = mfmblkencode(mfmnull, rp, &hcksum, 4); 1631 rp = mfmblkencode(&hcksum, rp, NULL, 1); 1632 1633 crp = rp; 1634 rp = mfmblkencode(dp, rp + 2, &dcksum, FDSECLWORDS); 1635 dp += FDSECLWORDS; 1636 crp = mfmblkencode(&dcksum, crp, NULL, 1); 1637 if (*(crp - 1) & 0x1) 1638 *crp &= 0x7fffffff; /* clock bit correction */ 1639 else if ((*crp & 0x40000000) == 0) 1640 *crp |= 0x80000000; 1641 } 1642 *rp = 0xaaa80000; 1643 if (*(rp - 1) & 0x1) 1644 *rp &= 0x7fffffff; 1645 } 1646 1647 u_long * 1648 fdfindsync(rp, ep) 1649 u_long *rp, *ep; 1650 { 1651 u_short *sp; 1652 1653 sp = (u_short *)rp; 1654 while ((u_long *)sp < ep && *sp != FDMFMSYNC) 1655 sp++; 1656 while ((u_long *)sp < ep && *sp == FDMFMSYNC) 1657 sp++; 1658 if ((u_long *)sp < ep) 1659 return((u_long *)sp); 1660 return(NULL); 1661 } 1662 1663 /* 1664 * decode raw MFM from dma into units track cache. 1665 * when we go to multiple disk formats, this will call type dependent 1666 * functions 1667 */ 1668 int 1669 fdrawtocache(sc) 1670 struct fd_softc *sc; 1671 { 1672 u_long mfmnull[4]; 1673 u_long *dp, *rp, *erp, *crp, *srp, hcksum, dcksum, info, cktmp; 1674 int cnt, doagain; 1675 1676 doagain = 1; 1677 srp = rp = fdc_dmap; 1678 erp = (u_long *)((u_short *)rp + sc->type->nreadw); 1679 cnt = 0; 1680 again: 1681 if (doagain == 0 || (rp = srp = fdfindsync(srp, erp)) == NULL) { 1682 #ifdef DIAGNOSTIC 1683 printf("%s: corrupted track (%d) data.\n", 1684 sc->dkdev.dk_dev.dv_xname, sc->cachetrk); 1685 #endif 1686 return(-1); 1687 } 1688 1689 /* 1690 * process sectors 1691 */ 1692 for (; cnt < sc->nsectors; cnt++) { 1693 hcksum = dcksum = 0; 1694 rp = mfmblkdecode(rp, &info, &hcksum, 1); 1695 rp = mfmblkdecode(rp, mfmnull, &hcksum, 4); 1696 rp = mfmblkdecode(rp, &cktmp, NULL, 1); 1697 if (cktmp != hcksum) { 1698 #ifdef FDDEBUG 1699 printf(" info 0x%x hchksum 0x%x trkhcksum 0x%x\n", 1700 info, hcksum, cktmp); 1701 #endif 1702 goto again; 1703 } 1704 if (((info >> 16) & 0xff) != sc->cachetrk) { 1705 #ifdef DEBUG 1706 printf("%s: incorrect track found: 0x%0x %d\n", 1707 sc->dkdev.dk_dev.dv_xname, info, sc->cachetrk); 1708 #endif 1709 goto again; 1710 } 1711 #ifdef FDDEBUG 1712 printf(" info 0x%x\n", info); 1713 #endif 1714 1715 rp = mfmblkdecode(rp, &cktmp, NULL, 1); 1716 dp = sc->cachep; 1717 dp += FDSECLWORDS * ((info >> 8) & 0xff); 1718 crp = mfmblkdecode(rp, dp, &dcksum, FDSECLWORDS); 1719 if (cktmp != dcksum) { 1720 #ifdef FDDEBUG 1721 printf(" info 0x%x dchksum 0x%x trkdcksum 0x%x\n", 1722 info, dcksum, cktmp); 1723 #endif 1724 goto again; 1725 } 1726 1727 /* 1728 * if we are at gap then we can no longer be sure 1729 * of correct sync marks 1730 */ 1731 if ((info && 0xff) == 1) 1732 doagain = 1; 1733 else 1734 doagain = 0; 1735 srp = rp = fdfindsync(crp, erp); 1736 } 1737 return(0); 1738 } 1739 1740 /* 1741 * encode len longwords of `dp' data in amiga mfm block format (`rp') 1742 * this format specified that the odd bits are at current pos and even 1743 * bits at len + current pos 1744 */ 1745 u_long * 1746 mfmblkencode(dp, rp, cp, len) 1747 u_long *dp, *rp, *cp; 1748 int len; 1749 { 1750 u_long *sdp, *edp, d, dtmp, correct; 1751 int i; 1752 1753 sdp = dp; 1754 edp = dp + len; 1755 1756 if (*(rp - 1) & 0x1) 1757 correct = 1; 1758 else 1759 correct = 0; 1760 /* 1761 * do odd bits 1762 */ 1763 while (dp < edp) { 1764 d = (*dp >> 1) & 0x55555555; /* remove clock bits */ 1765 dtmp = d ^ 0x55555555; 1766 d |= ((dtmp >> 1) | 0x80000000) & (dtmp << 1); 1767 /* 1768 * correct upper clock bit if needed 1769 */ 1770 if (correct) 1771 d &= 0x7fffffff; 1772 if (d & 0x1) 1773 correct = 1; 1774 else 1775 correct = 0; 1776 /* 1777 * do checksums and store in raw buffer 1778 */ 1779 if (cp) 1780 *cp ^= d; 1781 *rp++ = d; 1782 dp++; 1783 } 1784 /* 1785 * do even bits 1786 */ 1787 dp = sdp; 1788 while (dp < edp) { 1789 d = *dp & 0x55555555; /* remove clock bits */ 1790 dtmp = d ^ 0x55555555; 1791 d |= ((dtmp >> 1) | 0x80000000) & (dtmp << 1); 1792 /* 1793 * correct upper clock bit if needed 1794 */ 1795 if (correct) 1796 d &= 0x7fffffff; 1797 if (d & 0x1) 1798 correct = 1; 1799 else 1800 correct = 0; 1801 /* 1802 * do checksums and store in raw buffer 1803 */ 1804 if (cp) 1805 *cp ^= d; 1806 *rp++ = d; 1807 dp++; 1808 } 1809 if (cp) 1810 *cp &= 0x55555555; 1811 return(rp); 1812 } 1813 1814 /* 1815 * decode len longwords of `dp' data in amiga mfm block format (`rp') 1816 * this format specified that the odd bits are at current pos and even 1817 * bits at len + current pos 1818 */ 1819 u_long * 1820 mfmblkdecode(rp, dp, cp, len) 1821 u_long *rp, *dp, *cp; 1822 int len; 1823 { 1824 u_long o, e; 1825 int cnt; 1826 1827 cnt = len; 1828 while (cnt--) { 1829 o = *rp; 1830 e = *(rp + len); 1831 if (cp) { 1832 *cp ^= o; 1833 *cp ^= e; 1834 } 1835 o &= 0x55555555; 1836 e &= 0x55555555; 1837 *dp++ = (o << 1) | e; 1838 rp++; 1839 } 1840 if (cp) 1841 *cp &= 0x55555555; 1842 return(rp + len); 1843 } 1844