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