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