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