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