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