1 /* $NetBSD: fd.c,v 1.40 2001/12/27 02:23:24 wiz Exp $ */ 2 3 /*- 4 * Copyright (c) 1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Charles M. Hannum and Minoura Makoto. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /*- 40 * Copyright (c) 1990 The Regents of the University of California. 41 * All rights reserved. 42 * 43 * This code is derived from software contributed to Berkeley by 44 * Don Ahn. 45 * 46 * Redistribution and use in source and binary forms, with or without 47 * modification, are permitted provided that the following conditions 48 * are met: 49 * 1. Redistributions of source code must retain the above copyright 50 * notice, this list of conditions and the following disclaimer. 51 * 2. Redistributions in binary form must reproduce the above copyright 52 * notice, this list of conditions and the following disclaimer in the 53 * documentation and/or other materials provided with the distribution. 54 * 3. All advertising materials mentioning features or use of this software 55 * must display the following acknowledgement: 56 * This product includes software developed by the University of 57 * California, Berkeley and its contributors. 58 * 4. Neither the name of the University nor the names of its contributors 59 * may be used to endorse or promote products derived from this software 60 * without specific prior written permission. 61 * 62 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 63 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 64 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 65 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 66 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 67 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 68 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 69 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 70 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 71 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 72 * SUCH DAMAGE. 73 * 74 * @(#)fd.c 7.4 (Berkeley) 5/25/91 75 */ 76 77 #include "rnd.h" 78 #include "opt_ddb.h" 79 #include "opt_m680x0.h" 80 81 #include <sys/param.h> 82 #include <sys/systm.h> 83 #include <sys/callout.h> 84 #include <sys/kernel.h> 85 #include <sys/conf.h> 86 #include <sys/file.h> 87 #include <sys/stat.h> 88 #include <sys/ioctl.h> 89 #include <sys/malloc.h> 90 #include <sys/device.h> 91 #include <sys/disklabel.h> 92 #include <sys/dkstat.h> 93 #include <sys/disk.h> 94 #include <sys/buf.h> 95 #include <sys/uio.h> 96 #include <sys/syslog.h> 97 #include <sys/queue.h> 98 #include <sys/fdio.h> 99 #if NRND > 0 100 #include <sys/rnd.h> 101 #endif 102 103 #include <uvm/uvm_extern.h> 104 105 #include <machine/bus.h> 106 #include <machine/cpu.h> 107 108 #include <arch/x68k/dev/intiovar.h> 109 #include <arch/x68k/dev/dmacvar.h> 110 #include <arch/x68k/dev/fdreg.h> 111 #include <arch/x68k/dev/opmreg.h> /* for CT1 access */ 112 113 #include "locators.h" 114 115 #ifdef FDDEBUG 116 #define DPRINTF(x) if (fddebug) printf x 117 int fddebug = 0; 118 #else 119 #define DPRINTF(x) 120 #endif 121 122 #define FDUNIT(dev) (minor(dev) / 8) 123 #define FDTYPE(dev) (minor(dev) % 8) 124 125 enum fdc_state { 126 DEVIDLE = 0, 127 MOTORWAIT, 128 DOSEEK, 129 SEEKWAIT, 130 SEEKTIMEDOUT, 131 SEEKCOMPLETE, 132 DOIO, 133 IOCOMPLETE, 134 IOTIMEDOUT, 135 DORESET, 136 RESETCOMPLETE, 137 RESETTIMEDOUT, 138 DORECAL, 139 RECALWAIT, 140 RECALTIMEDOUT, 141 RECALCOMPLETE, 142 DOCOPY, 143 DOIOHALF, 144 COPYCOMPLETE, 145 }; 146 147 /* software state, per controller */ 148 struct fdc_softc { 149 struct device sc_dev; /* boilerplate */ 150 151 bus_space_tag_t sc_iot; /* intio i/o space identifier */ 152 bus_space_handle_t sc_ioh; /* intio io handle */ 153 154 struct callout sc_timo_ch; /* timeout callout */ 155 struct callout sc_intr_ch; /* pseudo-intr callout */ 156 157 bus_dma_tag_t sc_dmat; /* intio dma tag */ 158 bus_dmamap_t sc_dmamap; /* dma map */ 159 u_int8_t *sc_addr; /* physical address */ 160 struct dmac_channel_stat *sc_dmachan; /* intio dma channel */ 161 struct dmac_dma_xfer *sc_xfer; /* dma transfer */ 162 163 struct fd_softc *sc_fd[4]; /* pointers to children */ 164 TAILQ_HEAD(drivehead, fd_softc) sc_drives; 165 enum fdc_state sc_state; 166 int sc_errors; /* number of retries so far */ 167 u_char sc_status[7]; /* copy of registers */ 168 } fdc_softc; 169 170 bdev_decl(fd); 171 cdev_decl(fd); 172 173 int fdcintr __P((void*)); 174 void fdcreset __P((struct fdc_softc *)); 175 176 /* controller driver configuration */ 177 int fdcprobe __P((struct device *, struct cfdata *, void *)); 178 void fdcattach __P((struct device *, struct device *, void *)); 179 int fdprint __P((void *, const char *)); 180 181 struct cfattach fdc_ca = { 182 sizeof(struct fdc_softc), fdcprobe, fdcattach 183 }; 184 185 extern struct cfdriver fdc_cd; 186 187 /* 188 * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how 189 * we tell them apart. 190 */ 191 struct fd_type { 192 int sectrac; /* sectors per track */ 193 int heads; /* number of heads */ 194 int seccyl; /* sectors per cylinder */ 195 int secsize; /* size code for sectors */ 196 int datalen; /* data len when secsize = 0 */ 197 int steprate; /* step rate and head unload time */ 198 int gap1; /* gap len between sectors */ 199 int gap2; /* formatting gap */ 200 int cyls; /* total num of cylinders */ 201 int size; /* size of disk in sectors */ 202 int step; /* steps per cylinder */ 203 int rate; /* transfer speed code */ 204 char *name; 205 }; 206 207 /* The order of entries in the following table is important -- BEWARE! */ 208 struct fd_type fd_types[] = { 209 { 8,2,16,3,0xff,0xdf,0x35,0x74,77,1232,1,FDC_500KBPS, "1.2MB/[1024bytes/sector]" }, /* 1.2 MB japanese format */ 210 { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS,"1.44MB" }, /* 1.44MB diskette */ 211 { 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS, "1.2MB" }, /* 1.2 MB AT-diskettes */ 212 { 9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS, "360KB/AT" }, /* 360kB in 1.2MB drive */ 213 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS, "360KB/PC" }, /* 360kB PC diskettes */ 214 { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS, "720KB" }, /* 3.5" 720kB diskette */ 215 { 9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS, "720KB/x" }, /* 720kB in 1.2MB drive */ 216 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS, "360KB/x" }, /* 360kB in 720kB drive */ 217 }; 218 219 /* software state, per disk (with up to 4 disks per ctlr) */ 220 struct fd_softc { 221 struct device sc_dev; 222 struct disk sc_dk; 223 224 struct fd_type *sc_deftype; /* default type descriptor */ 225 struct fd_type *sc_type; /* current type descriptor */ 226 227 struct callout sc_motoron_ch; 228 struct callout sc_motoroff_ch; 229 230 daddr_t sc_blkno; /* starting block number */ 231 int sc_bcount; /* byte count left */ 232 int sc_opts; /* user-set options */ 233 int sc_skip; /* bytes already transferred */ 234 int sc_nblks; /* number of blocks currently transferring */ 235 int sc_nbytes; /* number of bytes currently transferring */ 236 237 int sc_drive; /* physical unit number */ 238 int sc_flags; 239 #define FD_BOPEN 0x01 /* it's open */ 240 #define FD_COPEN 0x02 /* it's open */ 241 #define FD_OPEN (FD_BOPEN|FD_COPEN) /* it's open */ 242 #define FD_MOTOR 0x04 /* motor should be on */ 243 #define FD_MOTOR_WAIT 0x08 /* motor coming up */ 244 #define FD_ALIVE 0x10 /* alive */ 245 int sc_cylin; /* where we think the head is */ 246 247 TAILQ_ENTRY(fd_softc) sc_drivechain; 248 int sc_ops; /* I/O ops since last switch */ 249 struct buf_queue sc_q; /* pending I/O requests */ 250 int sc_active; /* number of active I/O operations */ 251 u_char *sc_copybuf; /* for secsize >=3 */ 252 u_char sc_part; /* for secsize >=3 */ 253 #define SEC_P10 0x02 /* first part */ 254 #define SEC_P01 0x01 /* second part */ 255 #define SEC_P11 0x03 /* both part */ 256 257 #if NRND > 0 258 rndsource_element_t rnd_source; 259 #endif 260 }; 261 262 /* floppy driver configuration */ 263 int fdprobe __P((struct device *, struct cfdata *, void *)); 264 void fdattach __P((struct device *, struct device *, void *)); 265 266 struct cfattach fd_ca = { 267 sizeof(struct fd_softc), fdprobe, fdattach 268 }; 269 270 extern struct cfdriver fd_cd; 271 272 void fdstrategy __P((struct buf *)); 273 void fdstart __P((struct fd_softc *fd)); 274 275 struct dkdriver fddkdriver = { fdstrategy }; 276 277 void fd_set_motor __P((struct fdc_softc *fdc, int reset)); 278 void fd_motor_off __P((void *arg)); 279 void fd_motor_on __P((void *arg)); 280 int fdcresult __P((struct fdc_softc *fdc)); 281 int out_fdc __P((bus_space_tag_t, bus_space_handle_t, u_char x)); 282 void fdcstart __P((struct fdc_softc *fdc)); 283 void fdcstatus __P((struct device *dv, int n, char *s)); 284 void fdctimeout __P((void *arg)); 285 void fdcpseudointr __P((void *arg)); 286 void fdcretry __P((struct fdc_softc *fdc)); 287 void fdfinish __P((struct fd_softc *fd, struct buf *bp)); 288 __inline struct fd_type *fd_dev_to_type __P((struct fd_softc *, dev_t)); 289 static int fdcpoll __P((struct fdc_softc *)); 290 static int fdgetdisklabel __P((struct fd_softc *, dev_t)); 291 static void fd_do_eject __P((struct fdc_softc *, int)); 292 293 void fd_mountroot_hook __P((struct device *)); 294 295 /* dma transfer routines */ 296 __inline static void fdc_dmastart __P((struct fdc_softc*, int, 297 caddr_t, vsize_t)); 298 static int fdcdmaintr __P((void*)); 299 static int fdcdmaerrintr __P((void*)); 300 301 __inline static void 302 fdc_dmastart(fdc, read, addr, count) 303 struct fdc_softc *fdc; 304 int read; 305 caddr_t addr; 306 vsize_t count; 307 { 308 int error; 309 310 DPRINTF(("fdc_dmastart: (%s, addr = %p, count = %d\n", 311 read ? "read" : "write", (caddr_t) addr, count)); 312 313 error = bus_dmamap_load(fdc->sc_dmat, fdc->sc_dmamap, addr, count, 314 0, BUS_DMA_NOWAIT); 315 if (error) { 316 panic ("fdc_dmastart: cannot load dmamap"); 317 } 318 319 bus_dmamap_sync(fdc->sc_dmat, fdc->sc_dmamap, 0, count, 320 read?BUS_DMASYNC_PREREAD:BUS_DMASYNC_PREWRITE); 321 322 fdc->sc_xfer = dmac_prepare_xfer(fdc->sc_dmachan, fdc->sc_dmat, 323 fdc->sc_dmamap, 324 (read? 325 DMAC_OCR_DIR_DTM:DMAC_OCR_DIR_MTD), 326 (DMAC_SCR_MAC_COUNT_UP| 327 DMAC_SCR_DAC_NO_COUNT), 328 (u_int8_t*) (fdc->sc_addr + 329 fddata)); /* XXX */ 330 331 dmac_start_xfer(fdc->sc_dmachan->ch_softc, fdc->sc_xfer); 332 } 333 334 static int 335 fdcdmaintr(arg) 336 void *arg; 337 { 338 struct fdc_softc *fdc = arg; 339 340 bus_dmamap_unload(fdc->sc_dmat, fdc->sc_dmamap); 341 342 return 0; 343 } 344 345 static int 346 fdcdmaerrintr(dummy) 347 void *dummy; 348 { 349 DPRINTF(("fdcdmaerrintr\n")); 350 351 return 0; 352 } 353 354 /* ARGSUSED */ 355 int 356 fdcprobe(parent, cf, aux) 357 struct device *parent; 358 struct cfdata *cf; 359 void *aux; 360 { 361 struct intio_attach_args *ia = aux; 362 363 if (strcmp(ia->ia_name, "fdc") != 0) 364 return 0; 365 366 if (ia->ia_addr == INTIOCF_ADDR_DEFAULT) 367 ia->ia_addr = FDC_ADDR; 368 if (ia->ia_intr == INTIOCF_INTR_DEFAULT) 369 ia->ia_intr = FDC_INTR; 370 if (ia->ia_dma == INTIOCF_DMA_DEFAULT) 371 ia->ia_dma = FDC_DMA; 372 if (ia->ia_dmaintr == INTIOCF_DMAINTR_DEFAULT) 373 ia->ia_dmaintr = FDC_DMAINTR; 374 375 if ((ia->ia_intr & 0x03) != 0) 376 return 0; 377 378 ia->ia_size = 0x2000; 379 if (intio_map_allocate_region (parent, ia, INTIO_MAP_TESTONLY)) 380 return 0; 381 382 /* builtin device; always there */ 383 return 1; 384 } 385 386 /* 387 * Arguments passed between fdcattach and fdprobe. 388 */ 389 struct fdc_attach_args { 390 int fa_drive; 391 struct fd_type *fa_deftype; 392 }; 393 394 /* 395 * Print the location of a disk drive (called just before attaching the 396 * the drive). If `fdc' is not NULL, the drive was found but was not 397 * in the system config file; print the drive name as well. 398 * Return QUIET (config_find ignores this if the device was configured) to 399 * avoid printing `fdN not configured' messages. 400 */ 401 int 402 fdprint(aux, fdc) 403 void *aux; 404 const char *fdc; 405 { 406 register struct fdc_attach_args *fa = aux; 407 408 if (!fdc) 409 printf(" drive %d", fa->fa_drive); 410 return QUIET; 411 } 412 413 void 414 fdcattach(parent, self, aux) 415 struct device *parent, *self; 416 void *aux; 417 { 418 struct fdc_softc *fdc = (void *)self; 419 bus_space_tag_t iot; 420 bus_space_handle_t ioh; 421 struct intio_attach_args *ia = aux; 422 struct fdc_attach_args fa; 423 424 iot = ia->ia_bst; 425 426 printf("\n"); 427 428 callout_init(&fdc->sc_timo_ch); 429 callout_init(&fdc->sc_intr_ch); 430 431 /* Re-map the I/O space. */ 432 bus_space_map(iot, ia->ia_addr, 0x2000, BUS_SPACE_MAP_SHIFTED, &ioh); 433 434 fdc->sc_iot = iot; 435 fdc->sc_ioh = ioh; 436 fdc->sc_addr = (void*) ia->ia_addr; 437 438 fdc->sc_dmat = ia->ia_dmat; 439 fdc->sc_state = DEVIDLE; 440 TAILQ_INIT(&fdc->sc_drives); 441 442 /* Initialize DMAC channel */ 443 fdc->sc_dmachan = dmac_alloc_channel(parent, ia->ia_dma, "fdc", 444 ia->ia_dmaintr, fdcdmaintr, fdc, 445 ia->ia_dmaintr+1, fdcdmaerrintr, 446 fdc); 447 if (bus_dmamap_create(fdc->sc_dmat, FDC_MAXIOSIZE, 1, DMAC_MAXSEGSZ, 448 0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW, 449 &fdc->sc_dmamap)) { 450 printf("%s: can't set up intio DMA map\n", 451 fdc->sc_dev.dv_xname); 452 return; 453 } 454 455 if (intio_intr_establish(ia->ia_intr, "fdc", fdcintr, fdc)) 456 panic ("Could not establish interrupt (duplicated vector?)."); 457 intio_set_ivec(ia->ia_intr); 458 459 /* reset */ 460 intio_disable_intr(SICILIAN_INTR_FDD); 461 intio_enable_intr(SICILIAN_INTR_FDC); 462 fdcresult(fdc); 463 fdcreset(fdc); 464 465 printf("%s: uPD72065 FDC\n", fdc->sc_dev.dv_xname); 466 out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */ 467 out_fdc(iot, ioh, 0xd0); 468 out_fdc(iot, ioh, 0x10); 469 470 /* physical limit: four drives per controller. */ 471 for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) { 472 (void)config_found(self, (void *)&fa, fdprint); 473 } 474 475 intio_enable_intr(SICILIAN_INTR_FDC); 476 } 477 478 void 479 fdcreset(fdc) 480 struct fdc_softc *fdc; 481 { 482 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdsts, NE7CMD_RESET); 483 } 484 485 static int 486 fdcpoll(fdc) 487 struct fdc_softc *fdc; 488 { 489 int i = 25000, n; 490 while (--i > 0) { 491 if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC)) { 492 out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI); 493 n = fdcresult(fdc); 494 break; 495 } 496 DELAY(100); 497 } 498 return i; 499 } 500 501 int 502 fdprobe(parent, cf, aux) 503 struct device *parent; 504 struct cfdata *cf; 505 void *aux; 506 { 507 struct fdc_softc *fdc = (void *)parent; 508 struct fd_type *type; 509 struct fdc_attach_args *fa = aux; 510 int drive = fa->fa_drive; 511 bus_space_tag_t iot = fdc->sc_iot; 512 bus_space_handle_t ioh = fdc->sc_ioh; 513 int n; 514 int found = 0; 515 int i; 516 517 if (cf->cf_loc[FDCCF_UNIT] != FDCCF_UNIT_DEFAULT && 518 cf->cf_loc[FDCCF_UNIT] != drive) 519 return 0; 520 521 type = &fd_types[0]; /* XXX 1.2MB */ 522 523 intio_disable_intr(SICILIAN_INTR_FDC); 524 525 /* select drive and turn on motor */ 526 bus_space_write_1(iot, ioh, fdctl, 0x80 | (type->rate << 4)| drive); 527 fdc_force_ready(FDCRDY); 528 fdcpoll(fdc); 529 530 retry: 531 out_fdc(iot, ioh, NE7CMD_RECAL); 532 out_fdc(iot, ioh, drive); 533 534 i = 25000; 535 while (--i > 0) { 536 if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC)) { 537 out_fdc(iot, ioh, NE7CMD_SENSEI); 538 n = fdcresult(fdc); 539 break; 540 } 541 DELAY(100); 542 } 543 544 #ifdef FDDEBUG 545 { 546 int i; 547 DPRINTF(("fdprobe: status")); 548 for (i = 0; i < n; i++) 549 DPRINTF((" %x", fdc->sc_status[i])); 550 DPRINTF(("\n")); 551 } 552 #endif 553 554 if (n == 2) { 555 if ((fdc->sc_status[0] & 0xf0) == 0x20) { 556 found = 1; 557 } else if ((fdc->sc_status[0] & 0xf0) == 0xc0) { 558 goto retry; 559 } 560 } 561 562 /* turn off motor */ 563 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, 564 fdctl, (type->rate << 4)| drive); 565 fdc_force_ready(FDCSTBY); 566 if (!found) { 567 intio_enable_intr(SICILIAN_INTR_FDC); 568 return 0; 569 } 570 571 return 1; 572 } 573 574 /* 575 * Controller is working, and drive responded. Attach it. 576 */ 577 void 578 fdattach(parent, self, aux) 579 struct device *parent, *self; 580 void *aux; 581 { 582 struct fdc_softc *fdc = (void *)parent; 583 struct fd_softc *fd = (void *)self; 584 struct fdc_attach_args *fa = aux; 585 struct fd_type *type = &fd_types[0]; /* XXX 1.2MB */ 586 int drive = fa->fa_drive; 587 588 callout_init(&fd->sc_motoron_ch); 589 callout_init(&fd->sc_motoroff_ch); 590 591 fd->sc_flags = 0; 592 593 if (type) 594 printf(": %s, %d cyl, %d head, %d sec\n", type->name, 595 type->cyls, type->heads, type->sectrac); 596 else 597 printf(": density unknown\n"); 598 599 BUFQ_INIT(&fd->sc_q); 600 fd->sc_cylin = -1; 601 fd->sc_drive = drive; 602 fd->sc_deftype = type; 603 fdc->sc_fd[drive] = fd; 604 605 fd->sc_copybuf = (u_char *)malloc(NBPG, M_DEVBUF, M_WAITOK); 606 if (fd->sc_copybuf == 0) 607 printf("fdprobe: WARNING!! malloc() failed.\n"); 608 fd->sc_flags |= FD_ALIVE; 609 610 /* 611 * Initialize and attach the disk structure. 612 */ 613 fd->sc_dk.dk_name = fd->sc_dev.dv_xname; 614 fd->sc_dk.dk_driver = &fddkdriver; 615 disk_attach(&fd->sc_dk); 616 617 /* 618 * Establish a mountroot_hook anyway in case we booted 619 * with RB_ASKNAME and get selected as the boot device. 620 */ 621 mountroothook_establish(fd_mountroot_hook, &fd->sc_dev); 622 623 #if NRND > 0 624 rnd_attach_source(&fd->rnd_source, fd->sc_dev.dv_xname, 625 RND_TYPE_DISK, 0); 626 #endif 627 } 628 629 __inline struct fd_type * 630 fd_dev_to_type(fd, dev) 631 struct fd_softc *fd; 632 dev_t dev; 633 { 634 int type = FDTYPE(dev); 635 636 if (type > (sizeof(fd_types) / sizeof(fd_types[0]))) 637 return NULL; 638 return &fd_types[type]; 639 } 640 641 void 642 fdstrategy(bp) 643 register struct buf *bp; /* IO operation to perform */ 644 { 645 struct fd_softc *fd; 646 int unit = FDUNIT(bp->b_dev); 647 int sz; 648 int s; 649 650 if (unit >= fd_cd.cd_ndevs || 651 (fd = fd_cd.cd_devs[unit]) == 0 || 652 bp->b_blkno < 0 || 653 (bp->b_bcount % FDC_BSIZE) != 0) { 654 DPRINTF(("fdstrategy: unit=%d, blkno=%d, bcount=%d\n", unit, 655 bp->b_blkno, bp->b_bcount)); 656 bp->b_error = EINVAL; 657 goto bad; 658 } 659 660 /* If it's a null transfer, return immediately. */ 661 if (bp->b_bcount == 0) 662 goto done; 663 664 sz = howmany(bp->b_bcount, FDC_BSIZE); 665 666 if (bp->b_blkno + sz > (fd->sc_type->size << (fd->sc_type->secsize - 2))) { 667 sz = (fd->sc_type->size << (fd->sc_type->secsize - 2)) - bp->b_blkno; 668 if (sz == 0) { 669 /* If exactly at end of disk, return EOF. */ 670 bp->b_resid = bp->b_bcount; 671 goto done; 672 } 673 if (sz < 0) { 674 /* If past end of disk, return EINVAL. */ 675 bp->b_error = EINVAL; 676 goto bad; 677 } 678 /* Otherwise, truncate request. */ 679 bp->b_bcount = sz << DEV_BSHIFT; 680 } 681 682 bp->b_rawblkno = bp->b_blkno; 683 bp->b_cylinder = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE) 684 / (fd->sc_type->seccyl * (1 << (fd->sc_type->secsize - 2))); 685 686 DPRINTF(("fdstrategy: %s b_blkno %d b_bcount %ld cylin %ld\n", 687 bp->b_flags & B_READ ? "read" : "write", 688 bp->b_blkno, bp->b_bcount, bp->b_cylinder)); 689 /* Queue transfer on drive, activate drive and controller if idle. */ 690 s = splbio(); 691 disksort_cylinder(&fd->sc_q, bp); 692 callout_stop(&fd->sc_motoroff_ch); /* a good idea */ 693 if (fd->sc_active == 0) 694 fdstart(fd); 695 #ifdef DIAGNOSTIC 696 else { 697 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; 698 if (fdc->sc_state == DEVIDLE) { 699 printf("fdstrategy: controller inactive\n"); 700 fdcstart(fdc); 701 } 702 } 703 #endif 704 splx(s); 705 return; 706 707 bad: 708 bp->b_flags |= B_ERROR; 709 done: 710 /* Toss transfer; we're done early. */ 711 biodone(bp); 712 } 713 714 void 715 fdstart(fd) 716 struct fd_softc *fd; 717 { 718 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; 719 int active = fdc->sc_drives.tqh_first != 0; 720 721 /* Link into controller queue. */ 722 fd->sc_active = 1; 723 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain); 724 725 /* If controller not already active, start it. */ 726 if (!active) 727 fdcstart(fdc); 728 } 729 730 void 731 fdfinish(fd, bp) 732 struct fd_softc *fd; 733 struct buf *bp; 734 { 735 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; 736 737 /* 738 * Move this drive to the end of the queue to give others a `fair' 739 * chance. We only force a switch if N operations are completed while 740 * another drive is waiting to be serviced, since there is a long motor 741 * startup delay whenever we switch. 742 */ 743 if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) { 744 fd->sc_ops = 0; 745 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain); 746 if (BUFQ_NEXT(bp) != NULL) { 747 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain); 748 } else 749 fd->sc_active = 0; 750 } 751 bp->b_resid = fd->sc_bcount; 752 fd->sc_skip = 0; 753 BUFQ_REMOVE(&fd->sc_q, bp); 754 755 #if NRND > 0 756 rnd_add_uint32(&fd->rnd_source, bp->b_blkno); 757 #endif 758 759 biodone(bp); 760 /* turn off motor 5s from now */ 761 callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd); 762 fdc->sc_state = DEVIDLE; 763 } 764 765 int 766 fdread(dev, uio, flags) 767 dev_t dev; 768 struct uio *uio; 769 int flags; 770 { 771 772 return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio)); 773 } 774 775 int 776 fdwrite(dev, uio, flags) 777 dev_t dev; 778 struct uio *uio; 779 int flags; 780 { 781 782 return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio)); 783 } 784 785 void 786 fd_set_motor(fdc, reset) 787 struct fdc_softc *fdc; 788 int reset; 789 { 790 struct fd_softc *fd; 791 int n; 792 793 DPRINTF(("fd_set_motor:\n")); 794 for (n = 0; n < 4; n++) 795 if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR)) { 796 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdctl, 797 0x80 | (fd->sc_type->rate << 4)| n); 798 } 799 } 800 801 void 802 fd_motor_off(arg) 803 void *arg; 804 { 805 struct fd_softc *fd = arg; 806 struct fdc_softc *fdc = (struct fdc_softc*) fd->sc_dev.dv_parent; 807 int s; 808 809 DPRINTF(("fd_motor_off:\n")); 810 811 s = splbio(); 812 fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT); 813 bus_space_write_1 (fdc->sc_iot, fdc->sc_ioh, fdctl, 814 (fd->sc_type->rate << 4) | fd->sc_drive); 815 #if 0 816 fd_set_motor(fdc, 0); /* XXX */ 817 #endif 818 splx(s); 819 } 820 821 void 822 fd_motor_on(arg) 823 void *arg; 824 { 825 struct fd_softc *fd = arg; 826 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; 827 int s; 828 829 DPRINTF(("fd_motor_on:\n")); 830 831 s = splbio(); 832 fd->sc_flags &= ~FD_MOTOR_WAIT; 833 if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT)) 834 (void) fdcintr(fdc); 835 splx(s); 836 } 837 838 int 839 fdcresult(fdc) 840 struct fdc_softc *fdc; 841 { 842 bus_space_tag_t iot = fdc->sc_iot; 843 bus_space_handle_t ioh = fdc->sc_ioh; 844 u_char i; 845 int j = 100000, 846 n = 0; 847 848 for (; j; j--) { 849 i = bus_space_read_1(iot, ioh, fdsts) & 850 (NE7_DIO | NE7_RQM | NE7_CB); 851 852 if (i == NE7_RQM) 853 return n; 854 if (i == (NE7_DIO | NE7_RQM | NE7_CB)) { 855 if (n >= sizeof(fdc->sc_status)) { 856 log(LOG_ERR, "fdcresult: overrun\n"); 857 return -1; 858 } 859 fdc->sc_status[n++] = 860 bus_space_read_1(iot, ioh, fddata); 861 } 862 delay(10); 863 } 864 log(LOG_ERR, "fdcresult: timeout\n"); 865 return -1; 866 } 867 868 int 869 out_fdc(iot, ioh, x) 870 bus_space_tag_t iot; 871 bus_space_handle_t ioh; 872 u_char x; 873 { 874 int i = 100000; 875 876 while ((bus_space_read_1(iot, ioh, fdsts) & NE7_DIO) && i-- > 0); 877 if (i <= 0) 878 return -1; 879 while ((bus_space_read_1(iot, ioh, fdsts) & NE7_RQM) == 0 && i-- > 0); 880 if (i <= 0) 881 return -1; 882 bus_space_write_1(iot, ioh, fddata, x); 883 return 0; 884 } 885 886 int 887 fdopen(dev, flags, mode, p) 888 dev_t dev; 889 int flags, mode; 890 struct proc *p; 891 { 892 int unit; 893 struct fd_softc *fd; 894 struct fd_type *type; 895 struct fdc_softc *fdc; 896 897 unit = FDUNIT(dev); 898 if (unit >= fd_cd.cd_ndevs) 899 return ENXIO; 900 fd = fd_cd.cd_devs[unit]; 901 if (fd == 0) 902 return ENXIO; 903 type = fd_dev_to_type(fd, dev); 904 if (type == NULL) 905 return ENXIO; 906 907 if ((fd->sc_flags & FD_OPEN) != 0 && 908 fd->sc_type != type) 909 return EBUSY; 910 911 fdc = (void *)fd->sc_dev.dv_parent; 912 if ((fd->sc_flags & FD_OPEN) == 0) { 913 /* Lock eject button */ 914 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 915 0x40 | ( 1 << unit)); 916 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0x40); 917 } 918 919 fd->sc_type = type; 920 fd->sc_cylin = -1; 921 922 switch (mode) { 923 case S_IFCHR: 924 fd->sc_flags |= FD_COPEN; 925 break; 926 case S_IFBLK: 927 fd->sc_flags |= FD_BOPEN; 928 break; 929 } 930 931 fdgetdisklabel(fd, dev); 932 933 return 0; 934 } 935 936 int 937 fdclose(dev, flags, mode, p) 938 dev_t dev; 939 int flags, mode; 940 struct proc *p; 941 { 942 int unit = FDUNIT(dev); 943 struct fd_softc *fd = fd_cd.cd_devs[unit]; 944 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; 945 946 DPRINTF(("fdclose %d\n", unit)); 947 948 switch (mode) { 949 case S_IFCHR: 950 fd->sc_flags &= ~FD_COPEN; 951 break; 952 case S_IFBLK: 953 fd->sc_flags &= ~FD_BOPEN; 954 break; 955 } 956 957 if ((fd->sc_flags & FD_OPEN) == 0) { 958 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 959 ( 1 << unit)); 960 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0); 961 } 962 return 0; 963 } 964 965 void 966 fdcstart(fdc) 967 struct fdc_softc *fdc; 968 { 969 970 #ifdef DIAGNOSTIC 971 /* only got here if controller's drive queue was inactive; should 972 be in idle state */ 973 if (fdc->sc_state != DEVIDLE) { 974 printf("fdcstart: not idle\n"); 975 return; 976 } 977 #endif 978 (void) fdcintr(fdc); 979 } 980 981 void 982 fdcstatus(dv, n, s) 983 struct device *dv; 984 int n; 985 char *s; 986 { 987 struct fdc_softc *fdc = (void *)dv->dv_parent; 988 char bits[64]; 989 990 if (n == 0) { 991 out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI); 992 (void) fdcresult(fdc); 993 n = 2; 994 } 995 996 printf("%s: %s: state %d", dv->dv_xname, s, fdc->sc_state); 997 998 switch (n) { 999 case 0: 1000 printf("\n"); 1001 break; 1002 case 2: 1003 printf(" (st0 %s cyl %d)\n", 1004 bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS, 1005 bits, sizeof(bits)), fdc->sc_status[1]); 1006 break; 1007 case 7: 1008 printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0], 1009 NE7_ST0BITS, bits, sizeof(bits))); 1010 printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1], 1011 NE7_ST1BITS, bits, sizeof(bits))); 1012 printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2], 1013 NE7_ST2BITS, bits, sizeof(bits))); 1014 printf(" cyl %d head %d sec %d)\n", 1015 fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]); 1016 break; 1017 #ifdef DIAGNOSTIC 1018 default: 1019 printf(" fdcstatus: weird size: %d\n", n); 1020 break; 1021 #endif 1022 } 1023 } 1024 1025 void 1026 fdctimeout(arg) 1027 void *arg; 1028 { 1029 struct fdc_softc *fdc = arg; 1030 struct fd_softc *fd = fdc->sc_drives.tqh_first; 1031 int s; 1032 1033 s = splbio(); 1034 fdcstatus(&fd->sc_dev, 0, "timeout"); 1035 1036 if (BUFQ_FIRST(&fd->sc_q) != NULL) 1037 fdc->sc_state++; 1038 else 1039 fdc->sc_state = DEVIDLE; 1040 1041 (void) fdcintr(fdc); 1042 splx(s); 1043 } 1044 1045 #if 0 1046 void 1047 fdcpseudointr(arg) 1048 void *arg; 1049 { 1050 int s; 1051 struct fdc_softc *fdc = arg; 1052 1053 /* just ensure it has the right spl */ 1054 s = splbio(); 1055 (void) fdcintr(fdc); 1056 splx(s); 1057 } 1058 #endif 1059 1060 int 1061 fdcintr(arg) 1062 void *arg; 1063 { 1064 struct fdc_softc *fdc = arg; 1065 #define st0 fdc->sc_status[0] 1066 #define cyl fdc->sc_status[1] 1067 struct fd_softc *fd; 1068 struct buf *bp; 1069 bus_space_tag_t iot = fdc->sc_iot; 1070 bus_space_handle_t ioh = fdc->sc_ioh; 1071 int read, head, sec, pos, i, sectrac, nblks; 1072 int tmp; 1073 struct fd_type *type; 1074 1075 loop: 1076 fd = fdc->sc_drives.tqh_first; 1077 if (fd == NULL) { 1078 DPRINTF(("fdcintr: set DEVIDLE\n")); 1079 if (fdc->sc_state == DEVIDLE) { 1080 if (intio_get_sicilian_intr() & SICILIAN_STAT_FDC) { 1081 out_fdc(iot, ioh, NE7CMD_SENSEI); 1082 if ((tmp = fdcresult(fdc)) != 2 || 1083 (st0 & 0xf8) != 0x20) { 1084 goto loop; 1085 } 1086 } 1087 } 1088 /* no drives waiting; end */ 1089 fdc->sc_state = DEVIDLE; 1090 return 1; 1091 } 1092 1093 /* Is there a transfer to this drive? If not, deactivate drive. */ 1094 bp = BUFQ_FIRST(&fd->sc_q); 1095 if (bp == NULL) { 1096 fd->sc_ops = 0; 1097 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain); 1098 fd->sc_active = 0; 1099 goto loop; 1100 } 1101 1102 switch (fdc->sc_state) { 1103 case DEVIDLE: 1104 DPRINTF(("fdcintr: in DEVIDLE\n")); 1105 fdc->sc_errors = 0; 1106 fd->sc_skip = 0; 1107 fd->sc_bcount = bp->b_bcount; 1108 fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE); 1109 callout_stop(&fd->sc_motoroff_ch); 1110 if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) { 1111 fdc->sc_state = MOTORWAIT; 1112 return 1; 1113 } 1114 if ((fd->sc_flags & FD_MOTOR) == 0) { 1115 /* Turn on the motor */ 1116 /* being careful about other drives. */ 1117 for (i = 0; i < 4; i++) { 1118 struct fd_softc *ofd = fdc->sc_fd[i]; 1119 if (ofd && ofd->sc_flags & FD_MOTOR) { 1120 callout_stop(&ofd->sc_motoroff_ch); 1121 ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT); 1122 break; 1123 } 1124 } 1125 fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT; 1126 fd_set_motor(fdc, 0); 1127 fdc->sc_state = MOTORWAIT; 1128 /* allow .5s for motor to stabilize */ 1129 callout_reset(&fd->sc_motoron_ch, hz / 2, 1130 fd_motor_on, fd); 1131 return 1; 1132 } 1133 /* Make sure the right drive is selected. */ 1134 fd_set_motor(fdc, 0); 1135 1136 /* fall through */ 1137 case DOSEEK: 1138 doseek: 1139 DPRINTF(("fdcintr: in DOSEEK\n")); 1140 if (fd->sc_cylin == bp->b_cylinder) 1141 goto doio; 1142 1143 out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */ 1144 out_fdc(iot, ioh, 0xd0); /* XXX const */ 1145 out_fdc(iot, ioh, 0x10); 1146 1147 out_fdc(iot, ioh, NE7CMD_SEEK); /* seek function */ 1148 out_fdc(iot, ioh, fd->sc_drive); /* drive number */ 1149 out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step); 1150 1151 fd->sc_cylin = -1; 1152 fdc->sc_state = SEEKWAIT; 1153 1154 fd->sc_dk.dk_seek++; 1155 disk_busy(&fd->sc_dk); 1156 1157 callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc); 1158 return 1; 1159 1160 case DOIO: 1161 doio: 1162 DPRINTF(("fdcintr: DOIO: ")); 1163 type = fd->sc_type; 1164 sectrac = type->sectrac; 1165 pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2))); 1166 sec = pos / (1 << (type->secsize - 2)); 1167 if (type->secsize == 2) { 1168 fd->sc_part = SEC_P11; 1169 nblks = (sectrac - sec) << (type->secsize - 2); 1170 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE); 1171 DPRINTF(("nblks(0)")); 1172 } else if ((fd->sc_blkno % 2) == 0) { 1173 if (fd->sc_bcount & 0x00000200) { 1174 if (fd->sc_bcount == FDC_BSIZE) { 1175 fd->sc_part = SEC_P10; 1176 nblks = 1; 1177 DPRINTF(("nblks(1)")); 1178 } else { 1179 fd->sc_part = SEC_P11; 1180 nblks = (sectrac - sec) * 2; 1181 nblks = min(nblks, fd->sc_bcount 1182 / FDC_BSIZE - 1); 1183 DPRINTF(("nblks(2)")); 1184 } 1185 } else { 1186 fd->sc_part = SEC_P11; 1187 nblks = (sectrac - sec) 1188 << (type->secsize - 2); 1189 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE); 1190 DPRINTF(("nblks(3)")); 1191 } 1192 } else { 1193 fd->sc_part = SEC_P01; 1194 nblks = 1; 1195 DPRINTF(("nblks(4)")); 1196 } 1197 nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE); 1198 DPRINTF((" %d\n", nblks)); 1199 fd->sc_nblks = nblks; 1200 fd->sc_nbytes = nblks * FDC_BSIZE; 1201 head = (fd->sc_blkno 1202 % (type->seccyl * (1 << (type->secsize - 2)))) 1203 / (type->sectrac * (1 << (type->secsize - 2))); 1204 1205 #ifdef DIAGNOSTIC 1206 {int block; 1207 block = ((fd->sc_cylin * type->heads + head) * type->sectrac 1208 + sec) * (1 << (type->secsize - 2)); 1209 block += (fd->sc_part == SEC_P01) ? 1 : 0; 1210 if (block != fd->sc_blkno) { 1211 printf("C H R N: %d %d %d %d\n", fd->sc_cylin, head, sec, type->secsize); 1212 printf("fdcintr: doio: block %d != blkno %d\n", block, fd->sc_blkno); 1213 #ifdef DDB 1214 Debugger(); 1215 #endif 1216 }} 1217 #endif 1218 read = bp->b_flags & B_READ; 1219 DPRINTF(("fdcintr: %s drive %d track %d head %d sec %d nblks %d, skip %d\n", 1220 read ? "read" : "write", fd->sc_drive, fd->sc_cylin, 1221 head, sec, nblks, fd->sc_skip)); 1222 DPRINTF(("C H R N: %d %d %d %d\n", fd->sc_cylin, head, sec, 1223 type->secsize)); 1224 1225 if (fd->sc_part != SEC_P11) 1226 goto docopy; 1227 1228 fdc_dmastart(fdc, 1229 read, bp->b_data + fd->sc_skip, fd->sc_nbytes); 1230 if (read) 1231 out_fdc(iot, ioh, NE7CMD_READ); /* READ */ 1232 else 1233 out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */ 1234 out_fdc(iot, ioh, (head << 2) | fd->sc_drive); 1235 out_fdc(iot, ioh, bp->b_cylinder); /* cylinder */ 1236 out_fdc(iot, ioh, head); 1237 out_fdc(iot, ioh, sec + 1); /* sector +1 */ 1238 out_fdc(iot, ioh, type->secsize); /* sector size */ 1239 out_fdc(iot, ioh, type->sectrac); /* sectors/track */ 1240 out_fdc(iot, ioh, type->gap1); /* gap1 size */ 1241 out_fdc(iot, ioh, type->datalen); /* data length */ 1242 fdc->sc_state = IOCOMPLETE; 1243 1244 disk_busy(&fd->sc_dk); 1245 1246 /* allow 2 seconds for operation */ 1247 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc); 1248 return 1; /* will return later */ 1249 1250 case DOCOPY: 1251 docopy: 1252 DPRINTF(("fdcintr: DOCOPY:\n")); 1253 fdc_dmastart(fdc, B_READ, fd->sc_copybuf, 1024); 1254 out_fdc(iot, ioh, NE7CMD_READ); /* READ */ 1255 out_fdc(iot, ioh, (head << 2) | fd->sc_drive); 1256 out_fdc(iot, ioh, bp->b_cylinder); /* cylinder */ 1257 out_fdc(iot, ioh, head); 1258 out_fdc(iot, ioh, sec + 1); /* sector +1 */ 1259 out_fdc(iot, ioh, type->secsize); /* sector size */ 1260 out_fdc(iot, ioh, type->sectrac); /* sectors/track */ 1261 out_fdc(iot, ioh, type->gap1); /* gap1 size */ 1262 out_fdc(iot, ioh, type->datalen); /* data length */ 1263 fdc->sc_state = COPYCOMPLETE; 1264 /* allow 2 seconds for operation */ 1265 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc); 1266 return 1; /* will return later */ 1267 1268 case DOIOHALF: 1269 doiohalf: 1270 DPRINTF((" DOIOHALF:\n")); 1271 1272 #ifdef DIAGNOSTIC 1273 type = fd->sc_type; 1274 sectrac = type->sectrac; 1275 pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2))); 1276 sec = pos / (1 << (type->secsize - 2)); 1277 head = (fd->sc_blkno 1278 % (type->seccyl * (1 << (type->secsize - 2)))) 1279 / (type->sectrac * (1 << (type->secsize - 2))); 1280 {int block; 1281 block = ((fd->sc_cylin * type->heads + head) * type->sectrac + sec) 1282 * (1 << (type->secsize - 2)); 1283 block += (fd->sc_part == SEC_P01) ? 1 : 0; 1284 if (block != fd->sc_blkno) { 1285 printf("fdcintr: block %d != blkno %d\n", block, fd->sc_blkno); 1286 #ifdef DDB 1287 Debugger(); 1288 #endif 1289 }} 1290 #endif 1291 if ((read = bp->b_flags & B_READ)) { 1292 memcpy(bp->b_data + fd->sc_skip, fd->sc_copybuf 1293 + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0), 1294 FDC_BSIZE); 1295 fdc->sc_state = IOCOMPLETE; 1296 goto iocomplete2; 1297 } else { 1298 memcpy(fd->sc_copybuf 1299 + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0), 1300 bp->b_data + fd->sc_skip, FDC_BSIZE); 1301 fdc_dmastart(fdc, read, fd->sc_copybuf, 1024); 1302 } 1303 out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */ 1304 out_fdc(iot, ioh, (head << 2) | fd->sc_drive); 1305 out_fdc(iot, ioh, bp->b_cylinder); /* cylinder */ 1306 out_fdc(iot, ioh, head); 1307 out_fdc(iot, ioh, sec + 1); /* sector +1 */ 1308 out_fdc(iot, ioh, fd->sc_type->secsize); /* sector size */ 1309 out_fdc(iot, ioh, sectrac); /* sectors/track */ 1310 out_fdc(iot, ioh, fd->sc_type->gap1); /* gap1 size */ 1311 out_fdc(iot, ioh, fd->sc_type->datalen); /* data length */ 1312 fdc->sc_state = IOCOMPLETE; 1313 /* allow 2 seconds for operation */ 1314 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc); 1315 return 1; /* will return later */ 1316 1317 case SEEKWAIT: 1318 callout_stop(&fdc->sc_timo_ch); 1319 fdc->sc_state = SEEKCOMPLETE; 1320 /* allow 1/50 second for heads to settle */ 1321 #if 0 1322 callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc); 1323 #endif 1324 return 1; 1325 1326 case SEEKCOMPLETE: 1327 /* Make sure seek really happened */ 1328 DPRINTF(("fdcintr: SEEKCOMPLETE: FDC status = %x\n", 1329 bus_space_read_1(fdc->sc_iot, fdc->sc_ioh, fdsts))); 1330 out_fdc(iot, ioh, NE7CMD_SENSEI); 1331 tmp = fdcresult(fdc); 1332 if ((st0 & 0xf8) == 0xc0) { 1333 DPRINTF(("fdcintr: first seek!\n")); 1334 fdc->sc_state = DORECAL; 1335 goto loop; 1336 } else if (tmp != 2 || 1337 (st0 & 0xf8) != 0x20 || 1338 cyl != bp->b_cylinder) { 1339 #ifdef FDDEBUG 1340 fdcstatus(&fd->sc_dev, 2, "seek failed"); 1341 #endif 1342 fdcretry(fdc); 1343 goto loop; 1344 } 1345 fd->sc_cylin = bp->b_cylinder; 1346 goto doio; 1347 1348 case IOTIMEDOUT: 1349 #if 0 1350 isa_dmaabort(fdc->sc_drq); 1351 #endif 1352 case SEEKTIMEDOUT: 1353 case RECALTIMEDOUT: 1354 case RESETTIMEDOUT: 1355 fdcretry(fdc); 1356 goto loop; 1357 1358 case IOCOMPLETE: /* IO DONE, post-analyze */ 1359 callout_stop(&fdc->sc_timo_ch); 1360 DPRINTF(("fdcintr: in IOCOMPLETE\n")); 1361 if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) { 1362 printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0); 1363 #if 0 1364 isa_dmaabort(fdc->sc_drq); 1365 #endif 1366 fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ? 1367 "read failed" : "write failed"); 1368 printf("blkno %d nblks %d\n", 1369 fd->sc_blkno, fd->sc_nblks); 1370 fdcretry(fdc); 1371 goto loop; 1372 } 1373 #if 0 1374 isa_dmadone(bp->b_flags & B_READ, bp->b_data + fd->sc_skip, 1375 nblks * FDC_BSIZE, fdc->sc_drq); 1376 #endif 1377 iocomplete2: 1378 if (fdc->sc_errors) { 1379 diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF, 1380 fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL); 1381 printf("\n"); 1382 fdc->sc_errors = 0; 1383 } 1384 fd->sc_blkno += fd->sc_nblks; 1385 fd->sc_skip += fd->sc_nbytes; 1386 fd->sc_bcount -= fd->sc_nbytes; 1387 DPRINTF(("fd->sc_bcount = %d\n", fd->sc_bcount)); 1388 if (fd->sc_bcount > 0) { 1389 bp->b_cylinder = fd->sc_blkno 1390 / (fd->sc_type->seccyl 1391 * (1 << (fd->sc_type->secsize - 2))); 1392 goto doseek; 1393 } 1394 fdfinish(fd, bp); 1395 goto loop; 1396 1397 case COPYCOMPLETE: /* IO DONE, post-analyze */ 1398 DPRINTF(("fdcintr: COPYCOMPLETE:")); 1399 callout_stop(&fdc->sc_timo_ch); 1400 if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) { 1401 printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0); 1402 #if 0 1403 isa_dmaabort(fdc->sc_drq); 1404 #endif 1405 fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ? 1406 "read failed" : "write failed"); 1407 printf("blkno %d nblks %d\n", 1408 fd->sc_blkno, fd->sc_nblks); 1409 fdcretry(fdc); 1410 goto loop; 1411 } 1412 goto doiohalf; 1413 1414 case DORESET: 1415 DPRINTF(("fdcintr: in DORESET\n")); 1416 /* try a reset, keep motor on */ 1417 fd_set_motor(fdc, 1); 1418 DELAY(100); 1419 fd_set_motor(fdc, 0); 1420 fdc->sc_state = RESETCOMPLETE; 1421 callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc); 1422 return 1; /* will return later */ 1423 1424 case RESETCOMPLETE: 1425 DPRINTF(("fdcintr: in RESETCOMPLETE\n")); 1426 callout_stop(&fdc->sc_timo_ch); 1427 /* clear the controller output buffer */ 1428 for (i = 0; i < 4; i++) { 1429 out_fdc(iot, ioh, NE7CMD_SENSEI); 1430 (void) fdcresult(fdc); 1431 } 1432 1433 /* fall through */ 1434 case DORECAL: 1435 DPRINTF(("fdcintr: in DORECAL\n")); 1436 out_fdc(iot, ioh, NE7CMD_RECAL); /* recalibrate function */ 1437 out_fdc(iot, ioh, fd->sc_drive); 1438 fdc->sc_state = RECALWAIT; 1439 callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc); 1440 return 1; /* will return later */ 1441 1442 case RECALWAIT: 1443 DPRINTF(("fdcintr: in RECALWAIT\n")); 1444 callout_stop(&fdc->sc_timo_ch); 1445 fdc->sc_state = RECALCOMPLETE; 1446 /* allow 1/30 second for heads to settle */ 1447 #if 0 1448 callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc); 1449 #endif 1450 return 1; /* will return later */ 1451 1452 case RECALCOMPLETE: 1453 DPRINTF(("fdcintr: in RECALCOMPLETE\n")); 1454 out_fdc(iot, ioh, NE7CMD_SENSEI); 1455 tmp = fdcresult(fdc); 1456 if ((st0 & 0xf8) == 0xc0) { 1457 DPRINTF(("fdcintr: first seek!\n")); 1458 fdc->sc_state = DORECAL; 1459 goto loop; 1460 } else if (tmp != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) { 1461 #ifdef FDDEBUG 1462 fdcstatus(&fd->sc_dev, 2, "recalibrate failed"); 1463 #endif 1464 fdcretry(fdc); 1465 goto loop; 1466 } 1467 fd->sc_cylin = 0; 1468 goto doseek; 1469 1470 case MOTORWAIT: 1471 if (fd->sc_flags & FD_MOTOR_WAIT) 1472 return 1; /* time's not up yet */ 1473 goto doseek; 1474 1475 default: 1476 fdcstatus(&fd->sc_dev, 0, "stray interrupt"); 1477 return 1; 1478 } 1479 #ifdef DIAGNOSTIC 1480 panic("fdcintr: impossible"); 1481 #endif 1482 #undef st0 1483 #undef cyl 1484 } 1485 1486 void 1487 fdcretry(fdc) 1488 struct fdc_softc *fdc; 1489 { 1490 struct fd_softc *fd; 1491 struct buf *bp; 1492 char bits[64]; 1493 1494 DPRINTF(("fdcretry:\n")); 1495 fd = fdc->sc_drives.tqh_first; 1496 bp = BUFQ_FIRST(&fd->sc_q); 1497 1498 switch (fdc->sc_errors) { 1499 case 0: 1500 /* try again */ 1501 fdc->sc_state = SEEKCOMPLETE; 1502 break; 1503 1504 case 1: case 2: case 3: 1505 /* didn't work; try recalibrating */ 1506 fdc->sc_state = DORECAL; 1507 break; 1508 1509 case 4: 1510 /* still no go; reset the bastard */ 1511 fdc->sc_state = DORESET; 1512 break; 1513 1514 default: 1515 diskerr(bp, "fd", "hard error", LOG_PRINTF, 1516 fd->sc_skip, (struct disklabel *)NULL); 1517 printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0], 1518 NE7_ST0BITS, bits, 1519 sizeof(bits))); 1520 printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1], 1521 NE7_ST1BITS, bits, 1522 sizeof(bits))); 1523 printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2], 1524 NE7_ST2BITS, bits, 1525 sizeof(bits))); 1526 printf(" cyl %d head %d sec %d)\n", 1527 fdc->sc_status[3], 1528 fdc->sc_status[4], 1529 fdc->sc_status[5]); 1530 1531 bp->b_flags |= B_ERROR; 1532 bp->b_error = EIO; 1533 fdfinish(fd, bp); 1534 } 1535 fdc->sc_errors++; 1536 } 1537 1538 int 1539 fdsize(dev) 1540 dev_t dev; 1541 { 1542 1543 /* Swapping to floppies would not make sense. */ 1544 return -1; 1545 } 1546 1547 int 1548 fddump(dev, blkno, va, size) 1549 dev_t dev; 1550 daddr_t blkno; 1551 caddr_t va; 1552 size_t size; 1553 { 1554 1555 /* Not implemented. */ 1556 return ENXIO; 1557 } 1558 1559 int 1560 fdioctl(dev, cmd, addr, flag, p) 1561 dev_t dev; 1562 u_long cmd; 1563 caddr_t addr; 1564 int flag; 1565 struct proc *p; 1566 { 1567 struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)]; 1568 struct fdc_softc *fdc = (void*) fd->sc_dev.dv_parent; 1569 int unit = FDUNIT(dev); 1570 int part = DISKPART(dev); 1571 struct disklabel buffer; 1572 int error; 1573 1574 DPRINTF(("fdioctl:\n")); 1575 switch (cmd) { 1576 case DIOCGDINFO: 1577 #if 1 1578 *(struct disklabel *)addr = *(fd->sc_dk.dk_label); 1579 return(0); 1580 #else 1581 memset(&buffer, 0, sizeof(buffer)); 1582 1583 buffer.d_secpercyl = fd->sc_type->seccyl; 1584 buffer.d_type = DTYPE_FLOPPY; 1585 buffer.d_secsize = 128 << fd->sc_type->secsize; 1586 1587 if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL) 1588 return EINVAL; 1589 1590 *(struct disklabel *)addr = buffer; 1591 return 0; 1592 #endif 1593 1594 case DIOCGPART: 1595 ((struct partinfo *)addr)->disklab = fd->sc_dk.dk_label; 1596 ((struct partinfo *)addr)->part = 1597 &fd->sc_dk.dk_label->d_partitions[part]; 1598 return(0); 1599 1600 case DIOCWLABEL: 1601 if ((flag & FWRITE) == 0) 1602 return EBADF; 1603 /* XXX do something */ 1604 return 0; 1605 1606 case DIOCWDINFO: 1607 if ((flag & FWRITE) == 0) 1608 return EBADF; 1609 1610 error = setdisklabel(&buffer, (struct disklabel *)addr, 0, NULL); 1611 if (error) 1612 return error; 1613 1614 error = writedisklabel(dev, fdstrategy, &buffer, NULL); 1615 return error; 1616 1617 case DIOCLOCK: 1618 /* 1619 * Nothing to do here, really. 1620 */ 1621 return 0; /* XXX */ 1622 1623 case DIOCEJECT: 1624 if (*(int *)addr == 0) { 1625 /* 1626 * Don't force eject: check that we are the only 1627 * partition open. If so, unlock it. 1628 */ 1629 if ((fd->sc_dk.dk_openmask & ~(1 << part)) != 0 || 1630 fd->sc_dk.dk_bopenmask + fd->sc_dk.dk_copenmask != 1631 fd->sc_dk.dk_openmask) { 1632 return (EBUSY); 1633 } 1634 } 1635 /* FALLTHROUGH */ 1636 case ODIOCEJECT: 1637 fd_do_eject(fdc, unit); 1638 return 0; 1639 1640 default: 1641 return ENOTTY; 1642 } 1643 1644 #ifdef DIAGNOSTIC 1645 panic("fdioctl: impossible"); 1646 #endif 1647 } 1648 1649 void 1650 fd_do_eject(fdc, unit) 1651 struct fdc_softc *fdc; 1652 int unit; 1653 { 1654 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 1655 0x20 | ( 1 << unit)); 1656 DELAY(1); /* XXX */ 1657 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0x20); 1658 } 1659 1660 /* 1661 * Build disk label. For now we only create a label from what we know 1662 * from 'sc'. 1663 */ 1664 static int 1665 fdgetdisklabel(sc, dev) 1666 struct fd_softc *sc; 1667 dev_t dev; 1668 { 1669 struct disklabel *lp; 1670 int part; 1671 1672 DPRINTF(("fdgetdisklabel()\n")); 1673 1674 part = DISKPART(dev); 1675 lp = sc->sc_dk.dk_label; 1676 memset(lp, 0, sizeof(struct disklabel)); 1677 1678 lp->d_secsize = 128 << sc->sc_type->secsize; 1679 lp->d_ntracks = sc->sc_type->heads; 1680 lp->d_nsectors = sc->sc_type->sectrac; 1681 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 1682 lp->d_ncylinders = sc->sc_type->size / lp->d_secpercyl; 1683 lp->d_secperunit = sc->sc_type->size; 1684 1685 lp->d_type = DTYPE_FLOPPY; 1686 lp->d_rpm = 300; /* XXX */ 1687 lp->d_interleave = 1; /* FIXME: is this OK? */ 1688 lp->d_bbsize = 0; 1689 lp->d_sbsize = 0; 1690 lp->d_npartitions = part + 1; 1691 #define STEP_DELAY 6000 /* 6ms (6000us) delay after stepping */ 1692 lp->d_trkseek = STEP_DELAY; /* XXX */ 1693 lp->d_magic = DISKMAGIC; 1694 lp->d_magic2 = DISKMAGIC; 1695 lp->d_checksum = dkcksum(lp); 1696 lp->d_partitions[part].p_size = lp->d_secperunit; 1697 lp->d_partitions[part].p_fstype = FS_UNUSED; 1698 lp->d_partitions[part].p_fsize = 1024; 1699 lp->d_partitions[part].p_frag = 8; 1700 1701 return(0); 1702 } 1703 1704 #include <dev/cons.h> 1705 1706 /* 1707 * Mountroot hook: prompt the user to enter the root file system 1708 * floppy. 1709 */ 1710 void 1711 fd_mountroot_hook(dev) 1712 struct device *dev; 1713 { 1714 struct fd_softc *fd = (void*) dev; 1715 struct fdc_softc *fdc = (void*) fd->sc_dev.dv_parent; 1716 int c; 1717 1718 fd_do_eject(fdc, dev->dv_unit); 1719 printf("Insert filesystem floppy and press return."); 1720 for (;;) { 1721 c = cngetc(); 1722 if ((c == '\r') || (c == '\n')) { 1723 printf("\n"); 1724 break; 1725 } 1726 } 1727 } 1728