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