1 /* $NetBSD: fd.c,v 1.42 2013/12/16 15:46:57 mrg 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.42 2013/12/16 15:46:57 mrg 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 */ 104 static 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 */ 110 struct 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! */ 127 const 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) */ 145 struct 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 */ 177 static int fdprobe(device_t, cfdata_t, void *); 178 static void fdattach(device_t, device_t, void *); 179 180 CFATTACH_DECL_NEW(fd, sizeof(struct fd_softc), fdprobe, fdattach, NULL, NULL); 181 182 dev_type_open(fdopen); 183 dev_type_close(fdclose); 184 dev_type_read(fdread); 185 dev_type_write(fdwrite); 186 dev_type_ioctl(fdioctl); 187 dev_type_strategy(fdstrategy); 188 189 const struct bdevsw fd_bdevsw = { 190 fdopen, fdclose, fdstrategy, fdioctl, nodump, nosize, D_DISK 191 }; 192 193 const struct cdevsw fd_cdevsw = { 194 fdopen, fdclose, fdread, fdwrite, fdioctl, 195 nostop, notty, nopoll, nommap, nokqfilter, D_DISK 196 }; 197 198 static void fdstart(struct fd_softc *); 199 200 struct dkdriver fddkdriver = { fdstrategy }; 201 202 static bool fd_shutdown(device_t, int); 203 #if 0 204 static const struct fd_type *fd_nvtotype(char *, int, int); 205 #endif 206 static void fd_set_motor(struct fdc_softc *, int); 207 static void fd_motor_off(void *); 208 static void fd_motor_on(void *); 209 static int fdcresult(struct fdc_softc *); 210 static void fdcstart(struct fdc_softc *); 211 static void fdcstatus(device_t, int, const char *); 212 static void fdctimeout(void *); 213 static void fdcpseudointr(void *); 214 static void fdcretry(struct fdc_softc *); 215 static void fdfinish(struct fd_softc *, struct buf *); 216 static inline const struct fd_type *fd_dev_to_type(struct fd_softc *, dev_t); 217 static void fd_mountroot_hook(device_t); 218 219 /* 220 * Arguments passed between fdcattach and fdprobe. 221 */ 222 struct 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 */ 234 static int 235 fdprint(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 244 void 245 fdcattach(struct fdc_softc *fdc) 246 { 247 struct fdc_attach_args fa; 248 int type; 249 250 callout_init(&fdc->sc_timo_ch, 0); 251 callout_init(&fdc->sc_intr_ch, 0); 252 253 fdc->sc_state = DEVIDLE; 254 TAILQ_INIT(&fdc->sc_drives); 255 256 /* 257 * No way yet to determine default disk types. 258 * we assume 1.44 3.5" type for the moment. 259 */ 260 type = 0; 261 262 /* physical limit: two drives per controller. */ 263 for (fa.fa_drive = 0; fa.fa_drive < 2; fa.fa_drive++) { 264 fa.fa_deftype = &fd_types[type]; 265 (void)config_found(fdc->sc_dev, (void *)&fa, fdprint); 266 } 267 } 268 269 static int 270 fdprobe(device_t parent, cfdata_t cf , void *aux) 271 { 272 struct fdc_softc *fdc = device_private(parent); 273 struct fdc_attach_args *fa = aux; 274 int drive = fa->fa_drive; 275 bus_space_tag_t iot = fdc->sc_iot; 276 bus_space_handle_t ioh = fdc->sc_ioh; 277 int n; 278 279 if (cf->cf_loc[FDCCF_DRIVE] != FDCCF_DRIVE_DEFAULT && 280 cf->cf_loc[FDCCF_DRIVE] != drive) 281 return 0; 282 283 /* select drive and turn on motor */ 284 bus_space_write_1(iot, ioh, FDOUT, drive | FDO_FRST | FDO_MOEN(drive)); 285 /* wait for motor to spin up */ 286 delay(250000); 287 out_fdc(iot, ioh, NE7CMD_RECAL); 288 out_fdc(iot, ioh, drive); 289 /* wait for recalibrate */ 290 delay(2000000); 291 out_fdc(iot, ioh, NE7CMD_SENSEI); 292 n = fdcresult(fdc); 293 #ifdef FD_DEBUG 294 { 295 int i; 296 aprint_debug("%s: status", __func__); 297 for (i = 0; i < n; i++) 298 aprint_debug(" %x", fdc->sc_status[i]); 299 aprint_debug("\n"); 300 } 301 #endif 302 if (n != 2 || (fdc->sc_status[0] & 0xf8) != 0x20) 303 return 0; 304 /* turn off motor */ 305 bus_space_write_1(iot, ioh, FDOUT, FDO_FRST); 306 307 return 1; 308 } 309 310 /* 311 * Controller is working, and drive responded. Attach it. 312 */ 313 void 314 fdattach(device_t parent, device_t self, void *aux) 315 { 316 struct fdc_softc *fdc = device_private(parent); 317 struct fd_softc *fd = device_private(self); 318 struct fdc_attach_args *fa = aux; 319 const struct fd_type *type = fa->fa_deftype; 320 int drive = fa->fa_drive; 321 322 fd->sc_dev = self; 323 324 callout_init(&fd->sc_motoron_ch, 0); 325 callout_init(&fd->sc_motoroff_ch, 0); 326 327 /* XXX Allow `flags' to override device type? */ 328 329 if (type) 330 printf(": %s, %d cyl, %d head, %d sec\n", type->name, 331 type->cyls, type->heads, type->sectrac); 332 else 333 printf(": density unknown\n"); 334 335 bufq_alloc(&fd->sc_q, "disksort", BUFQ_SORT_CYLINDER); 336 fd->sc_cylin = -1; 337 fd->sc_drive = drive; 338 fd->sc_deftype = type; 339 fdc->sc_fd[drive] = fd; 340 341 /* 342 * Initialize and attach the disk structure. 343 */ 344 disk_init(&fd->sc_dk, device_xname(fd->sc_dev), &fddkdriver); 345 disk_attach(&fd->sc_dk); 346 347 /* Establish a mountroot hook. */ 348 mountroothook_establish(fd_mountroot_hook, fd->sc_dev); 349 350 /* Needed to power off if the motor is on when we halt. */ 351 if (!pmf_device_register1(self, NULL, NULL, fd_shutdown)) 352 aprint_error_dev(self, "couldn't establish power handler\n"); 353 } 354 355 bool 356 fd_shutdown(device_t self, int howto) 357 { 358 struct fd_softc *fd; 359 360 fd = device_private(self); 361 fd_motor_off(fd); 362 363 return true; 364 } 365 366 #if 0 367 /* 368 * Translate nvram type into internal data structure. Return NULL for 369 * none/unknown/unusable. 370 */ 371 static const struct fd_type * 372 fd_nvtotype(char *fdc, int nvraminfo, int drive) 373 { 374 int type; 375 376 type = (drive == 0 ? nvraminfo : nvraminfo << 4) & 0xf0; 377 #if 0 378 switch (type) { 379 case NVRAM_DISKETTE_NONE: 380 return NULL; 381 case NVRAM_DISKETTE_12M: 382 return &fd_types[1]; 383 case NVRAM_DISKETTE_TYPE5: 384 case NVRAM_DISKETTE_TYPE6: 385 /* XXX We really ought to handle 2.88MB format. */ 386 case NVRAM_DISKETTE_144M: 387 return &fd_types[0]; 388 case NVRAM_DISKETTE_360K: 389 return &fd_types[3]; 390 case NVRAM_DISKETTE_720K: 391 return &fd_types[4]; 392 default: 393 printf("%s: drive %d: unknown device type 0x%x\n", 394 fdc, drive, type); 395 return NULL; 396 } 397 #else 398 return &fd_types[0]; /* Use only 1.44 for now */ 399 #endif 400 } 401 #endif 402 403 static inline const struct fd_type * 404 fd_dev_to_type(struct fd_softc *fd, dev_t dev) 405 { 406 int type = FDTYPE(dev); 407 408 if (type > __arraycount(fd_types)) 409 return NULL; 410 return type ? &fd_types[type - 1] : fd->sc_deftype; 411 } 412 413 void 414 fdstrategy(struct buf *bp) 415 { 416 struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(bp->b_dev)); 417 int sz; 418 int s; 419 420 /* Valid unit, controller, and request? */ 421 if (bp->b_blkno < 0 || 422 (bp->b_bcount % FDC_BSIZE) != 0) { 423 bp->b_error = EINVAL; 424 goto done; 425 } 426 427 /* If it's a null transfer, return immediately. */ 428 if (bp->b_bcount == 0) 429 goto done; 430 431 sz = howmany(bp->b_bcount, FDC_BSIZE); 432 433 if (bp->b_blkno + sz > fd->sc_type->size) { 434 sz = fd->sc_type->size - bp->b_blkno; 435 if (sz == 0) { 436 /* If exactly at end of disk, return EOF. */ 437 goto done; 438 } 439 if (sz < 0) { 440 /* If past end of disk, return EINVAL. */ 441 bp->b_error = EINVAL; 442 goto done; 443 } 444 /* Otherwise, truncate request. */ 445 bp->b_bcount = sz << DEV_BSHIFT; 446 } 447 448 bp->b_rawblkno = bp->b_blkno; 449 bp->b_cylinder = 450 bp->b_blkno / (FDC_BSIZE / DEV_BSIZE) / fd->sc_type->seccyl; 451 452 #ifdef FD_DEBUG 453 printf("%s: b_blkno %" PRId64 " b_bcount %ld blkno %" PRId64 454 " cylin %ld sz %d\n", __func__, 455 bp->b_blkno, bp->b_bcount, fd->sc_blkno, bp->b_cylinder, sz); 456 #endif 457 458 /* Queue transfer on drive, activate drive and controller if idle. */ 459 s = splbio(); 460 bufq_put(fd->sc_q, bp); 461 callout_stop(&fd->sc_motoroff_ch); /* a good idea */ 462 if (fd->sc_active == 0) 463 fdstart(fd); 464 #ifdef DIAGNOSTIC 465 else { 466 struct fdc_softc *fdc = 467 device_private(device_parent(fd->sc_dev)); 468 if (fdc->sc_state == DEVIDLE) { 469 printf("%s: controller inactive\n", __func__); 470 fdcstart(fdc); 471 } 472 } 473 #endif 474 splx(s); 475 return; 476 477 done: 478 /* Toss transfer; we're done early. */ 479 bp->b_resid = bp->b_bcount; 480 biodone(bp); 481 } 482 483 void 484 fdstart(struct fd_softc *fd) 485 { 486 struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev)); 487 int active = TAILQ_FIRST(&fdc->sc_drives) != 0; 488 489 /* Link into controller queue. */ 490 fd->sc_active = 1; 491 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain); 492 493 /* If controller not already active, start it. */ 494 if (!active) 495 fdcstart(fdc); 496 } 497 498 void 499 fdfinish(struct fd_softc *fd, struct buf *bp) 500 { 501 struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev)); 502 503 /* 504 * Move this drive to the end of the queue to give others a `fair' 505 * chance. We only force a switch if N operations are completed while 506 * another drive is waiting to be serviced, since there is a long motor 507 * startup delay whenever we switch. 508 */ 509 (void)bufq_get(fd->sc_q); 510 if (TAILQ_NEXT(fd, sc_drivechain) && ++fd->sc_ops >= 8) { 511 fd->sc_ops = 0; 512 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain); 513 if (bufq_peek(fd->sc_q) != NULL) 514 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain); 515 else 516 fd->sc_active = 0; 517 } 518 bp->b_resid = fd->sc_bcount; 519 fd->sc_skip = 0; 520 biodone(bp); 521 /* turn off motor 5s from now */ 522 callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd); 523 fdc->sc_state = DEVIDLE; 524 } 525 526 int 527 fdread(dev_t dev, struct uio *uio, int flags) 528 { 529 530 return physio(fdstrategy, NULL, dev, B_READ, minphys, uio); 531 } 532 533 int 534 fdwrite(dev_t dev, struct uio *uio, int flags) 535 { 536 537 return physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio); 538 } 539 540 void 541 fd_set_motor(struct fdc_softc *fdc, int reset) 542 { 543 struct fd_softc *fd; 544 u_char status; 545 int n; 546 547 if ((fd = TAILQ_FIRST(&fdc->sc_drives)) != NULL) 548 status = fd->sc_drive; 549 else 550 status = 0; 551 if (!reset) 552 status |= FDO_FRST | FDO_FDMAEN; 553 for (n = 0; n < 4; n++) 554 if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR)) 555 status |= FDO_MOEN(n); 556 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, FDOUT, status); 557 } 558 559 void 560 fd_motor_off(void *arg) 561 { 562 struct fd_softc *fd = arg; 563 struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev)); 564 int s; 565 566 s = splbio(); 567 fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT); 568 fd_set_motor(fdc, 0); 569 splx(s); 570 } 571 572 void 573 fd_motor_on(void *arg) 574 { 575 struct fd_softc *fd = arg; 576 struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev)); 577 int s; 578 579 s = splbio(); 580 fd->sc_flags &= ~FD_MOTOR_WAIT; 581 if ((TAILQ_FIRST(&fdc->sc_drives) == fd) && 582 (fdc->sc_state == MOTORWAIT)) 583 (void)fdcintr(fdc); 584 splx(s); 585 } 586 587 int 588 fdcresult(struct fdc_softc *fdc) 589 { 590 bus_space_tag_t iot = fdc->sc_iot; 591 bus_space_handle_t ioh = fdc->sc_ioh; 592 u_char i; 593 int j, n = 0; 594 595 for (j = 100000; j; j--) { 596 i = bus_space_read_1(iot, ioh, FDSTS) & 597 (NE7_DIO | NE7_RQM | NE7_CB); 598 if (i == NE7_RQM) 599 return n; 600 if (i == (NE7_DIO | NE7_RQM | NE7_CB)) { 601 if (n >= sizeof(fdc->sc_status)) { 602 log(LOG_ERR, "%s: overrun\n", __func__); 603 return -1; 604 } 605 fdc->sc_status[n++] = 606 bus_space_read_1(iot, ioh, FDDATA); 607 } 608 delay(10); 609 } 610 log(LOG_ERR, "%s: timeout\n", __func__); 611 return -1; 612 } 613 614 int 615 out_fdc(bus_space_tag_t iot, bus_space_handle_t ioh, uint8_t x) 616 { 617 int i = 100000; 618 619 while ((bus_space_read_1(iot, ioh, FDSTS) & NE7_DIO) && i-- > 0); 620 if (i <= 0) 621 return -1; 622 while ((bus_space_read_1(iot, ioh, FDSTS) & NE7_RQM) == 0 && i-- > 0); 623 if (i <= 0) 624 return -1; 625 bus_space_write_1(iot, ioh, FDDATA, x); 626 return 0; 627 } 628 629 int 630 fdopen(dev_t dev, int flags, int mode, struct lwp *l) 631 { 632 struct fd_softc *fd; 633 const struct fd_type *type; 634 635 fd = device_lookup_private(&fd_cd, FDUNIT(dev)); 636 if (fd == NULL) 637 return ENXIO; 638 639 type = fd_dev_to_type(fd, dev); 640 if (type == NULL) 641 return ENXIO; 642 643 if ((fd->sc_flags & FD_OPEN) != 0 && 644 memcmp(fd->sc_type, type, sizeof(*type))) 645 return EBUSY; 646 647 fd->sc_type_copy = *type; 648 fd->sc_type = &fd->sc_type_copy; 649 fd->sc_cylin = -1; 650 fd->sc_flags |= FD_OPEN; 651 652 return 0; 653 } 654 655 int 656 fdclose(dev_t dev, int flags, int mode, struct lwp *l) 657 { 658 struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(dev)); 659 660 fd->sc_flags &= ~FD_OPEN; 661 return 0; 662 } 663 664 void 665 fdcstart(struct fdc_softc *fdc) 666 { 667 668 #ifdef DIAGNOSTIC 669 /* only got here if controller's drive queue was inactive; should 670 be in idle state */ 671 if (fdc->sc_state != DEVIDLE) { 672 printf("%s: not idle\n", __func__); 673 return; 674 } 675 #endif 676 (void)fdcintr(fdc); 677 } 678 679 static void 680 fdcpstatus(int n, struct fdc_softc *fdc) 681 { 682 char bits[64]; 683 684 switch (n) { 685 case 0: 686 printf("\n"); 687 break; 688 case 2: 689 snprintb(bits, sizeof(bits), NE7_ST0BITS, fdc->sc_status[0]); 690 printf(" (st0 %s cyl %d)\n", bits, fdc->sc_status[1]); 691 break; 692 case 7: 693 snprintb(bits, sizeof(bits), NE7_ST0BITS, fdc->sc_status[0]); 694 printf(" (st0 %s", bits); 695 snprintb(bits, sizeof(bits), NE7_ST1BITS, fdc->sc_status[1]); 696 printf(" st1 %s", bits); 697 snprintb(bits, sizeof(bits), NE7_ST2BITS, fdc->sc_status[2]); 698 printf(" st2 %s", bits); 699 printf(" cyl %d head %d sec %d)\n", 700 fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]); 701 break; 702 #ifdef DIAGNOSTIC 703 default: 704 printf("\nfdcstatus: weird size"); 705 break; 706 #endif 707 } 708 } 709 710 void 711 fdcstatus(device_t dev, int n, const char *s) 712 { 713 struct fdc_softc *fdc = device_private(device_parent(dev)); 714 715 if (n == 0) { 716 out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI); 717 (void)fdcresult(fdc); 718 n = 2; 719 } 720 721 printf("%s: %s", device_xname(dev), s); 722 fdcpstatus(n, fdc); 723 } 724 725 void 726 fdctimeout(void *arg) 727 { 728 struct fdc_softc *fdc = arg; 729 struct fd_softc *fd = TAILQ_FIRST(&fdc->sc_drives); 730 int s; 731 732 s = splbio(); 733 #ifdef DEBUG 734 log(LOG_ERR, "%s: state %d\n", __func__, fdc->sc_state); 735 #endif 736 fdcstatus(fd->sc_dev, 0, "timeout"); 737 738 if (bufq_peek(fd->sc_q) != NULL) 739 fdc->sc_state++; 740 else 741 fdc->sc_state = DEVIDLE; 742 743 (void)fdcintr(fdc); 744 splx(s); 745 } 746 747 void 748 fdcpseudointr(void *arg) 749 { 750 int s; 751 752 /* Just ensure it has the right spl. */ 753 s = splbio(); 754 (void)fdcintr(arg); 755 splx(s); 756 } 757 758 int 759 fdcintr(void *arg) 760 { 761 struct fdc_softc *fdc = arg; 762 #define st0 fdc->sc_status[0] 763 #define cyl fdc->sc_status[1] 764 struct fd_softc *fd; 765 struct buf *bp; 766 bus_space_tag_t iot = fdc->sc_iot; 767 bus_space_handle_t ioh = fdc->sc_ioh; 768 int read, head, sec, i, nblks; 769 struct fd_type *type; 770 771 loop: 772 /* Is there a drive for the controller to do a transfer with? */ 773 fd = TAILQ_FIRST(&fdc->sc_drives); 774 if (fd == NULL) { 775 fdc->sc_state = DEVIDLE; 776 return 1; 777 } 778 779 /* Is there a transfer to this drive? If not, deactivate drive. */ 780 bp = bufq_peek(fd->sc_q); 781 if (bp == NULL) { 782 fd->sc_ops = 0; 783 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain); 784 fd->sc_active = 0; 785 goto loop; 786 } 787 788 switch (fdc->sc_state) { 789 case DEVIDLE: 790 fdc->sc_errors = 0; 791 fd->sc_skip = 0; 792 fd->sc_bcount = bp->b_bcount; 793 fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE); 794 callout_stop(&fd->sc_motoroff_ch); 795 if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) { 796 fdc->sc_state = MOTORWAIT; 797 return 1; 798 } 799 if ((fd->sc_flags & FD_MOTOR) == 0) { 800 /* Turn on the motor, being careful about pairing. */ 801 struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1]; 802 if (ofd && ofd->sc_flags & FD_MOTOR) { 803 callout_stop(&ofd->sc_motoroff_ch); 804 ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT); 805 } 806 fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT; 807 fd_set_motor(fdc, 0); 808 fdc->sc_state = MOTORWAIT; 809 /* Allow .25s for motor to stabilize. */ 810 callout_reset(&fd->sc_motoron_ch, hz / 4, 811 fd_motor_on, fd); 812 return 1; 813 } 814 /* Make sure the right drive is selected. */ 815 fd_set_motor(fdc, 0); 816 817 /* fall through */ 818 case DOSEEK: 819 doseek: 820 if (fd->sc_cylin == bp->b_cylinder) 821 goto doio; 822 823 out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */ 824 out_fdc(iot, ioh, fd->sc_type->steprate); 825 out_fdc(iot, ioh, 6); /* XXX head load time == 6ms */ 826 827 out_fdc(iot, ioh, NE7CMD_SEEK); /* seek function */ 828 out_fdc(iot, ioh, fd->sc_drive); /* drive number */ 829 out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step); 830 831 fd->sc_cylin = -1; 832 fdc->sc_state = SEEKWAIT; 833 834 iostat_seek(fd->sc_dk.dk_stats); 835 disk_busy(&fd->sc_dk); 836 837 callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc); 838 return 1; 839 840 case DOIO: 841 doio: 842 type = fd->sc_type; 843 sec = fd->sc_blkno % type->seccyl; 844 nblks = type->seccyl - sec; 845 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE); 846 nblks = min(nblks, fdc->sc_maxiosize / FDC_BSIZE); 847 fd->sc_nblks = nblks; 848 fd->sc_nbytes = nblks * FDC_BSIZE; 849 head = sec / type->sectrac; 850 sec -= head * type->sectrac; 851 #ifdef DIAGNOSTIC 852 { 853 int block; 854 block = (fd->sc_cylin * type->heads + head) * 855 type->sectrac + sec; 856 if (block != fd->sc_blkno) { 857 printf("%s: block %d != blkno %" PRId64 858 "\n", __func__, block, fd->sc_blkno); 859 #ifdef DDB 860 Debugger(); 861 #endif 862 } 863 } 864 #endif 865 read = (bp->b_flags & B_READ) != 0; 866 FDCDMA_START(fdc, (uint8_t *)bp->b_data + fd->sc_skip, 867 fd->sc_nbytes, read); 868 bus_space_write_1(iot, ioh, FDCTL, type->rate); 869 #ifdef FD_DEBUG 870 printf("%s: %s drive %d track %d head %d sec %d nblks %d\n", 871 __func__, read ? "read" : "write", fd->sc_drive, 872 fd->sc_cylin, head, sec, nblks); 873 #endif 874 if (read) 875 out_fdc(iot, ioh, NE7CMD_READ); /* READ */ 876 else 877 out_fdc(iot, ioh, NE7CMD_WRITE);/* WRITE */ 878 out_fdc(iot, ioh, (head << 2) | fd->sc_drive); 879 out_fdc(iot, ioh, fd->sc_cylin); /* track */ 880 out_fdc(iot, ioh, head); 881 out_fdc(iot, ioh, sec + 1); /* sector + 1 */ 882 out_fdc(iot, ioh, type->secsize); /* sector size */ 883 out_fdc(iot, ioh, type->sectrac); /* sectors/track */ 884 out_fdc(iot, ioh, type->gap1); /* gap1 size */ 885 out_fdc(iot, ioh, type->datalen); /* data length */ 886 fdc->sc_state = IOCOMPLETE; 887 888 disk_busy(&fd->sc_dk); 889 890 /* allow 2 seconds for operation */ 891 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc); 892 return 1; /* will return later */ 893 894 case SEEKWAIT: 895 callout_stop(&fdc->sc_timo_ch); 896 fdc->sc_state = SEEKCOMPLETE; 897 /* allow 1/50 second for heads to settle */ 898 callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc); 899 return 1; 900 901 case SEEKCOMPLETE: 902 disk_unbusy(&fd->sc_dk, 0, 0); 903 904 /* Make sure seek really happened. */ 905 out_fdc(iot, ioh, NE7CMD_SENSEI); 906 if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || 907 cyl != bp->b_cylinder * fd->sc_type->step) { 908 #ifdef FD_DEBUG 909 fdcstatus(fd->sc_dev, 2, "seek failed"); 910 #endif 911 fdcretry(fdc); 912 goto loop; 913 } 914 fd->sc_cylin = bp->b_cylinder; 915 goto doio; 916 917 case IOTIMEDOUT: 918 FDCDMA_ABORT(fdc); 919 920 case SEEKTIMEDOUT: 921 case RECALTIMEDOUT: 922 case RESETTIMEDOUT: 923 fdcretry(fdc); 924 goto loop; 925 926 case IOCOMPLETE: /* IO DONE, post-analyze */ 927 callout_stop(&fdc->sc_timo_ch); 928 929 disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid), 930 (bp->b_flags & B_READ)); 931 932 i = fdcresult(fdc); 933 if (i != 7 || (st0 & 0xf8) != 0) { 934 FDCDMA_ABORT(fdc); 935 #ifdef FD_DEBUG 936 fdcstatus(fd->sc_dev, 7, bp->b_flags & B_READ ? 937 "read failed" : "write failed"); 938 printf("blkno %" PRId64 " nblks %d\n", 939 fd->sc_blkno, fd->sc_nblks); 940 #endif 941 fdcretry(fdc); 942 goto loop; 943 } 944 FDCDMA_DONE(fdc); 945 if (fdc->sc_errors) { 946 diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF, 947 fd->sc_skip / FDC_BSIZE, NULL); 948 printf("\n"); 949 fdc->sc_errors = 0; 950 } 951 fd->sc_blkno += fd->sc_nblks; 952 fd->sc_skip += fd->sc_nbytes; 953 fd->sc_bcount -= fd->sc_nbytes; 954 if (fd->sc_bcount > 0) { 955 bp->b_cylinder = fd->sc_blkno / fd->sc_type->seccyl; 956 goto doseek; 957 } 958 fdfinish(fd, bp); 959 goto loop; 960 961 case DORESET: 962 /* try a reset, keep motor on */ 963 fd_set_motor(fdc, 1); 964 delay(100); 965 fd_set_motor(fdc, 0); 966 fdc->sc_state = RESETCOMPLETE; 967 callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc); 968 return 1; /* will return later */ 969 970 case RESETCOMPLETE: 971 callout_stop(&fdc->sc_timo_ch); 972 /* clear the controller output buffer */ 973 for (i = 0; i < 4; i++) { 974 out_fdc(iot, ioh, NE7CMD_SENSEI); 975 (void)fdcresult(fdc); 976 } 977 978 /* fall through */ 979 case DORECAL: 980 out_fdc(iot, ioh, NE7CMD_RECAL); /* recalibrate function */ 981 out_fdc(iot, ioh, fd->sc_drive); 982 fdc->sc_state = RECALWAIT; 983 callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc); 984 return 1; /* will return later */ 985 986 case RECALWAIT: 987 callout_stop(&fdc->sc_timo_ch); 988 fdc->sc_state = RECALCOMPLETE; 989 /* allow 1/30 second for heads to settle */ 990 callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc); 991 return 1; /* will return later */ 992 993 case RECALCOMPLETE: 994 out_fdc(iot, ioh, NE7CMD_SENSEI); 995 if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) { 996 #ifdef FD_DEBUG 997 fdcstatus(fd->sc_dev, 2, "recalibrate failed"); 998 #endif 999 fdcretry(fdc); 1000 goto loop; 1001 } 1002 fd->sc_cylin = 0; 1003 goto doseek; 1004 1005 case MOTORWAIT: 1006 if (fd->sc_flags & FD_MOTOR_WAIT) 1007 return 1; /* time's not up yet */ 1008 goto doseek; 1009 1010 default: 1011 fdcstatus(fd->sc_dev, 0, "stray interrupt"); 1012 return 1; 1013 } 1014 #ifdef DIAGNOSTIC 1015 panic("%s: impossible", __func__); 1016 #endif 1017 #undef st0 1018 #undef cyl 1019 } 1020 1021 void 1022 fdcretry(struct fdc_softc *fdc) 1023 { 1024 struct fd_softc *fd; 1025 struct buf *bp; 1026 1027 fd = TAILQ_FIRST(&fdc->sc_drives); 1028 bp = bufq_peek(fd->sc_q); 1029 1030 switch (fdc->sc_errors) { 1031 case 0: 1032 /* try again */ 1033 fdc->sc_state = DOSEEK; 1034 break; 1035 1036 case 1: 1037 case 2: 1038 case 3: 1039 /* didn't work; try recalibrating */ 1040 fdc->sc_state = DORECAL; 1041 break; 1042 1043 case 4: 1044 /* still no go; reset the bastard */ 1045 fdc->sc_state = DORESET; 1046 break; 1047 1048 default: 1049 diskerr(bp, "fd", "hard error", LOG_PRINTF, 1050 fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL); 1051 1052 fdcpstatus(7, fdc); 1053 bp->b_error = EIO; 1054 fdfinish(fd, bp); 1055 } 1056 fdc->sc_errors++; 1057 } 1058 1059 int 1060 fdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) 1061 { 1062 struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(dev)); 1063 struct disklabel buffer; 1064 int error; 1065 1066 switch (cmd) { 1067 case DIOCGDINFO: 1068 memset(&buffer, 0, sizeof(buffer)); 1069 1070 buffer.d_secpercyl = fd->sc_type->seccyl; 1071 buffer.d_type = DTYPE_FLOPPY; 1072 buffer.d_secsize = FDC_BSIZE; 1073 1074 if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL) 1075 return EINVAL; 1076 1077 *(struct disklabel *)addr = buffer; 1078 return 0; 1079 1080 case DIOCWLABEL: 1081 if ((flag & FWRITE) == 0) 1082 return EBADF; 1083 /* XXX do something */ 1084 return 0; 1085 1086 case DIOCWDINFO: 1087 if ((flag & FWRITE) == 0) 1088 return EBADF; 1089 1090 error = setdisklabel(&buffer, (struct disklabel *)addr, 1091 0, NULL); 1092 if (error) 1093 return error; 1094 1095 error = writedisklabel(dev, fdstrategy, &buffer, NULL); 1096 return error; 1097 1098 default: 1099 return ENOTTY; 1100 } 1101 1102 #ifdef DIAGNOSTIC 1103 panic("%s: impossible", __func__); 1104 #endif 1105 } 1106 1107 /* 1108 * Mountroot hook: prompt the user to enter the root file system floppy. 1109 */ 1110 void 1111 fd_mountroot_hook(device_t dev) 1112 { 1113 int c; 1114 1115 printf("Insert filesystem floppy and press return."); 1116 cnpollc(1); 1117 for (;;) { 1118 c = cngetc(); 1119 if ((c == '\r') || (c == '\n')) { 1120 printf("\n"); 1121 break; 1122 } 1123 } 1124 cnpollc(0); 1125 } 1126