1/* $NetBSD: fd.c,v 1.40 2009/09/27 05:29:20 tsutsui Exp $ */ 2/* $OpenBSD: fd.c,v 1.6 1998/10/03 21:18:57 millert Exp $ */ 3/* NetBSD: fd.c,v 1.78 1995/07/04 07:23:09 mycroft Exp */ 4 5/*- 6 * Copyright (c) 1998 The NetBSD Foundation, Inc. 7 * All rights reserved. 8 * 9 * This code is derived from software contributed to The NetBSD Foundation 10 * by Charles M. Hannum. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34/*- 35 * Copyright (c) 1990 The Regents of the University of California. 36 * All rights reserved. 37 * 38 * This code is derived from software contributed to Berkeley by 39 * Don Ahn. 40 * 41 * Redistribution and use in source and binary forms, with or without 42 * modification, are permitted provided that the following conditions 43 * are met: 44 * 1. Redistributions of source code must retain the above copyright 45 * notice, this list of conditions and the following disclaimer. 46 * 2. Redistributions in binary form must reproduce the above copyright 47 * notice, this list of conditions and the following disclaimer in the 48 * documentation and/or other materials provided with the distribution. 49 * 3. Neither the name of the University nor the names of its contributors 50 * may be used to endorse or promote products derived from this software 51 * without specific prior written permission. 52 * 53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 63 * SUCH DAMAGE. 64 * 65 * @(#)fd.c 7.4 (Berkeley) 5/25/91 66 */ 67 68#include <sys/cdefs.h> 69__KERNEL_RCSID(0, "$NetBSD: fd.c,v 1.40 2009/09/27 05:29:20 tsutsui Exp $"); 70 71#include <sys/param.h> 72#include <sys/systm.h> 73#include <sys/callout.h> 74#include <sys/kernel.h> 75#include <sys/conf.h> 76#include <sys/file.h> 77#include <sys/ioctl.h> 78#include <sys/device.h> 79#include <sys/disklabel.h> 80#include <sys/disk.h> 81#include <sys/buf.h> 82#include <sys/bufq.h> 83#include <sys/uio.h> 84#include <sys/syslog.h> 85#include <sys/queue.h> 86 87#include <uvm/uvm_extern.h> 88 89#include <dev/cons.h> 90 91#include <sys/bus.h> 92#include <machine/cpu.h> 93 94#include <arc/jazz/fdreg.h> 95#include <arc/jazz/fdcvar.h> 96 97#include "ioconf.h" 98#include "locators.h" 99 100#define FDUNIT(dev) DISKUNIT(dev) 101#define FDTYPE(dev) DISKPART(dev) 102 103/* controller driver configuration */ 104static int fdprint(void *, const char *); 105 106/* 107 * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how 108 * we tell them apart. 109 */ 110struct fd_type { 111 int sectrac; /* sectors per track */ 112 int heads; /* number of heads */ 113 int seccyl; /* sectors per cylinder */ 114 int secsize; /* size code for sectors */ 115 int datalen; /* data len when secsize = 0 */ 116 int steprate; /* step rate and head unload time */ 117 int gap1; /* gap len between sectors */ 118 int gap2; /* formatting gap */ 119 int cyls; /* total num of cylinders */ 120 int size; /* size of disk in sectors */ 121 int step; /* steps per cylinder */ 122 int rate; /* transfer speed code */ 123 const char *name; 124}; 125 126/* The order of entries in the following table is important -- BEWARE! */ 127const static struct fd_type fd_types[] = { 128 /* 1.44MB diskette */ 129 { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS,"1.44MB" }, 130 /* 1.2 MB AT-diskettes */ 131 { 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS, "1.2MB" }, 132 /* 360kB in 1.2MB drive */ 133 { 9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS, "360KB/AT" }, 134 /* 360kB PC diskettes */ 135 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS, "360KB/PC" }, 136 /* 3.5" 720kB diskette */ 137 { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS, "720KB" }, 138 /* 720kB in 1.2MB drive */ 139 { 9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS, "720KB/x" }, 140 /* 360kB in 720kB drive */ 141 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS, "360KB/x" }, 142}; 143 144/* software state, per disk (with up to 4 disks per ctlr) */ 145struct fd_softc { 146 device_t sc_dev; 147 struct disk sc_dk; 148 149 const struct fd_type *sc_deftype; /* default type descriptor */ 150 struct fd_type *sc_type; /* current type descriptor */ 151 struct fd_type sc_type_copy; /* copy for fiddling when formatting */ 152 153 struct callout sc_motoron_ch; 154 struct callout sc_motoroff_ch; 155 156 daddr_t sc_blkno; /* starting block number */ 157 int sc_bcount; /* byte count left */ 158 int sc_opts; /* user-set options */ 159 int sc_skip; /* bytes already transferred */ 160 int sc_nblks; /* number of blocks currently transferring */ 161 int sc_nbytes; /* number of bytes currently transferring */ 162 163 int sc_drive; /* physical unit number */ 164 int sc_flags; 165#define FD_OPEN 0x01 /* it's open */ 166#define FD_MOTOR 0x02 /* motor should be on */ 167#define FD_MOTOR_WAIT 0x04 /* motor coming up */ 168 int sc_cylin; /* where we think the head is */ 169 170 TAILQ_ENTRY(fd_softc) sc_drivechain; 171 int sc_ops; /* I/O ops since last switch */ 172 struct bufq_state *sc_q;/* pending I/O requests */ 173 int sc_active; /* number of active I/O operations */ 174}; 175 176/* floppy driver configuration */ 177static int fdprobe(device_t, cfdata_t, void *); 178static void fdattach(device_t, device_t, void *); 179 180CFATTACH_DECL_NEW(fd, sizeof(struct fd_softc), fdprobe, fdattach, NULL, NULL); 181 182dev_type_open(fdopen); 183dev_type_close(fdclose); 184dev_type_read(fdread); 185dev_type_write(fdwrite); 186dev_type_ioctl(fdioctl); 187dev_type_strategy(fdstrategy); 188 189const struct bdevsw fd_bdevsw = { 190 fdopen, fdclose, fdstrategy, fdioctl, nodump, nosize, D_DISK 191}; 192 193const struct cdevsw fd_cdevsw = { 194 fdopen, fdclose, fdread, fdwrite, fdioctl, 195 nostop, notty, nopoll, nommap, nokqfilter, D_DISK 196}; 197 198static void fdstart(struct fd_softc *); 199 200struct dkdriver fddkdriver = { fdstrategy }; 201 202static bool fd_shutdown(device_t, int); 203#if 0 204static const struct fd_type *fd_nvtotype(char *, int, int); 205#endif 206static void fd_set_motor(struct fdc_softc *, int); 207static void fd_motor_off(void *); 208static void fd_motor_on(void *); 209static int fdcresult(struct fdc_softc *); 210static void fdcstart(struct fdc_softc *); 211static void fdcstatus(device_t, int, const char *); 212static void fdctimeout(void *); 213static void fdcpseudointr(void *); 214static void fdcretry(struct fdc_softc *); 215static void fdfinish(struct fd_softc *, struct buf *); 216static inline const struct fd_type *fd_dev_to_type(struct fd_softc *, dev_t); 217static void fd_mountroot_hook(device_t); 218 219/* 220 * Arguments passed between fdcattach and fdprobe. 221 */ 222struct fdc_attach_args { 223 int fa_drive; 224 const struct fd_type *fa_deftype; 225}; 226 227/* 228 * Print the location of a disk drive (called just before attaching the 229 * the drive). If `fdc' is not NULL, the drive was found but was not 230 * in the system config file; print the drive name as well. 231 * Return QUIET (config_find ignores this if the device was configured) to 232 * avoid printing `fdN not configured' messages. 233 */ 234static int 235fdprint(void *aux, const char *fdc) 236{ 237 struct fdc_attach_args *fa = aux; 238 239 if (fdc == NULL) 240 aprint_normal(" drive %d", fa->fa_drive); 241 return QUIET; 242} 243 244void 245fdcattach(struct fdc_softc *fdc) 246{ 247 struct fdc_attach_args fa; 248 bus_space_tag_t iot; 249 bus_space_handle_t ioh; 250 int type; 251 252 iot = fdc->sc_iot; 253 ioh = fdc->sc_ioh; 254 callout_init(&fdc->sc_timo_ch, 0); 255 callout_init(&fdc->sc_intr_ch, 0); 256 257 fdc->sc_state = DEVIDLE; 258 TAILQ_INIT(&fdc->sc_drives); 259 260 /* 261 * No way yet to determine default disk types. 262 * we assume 1.44 3.5" type for the moment. 263 */ 264 type = 0; 265 266 /* physical limit: two drives per controller. */ 267 for (fa.fa_drive = 0; fa.fa_drive < 2; fa.fa_drive++) { 268 fa.fa_deftype = &fd_types[type]; 269 (void)config_found(fdc->sc_dev, (void *)&fa, fdprint); 270 } 271} 272 273static int 274fdprobe(device_t parent, cfdata_t cf , void *aux) 275{ 276 struct fdc_softc *fdc = device_private(parent); 277 struct fdc_attach_args *fa = aux; 278 int drive = fa->fa_drive; 279 bus_space_tag_t iot = fdc->sc_iot; 280 bus_space_handle_t ioh = fdc->sc_ioh; 281 int n; 282 283 if (cf->cf_loc[FDCCF_DRIVE] != FDCCF_DRIVE_DEFAULT && 284 cf->cf_loc[FDCCF_DRIVE] != drive) 285 return 0; 286 287 /* select drive and turn on motor */ 288 bus_space_write_1(iot, ioh, FDOUT, drive | FDO_FRST | FDO_MOEN(drive)); 289 /* wait for motor to spin up */ 290 delay(250000); 291 out_fdc(iot, ioh, NE7CMD_RECAL); 292 out_fdc(iot, ioh, drive); 293 /* wait for recalibrate */ 294 delay(2000000); 295 out_fdc(iot, ioh, NE7CMD_SENSEI); 296 n = fdcresult(fdc); 297#ifdef FD_DEBUG 298 { 299 int i; 300 aprint_debug("%s: status", __func__); 301 for (i = 0; i < n; i++) 302 aprint_debug(" %x", fdc->sc_status[i]); 303 aprint_debug("\n"); 304 } 305#endif 306 if (n != 2 || (fdc->sc_status[0] & 0xf8) != 0x20) 307 return 0; 308 /* turn off motor */ 309 bus_space_write_1(iot, ioh, FDOUT, FDO_FRST); 310 311 return 1; 312} 313 314/* 315 * Controller is working, and drive responded. Attach it. 316 */ 317void 318fdattach(device_t parent, device_t self, void *aux) 319{ 320 struct fdc_softc *fdc = device_private(parent); 321 struct fd_softc *fd = device_private(self); 322 struct fdc_attach_args *fa = aux; 323 const struct fd_type *type = fa->fa_deftype; 324 int drive = fa->fa_drive; 325 326 fd->sc_dev = self; 327 328 callout_init(&fd->sc_motoron_ch, 0); 329 callout_init(&fd->sc_motoroff_ch, 0); 330 331 /* XXX Allow `flags' to override device type? */ 332 333 if (type) 334 printf(": %s, %d cyl, %d head, %d sec\n", type->name, 335 type->cyls, type->heads, type->sectrac); 336 else 337 printf(": density unknown\n"); 338 339 bufq_alloc(&fd->sc_q, "disksort", BUFQ_SORT_CYLINDER); 340 fd->sc_cylin = -1; 341 fd->sc_drive = drive; 342 fd->sc_deftype = type; 343 fdc->sc_fd[drive] = fd; 344 345 /* 346 * Initialize and attach the disk structure. 347 */ 348 disk_init(&fd->sc_dk, device_xname(fd->sc_dev), &fddkdriver); 349 disk_attach(&fd->sc_dk); 350 351 /* Establish a mountroot hook. */ 352 mountroothook_establish(fd_mountroot_hook, fd->sc_dev); 353 354 /* Needed to power off if the motor is on when we halt. */ 355 if (!pmf_device_register1(self, NULL, NULL, fd_shutdown)) 356 aprint_error_dev(self, "couldn't establish power handler\n"); 357} 358 359bool 360fd_shutdown(device_t self, int howto) 361{ 362 struct fd_softc *fd; 363 364 fd = device_private(self); 365 fd_motor_off(fd); 366 367 return true; 368} 369 370#if 0 371/* 372 * Translate nvram type into internal data structure. Return NULL for 373 * none/unknown/unusable. 374 */ 375static const struct fd_type * 376fd_nvtotype(char *fdc, int nvraminfo, int drive) 377{ 378 int type; 379 380 type = (drive == 0 ? nvraminfo : nvraminfo << 4) & 0xf0; 381#if 0 382 switch (type) { 383 case NVRAM_DISKETTE_NONE: 384 return NULL; 385 case NVRAM_DISKETTE_12M: 386 return &fd_types[1]; 387 case NVRAM_DISKETTE_TYPE5: 388 case NVRAM_DISKETTE_TYPE6: 389 /* XXX We really ought to handle 2.88MB format. */ 390 case NVRAM_DISKETTE_144M: 391 return &fd_types[0]; 392 case NVRAM_DISKETTE_360K: 393 return &fd_types[3]; 394 case NVRAM_DISKETTE_720K: 395 return &fd_types[4]; 396 default: 397 printf("%s: drive %d: unknown device type 0x%x\n", 398 fdc, drive, type); 399 return NULL; 400 } 401#else 402 return &fd_types[0]; /* Use only 1.44 for now */ 403#endif 404} 405#endif 406 407static inline const struct fd_type * 408fd_dev_to_type(struct fd_softc *fd, dev_t dev) 409{ 410 int type = FDTYPE(dev); 411 412 if (type > __arraycount(fd_types)) 413 return NULL; 414 return type ? &fd_types[type - 1] : fd->sc_deftype; 415} 416 417void 418fdstrategy(struct buf *bp) 419{ 420 struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(bp->b_dev)); 421 int sz; 422 int s; 423 424 /* Valid unit, controller, and request? */ 425 if (bp->b_blkno < 0 || 426 (bp->b_bcount % FDC_BSIZE) != 0) { 427 bp->b_error = EINVAL; 428 goto done; 429 } 430 431 /* If it's a null transfer, return immediately. */ 432 if (bp->b_bcount == 0) 433 goto done; 434 435 sz = howmany(bp->b_bcount, FDC_BSIZE); 436 437 if (bp->b_blkno + sz > fd->sc_type->size) { 438 sz = fd->sc_type->size - bp->b_blkno; 439 if (sz == 0) { 440 /* If exactly at end of disk, return EOF. */ 441 goto done; 442 } 443 if (sz < 0) { 444 /* If past end of disk, return EINVAL. */ 445 bp->b_error = EINVAL; 446 goto done; 447 } 448 /* Otherwise, truncate request. */ 449 bp->b_bcount = sz << DEV_BSHIFT; 450 } 451 452 bp->b_rawblkno = bp->b_blkno; 453 bp->b_cylinder = 454 bp->b_blkno / (FDC_BSIZE / DEV_BSIZE) / fd->sc_type->seccyl; 455 456#ifdef FD_DEBUG 457 printf("%s: b_blkno %" PRId64 " b_bcount %ld blkno %" PRId64 458 " cylin %ld sz %d\n", __func__, 459 bp->b_blkno, bp->b_bcount, fd->sc_blkno, bp->b_cylinder, sz); 460#endif 461 462 /* Queue transfer on drive, activate drive and controller if idle. */ 463 s = splbio(); 464 bufq_put(fd->sc_q, bp); 465 callout_stop(&fd->sc_motoroff_ch); /* a good idea */ 466 if (fd->sc_active == 0) 467 fdstart(fd); 468#ifdef DIAGNOSTIC 469 else { 470 struct fdc_softc *fdc = 471 device_private(device_parent(fd->sc_dev)); 472 if (fdc->sc_state == DEVIDLE) { 473 printf("%s: controller inactive\n", __func__); 474 fdcstart(fdc); 475 } 476 } 477#endif 478 splx(s); 479 return; 480 481 done: 482 /* Toss transfer; we're done early. */ 483 bp->b_resid = bp->b_bcount; 484 biodone(bp); 485} 486 487void 488fdstart(struct fd_softc *fd) 489{ 490 struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev)); 491 int active = TAILQ_FIRST(&fdc->sc_drives) != 0; 492 493 /* Link into controller queue. */ 494 fd->sc_active = 1; 495 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain); 496 497 /* If controller not already active, start it. */ 498 if (!active) 499 fdcstart(fdc); 500} 501 502void 503fdfinish(struct fd_softc *fd, struct buf *bp) 504{ 505 struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev)); 506 507 /* 508 * Move this drive to the end of the queue to give others a `fair' 509 * chance. We only force a switch if N operations are completed while 510 * another drive is waiting to be serviced, since there is a long motor 511 * startup delay whenever we switch. 512 */ 513 (void)bufq_get(fd->sc_q); 514 if (TAILQ_NEXT(fd, sc_drivechain) && ++fd->sc_ops >= 8) { 515 fd->sc_ops = 0; 516 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain); 517 if (bufq_peek(fd->sc_q) != NULL) 518 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain); 519 else 520 fd->sc_active = 0; 521 } 522 bp->b_resid = fd->sc_bcount; 523 fd->sc_skip = 0; 524 biodone(bp); 525 /* turn off motor 5s from now */ 526 callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd); 527 fdc->sc_state = DEVIDLE; 528} 529 530int 531fdread(dev_t dev, struct uio *uio, int flags) 532{ 533 534 return physio(fdstrategy, NULL, dev, B_READ, minphys, uio); 535} 536 537int 538fdwrite(dev_t dev, struct uio *uio, int flags) 539{ 540 541 return physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio); 542} 543 544void 545fd_set_motor(struct fdc_softc *fdc, int reset) 546{ 547 struct fd_softc *fd; 548 u_char status; 549 int n; 550 551 if ((fd = TAILQ_FIRST(&fdc->sc_drives)) != NULL) 552 status = fd->sc_drive; 553 else 554 status = 0; 555 if (!reset) 556 status |= FDO_FRST | FDO_FDMAEN; 557 for (n = 0; n < 4; n++) 558 if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR)) 559 status |= FDO_MOEN(n); 560 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, FDOUT, status); 561} 562 563void 564fd_motor_off(void *arg) 565{ 566 struct fd_softc *fd = arg; 567 struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev)); 568 int s; 569 570 s = splbio(); 571 fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT); 572 fd_set_motor(fdc, 0); 573 splx(s); 574} 575 576void 577fd_motor_on(void *arg) 578{ 579 struct fd_softc *fd = arg; 580 struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev)); 581 int s; 582 583 s = splbio(); 584 fd->sc_flags &= ~FD_MOTOR_WAIT; 585 if ((TAILQ_FIRST(&fdc->sc_drives) == fd) && 586 (fdc->sc_state == MOTORWAIT)) 587 (void)fdcintr(fdc); 588 splx(s); 589} 590 591int 592fdcresult(struct fdc_softc *fdc) 593{ 594 bus_space_tag_t iot = fdc->sc_iot; 595 bus_space_handle_t ioh = fdc->sc_ioh; 596 u_char i; 597 int j, n = 0; 598 599 for (j = 100000; j; j--) { 600 i = bus_space_read_1(iot, ioh, FDSTS) & 601 (NE7_DIO | NE7_RQM | NE7_CB); 602 if (i == NE7_RQM) 603 return n; 604 if (i == (NE7_DIO | NE7_RQM | NE7_CB)) { 605 if (n >= sizeof(fdc->sc_status)) { 606 log(LOG_ERR, "%s: overrun\n", __func__); 607 return -1; 608 } 609 fdc->sc_status[n++] = 610 bus_space_read_1(iot, ioh, FDDATA); 611 } 612 delay(10); 613 } 614 log(LOG_ERR, "%s: timeout\n", __func__); 615 return -1; 616} 617 618int 619out_fdc(bus_space_tag_t iot, bus_space_handle_t ioh, uint8_t x) 620{ 621 int i = 100000; 622 623 while ((bus_space_read_1(iot, ioh, FDSTS) & NE7_DIO) && i-- > 0); 624 if (i <= 0) 625 return -1; 626 while ((bus_space_read_1(iot, ioh, FDSTS) & NE7_RQM) == 0 && i-- > 0); 627 if (i <= 0) 628 return -1; 629 bus_space_write_1(iot, ioh, FDDATA, x); 630 return 0; 631} 632 633int 634fdopen(dev_t dev, int flags, int mode, struct lwp *l) 635{ 636 struct fd_softc *fd; 637 const struct fd_type *type; 638 639 fd = device_lookup_private(&fd_cd, FDUNIT(dev)); 640 if (fd == NULL) 641 return ENXIO; 642 643 type = fd_dev_to_type(fd, dev); 644 if (type == NULL) 645 return ENXIO; 646 647 if ((fd->sc_flags & FD_OPEN) != 0 && 648 memcmp(fd->sc_type, type, sizeof(*type))) 649 return EBUSY; 650 651 fd->sc_type_copy = *type; 652 fd->sc_type = &fd->sc_type_copy; 653 fd->sc_cylin = -1; 654 fd->sc_flags |= FD_OPEN; 655 656 return 0; 657} 658 659int 660fdclose(dev_t dev, int flags, int mode, struct lwp *l) 661{ 662 struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(dev)); 663 664 fd->sc_flags &= ~FD_OPEN; 665 return 0; 666} 667 668void 669fdcstart(struct fdc_softc *fdc) 670{ 671 672#ifdef DIAGNOSTIC 673 /* only got here if controller's drive queue was inactive; should 674 be in idle state */ 675 if (fdc->sc_state != DEVIDLE) { 676 printf("%s: not idle\n", __func__); 677 return; 678 } 679#endif 680 (void)fdcintr(fdc); 681} 682 683static void 684fdcpstatus(int n, struct fdc_softc *fdc) 685{ 686 char bits[64]; 687 688 switch (n) { 689 case 0: 690 printf("\n"); 691 break; 692 case 2: 693 snprintb(bits, sizeof(bits), NE7_ST0BITS, fdc->sc_status[0]); 694 printf(" (st0 %s cyl %d)\n", bits, fdc->sc_status[1]); 695 break; 696 case 7: 697 snprintb(bits, sizeof(bits), NE7_ST0BITS, fdc->sc_status[0]); 698 printf(" (st0 %s", bits); 699 snprintb(bits, sizeof(bits), NE7_ST1BITS, fdc->sc_status[1]); 700 printf(" st1 %s", bits); 701 snprintb(bits, sizeof(bits), NE7_ST2BITS, fdc->sc_status[2]); 702 printf(" st2 %s", bits); 703 printf(" cyl %d head %d sec %d)\n", 704 fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]); 705 break; 706#ifdef DIAGNOSTIC 707 default: 708 printf("\nfdcstatus: weird size"); 709 break; 710#endif 711 } 712} 713 714void 715fdcstatus(device_t dev, int n, const char *s) 716{ 717 struct fdc_softc *fdc = device_private(device_parent(dev)); 718 719 if (n == 0) { 720 out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI); 721 (void)fdcresult(fdc); 722 n = 2; 723 } 724 725 printf("%s: %s", device_xname(dev), s); 726 fdcpstatus(n, fdc); 727} 728 729void 730fdctimeout(void *arg) 731{ 732 struct fdc_softc *fdc = arg; 733 struct fd_softc *fd = TAILQ_FIRST(&fdc->sc_drives); 734 int s; 735 736 s = splbio(); 737#ifdef DEBUG 738 log(LOG_ERR, "%s: state %d\n", __func__, fdc->sc_state); 739#endif 740 fdcstatus(fd->sc_dev, 0, "timeout"); 741 742 if (bufq_peek(fd->sc_q) != NULL) 743 fdc->sc_state++; 744 else 745 fdc->sc_state = DEVIDLE; 746 747 (void)fdcintr(fdc); 748 splx(s); 749} 750 751void 752fdcpseudointr(void *arg) 753{ 754 int s; 755 756 /* Just ensure it has the right spl. */ 757 s = splbio(); 758 (void)fdcintr(arg); 759 splx(s); 760} 761 762int 763fdcintr(void *arg) 764{ 765 struct fdc_softc *fdc = arg; 766#define st0 fdc->sc_status[0] 767#define cyl fdc->sc_status[1] 768 struct fd_softc *fd; 769 struct buf *bp; 770 bus_space_tag_t iot = fdc->sc_iot; 771 bus_space_handle_t ioh = fdc->sc_ioh; 772 int read, head, sec, i, nblks; 773 struct fd_type *type; 774 775 loop: 776 /* Is there a drive for the controller to do a transfer with? */ 777 fd = TAILQ_FIRST(&fdc->sc_drives); 778 if (fd == NULL) { 779 fdc->sc_state = DEVIDLE; 780 return 1; 781 } 782 783 /* Is there a transfer to this drive? If not, deactivate drive. */ 784 bp = bufq_peek(fd->sc_q); 785 if (bp == NULL) { 786 fd->sc_ops = 0; 787 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain); 788 fd->sc_active = 0; 789 goto loop; 790 } 791 792 switch (fdc->sc_state) { 793 case DEVIDLE: 794 fdc->sc_errors = 0; 795 fd->sc_skip = 0; 796 fd->sc_bcount = bp->b_bcount; 797 fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE); 798 callout_stop(&fd->sc_motoroff_ch); 799 if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) { 800 fdc->sc_state = MOTORWAIT; 801 return 1; 802 } 803 if ((fd->sc_flags & FD_MOTOR) == 0) { 804 /* Turn on the motor, being careful about pairing. */ 805 struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1]; 806 if (ofd && ofd->sc_flags & FD_MOTOR) { 807 callout_stop(&ofd->sc_motoroff_ch); 808 ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT); 809 } 810 fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT; 811 fd_set_motor(fdc, 0); 812 fdc->sc_state = MOTORWAIT; 813 /* Allow .25s for motor to stabilize. */ 814 callout_reset(&fd->sc_motoron_ch, hz / 4, 815 fd_motor_on, fd); 816 return 1; 817 } 818 /* Make sure the right drive is selected. */ 819 fd_set_motor(fdc, 0); 820 821 /* fall through */ 822 case DOSEEK: 823 doseek: 824 if (fd->sc_cylin == bp->b_cylinder) 825 goto doio; 826 827 out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */ 828 out_fdc(iot, ioh, fd->sc_type->steprate); 829 out_fdc(iot, ioh, 6); /* XXX head load time == 6ms */ 830 831 out_fdc(iot, ioh, NE7CMD_SEEK); /* seek function */ 832 out_fdc(iot, ioh, fd->sc_drive); /* drive number */ 833 out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step); 834 835 fd->sc_cylin = -1; 836 fdc->sc_state = SEEKWAIT; 837 838 iostat_seek(fd->sc_dk.dk_stats); 839 disk_busy(&fd->sc_dk); 840 841 callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc); 842 return 1; 843 844 case DOIO: 845 doio: 846 type = fd->sc_type; 847 sec = fd->sc_blkno % type->seccyl; 848 nblks = type->seccyl - sec; 849 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE); 850 nblks = min(nblks, fdc->sc_maxiosize / FDC_BSIZE); 851 fd->sc_nblks = nblks; 852 fd->sc_nbytes = nblks * FDC_BSIZE; 853 head = sec / type->sectrac; 854 sec -= head * type->sectrac; 855#ifdef DIAGNOSTIC 856 { 857 int block; 858 block = (fd->sc_cylin * type->heads + head) * 859 type->sectrac + sec; 860 if (block != fd->sc_blkno) { 861 printf("%s: block %d != blkno %" PRId64 862 "\n", __func__, block, fd->sc_blkno); 863#ifdef DDB 864 Debugger(); 865#endif 866 } 867 } 868#endif 869 read = (bp->b_flags & B_READ) != 0; 870 FDCDMA_START(fdc, (uint8_t *)bp->b_data + fd->sc_skip, 871 fd->sc_nbytes, read); 872 bus_space_write_1(iot, ioh, FDCTL, type->rate); 873#ifdef FD_DEBUG 874 printf("%s: %s drive %d track %d head %d sec %d nblks %d\n", 875 __func__, read ? "read" : "write", fd->sc_drive, 876 fd->sc_cylin, head, sec, nblks); 877#endif 878 if (read) 879 out_fdc(iot, ioh, NE7CMD_READ); /* READ */ 880 else 881 out_fdc(iot, ioh, NE7CMD_WRITE);/* WRITE */ 882 out_fdc(iot, ioh, (head << 2) | fd->sc_drive); 883 out_fdc(iot, ioh, fd->sc_cylin); /* track */ 884 out_fdc(iot, ioh, head); 885 out_fdc(iot, ioh, sec + 1); /* sector + 1 */ 886 out_fdc(iot, ioh, type->secsize); /* sector size */ 887 out_fdc(iot, ioh, type->sectrac); /* sectors/track */ 888 out_fdc(iot, ioh, type->gap1); /* gap1 size */ 889 out_fdc(iot, ioh, type->datalen); /* data length */ 890 fdc->sc_state = IOCOMPLETE; 891 892 disk_busy(&fd->sc_dk); 893 894 /* allow 2 seconds for operation */ 895 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc); 896 return 1; /* will return later */ 897 898 case SEEKWAIT: 899 callout_stop(&fdc->sc_timo_ch); 900 fdc->sc_state = SEEKCOMPLETE; 901 /* allow 1/50 second for heads to settle */ 902 callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc); 903 return 1; 904 905 case SEEKCOMPLETE: 906 disk_unbusy(&fd->sc_dk, 0, 0); 907 908 /* Make sure seek really happened. */ 909 out_fdc(iot, ioh, NE7CMD_SENSEI); 910 if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || 911 cyl != bp->b_cylinder * fd->sc_type->step) { 912#ifdef FD_DEBUG 913 fdcstatus(fd->sc_dev, 2, "seek failed"); 914#endif 915 fdcretry(fdc); 916 goto loop; 917 } 918 fd->sc_cylin = bp->b_cylinder; 919 goto doio; 920 921 case IOTIMEDOUT: 922 FDCDMA_ABORT(fdc); 923 924 case SEEKTIMEDOUT: 925 case RECALTIMEDOUT: 926 case RESETTIMEDOUT: 927 fdcretry(fdc); 928 goto loop; 929 930 case IOCOMPLETE: /* IO DONE, post-analyze */ 931 callout_stop(&fdc->sc_timo_ch); 932 933 disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid), 934 (bp->b_flags & B_READ)); 935 936 i = fdcresult(fdc); 937 if (i != 7 || (st0 & 0xf8) != 0) { 938 FDCDMA_ABORT(fdc); 939#ifdef FD_DEBUG 940 fdcstatus(fd->sc_dev, 7, bp->b_flags & B_READ ? 941 "read failed" : "write failed"); 942 printf("blkno %" PRId64 " nblks %d\n", 943 fd->sc_blkno, fd->sc_nblks); 944#endif 945 fdcretry(fdc); 946 goto loop; 947 } 948 FDCDMA_DONE(fdc); 949 if (fdc->sc_errors) { 950 diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF, 951 fd->sc_skip / FDC_BSIZE, NULL); 952 printf("\n"); 953 fdc->sc_errors = 0; 954 } 955 fd->sc_blkno += fd->sc_nblks; 956 fd->sc_skip += fd->sc_nbytes; 957 fd->sc_bcount -= fd->sc_nbytes; 958 if (fd->sc_bcount > 0) { 959 bp->b_cylinder = fd->sc_blkno / fd->sc_type->seccyl; 960 goto doseek; 961 } 962 fdfinish(fd, bp); 963 goto loop; 964 965 case DORESET: 966 /* try a reset, keep motor on */ 967 fd_set_motor(fdc, 1); 968 delay(100); 969 fd_set_motor(fdc, 0); 970 fdc->sc_state = RESETCOMPLETE; 971 callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc); 972 return 1; /* will return later */ 973 974 case RESETCOMPLETE: 975 callout_stop(&fdc->sc_timo_ch); 976 /* clear the controller output buffer */ 977 for (i = 0; i < 4; i++) { 978 out_fdc(iot, ioh, NE7CMD_SENSEI); 979 (void)fdcresult(fdc); 980 } 981 982 /* fall through */ 983 case DORECAL: 984 out_fdc(iot, ioh, NE7CMD_RECAL); /* recalibrate function */ 985 out_fdc(iot, ioh, fd->sc_drive); 986 fdc->sc_state = RECALWAIT; 987 callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc); 988 return 1; /* will return later */ 989 990 case RECALWAIT: 991 callout_stop(&fdc->sc_timo_ch); 992 fdc->sc_state = RECALCOMPLETE; 993 /* allow 1/30 second for heads to settle */ 994 callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc); 995 return 1; /* will return later */ 996 997 case RECALCOMPLETE: 998 out_fdc(iot, ioh, NE7CMD_SENSEI); 999 if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) { 1000#ifdef FD_DEBUG 1001 fdcstatus(fd->sc_dev, 2, "recalibrate failed"); 1002#endif 1003 fdcretry(fdc); 1004 goto loop; 1005 } 1006 fd->sc_cylin = 0; 1007 goto doseek; 1008 1009 case MOTORWAIT: 1010 if (fd->sc_flags & FD_MOTOR_WAIT) 1011 return 1; /* time's not up yet */ 1012 goto doseek; 1013 1014 default: 1015 fdcstatus(fd->sc_dev, 0, "stray interrupt"); 1016 return 1; 1017 } 1018#ifdef DIAGNOSTIC 1019 panic("%s: impossible", __func__); 1020#endif 1021#undef st0 1022#undef cyl 1023} 1024 1025void 1026fdcretry(struct fdc_softc *fdc) 1027{ 1028 struct fd_softc *fd; 1029 struct buf *bp; 1030 1031 fd = TAILQ_FIRST(&fdc->sc_drives); 1032 bp = bufq_peek(fd->sc_q); 1033 1034 switch (fdc->sc_errors) { 1035 case 0: 1036 /* try again */ 1037 fdc->sc_state = DOSEEK; 1038 break; 1039 1040 case 1: 1041 case 2: 1042 case 3: 1043 /* didn't work; try recalibrating */ 1044 fdc->sc_state = DORECAL; 1045 break; 1046 1047 case 4: 1048 /* still no go; reset the bastard */ 1049 fdc->sc_state = DORESET; 1050 break; 1051 1052 default: 1053 diskerr(bp, "fd", "hard error", LOG_PRINTF, 1054 fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL); 1055 1056 fdcpstatus(7, fdc); 1057 bp->b_error = EIO; 1058 fdfinish(fd, bp); 1059 } 1060 fdc->sc_errors++; 1061} 1062 1063int 1064fdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) 1065{ 1066 struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(dev)); 1067 struct disklabel buffer; 1068 int error; 1069 1070 switch (cmd) { 1071 case DIOCGDINFO: 1072 memset(&buffer, 0, sizeof(buffer)); 1073 1074 buffer.d_secpercyl = fd->sc_type->seccyl; 1075 buffer.d_type = DTYPE_FLOPPY; 1076 buffer.d_secsize = FDC_BSIZE; 1077 1078 if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL) 1079 return EINVAL; 1080 1081 *(struct disklabel *)addr = buffer; 1082 return 0; 1083 1084 case DIOCWLABEL: 1085 if ((flag & FWRITE) == 0) 1086 return EBADF; 1087 /* XXX do something */ 1088 return 0; 1089 1090 case DIOCWDINFO: 1091 if ((flag & FWRITE) == 0) 1092 return EBADF; 1093 1094 error = setdisklabel(&buffer, (struct disklabel *)addr, 1095 0, NULL); 1096 if (error) 1097 return error; 1098 1099 error = writedisklabel(dev, fdstrategy, &buffer, NULL); 1100 return error; 1101 1102 default: 1103 return ENOTTY; 1104 } 1105 1106#ifdef DIAGNOSTIC 1107 panic("%s: impossible", __func__); 1108#endif 1109} 1110 1111/* 1112 * Mountroot hook: prompt the user to enter the root file system floppy. 1113 */ 1114void 1115fd_mountroot_hook(device_t dev) 1116{ 1117 int c; 1118 1119 printf("Insert filesystem floppy and press return."); 1120 cnpollc(1); 1121 for (;;) { 1122 c = cngetc(); 1123 if ((c == '\r') || (c == '\n')) { 1124 printf("\n"); 1125 break; 1126 } 1127 } 1128 cnpollc(0); 1129} 1130