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