1 /* $NetBSD: fd.c,v 1.102 2026/08/14 10:46:09 andvar Exp $ */ 2 3 /* 4 * Copyright (c) 1995 Leo Weppelman. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 /* 29 * This file contains a driver for the Floppy Disk Controller (FDC) 30 * on the Atari TT. It uses the WD 1772 chip, modified for steprates. 31 * 32 * The ST floppy disk controller shares the access to the DMA circuitry 33 * with other devices. For this reason the floppy disk controller makes 34 * use of some special DMA accessing code. 35 * 36 * Interrupts from the FDC are in fact DMA interrupts which get their 37 * first level handling in 'dma.c' . If the floppy driver is currently 38 * using DMA the interrupt is signalled to 'fdcint'. 39 * 40 * TODO: 41 * - Test it with 2 drives (I don't have them) 42 * - Test it with an HD-drive (Don't have that either) 43 * - Finish ioctl's 44 */ 45 46 #include <sys/cdefs.h> 47 __KERNEL_RCSID(0, "$NetBSD: fd.c,v 1.102 2026/08/14 10:46:09 andvar Exp $"); 48 49 #include <sys/param.h> 50 #include <sys/systm.h> 51 #include <sys/callout.h> 52 #include <sys/kernel.h> 53 #include <sys/buf.h> 54 #include <sys/bufq.h> 55 #include <sys/proc.h> 56 #include <sys/device.h> 57 #include <sys/ioctl.h> 58 #include <sys/fcntl.h> 59 #include <sys/conf.h> 60 #include <sys/disklabel.h> 61 #include <sys/disk.h> 62 #include <atari/atari/device.h> 63 #include <atari/atari/stalloc.h> 64 #include <machine/disklabel.h> 65 #include <machine/iomap.h> 66 #include <machine/mfp.h> 67 #include <machine/dma.h> 68 #include <machine/video.h> 69 #include <machine/cpu.h> 70 #include <atari/dev/ym2149reg.h> 71 #include <atari/dev/fdreg.h> 72 73 #include "ioconf.h" 74 75 /* 76 * Be verbose for debugging 77 */ 78 /*#define FLP_DEBUG 1 */ 79 80 #define FDC_MAX_DMA_AD 0x1000000 /* No DMA possible beyond */ 81 82 /* Parameters for the disk drive. */ 83 #define SECTOR_SIZE 512 /* physical sector size in bytes */ 84 #define NR_DRIVES 2 /* maximum number of drives */ 85 #define NR_TYPES 3 /* number of diskette/drive combinations*/ 86 #define MAX_ERRORS 10 /* how often to try rd/wt before quitting*/ 87 #define STEP_DELAY 6000 /* 6ms (6000us) delay after stepping */ 88 89 90 #define INV_TRK 32000 /* Should fit in unsigned short */ 91 #define INV_PART NR_TYPES 92 93 /* 94 * Driver states 95 */ 96 #define FLP_IDLE 0x00 /* floppy is idle */ 97 #define FLP_MON 0x01 /* idle with motor on */ 98 #define FLP_STAT 0x02 /* determine floppy status */ 99 #define FLP_XFER 0x04 /* read/write data from floppy */ 100 101 /* 102 * Timer delay's 103 */ 104 #define FLP_MONDELAY (3 * hz) /* motor-on delay */ 105 #define FLP_XFERDELAY (2 * hz) /* timeout on transfer */ 106 107 /* 108 * The density codes 109 */ 110 #define FLP_DD 0 /* Double density */ 111 #define FLP_HD 1 /* High density */ 112 113 114 #define b_block b_resid /* FIXME: this is not the place */ 115 116 /* 117 * Global data for all physical floppy devices 118 */ 119 static short selected = 0; /* drive/head currently selected*/ 120 static short motoron = 0; /* motor is spinning */ 121 static short nopens = 0; /* Number of opens executed */ 122 123 static short fd_state = FLP_IDLE; /* Current driver state */ 124 static int lock_stat = 0; /* DMA locking status */ 125 static short fd_cmd = 0; /* command being executed */ 126 static const char *fd_error = NULL; /* error from fd_xfer_ok() */ 127 128 /* 129 * Private per device data 130 */ 131 struct fd_softc { 132 device_t sc_dev; /* generic device info */ 133 struct disk dkdev; /* generic disk info */ 134 struct bufq_state *bufq; /* queue of buf's */ 135 struct callout sc_motor_ch; 136 int unit; /* unit for atari controlling hw*/ 137 int nheads; /* number of heads in use */ 138 int nsectors; /* number of sectors/track */ 139 int density; /* density code */ 140 int nblocks; /* number of blocks on disk */ 141 int curtrk; /* track head positioned on */ 142 short flags; /* misc flags */ 143 short part; /* Current open partition */ 144 int sector; /* logical sector for I/O */ 145 uint8_t *io_data; /* KVA for data transfer */ 146 int io_bytes; /* bytes left for I/O */ 147 int io_dir; /* B_READ/B_WRITE */ 148 int errcnt; /* current error count */ 149 uint8_t *bounceb; /* Bounce buffer */ 150 151 }; 152 153 /* 154 * Flags in fd_softc: 155 */ 156 #define FLPF_NOTRESP 0x001 /* Unit not responding */ 157 #define FLPF_ISOPEN 0x002 /* Unit is open */ 158 #define FLPF_SPARE 0x004 /* Not used */ 159 #define FLPF_HAVELAB 0x008 /* We have a valid label */ 160 #define FLPF_BOUNCE 0x010 /* Now using the bounce buffer */ 161 #define FLPF_WRTPROT 0x020 /* Unit is write-protected */ 162 #define FLPF_EMPTY 0x040 /* Unit is empty */ 163 #define FLPF_INOPEN 0x080 /* Currently being opened */ 164 #define FLPF_GETSTAT 0x100 /* Getting unit status */ 165 166 struct fd_types { 167 int nheads; /* Heads in use */ 168 int nsectors; /* sectors per track */ 169 int nblocks; /* number of blocks */ 170 int density; /* density code */ 171 const char *descr; /* type description */ 172 } fdtypes[NR_TYPES] = { 173 { 1, 9, 720 , FLP_DD , "360KB" }, /* 360 Kb */ 174 { 2, 9, 1440 , FLP_DD , "720KB" }, /* 720 Kb */ 175 { 2, 18, 2880 , FLP_HD , "1.44MB" }, /* 1.44 Mb */ 176 }; 177 178 #define FLP_TYPE_360 0 /* XXX: Please keep these in */ 179 #define FLP_TYPE_720 1 /* sync with the numbering in */ 180 #define FLP_TYPE_144 2 /* 'fdtypes' right above! */ 181 182 /* 183 * This is set only once at attach time. The value is determined by reading 184 * the configuration switches and is one of the FLP_TYPE_*'s. 185 * This is similar to the way Atari handles the _FLP cookie. 186 */ 187 static short def_type = 0; /* Reflects config-switches */ 188 189 #define FLP_DEFTYPE 1 /* 720Kb, reasonable default */ 190 #define FLP_TYPE(dev) ( DISKPART(dev) == 0 ? def_type : DISKPART(dev) - 1 ) 191 192 typedef void (*FPV)(void *); 193 194 static dev_type_open(fdopen); 195 static dev_type_close(fdclose); 196 static dev_type_read(fdread); 197 static dev_type_write(fdwrite); 198 static dev_type_ioctl(fdioctl); 199 static dev_type_strategy(fdstrategy); 200 201 /* 202 * Private drive functions.... 203 */ 204 static void fdstart(struct fd_softc *); 205 static void fddone(struct fd_softc *); 206 static void fdstatus(struct fd_softc *); 207 static void fd_xfer(struct fd_softc *); 208 static void fdcint(struct fd_softc *); 209 static int fd_xfer_ok(struct fd_softc *); 210 static void fdmotoroff(struct fd_softc *); 211 static void fdminphys(struct buf *); 212 static void fdtestdrv(struct fd_softc *); 213 static void fdgetdefaultlabel(struct fd_softc *, struct disklabel *, 214 int); 215 static int fdgetdisklabel(struct fd_softc *, dev_t); 216 static int fdselect(int, int, int); 217 static void fddeselect(void); 218 static void fdmoff(struct fd_softc *); 219 220 static u_short rd_cfg_switch(void); 221 222 static inline uint8_t read_fdreg(u_short); 223 static inline void write_fdreg(u_short, u_short); 224 static inline uint8_t read_dmastat(void); 225 226 static inline 227 uint8_t read_fdreg(u_short regno) 228 { 229 230 DMA->dma_mode = regno; 231 return DMA->dma_data; 232 } 233 234 static inline 235 void write_fdreg(u_short regno, u_short val) 236 { 237 238 DMA->dma_mode = regno; 239 DMA->dma_data = val; 240 } 241 242 static inline 243 uint8_t read_dmastat(void) 244 { 245 246 DMA->dma_mode = FDC_CS | DMA_SCREG; 247 return DMA->dma_stat; 248 } 249 250 /* 251 * Config switch stuff. Used only for the floppy type for now. That's 252 * why it's here... 253 * XXX: If needed in more places, it should be moved to its own include file. 254 * Note: This location _must_ be read as an u_short. Failure to do so 255 * will return garbage! 256 */ 257 static u_short 258 rd_cfg_switch(void) 259 { 260 261 return *(volatile u_short *)AD_CFG_SWITCH; 262 } 263 264 /* 265 * Switch definitions. 266 * Note: ON reads as a zero bit! 267 */ 268 #define CFG_SWITCH_NOHD 0x4000 269 270 /* 271 * Autoconfig stuff.... 272 */ 273 static int fdcmatch(device_t, cfdata_t, void *); 274 static int fdcprint(void *, const char *); 275 static void fdcattach(device_t, device_t, void *); 276 277 CFATTACH_DECL_NEW(fdc, 0, 278 fdcmatch, fdcattach, NULL, NULL); 279 280 const struct bdevsw fd_bdevsw = { 281 .d_open = fdopen, 282 .d_close = fdclose, 283 .d_strategy = fdstrategy, 284 .d_ioctl = fdioctl, 285 .d_dump = nodump, 286 .d_psize = nosize, 287 .d_discard = nodiscard, 288 .d_flag = D_DISK 289 }; 290 291 const struct cdevsw fd_cdevsw = { 292 .d_open = fdopen, 293 .d_close = fdclose, 294 .d_read = fdread, 295 .d_write = fdwrite, 296 .d_ioctl = fdioctl, 297 .d_stop = nostop, 298 .d_tty = notty, 299 .d_poll = nopoll, 300 .d_mmap = nommap, 301 .d_kqfilter = nokqfilter, 302 .d_discard = nodiscard, 303 .d_flag = D_DISK 304 }; 305 306 static int 307 fdcmatch(device_t parent, cfdata_t match, void *aux) 308 { 309 static int fdc_matched = 0; 310 311 /* Match only once */ 312 if (strcmp("fdc", aux) || fdc_matched) 313 return 0; 314 fdc_matched = 1; 315 return 1; 316 } 317 318 static void 319 fdcattach(device_t parent, device_t self, void *aux) 320 { 321 struct fd_softc fdsoftc; 322 int i, nfound, first_found; 323 324 nfound = first_found = 0; 325 aprint_normal("\n"); 326 fddeselect(); 327 for (i = 0; i < NR_DRIVES; i++) { 328 329 /* 330 * Test if unit is present 331 */ 332 fdsoftc.unit = i; 333 fdsoftc.flags = 0; 334 st_dmagrab((dma_farg)fdcint, (dma_farg)fdtestdrv, &fdsoftc, 335 &lock_stat, 0, NULL); 336 st_dmafree(&fdsoftc, &lock_stat); 337 338 if ((fdsoftc.flags & FLPF_NOTRESP) == 0) { 339 if (nfound == 0) 340 first_found = i; 341 nfound++; 342 config_found(self, (void *)i, fdcprint, CFARGS_NONE); 343 } 344 } 345 346 if (nfound != 0) { 347 struct fd_softc *fdsc = 348 device_lookup_private(&fd_cd, first_found); 349 350 /* 351 * Make sure motor will be turned of when a floppy is 352 * inserted in the first selected drive. 353 */ 354 fdselect(first_found, 0, FLP_DD); 355 fd_state = FLP_MON; 356 callout_reset(&fdsc->sc_motor_ch, 0, (FPV)fdmotoroff, fdsc); 357 358 /* 359 * enable disk related interrupts 360 */ 361 MFP->mf_ierb |= IB_DINT; 362 MFP->mf_iprb = (uint8_t)~IB_DINT; 363 MFP->mf_imrb |= IB_DINT; 364 } 365 } 366 367 static int 368 fdcprint(void *aux, const char *pnp) 369 { 370 371 if (pnp != NULL) 372 aprint_normal("fd%d at %s:", (int)aux, pnp); 373 374 return UNCONF; 375 } 376 377 static int fdmatch(device_t, cfdata_t, void *); 378 static void fdattach(device_t, device_t, void *); 379 380 struct dkdriver fddkdriver = { 381 .d_strategy = fdstrategy 382 }; 383 384 CFATTACH_DECL_NEW(fd, sizeof(struct fd_softc), 385 fdmatch, fdattach, NULL, NULL); 386 387 static int 388 fdmatch(device_t parent, cfdata_t match, void *aux) 389 { 390 391 return 1; 392 } 393 394 static void 395 fdattach(device_t parent, device_t self, void *aux) 396 { 397 struct fd_softc *sc; 398 struct fd_types *type; 399 u_short swtch; 400 401 sc = device_private(self); 402 sc->sc_dev = self; 403 404 callout_init(&sc->sc_motor_ch, 0); 405 406 /* 407 * Find out if an Ajax chip might be installed. Set the default 408 * floppy type accordingly. 409 */ 410 swtch = rd_cfg_switch(); 411 def_type = (swtch & CFG_SWITCH_NOHD) ? FLP_TYPE_720 : FLP_TYPE_144; 412 type = &fdtypes[def_type]; 413 414 aprint_normal(": %s %d cyl, %d head, %d sec\n", type->descr, 415 type->nblocks / (type->nsectors * type->nheads), type->nheads, 416 type->nsectors); 417 418 /* 419 * Initialize and attach the disk structure. 420 */ 421 disk_init(&sc->dkdev, device_xname(sc->sc_dev), &fddkdriver); 422 disk_attach(&sc->dkdev); 423 } 424 425 static int 426 fdioctl(dev_t dev, u_long cmd, void * addr, int flag, struct lwp *l) 427 { 428 struct fd_softc *sc; 429 int error; 430 431 sc = device_lookup_private(&fd_cd, DISKUNIT(dev)); 432 433 if ((sc->flags & FLPF_HAVELAB) == 0) 434 return EBADF; 435 436 error = disk_ioctl(&sc->dkdev, RAW_PART, cmd, addr, flag, l); 437 if (error != EPASSTHROUGH) 438 return error; 439 440 switch (cmd) { 441 #ifdef notyet /* XXX LWP */ 442 case DIOCSRETRIES: 443 case DIOCSSTEP: 444 case DIOCSDINFO: 445 case DIOCWDINFO: 446 case DIOCWLABEL: 447 break; 448 #endif /* notyet */ 449 case DIOCGDEFLABEL: 450 fdgetdefaultlabel(sc, (struct disklabel *)addr, RAW_PART); 451 return 0; 452 } 453 return ENOTTY; 454 } 455 456 /* 457 * Open the device. If this is the first open on both the floppy devices, 458 * initialize the controller. 459 * Note that partition info on the floppy device is used to distinguish 460 * between 780Kb and 360Kb floppy's. 461 * partition 0: 360Kb 462 * partition 1: 780Kb 463 */ 464 static int 465 fdopen(dev_t dev, int flags, int devtype, struct lwp *l) 466 { 467 struct fd_softc *sc; 468 int s; 469 470 #ifdef FLP_DEBUG 471 printf("fdopen dev=0x%llx\n", dev); 472 #endif 473 474 if (FLP_TYPE(dev) >= NR_TYPES) 475 return ENXIO; 476 477 if ((sc = device_lookup_private(&fd_cd, DISKUNIT(dev))) == NULL) 478 return ENXIO; 479 480 /* 481 * If no floppy currently open, reset the controller and select 482 * floppy type. 483 */ 484 if (nopens == 0) { 485 486 #ifdef FLP_DEBUG 487 printf("fdopen device not yet open\n"); 488 #endif 489 nopens++; 490 write_fdreg(FDC_CS, IRUPT); 491 delay(40); 492 } 493 494 /* 495 * Sleep while other process is opening the device 496 */ 497 s = splbio(); 498 while (sc->flags & FLPF_INOPEN) 499 tsleep((void *)sc, PRIBIO, "fdopen", 0); 500 splx(s); 501 502 if ((sc->flags & FLPF_ISOPEN) == 0) { 503 /* 504 * Initialise some driver values. 505 */ 506 int type; 507 void *addr; 508 509 type = FLP_TYPE(dev); 510 511 bufq_alloc(&sc->bufq, "disksort", BUFQ_SORT_RAWBLOCK); 512 sc->unit = DISKUNIT(dev); 513 sc->part = RAW_PART; 514 sc->nheads = fdtypes[type].nheads; 515 sc->nsectors = fdtypes[type].nsectors; 516 sc->nblocks = fdtypes[type].nblocks; 517 sc->density = fdtypes[type].density; 518 sc->curtrk = INV_TRK; 519 sc->sector = 0; 520 sc->errcnt = 0; 521 sc->bounceb = alloc_stmem(SECTOR_SIZE, &addr); 522 if (sc->bounceb == NULL) 523 return ENOMEM; /* XXX */ 524 525 /* 526 * Go get write protect + loaded status 527 */ 528 sc->flags |= FLPF_INOPEN|FLPF_GETSTAT; 529 s = splbio(); 530 st_dmagrab((dma_farg)fdcint, (dma_farg)fdstatus, sc, 531 &lock_stat, 0, NULL); 532 while ((sc->flags & FLPF_GETSTAT) != 0) 533 tsleep((void *)sc, PRIBIO, "fdopen", 0); 534 splx(s); 535 wakeup((void *)sc); 536 537 if ((sc->flags & FLPF_WRTPROT) != 0 && 538 (flags & FWRITE) != 0) { 539 sc->flags = 0; 540 return EPERM; 541 } 542 if ((sc->flags & FLPF_EMPTY) != 0) { 543 sc->flags = 0; 544 return ENXIO; 545 } 546 sc->flags &= ~(FLPF_INOPEN|FLPF_GETSTAT); 547 sc->flags |= FLPF_ISOPEN; 548 } else { 549 /* 550 * Multiply opens are granted when accessing the same type of 551 * floppy (eq. the same partition). 552 */ 553 if (sc->density != fdtypes[DISKPART(dev)].density) 554 return ENXIO; /* XXX temporarily out of business */ 555 } 556 fdgetdisklabel(sc, dev); 557 #ifdef FLP_DEBUG 558 printf("fdopen open succeeded on type %d\n", sc->part); 559 #endif 560 return 0; 561 } 562 563 static int 564 fdclose(dev_t dev, int flags, int devtype, struct lwp *l) 565 { 566 struct fd_softc *sc; 567 568 sc = device_lookup_private(&fd_cd, DISKUNIT(dev)); 569 free_stmem(sc->bounceb); 570 sc->flags = 0; 571 nopens--; 572 573 #ifdef FLP_DEBUG 574 printf("Closed floppy device -- nopens: %d\n", nopens); 575 #endif 576 return 0; 577 } 578 579 static void 580 fdstrategy(struct buf *bp) 581 { 582 struct fd_softc *sc; 583 struct disklabel *lp; 584 int s, sz; 585 586 sc = device_lookup_private(&fd_cd, DISKUNIT(bp->b_dev)); 587 588 #ifdef FLP_DEBUG 589 printf("fdstrategy: %p, b_bcount: %d\n", bp, bp->b_bcount); 590 #endif 591 592 /* 593 * check for valid partition and bounds 594 */ 595 lp = sc->dkdev.dk_label; 596 if ((sc->flags & FLPF_HAVELAB) == 0) { 597 bp->b_error = EIO; 598 goto done; 599 } 600 if (bp->b_blkno < 0 || (bp->b_bcount % SECTOR_SIZE) != 0) { 601 bp->b_error = EINVAL; 602 goto done; 603 } 604 if (bp->b_bcount == 0) 605 goto done; 606 607 sz = howmany(bp->b_bcount, SECTOR_SIZE); 608 609 if (bp->b_blkno + sz > sc->nblocks) { 610 sz = sc->nblocks - bp->b_blkno; 611 if (sz == 0) /* Exactly at EndOfDisk */ 612 goto done; 613 if (sz < 0) { /* Past EndOfDisk */ 614 bp->b_error = EINVAL; 615 goto done; 616 } 617 /* Truncate it */ 618 if (bp->b_flags & B_RAW) 619 bp->b_bcount = sz << DEV_BSHIFT; 620 else 621 bp->b_bcount = sz * lp->d_secsize; 622 } 623 624 /* No partition translation. */ 625 bp->b_rawblkno = bp->b_blkno; 626 627 /* 628 * queue the buf and kick the low level code 629 */ 630 s = splbio(); 631 bufq_put(sc->bufq, bp); /* XXX disksort_cylinder */ 632 if (!lock_stat) { 633 if (fd_state & FLP_MON) 634 callout_stop(&sc->sc_motor_ch); 635 fd_state = FLP_IDLE; 636 st_dmagrab((dma_farg)fdcint, (dma_farg)fdstart, sc, 637 &lock_stat, 0, NULL); 638 } 639 splx(s); 640 641 return; 642 done: 643 bp->b_resid = bp->b_bcount; 644 biodone(bp); 645 } 646 647 static int 648 fdread(dev_t dev, struct uio *uio, int flags) 649 { 650 651 return physio(fdstrategy, NULL, dev, B_READ, fdminphys, uio); 652 } 653 654 static int 655 fdwrite(dev_t dev, struct uio *uio, int flags) 656 { 657 658 return physio(fdstrategy, NULL, dev, B_WRITE, fdminphys, uio); 659 } 660 661 /* 662 * Called through DMA-dispatcher, get status. 663 */ 664 static void 665 fdstatus(struct fd_softc *sc) 666 { 667 668 #ifdef FLP_DEBUG 669 printf("fdstatus\n"); 670 #endif 671 sc->errcnt = 0; 672 fd_state = FLP_STAT; 673 fd_xfer(sc); 674 } 675 676 /* 677 * Called through the DMA-dispatcher. So we know we are the only ones 678 * messing with the floppy-controller. 679 * Initialize some fields in the fdsoftc for the state-machine and get 680 * it going. 681 */ 682 static void 683 fdstart(struct fd_softc *sc) 684 { 685 struct buf *bp; 686 687 bp = bufq_peek(sc->bufq); 688 sc->sector = bp->b_blkno; /* Start sector for I/O */ 689 sc->io_data = bp->b_data; /* KVA base for I/O */ 690 sc->io_bytes = bp->b_bcount; /* Transfer size in bytes */ 691 sc->io_dir = bp->b_flags & B_READ;/* Direction of transfer */ 692 sc->errcnt = 0; /* No errors yet */ 693 fd_state = FLP_XFER; /* Yes, we're going to transfer */ 694 695 /* Instrumentation. */ 696 disk_busy(&sc->dkdev); 697 698 fd_xfer(sc); 699 } 700 701 /* 702 * The current transaction is finished (for good or bad). Let go of 703 * the DMA-resources. Call biodone() to finish the transaction. 704 * Find a new transaction to work on. 705 */ 706 static void 707 fddone(register struct fd_softc *sc) 708 { 709 struct buf *bp; 710 struct fd_softc *sc1; 711 int i, s; 712 713 /* 714 * Give others a chance to use the DMA. 715 */ 716 st_dmafree(sc, &lock_stat); 717 718 719 if (fd_state != FLP_STAT) { 720 /* 721 * Finish current transaction. 722 */ 723 s = splbio(); 724 bp = bufq_get(sc->bufq); 725 if (bp == NULL) 726 panic("fddone"); 727 splx(s); 728 729 #ifdef FLP_DEBUG 730 printf("fddone: unit: %d, buf: %p, resid: %d\n",sc->unit, bp, 731 sc->io_bytes); 732 #endif 733 bp->b_resid = sc->io_bytes; 734 735 disk_unbusy(&sc->dkdev, (bp->b_bcount - bp->b_resid), 736 (bp->b_flags & B_READ)); 737 738 biodone(bp); 739 } 740 fd_state = FLP_MON; 741 742 if (lock_stat) 743 return; /* XXX Is this possible? */ 744 745 /* 746 * Find a new transaction on round-robin basis. 747 */ 748 for (i = sc->unit + 1;; i++) { 749 if (i >= fd_cd.cd_ndevs) 750 i = 0; 751 if ((sc1 = device_lookup_private(&fd_cd, i)) == NULL) 752 continue; 753 if (bufq_peek(sc1->bufq) != NULL) 754 break; 755 if (i == sc->unit) { 756 callout_reset(&sc->sc_motor_ch, FLP_MONDELAY, 757 (FPV)fdmotoroff, sc); 758 #ifdef FLP_DEBUG 759 printf("fddone: Nothing to do\n"); 760 #endif 761 return; /* No work */ 762 } 763 } 764 fd_state = FLP_IDLE; 765 #ifdef FLP_DEBUG 766 printf("fddone: Starting job on unit %d\n", sc1->unit); 767 #endif 768 st_dmagrab((dma_farg)fdcint, (dma_farg)fdstart, sc1, &lock_stat, 0, 769 NULL); 770 } 771 772 static int 773 fdselect(int drive, int head, int dense) 774 { 775 int i, spinning; 776 777 #ifdef FLP_DEBUG 778 printf("fdselect: drive=%d, head=%d, dense=%d\n", drive, head, dense); 779 #endif 780 i = ((drive == 1) ? PA_FLOP1 : PA_FLOP0) | head; 781 spinning = motoron; 782 motoron = 1; 783 784 switch (dense) { 785 case FLP_DD: 786 DMA->dma_drvmode = 0; 787 break; 788 case FLP_HD: 789 DMA->dma_drvmode = (FDC_HDSET|FDC_HDSIG); 790 break; 791 default: 792 panic("fdselect: unknown density code"); 793 } 794 if (i != selected) { 795 selected = i; 796 ym2149_fd_select((i ^ PA_FDSEL)); 797 } 798 return spinning; 799 } 800 801 static void 802 fddeselect(void) 803 { 804 805 ym2149_fd_select(PA_FDSEL); 806 motoron = selected = 0; 807 DMA->dma_drvmode = 0; 808 } 809 810 /**************************************************************************** 811 * The following functions assume to be running as a result of a * 812 * disk-interrupt (e.q. spl = splbio). * 813 * They form the finit-state machine, the actual driver. * 814 * * 815 * fdstart()/ --> fd_xfer() -> activate hardware * 816 * fdopen() ^ * 817 * | * 818 * +-- not ready -<------------+ * 819 * | * 820 * fdmotoroff()/ --> fdcint() -> fd_xfer_ok() ---+ * 821 * h/w interrupt | * 822 * \|/ * 823 * finished ---> fdone() * 824 * * 825 ****************************************************************************/ 826 static void 827 fd_xfer(struct fd_softc *sc) 828 { 829 int head; 830 int track, sector, hbit; 831 paddr_t phys_addr; 832 833 head = track = 0; 834 switch (fd_state) { 835 case FLP_XFER: 836 /* 837 * Calculate head/track values 838 */ 839 track = sc->sector / sc->nsectors; 840 head = track % sc->nheads; 841 track = track / sc->nheads; 842 #ifdef FLP_DEBUG 843 printf("fd_xfer: sector:%d,head:%d,track:%d\n", 844 sc->sector, head, track); 845 #endif 846 break; 847 848 case FLP_STAT: 849 /* 850 * FLP_STAT only wants to recalibrate 851 */ 852 sc->curtrk = INV_TRK; 853 break; 854 default: 855 panic("fd_xfer: wrong state (0x%x)", fd_state); 856 } 857 858 /* 859 * Select the drive. 860 */ 861 hbit = fdselect(sc->unit, head, sc->density) ? HBIT : 0; 862 863 if (sc->curtrk == INV_TRK) { 864 /* 865 * Recalibrate, since we lost track of head positioning. 866 * The floppy disk controller has no way of determining its 867 * absolute arm position (track). Instead, it steps the 868 * arm a track at a time and keeps track of where it 869 * thinks it is (in software). However, after a SEEK, the 870 * hardware reads information from the diskette telling 871 * where the arm actually is. If the arm is in the wrong place, 872 * a recalibration is done, which forces the arm to track 0. 873 * This way the controller can get back into sync with reality. 874 */ 875 fd_cmd = RESTORE; 876 write_fdreg(FDC_CS, RESTORE|VBIT|hbit); 877 callout_reset(&sc->sc_motor_ch, FLP_XFERDELAY, 878 (FPV)fdmotoroff, sc); 879 880 #ifdef FLP_DEBUG 881 printf("fd_xfer:Recalibrating drive %d\n", sc->unit); 882 #endif 883 return; 884 } 885 886 write_fdreg(FDC_TR, sc->curtrk); 887 888 /* 889 * Issue a SEEK command on the indicated drive unless the arm is 890 * already positioned on the correct track. 891 */ 892 if (track != sc->curtrk) { 893 sc->curtrk = track; /* be optimistic */ 894 write_fdreg(FDC_DR, track); 895 write_fdreg(FDC_CS, SEEK|RATE6|VBIT|hbit); 896 callout_reset(&sc->sc_motor_ch, FLP_XFERDELAY, 897 (FPV)fdmotoroff, sc); 898 fd_cmd = SEEK; 899 #ifdef FLP_DEBUG 900 printf("fd_xfer:Seek to track %d on drive %d\n", 901 track, sc->unit); 902 #endif 903 return; 904 } 905 906 /* 907 * The drive is now on the proper track. Read or write 1 block. 908 */ 909 sector = sc->sector % sc->nsectors; 910 sector++; /* start numbering at 1 */ 911 912 write_fdreg(FDC_SR, sector); 913 914 phys_addr = (paddr_t)kvtop(sc->io_data); 915 if (phys_addr >= FDC_MAX_DMA_AD) { 916 /* 917 * We _must_ bounce this address 918 */ 919 phys_addr = (paddr_t)kvtop(sc->bounceb); 920 if (sc->io_dir == B_WRITE) 921 memcpy(sc->bounceb, sc->io_data, SECTOR_SIZE); 922 sc->flags |= FLPF_BOUNCE; 923 } 924 st_dmaaddr_set((void *)phys_addr); /* DMA address setup */ 925 926 #ifdef FLP_DEBUG 927 printf("fd_xfer:Start io (io_addr:%lx)\n", (u_long)kvtop(sc->io_data)); 928 #endif 929 930 if (sc->io_dir == B_READ) { 931 /* Issue the command */ 932 st_dmacomm(DMA_FDC | DMA_SCREG, 1); 933 write_fdreg(FDC_CS, F_READ|hbit); 934 fd_cmd = F_READ; 935 } else { 936 /* Issue the command */ 937 st_dmacomm(DMA_WRBIT | DMA_FDC | DMA_SCREG, 1); 938 write_fdreg(DMA_WRBIT | FDC_CS, F_WRITE|hbit|EBIT|PBIT); 939 fd_cmd = F_WRITE; 940 } 941 callout_reset(&sc->sc_motor_ch, FLP_XFERDELAY, (FPV)fdmotoroff, sc); 942 } 943 944 /* return values of fd_xfer_ok(): */ 945 #define X_OK 0 946 #define X_AGAIN 1 947 #define X_ERROR 2 948 #define X_FAIL 3 949 950 /* 951 * Hardware interrupt function. 952 */ 953 static void 954 fdcint(struct fd_softc *sc) 955 { 956 struct buf *bp; 957 958 #ifdef FLP_DEBUG 959 printf("fdcint: unit = %d\n", sc->unit); 960 #endif 961 962 /* 963 * Cancel timeout (we made it, didn't we) 964 */ 965 callout_stop(&sc->sc_motor_ch); 966 967 switch (fd_xfer_ok(sc)) { 968 case X_ERROR: 969 if (++sc->errcnt < MAX_ERRORS) { 970 /* 971 * Command failed but still retries left. 972 */ 973 break; 974 } 975 /* FALL THROUGH */ 976 case X_FAIL: 977 /* 978 * Non recoverable error. Fall back to motor-on 979 * idle-state. 980 */ 981 if (fd_error != NULL) { 982 printf("Floppy error: %s\n", fd_error); 983 fd_error = NULL; 984 } 985 986 if (fd_state == FLP_STAT) { 987 sc->flags |= FLPF_EMPTY; 988 sc->flags &= ~FLPF_GETSTAT; 989 wakeup((void *)sc); 990 fddone(sc); 991 return; 992 } 993 994 bp = bufq_peek(sc->bufq); 995 996 bp->b_error = EIO; 997 fd_state = FLP_MON; 998 999 break; 1000 case X_AGAIN: 1001 /* 1002 * Start next part of state machine. 1003 */ 1004 break; 1005 case X_OK: 1006 /* 1007 * Command ok and finished. Reset error-counter. 1008 * If there are no more bytes to transfer fall back 1009 * to motor-on idle state. 1010 */ 1011 sc->errcnt = 0; 1012 1013 if (fd_state == FLP_STAT) { 1014 sc->flags &= ~FLPF_GETSTAT; 1015 wakeup((void *)sc); 1016 fddone(sc); 1017 return; 1018 } 1019 1020 if ((sc->flags & FLPF_BOUNCE) != 0 && 1021 sc->io_dir == B_READ) 1022 memcpy(sc->io_data, sc->bounceb, SECTOR_SIZE); 1023 sc->flags &= ~FLPF_BOUNCE; 1024 1025 sc->sector++; 1026 sc->io_data += SECTOR_SIZE; 1027 sc->io_bytes -= SECTOR_SIZE; 1028 if (sc->io_bytes <= 0) 1029 fd_state = FLP_MON; 1030 } 1031 if (fd_state == FLP_MON) 1032 fddone(sc); 1033 else 1034 fd_xfer(sc); 1035 } 1036 1037 /* 1038 * Determine status of last command. Should only be called through 1039 * 'fdcint()'. 1040 * Returns: 1041 * X_ERROR : Error on command; might succeed next time. 1042 * X_FAIL : Error on command; will never succeed. 1043 * X_AGAIN : Part of a command succeeded, call 'fd_xfer()' to complete. 1044 * X_OK : Command succeeded and is complete. 1045 * 1046 * This function only affects sc->curtrk. 1047 */ 1048 static int 1049 fd_xfer_ok(register struct fd_softc *sc) 1050 { 1051 int status; 1052 1053 #ifdef FLP_DEBUG 1054 printf("fd_xfer_ok: cmd: 0x%x, state: 0x%x\n", fd_cmd, fd_state); 1055 #endif 1056 switch (fd_cmd) { 1057 case IRUPT: 1058 /* 1059 * Timeout. Force a recalibrate before we try again. 1060 */ 1061 status = read_fdreg(FDC_CS); 1062 1063 fd_error = "Timeout"; 1064 sc->curtrk = INV_TRK; 1065 return X_ERROR; 1066 case F_READ: 1067 /* 1068 * Test for DMA error 1069 */ 1070 status = read_dmastat(); 1071 if ((status & DMAOK) == 0) { 1072 fd_error = "DMA error"; 1073 return X_ERROR; 1074 } 1075 /* 1076 * Get controller status and check for errors. 1077 */ 1078 status = read_fdreg(FDC_CS); 1079 if ((status & (RNF | CRCERR | LD_T00)) != 0) { 1080 fd_error = "Read error"; 1081 if ((status & RNF) != 0) 1082 sc->curtrk = INV_TRK; 1083 return X_ERROR; 1084 } 1085 break; 1086 case F_WRITE: 1087 /* 1088 * Test for DMA error 1089 */ 1090 status = read_dmastat(); 1091 if ((status & DMAOK) == 0) { 1092 fd_error = "DMA error"; 1093 return X_ERROR; 1094 } 1095 /* 1096 * Get controller status and check for errors. 1097 */ 1098 status = read_fdreg(FDC_CS); 1099 if ((status & WRI_PRO) != 0) { 1100 fd_error = "Write protected"; 1101 return X_FAIL; 1102 } 1103 if ((status & (RNF | CRCERR | LD_T00)) != 0) { 1104 fd_error = "Write error"; 1105 sc->curtrk = INV_TRK; 1106 return X_ERROR; 1107 } 1108 break; 1109 case SEEK: 1110 status = read_fdreg(FDC_CS); 1111 if ((status & (RNF | CRCERR)) != 0) { 1112 fd_error = "Seek error"; 1113 sc->curtrk = INV_TRK; 1114 return X_ERROR; 1115 } 1116 return X_AGAIN; 1117 case RESTORE: 1118 /* 1119 * Determine if the recalibration succeeded. 1120 */ 1121 status = read_fdreg(FDC_CS); 1122 if ((status & RNF) != 0) { 1123 fd_error = "Recalibrate error"; 1124 /* reset controller */ 1125 write_fdreg(FDC_CS, IRUPT); 1126 sc->curtrk = INV_TRK; 1127 return X_ERROR; 1128 } 1129 sc->curtrk = 0; 1130 if (fd_state == FLP_STAT) { 1131 if ((status & WRI_PRO) != 0) 1132 sc->flags |= FLPF_WRTPROT; 1133 break; 1134 } 1135 return X_AGAIN; 1136 default: 1137 fd_error = "Driver error: fd_xfer_ok : Unknown state"; 1138 return X_FAIL; 1139 } 1140 return X_OK; 1141 } 1142 1143 /* 1144 * All timeouts will call this function. 1145 */ 1146 static void 1147 fdmotoroff(struct fd_softc *sc) 1148 { 1149 int s; 1150 1151 /* 1152 * Get at hardware interrupt level 1153 */ 1154 s = splbio(); 1155 1156 #if FLP_DEBUG 1157 printf("fdmotoroff, state = 0x%x\n", fd_state); 1158 #endif 1159 1160 switch (fd_state) { 1161 case FLP_STAT: 1162 case FLP_XFER: 1163 /* 1164 * Timeout during a transfer; cancel transaction 1165 * set command to 'IRUPT'. 1166 * A drive-interrupt is simulated to trigger the state 1167 * machine. 1168 */ 1169 /* 1170 * Cancel current transaction 1171 */ 1172 fd_cmd = IRUPT; 1173 write_fdreg(FDC_CS, IRUPT); 1174 delay(20); 1175 (void)read_fdreg(FDC_CS); 1176 write_fdreg(FDC_CS, RESTORE); 1177 break; 1178 1179 case FLP_MON: 1180 /* 1181 * Turn motor off. 1182 */ 1183 if (selected) { 1184 int tmp; 1185 1186 st_dmagrab((dma_farg)fdcint, (dma_farg)fdmoff, sc, 1187 &tmp, 0, NULL); 1188 } else 1189 fd_state = FLP_IDLE; 1190 break; 1191 } 1192 splx(s); 1193 } 1194 1195 /* 1196 * min byte count to whats left of the track in question 1197 */ 1198 static void 1199 fdminphys(struct buf *bp) 1200 { 1201 struct fd_softc *sc; 1202 int sec, toff, tsz; 1203 1204 if ((sc = device_lookup_private(&fd_cd, DISKUNIT(bp->b_dev))) == NULL) 1205 panic("fdminphys: couldn't get softc"); 1206 1207 sec = bp->b_blkno % (sc->nsectors * sc->nheads); 1208 toff = sec * SECTOR_SIZE; 1209 tsz = sc->nsectors * sc->nheads * SECTOR_SIZE; 1210 1211 #ifdef FLP_DEBUG 1212 printf("fdminphys: before %d", bp->b_bcount); 1213 #endif 1214 1215 bp->b_bcount = uimin(bp->b_bcount, tsz - toff); 1216 1217 #ifdef FLP_DEBUG 1218 printf(" after %d\n", bp->b_bcount); 1219 #endif 1220 1221 minphys(bp); 1222 } 1223 1224 /* 1225 * Called from fdmotoroff to turn the motor actually off.... 1226 * This can't be done in fdmotoroff itself, because exclusive access to the 1227 * DMA controller is needed to read the FDC-status register. The function 1228 * 'fdmoff()' always runs as the result of a 'dmagrab()'. 1229 * We need to test the status-register because we want to be sure that the 1230 * drive motor is really off before deselecting the drive. The FDC only 1231 * turns off the drive motor after having seen 10 index-pulses. You only 1232 * get index-pulses when a drive is selected....This means that if the 1233 * drive is deselected when the motor is still spinning, it will continue 1234 * to spin _even_ when you insert a floppy later on... 1235 */ 1236 static void 1237 fdmoff(struct fd_softc *fdsoftc) 1238 { 1239 int tmp; 1240 1241 if ((fd_state == FLP_MON) && selected) { 1242 tmp = read_fdreg(FDC_CS); 1243 if ((tmp & MOTORON) == 0) { 1244 fddeselect(); 1245 fd_state = FLP_IDLE; 1246 } else 1247 callout_reset(&fdsoftc->sc_motor_ch, 10 * FLP_MONDELAY, 1248 (FPV)fdmotoroff, fdsoftc); 1249 } 1250 st_dmafree(fdsoftc, &tmp); 1251 } 1252 1253 /* 1254 * Used to find out which drives are actually connected. We do this by issuing 1255 * is 'RESTORE' command and check if the 'track-0' bit is set. This also works 1256 * if the drive is present but no floppy is inserted. 1257 */ 1258 static void 1259 fdtestdrv(struct fd_softc *fdsoftc) 1260 { 1261 int status; 1262 1263 /* 1264 * Select the right unit and head. 1265 */ 1266 fdselect(fdsoftc->unit, 0, FLP_DD); 1267 1268 write_fdreg(FDC_CS, RESTORE|HBIT); 1269 1270 /* 1271 * Wait for about 2 seconds. 1272 */ 1273 delay(2000000); 1274 1275 status = read_fdreg(FDC_CS); 1276 if ((status & (RNF|BUSY)) != 0) { 1277 write_fdreg(FDC_CS, IRUPT); /* reset controller */ 1278 delay(40); 1279 } 1280 1281 if ((status & LD_T00) == 0) 1282 fdsoftc->flags |= FLPF_NOTRESP; 1283 1284 fddeselect(); 1285 } 1286 1287 static void 1288 fdgetdefaultlabel(struct fd_softc *sc, struct disklabel *lp, int part) 1289 { 1290 1291 memset(lp, 0, sizeof(struct disklabel)); 1292 1293 lp->d_secsize = SECTOR_SIZE; 1294 lp->d_ntracks = sc->nheads; 1295 lp->d_nsectors = sc->nsectors; 1296 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 1297 lp->d_ncylinders = sc->nblocks / lp->d_secpercyl; 1298 lp->d_secperunit = sc->nblocks; 1299 1300 lp->d_type = DKTYPE_FLOPPY; 1301 lp->d_rpm = 300; /* good guess I suppose. */ 1302 lp->d_interleave = 1; /* FIXME: is this OK? */ 1303 lp->d_bbsize = 0; 1304 lp->d_sbsize = 0; 1305 lp->d_npartitions = part + 1; 1306 lp->d_trkseek = STEP_DELAY; 1307 lp->d_magic = DISKMAGIC; 1308 lp->d_magic2 = DISKMAGIC; 1309 lp->d_checksum = dkcksum(lp); 1310 lp->d_partitions[part].p_size = lp->d_secperunit; 1311 lp->d_partitions[part].p_fstype = FS_UNUSED; 1312 lp->d_partitions[part].p_fsize = 1024; 1313 lp->d_partitions[part].p_frag = 8; 1314 } 1315 1316 /* 1317 * Build disk label. For now we only create a label from what we know 1318 * from 'sc'. 1319 */ 1320 static int 1321 fdgetdisklabel(struct fd_softc *sc, dev_t dev) 1322 { 1323 struct disklabel *lp; 1324 int part; 1325 1326 /* 1327 * If we already got one, get out. 1328 */ 1329 if ((sc->flags & FLPF_HAVELAB) != 0) 1330 return 0; 1331 1332 #ifdef FLP_DEBUG 1333 printf("fdgetdisklabel()\n"); 1334 #endif 1335 1336 part = RAW_PART; 1337 lp = sc->dkdev.dk_label; 1338 fdgetdefaultlabel(sc, lp, part); 1339 sc->flags |= FLPF_HAVELAB; 1340 1341 return 0; 1342 } 1343