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