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