1 /* $NetBSD: fd.c,v 1.35 2000/06/29 07:07:52 mrg 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 tranferring */ 235 int sc_nbytes; /* number of bytes currently tranferring */ 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 #if defined(M68040) || defined(M68060) 331 if (mmutype == MMU_68040) 332 dma_cachectl(addr, count); 333 #endif 334 335 dmac_start_xfer(fdc->sc_dmachan->ch_softc, fdc->sc_xfer); 336 } 337 338 static int 339 fdcdmaintr(arg) 340 void *arg; 341 { 342 struct fdc_softc *fdc = arg; 343 344 bus_dmamap_unload(fdc->sc_dmat, fdc->sc_dmamap); 345 346 return 0; 347 } 348 349 static int 350 fdcdmaerrintr(dummy) 351 void *dummy; 352 { 353 DPRINTF(("fdcdmaerrintr\n")); 354 355 return 0; 356 } 357 358 /* ARGSUSED */ 359 int 360 fdcprobe(parent, cf, aux) 361 struct device *parent; 362 struct cfdata *cf; 363 void *aux; 364 { 365 struct intio_attach_args *ia = aux; 366 367 if (strcmp(ia->ia_name, "fdc") != 0) 368 return 0; 369 370 if (ia->ia_addr == INTIOCF_ADDR_DEFAULT) 371 ia->ia_addr = FDC_ADDR; 372 if (ia->ia_intr == INTIOCF_INTR_DEFAULT) 373 ia->ia_intr = FDC_INTR; 374 if (ia->ia_dma == INTIOCF_DMA_DEFAULT) 375 ia->ia_dma = FDC_DMA; 376 if (ia->ia_dmaintr == INTIOCF_DMAINTR_DEFAULT) 377 ia->ia_dmaintr = FDC_DMAINTR; 378 379 if ((ia->ia_intr & 0x03) != 0) 380 return 0; 381 382 ia->ia_size = 0x2000; 383 if (intio_map_allocate_region (parent, ia, INTIO_MAP_TESTONLY)) 384 return 0; 385 386 /* builtin device; always there */ 387 return 1; 388 } 389 390 /* 391 * Arguments passed between fdcattach and fdprobe. 392 */ 393 struct fdc_attach_args { 394 int fa_drive; 395 struct fd_type *fa_deftype; 396 }; 397 398 /* 399 * Print the location of a disk drive (called just before attaching the 400 * the drive). If `fdc' is not NULL, the drive was found but was not 401 * in the system config file; print the drive name as well. 402 * Return QUIET (config_find ignores this if the device was configured) to 403 * avoid printing `fdN not configured' messages. 404 */ 405 int 406 fdprint(aux, fdc) 407 void *aux; 408 const char *fdc; 409 { 410 register struct fdc_attach_args *fa = aux; 411 412 if (!fdc) 413 printf(" drive %d", fa->fa_drive); 414 return QUIET; 415 } 416 417 void 418 fdcattach(parent, self, aux) 419 struct device *parent, *self; 420 void *aux; 421 { 422 struct fdc_softc *fdc = (void *)self; 423 bus_space_tag_t iot; 424 bus_space_handle_t ioh; 425 struct intio_attach_args *ia = aux; 426 struct fdc_attach_args fa; 427 428 iot = ia->ia_bst; 429 430 printf("\n"); 431 432 callout_init(&fdc->sc_timo_ch); 433 callout_init(&fdc->sc_intr_ch); 434 435 /* Re-map the I/O space. */ 436 bus_space_map(iot, ia->ia_addr, 0x2000, BUS_SPACE_MAP_SHIFTED, &ioh); 437 438 fdc->sc_iot = iot; 439 fdc->sc_ioh = ioh; 440 fdc->sc_addr = (void*) ia->ia_addr; 441 442 fdc->sc_dmat = ia->ia_dmat; 443 fdc->sc_state = DEVIDLE; 444 TAILQ_INIT(&fdc->sc_drives); 445 446 /* Initialize DMAC channel */ 447 fdc->sc_dmachan = dmac_alloc_channel(parent, ia->ia_dma, "fdc", 448 ia->ia_dmaintr, fdcdmaintr, fdc, 449 ia->ia_dmaintr+1, fdcdmaerrintr, 450 fdc); 451 if (bus_dmamap_create(fdc->sc_dmat, FDC_MAXIOSIZE, 16, 0xf000, 0, 452 BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW, 453 &fdc->sc_dmamap)) { 454 printf("%s: can't set up intio DMA map\n", 455 fdc->sc_dev.dv_xname); 456 return; 457 } 458 459 if (intio_intr_establish(ia->ia_intr, "fdc", fdcintr, fdc)) 460 panic ("Could not establish interrupt (duplicated vector?)."); 461 intio_set_ivec(ia->ia_intr); 462 463 /* reset */ 464 intio_disable_intr(SICILIAN_INTR_FDD); 465 intio_enable_intr(SICILIAN_INTR_FDC); 466 fdcresult(fdc); 467 fdcreset(fdc); 468 469 printf("%s: uPD72065 FDC\n", fdc->sc_dev.dv_xname); 470 out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */ 471 out_fdc(iot, ioh, 0xd0); 472 out_fdc(iot, ioh, 0x10); 473 474 /* physical limit: four drives per controller. */ 475 for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) { 476 (void)config_found(self, (void *)&fa, fdprint); 477 } 478 479 intio_enable_intr(SICILIAN_INTR_FDC); 480 } 481 482 void 483 fdcreset(fdc) 484 struct fdc_softc *fdc; 485 { 486 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdsts, NE7CMD_RESET); 487 } 488 489 static int 490 fdcpoll(fdc) 491 struct fdc_softc *fdc; 492 { 493 int i = 25000, n; 494 while (--i > 0) { 495 if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC)) { 496 out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI); 497 n = fdcresult(fdc); 498 break; 499 } 500 DELAY(100); 501 } 502 return i; 503 } 504 505 int 506 fdprobe(parent, cf, aux) 507 struct device *parent; 508 struct cfdata *cf; 509 void *aux; 510 { 511 struct fdc_softc *fdc = (void *)parent; 512 struct fd_type *type; 513 struct fdc_attach_args *fa = aux; 514 int drive = fa->fa_drive; 515 bus_space_tag_t iot = fdc->sc_iot; 516 bus_space_handle_t ioh = fdc->sc_ioh; 517 int n; 518 int found = 0; 519 int i; 520 521 if (cf->cf_loc[FDCCF_UNIT] != FDCCF_UNIT_DEFAULT && 522 cf->cf_loc[FDCCF_UNIT] != drive) 523 return 0; 524 525 type = &fd_types[0]; /* XXX 1.2MB */ 526 527 intio_disable_intr(SICILIAN_INTR_FDC); 528 529 /* select drive and turn on motor */ 530 bus_space_write_1(iot, ioh, fdctl, 0x80 | (type->rate << 4)| drive); 531 fdc_force_ready(FDCRDY); 532 fdcpoll(fdc); 533 534 retry: 535 out_fdc(iot, ioh, NE7CMD_RECAL); 536 out_fdc(iot, ioh, drive); 537 538 i = 25000; 539 while (--i > 0) { 540 if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC)) { 541 out_fdc(iot, ioh, NE7CMD_SENSEI); 542 n = fdcresult(fdc); 543 break; 544 } 545 DELAY(100); 546 } 547 548 #ifdef FDDEBUG 549 { 550 int i; 551 DPRINTF(("fdprobe: status")); 552 for (i = 0; i < n; i++) 553 DPRINTF((" %x", fdc->sc_status[i])); 554 DPRINTF(("\n")); 555 } 556 #endif 557 558 if (n == 2) { 559 if ((fdc->sc_status[0] & 0xf0) == 0x20) { 560 found = 1; 561 } else if ((fdc->sc_status[0] & 0xf0) == 0xc0) { 562 goto retry; 563 } 564 } 565 566 /* turn off motor */ 567 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, 568 fdctl, (type->rate << 4)| drive); 569 fdc_force_ready(FDCSTBY); 570 if (!found) { 571 intio_enable_intr(SICILIAN_INTR_FDC); 572 return 0; 573 } 574 575 return 1; 576 } 577 578 /* 579 * Controller is working, and drive responded. Attach it. 580 */ 581 void 582 fdattach(parent, self, aux) 583 struct device *parent, *self; 584 void *aux; 585 { 586 struct fdc_softc *fdc = (void *)parent; 587 struct fd_softc *fd = (void *)self; 588 struct fdc_attach_args *fa = aux; 589 struct fd_type *type = &fd_types[0]; /* XXX 1.2MB */ 590 int drive = fa->fa_drive; 591 592 callout_init(&fd->sc_motoron_ch); 593 callout_init(&fd->sc_motoroff_ch); 594 595 fd->sc_flags = 0; 596 597 if (type) 598 printf(": %s, %d cyl, %d head, %d sec\n", type->name, 599 type->cyls, type->heads, type->sectrac); 600 else 601 printf(": density unknown\n"); 602 603 BUFQ_INIT(&fd->sc_q); 604 fd->sc_cylin = -1; 605 fd->sc_drive = drive; 606 fd->sc_deftype = type; 607 fdc->sc_fd[drive] = fd; 608 609 fd->sc_copybuf = (u_char *)malloc(NBPG, M_DEVBUF, M_WAITOK); 610 if (fd->sc_copybuf == 0) 611 printf("fdprobe: WARNING!! malloc() failed.\n"); 612 fd->sc_flags |= FD_ALIVE; 613 614 /* 615 * Initialize and attach the disk structure. 616 */ 617 fd->sc_dk.dk_name = fd->sc_dev.dv_xname; 618 fd->sc_dk.dk_driver = &fddkdriver; 619 disk_attach(&fd->sc_dk); 620 621 /* 622 * Establish a mountroot_hook anyway in case we booted 623 * with RB_ASKNAME and get selected as the boot device. 624 */ 625 mountroothook_establish(fd_mountroot_hook, &fd->sc_dev); 626 627 #if NRND > 0 628 rnd_attach_source(&fd->rnd_source, fd->sc_dev.dv_xname, 629 RND_TYPE_DISK, 0); 630 #endif 631 } 632 633 __inline struct fd_type * 634 fd_dev_to_type(fd, dev) 635 struct fd_softc *fd; 636 dev_t dev; 637 { 638 int type = FDTYPE(dev); 639 640 if (type > (sizeof(fd_types) / sizeof(fd_types[0]))) 641 return NULL; 642 return &fd_types[type]; 643 } 644 645 void 646 fdstrategy(bp) 647 register struct buf *bp; /* IO operation to perform */ 648 { 649 struct fd_softc *fd; 650 int unit = FDUNIT(bp->b_dev); 651 int sz; 652 int s; 653 654 if (unit >= fd_cd.cd_ndevs || 655 (fd = fd_cd.cd_devs[unit]) == 0 || 656 bp->b_blkno < 0 || 657 (bp->b_bcount % FDC_BSIZE) != 0) { 658 DPRINTF(("fdstrategy: unit=%d, blkno=%d, bcount=%d\n", unit, 659 bp->b_blkno, bp->b_bcount)); 660 bp->b_error = EINVAL; 661 goto bad; 662 } 663 664 /* If it's a null transfer, return immediately. */ 665 if (bp->b_bcount == 0) 666 goto done; 667 668 sz = howmany(bp->b_bcount, FDC_BSIZE); 669 670 if (bp->b_blkno + sz > (fd->sc_type->size << (fd->sc_type->secsize - 2))) { 671 sz = (fd->sc_type->size << (fd->sc_type->secsize - 2)) - bp->b_blkno; 672 if (sz == 0) { 673 /* If exactly at end of disk, return EOF. */ 674 bp->b_resid = bp->b_bcount; 675 goto done; 676 } 677 if (sz < 0) { 678 /* If past end of disk, return EINVAL. */ 679 bp->b_error = EINVAL; 680 goto bad; 681 } 682 /* Otherwise, truncate request. */ 683 bp->b_bcount = sz << DEV_BSHIFT; 684 } 685 686 bp->b_rawblkno = bp->b_blkno; 687 bp->b_cylinder = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE) 688 / (fd->sc_type->seccyl * (1 << (fd->sc_type->secsize - 2))); 689 690 DPRINTF(("fdstrategy: %s b_blkno %d b_bcount %ld cylin %ld\n", 691 bp->b_flags & B_READ ? "read" : "write", 692 bp->b_blkno, bp->b_bcount, bp->b_cylinder)); 693 /* Queue transfer on drive, activate drive and controller if idle. */ 694 s = splbio(); 695 disksort_cylinder(&fd->sc_q, bp); 696 callout_stop(&fd->sc_motoroff_ch); /* a good idea */ 697 if (fd->sc_active == 0) 698 fdstart(fd); 699 #ifdef DIAGNOSTIC 700 else { 701 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; 702 if (fdc->sc_state == DEVIDLE) { 703 printf("fdstrategy: controller inactive\n"); 704 fdcstart(fdc); 705 } 706 } 707 #endif 708 splx(s); 709 return; 710 711 bad: 712 bp->b_flags |= B_ERROR; 713 done: 714 /* Toss transfer; we're done early. */ 715 biodone(bp); 716 } 717 718 void 719 fdstart(fd) 720 struct fd_softc *fd; 721 { 722 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; 723 int active = fdc->sc_drives.tqh_first != 0; 724 725 /* Link into controller queue. */ 726 fd->sc_active = 1; 727 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain); 728 729 /* If controller not already active, start it. */ 730 if (!active) 731 fdcstart(fdc); 732 } 733 734 void 735 fdfinish(fd, bp) 736 struct fd_softc *fd; 737 struct buf *bp; 738 { 739 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; 740 741 /* 742 * Move this drive to the end of the queue to give others a `fair' 743 * chance. We only force a switch if N operations are completed while 744 * another drive is waiting to be serviced, since there is a long motor 745 * startup delay whenever we switch. 746 */ 747 if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) { 748 fd->sc_ops = 0; 749 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain); 750 if (BUFQ_NEXT(bp) != NULL) { 751 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain); 752 } else 753 fd->sc_active = 0; 754 } 755 bp->b_resid = fd->sc_bcount; 756 fd->sc_skip = 0; 757 BUFQ_REMOVE(&fd->sc_q, bp); 758 759 #if NRND > 0 760 rnd_add_uint32(&fd->rnd_source, bp->b_blkno); 761 #endif 762 763 biodone(bp); 764 /* turn off motor 5s from now */ 765 callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd); 766 fdc->sc_state = DEVIDLE; 767 } 768 769 int 770 fdread(dev, uio, flags) 771 dev_t dev; 772 struct uio *uio; 773 int flags; 774 { 775 776 return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio)); 777 } 778 779 int 780 fdwrite(dev, uio, flags) 781 dev_t dev; 782 struct uio *uio; 783 int flags; 784 { 785 786 return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio)); 787 } 788 789 void 790 fd_set_motor(fdc, reset) 791 struct fdc_softc *fdc; 792 int reset; 793 { 794 struct fd_softc *fd; 795 int n; 796 797 DPRINTF(("fd_set_motor:\n")); 798 for (n = 0; n < 4; n++) 799 if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR)) { 800 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdctl, 801 0x80 | (fd->sc_type->rate << 4)| n); 802 } 803 } 804 805 void 806 fd_motor_off(arg) 807 void *arg; 808 { 809 struct fd_softc *fd = arg; 810 struct fdc_softc *fdc = (struct fdc_softc*) fd->sc_dev.dv_parent; 811 int s; 812 813 DPRINTF(("fd_motor_off:\n")); 814 815 s = splbio(); 816 fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT); 817 bus_space_write_1 (fdc->sc_iot, fdc->sc_ioh, fdctl, 818 (fd->sc_type->rate << 4) | fd->sc_drive); 819 #if 0 820 fd_set_motor(fdc, 0); /* XXX */ 821 #endif 822 splx(s); 823 } 824 825 void 826 fd_motor_on(arg) 827 void *arg; 828 { 829 struct fd_softc *fd = arg; 830 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; 831 int s; 832 833 DPRINTF(("fd_motor_on:\n")); 834 835 s = splbio(); 836 fd->sc_flags &= ~FD_MOTOR_WAIT; 837 if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT)) 838 (void) fdcintr(fdc); 839 splx(s); 840 } 841 842 int 843 fdcresult(fdc) 844 struct fdc_softc *fdc; 845 { 846 bus_space_tag_t iot = fdc->sc_iot; 847 bus_space_handle_t ioh = fdc->sc_ioh; 848 u_char i; 849 int j = 100000, 850 n = 0; 851 852 for (; j; j--) { 853 i = bus_space_read_1(iot, ioh, fdsts) & 854 (NE7_DIO | NE7_RQM | NE7_CB); 855 856 if (i == NE7_RQM) 857 return n; 858 if (i == (NE7_DIO | NE7_RQM | NE7_CB)) { 859 if (n >= sizeof(fdc->sc_status)) { 860 log(LOG_ERR, "fdcresult: overrun\n"); 861 return -1; 862 } 863 fdc->sc_status[n++] = 864 bus_space_read_1(iot, ioh, fddata); 865 } 866 delay(10); 867 } 868 log(LOG_ERR, "fdcresult: timeout\n"); 869 return -1; 870 } 871 872 int 873 out_fdc(iot, ioh, x) 874 bus_space_tag_t iot; 875 bus_space_handle_t ioh; 876 u_char x; 877 { 878 int i = 100000; 879 880 while ((bus_space_read_1(iot, ioh, fdsts) & NE7_DIO) && i-- > 0); 881 if (i <= 0) 882 return -1; 883 while ((bus_space_read_1(iot, ioh, fdsts) & NE7_RQM) == 0 && i-- > 0); 884 if (i <= 0) 885 return -1; 886 bus_space_write_1(iot, ioh, fddata, x); 887 return 0; 888 } 889 890 int 891 fdopen(dev, flags, mode, p) 892 dev_t dev; 893 int flags, mode; 894 struct proc *p; 895 { 896 int unit; 897 struct fd_softc *fd; 898 struct fd_type *type; 899 struct fdc_softc *fdc; 900 901 unit = FDUNIT(dev); 902 if (unit >= fd_cd.cd_ndevs) 903 return ENXIO; 904 fd = fd_cd.cd_devs[unit]; 905 if (fd == 0) 906 return ENXIO; 907 type = fd_dev_to_type(fd, dev); 908 if (type == NULL) 909 return ENXIO; 910 911 if ((fd->sc_flags & FD_OPEN) != 0 && 912 fd->sc_type != type) 913 return EBUSY; 914 915 fdc = (void *)fd->sc_dev.dv_parent; 916 if ((fd->sc_flags & FD_OPEN) == 0) { 917 /* Lock eject button */ 918 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 919 0x40 | ( 1 << unit)); 920 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0x40); 921 } 922 923 fd->sc_type = type; 924 fd->sc_cylin = -1; 925 926 switch (mode) { 927 case S_IFCHR: 928 fd->sc_flags |= FD_COPEN; 929 break; 930 case S_IFBLK: 931 fd->sc_flags |= FD_BOPEN; 932 break; 933 } 934 935 fdgetdisklabel(fd, dev); 936 937 return 0; 938 } 939 940 int 941 fdclose(dev, flags, mode, p) 942 dev_t dev; 943 int flags, mode; 944 struct proc *p; 945 { 946 int unit = FDUNIT(dev); 947 struct fd_softc *fd = fd_cd.cd_devs[unit]; 948 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; 949 950 DPRINTF(("fdclose %d\n", unit)); 951 952 switch (mode) { 953 case S_IFCHR: 954 fd->sc_flags &= ~FD_COPEN; 955 break; 956 case S_IFBLK: 957 fd->sc_flags &= ~FD_BOPEN; 958 break; 959 } 960 961 if ((fd->sc_flags & FD_OPEN) == 0) { 962 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 963 ( 1 << unit)); 964 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0); 965 } 966 return 0; 967 } 968 969 void 970 fdcstart(fdc) 971 struct fdc_softc *fdc; 972 { 973 974 #ifdef DIAGNOSTIC 975 /* only got here if controller's drive queue was inactive; should 976 be in idle state */ 977 if (fdc->sc_state != DEVIDLE) { 978 printf("fdcstart: not idle\n"); 979 return; 980 } 981 #endif 982 (void) fdcintr(fdc); 983 } 984 985 void 986 fdcstatus(dv, n, s) 987 struct device *dv; 988 int n; 989 char *s; 990 { 991 struct fdc_softc *fdc = (void *)dv->dv_parent; 992 char bits[64]; 993 994 if (n == 0) { 995 out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI); 996 (void) fdcresult(fdc); 997 n = 2; 998 } 999 1000 printf("%s: %s: state %d", dv->dv_xname, s, fdc->sc_state); 1001 1002 switch (n) { 1003 case 0: 1004 printf("\n"); 1005 break; 1006 case 2: 1007 printf(" (st0 %s cyl %d)\n", 1008 bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS, 1009 bits, sizeof(bits)), fdc->sc_status[1]); 1010 break; 1011 case 7: 1012 printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0], 1013 NE7_ST0BITS, bits, sizeof(bits))); 1014 printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1], 1015 NE7_ST1BITS, bits, sizeof(bits))); 1016 printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2], 1017 NE7_ST2BITS, bits, sizeof(bits))); 1018 printf(" cyl %d head %d sec %d)\n", 1019 fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]); 1020 break; 1021 #ifdef DIAGNOSTIC 1022 default: 1023 printf(" fdcstatus: weird size: %d\n", n); 1024 break; 1025 #endif 1026 } 1027 } 1028 1029 void 1030 fdctimeout(arg) 1031 void *arg; 1032 { 1033 struct fdc_softc *fdc = arg; 1034 struct fd_softc *fd = fdc->sc_drives.tqh_first; 1035 int s; 1036 1037 s = splbio(); 1038 fdcstatus(&fd->sc_dev, 0, "timeout"); 1039 1040 if (BUFQ_FIRST(&fd->sc_q) != NULL) 1041 fdc->sc_state++; 1042 else 1043 fdc->sc_state = DEVIDLE; 1044 1045 (void) fdcintr(fdc); 1046 splx(s); 1047 } 1048 1049 #if 0 1050 void 1051 fdcpseudointr(arg) 1052 void *arg; 1053 { 1054 int s; 1055 struct fdc_softc *fdc = arg; 1056 1057 /* just ensure it has the right spl */ 1058 s = splbio(); 1059 (void) fdcintr(fdc); 1060 splx(s); 1061 } 1062 #endif 1063 1064 int 1065 fdcintr(arg) 1066 void *arg; 1067 { 1068 struct fdc_softc *fdc = arg; 1069 #define st0 fdc->sc_status[0] 1070 #define cyl fdc->sc_status[1] 1071 struct fd_softc *fd; 1072 struct buf *bp; 1073 bus_space_tag_t iot = fdc->sc_iot; 1074 bus_space_handle_t ioh = fdc->sc_ioh; 1075 int read, head, sec, pos, i, sectrac, nblks; 1076 int tmp; 1077 struct fd_type *type; 1078 1079 loop: 1080 fd = fdc->sc_drives.tqh_first; 1081 if (fd == NULL) { 1082 DPRINTF(("fdcintr: set DEVIDLE\n")); 1083 if (fdc->sc_state == DEVIDLE) { 1084 if (intio_get_sicilian_intr() & SICILIAN_STAT_FDC) { 1085 out_fdc(iot, ioh, NE7CMD_SENSEI); 1086 if ((tmp = fdcresult(fdc)) != 2 || 1087 (st0 & 0xf8) != 0x20) { 1088 goto loop; 1089 } 1090 } 1091 } 1092 /* no drives waiting; end */ 1093 fdc->sc_state = DEVIDLE; 1094 return 1; 1095 } 1096 1097 /* Is there a transfer to this drive? If not, deactivate drive. */ 1098 bp = BUFQ_FIRST(&fd->sc_q); 1099 if (bp == NULL) { 1100 fd->sc_ops = 0; 1101 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain); 1102 fd->sc_active = 0; 1103 goto loop; 1104 } 1105 1106 switch (fdc->sc_state) { 1107 case DEVIDLE: 1108 DPRINTF(("fdcintr: in DEVIDLE\n")); 1109 fdc->sc_errors = 0; 1110 fd->sc_skip = 0; 1111 fd->sc_bcount = bp->b_bcount; 1112 fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE); 1113 callout_stop(&fd->sc_motoroff_ch); 1114 if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) { 1115 fdc->sc_state = MOTORWAIT; 1116 return 1; 1117 } 1118 if ((fd->sc_flags & FD_MOTOR) == 0) { 1119 /* Turn on the motor */ 1120 /* being careful about other drives. */ 1121 for (i = 0; i < 4; i++) { 1122 struct fd_softc *ofd = fdc->sc_fd[i]; 1123 if (ofd && ofd->sc_flags & FD_MOTOR) { 1124 callout_stop(&ofd->sc_motoroff_ch); 1125 ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT); 1126 break; 1127 } 1128 } 1129 fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT; 1130 fd_set_motor(fdc, 0); 1131 fdc->sc_state = MOTORWAIT; 1132 /* allow .5s for motor to stabilize */ 1133 callout_reset(&fd->sc_motoron_ch, hz / 2, 1134 fd_motor_on, fd); 1135 return 1; 1136 } 1137 /* Make sure the right drive is selected. */ 1138 fd_set_motor(fdc, 0); 1139 1140 /* fall through */ 1141 case DOSEEK: 1142 doseek: 1143 DPRINTF(("fdcintr: in DOSEEK\n")); 1144 if (fd->sc_cylin == bp->b_cylinder) 1145 goto doio; 1146 1147 out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */ 1148 out_fdc(iot, ioh, 0xd0); /* XXX const */ 1149 out_fdc(iot, ioh, 0x10); 1150 1151 out_fdc(iot, ioh, NE7CMD_SEEK); /* seek function */ 1152 out_fdc(iot, ioh, fd->sc_drive); /* drive number */ 1153 out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step); 1154 1155 fd->sc_cylin = -1; 1156 fdc->sc_state = SEEKWAIT; 1157 1158 fd->sc_dk.dk_seek++; 1159 disk_busy(&fd->sc_dk); 1160 1161 callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc); 1162 return 1; 1163 1164 case DOIO: 1165 doio: 1166 DPRINTF(("fdcintr: DOIO: ")); 1167 type = fd->sc_type; 1168 sectrac = type->sectrac; 1169 pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2))); 1170 sec = pos / (1 << (type->secsize - 2)); 1171 if (type->secsize == 2) { 1172 fd->sc_part = SEC_P11; 1173 nblks = (sectrac - sec) << (type->secsize - 2); 1174 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE); 1175 DPRINTF(("nblks(0)")); 1176 } else if ((fd->sc_blkno % 2) == 0) { 1177 if (fd->sc_bcount & 0x00000200) { 1178 if (fd->sc_bcount == FDC_BSIZE) { 1179 fd->sc_part = SEC_P10; 1180 nblks = 1; 1181 DPRINTF(("nblks(1)")); 1182 } else { 1183 fd->sc_part = SEC_P11; 1184 nblks = (sectrac - sec) * 2; 1185 nblks = min(nblks, fd->sc_bcount 1186 / FDC_BSIZE - 1); 1187 DPRINTF(("nblks(2)")); 1188 } 1189 } else { 1190 fd->sc_part = SEC_P11; 1191 nblks = (sectrac - sec) 1192 << (type->secsize - 2); 1193 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE); 1194 DPRINTF(("nblks(3)")); 1195 } 1196 } else { 1197 fd->sc_part = SEC_P01; 1198 nblks = 1; 1199 DPRINTF(("nblks(4)")); 1200 } 1201 nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE); 1202 DPRINTF((" %d\n", nblks)); 1203 fd->sc_nblks = nblks; 1204 fd->sc_nbytes = nblks * FDC_BSIZE; 1205 head = (fd->sc_blkno 1206 % (type->seccyl * (1 << (type->secsize - 2)))) 1207 / (type->sectrac * (1 << (type->secsize - 2))); 1208 1209 #ifdef DIAGNOSTIC 1210 {int block; 1211 block = ((fd->sc_cylin * type->heads + head) * type->sectrac 1212 + sec) * (1 << (type->secsize - 2)); 1213 block += (fd->sc_part == SEC_P01) ? 1 : 0; 1214 if (block != fd->sc_blkno) { 1215 printf("C H R N: %d %d %d %d\n", fd->sc_cylin, head, sec, type->secsize); 1216 printf("fdcintr: doio: block %d != blkno %d\n", block, fd->sc_blkno); 1217 #ifdef DDB 1218 Debugger(); 1219 #endif 1220 }} 1221 #endif 1222 read = bp->b_flags & B_READ; 1223 DPRINTF(("fdcintr: %s drive %d track %d head %d sec %d nblks %d, skip %d\n", 1224 read ? "read" : "write", fd->sc_drive, fd->sc_cylin, 1225 head, sec, nblks, fd->sc_skip)); 1226 DPRINTF(("C H R N: %d %d %d %d\n", fd->sc_cylin, head, sec, 1227 type->secsize)); 1228 1229 if (fd->sc_part != SEC_P11) 1230 goto docopy; 1231 1232 fdc_dmastart(fdc, 1233 read, bp->b_data + fd->sc_skip, fd->sc_nbytes); 1234 if (read) 1235 out_fdc(iot, ioh, NE7CMD_READ); /* READ */ 1236 else 1237 out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */ 1238 out_fdc(iot, ioh, (head << 2) | fd->sc_drive); 1239 out_fdc(iot, ioh, bp->b_cylinder); /* cylinder */ 1240 out_fdc(iot, ioh, head); 1241 out_fdc(iot, ioh, sec + 1); /* sector +1 */ 1242 out_fdc(iot, ioh, type->secsize); /* sector size */ 1243 out_fdc(iot, ioh, type->sectrac); /* sectors/track */ 1244 out_fdc(iot, ioh, type->gap1); /* gap1 size */ 1245 out_fdc(iot, ioh, type->datalen); /* data length */ 1246 fdc->sc_state = IOCOMPLETE; 1247 1248 disk_busy(&fd->sc_dk); 1249 1250 /* allow 2 seconds for operation */ 1251 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc); 1252 return 1; /* will return later */ 1253 1254 case DOCOPY: 1255 docopy: 1256 DPRINTF(("fdcintr: DOCOPY:\n")); 1257 fdc_dmastart(fdc, B_READ, fd->sc_copybuf, 1024); 1258 out_fdc(iot, ioh, NE7CMD_READ); /* READ */ 1259 out_fdc(iot, ioh, (head << 2) | fd->sc_drive); 1260 out_fdc(iot, ioh, bp->b_cylinder); /* cylinder */ 1261 out_fdc(iot, ioh, head); 1262 out_fdc(iot, ioh, sec + 1); /* sector +1 */ 1263 out_fdc(iot, ioh, type->secsize); /* sector size */ 1264 out_fdc(iot, ioh, type->sectrac); /* sectors/track */ 1265 out_fdc(iot, ioh, type->gap1); /* gap1 size */ 1266 out_fdc(iot, ioh, type->datalen); /* data length */ 1267 fdc->sc_state = COPYCOMPLETE; 1268 /* allow 2 seconds for operation */ 1269 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc); 1270 return 1; /* will return later */ 1271 1272 case DOIOHALF: 1273 doiohalf: 1274 DPRINTF((" DOIOHALF:\n")); 1275 1276 #ifdef DIAGNOSTIC 1277 type = fd->sc_type; 1278 sectrac = type->sectrac; 1279 pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2))); 1280 sec = pos / (1 << (type->secsize - 2)); 1281 head = (fd->sc_blkno 1282 % (type->seccyl * (1 << (type->secsize - 2)))) 1283 / (type->sectrac * (1 << (type->secsize - 2))); 1284 {int block; 1285 block = ((fd->sc_cylin * type->heads + head) * type->sectrac + sec) 1286 * (1 << (type->secsize - 2)); 1287 block += (fd->sc_part == SEC_P01) ? 1 : 0; 1288 if (block != fd->sc_blkno) { 1289 printf("fdcintr: block %d != blkno %d\n", block, fd->sc_blkno); 1290 #ifdef DDB 1291 Debugger(); 1292 #endif 1293 }} 1294 #endif 1295 if ((read = bp->b_flags & B_READ)) { 1296 bcopy(fd->sc_copybuf 1297 + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0), 1298 bp->b_data + fd->sc_skip, 1299 FDC_BSIZE); 1300 fdc->sc_state = IOCOMPLETE; 1301 goto iocomplete2; 1302 } else { 1303 bcopy(bp->b_data + fd->sc_skip, 1304 fd->sc_copybuf 1305 + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0), 1306 FDC_BSIZE); 1307 fdc_dmastart(fdc, read, fd->sc_copybuf, 1024); 1308 } 1309 out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */ 1310 out_fdc(iot, ioh, (head << 2) | fd->sc_drive); 1311 out_fdc(iot, ioh, bp->b_cylinder); /* cylinder */ 1312 out_fdc(iot, ioh, head); 1313 out_fdc(iot, ioh, sec + 1); /* sector +1 */ 1314 out_fdc(iot, ioh, fd->sc_type->secsize); /* sector size */ 1315 out_fdc(iot, ioh, sectrac); /* sectors/track */ 1316 out_fdc(iot, ioh, fd->sc_type->gap1); /* gap1 size */ 1317 out_fdc(iot, ioh, fd->sc_type->datalen); /* data length */ 1318 fdc->sc_state = IOCOMPLETE; 1319 /* allow 2 seconds for operation */ 1320 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc); 1321 return 1; /* will return later */ 1322 1323 case SEEKWAIT: 1324 callout_stop(&fdc->sc_timo_ch); 1325 fdc->sc_state = SEEKCOMPLETE; 1326 /* allow 1/50 second for heads to settle */ 1327 #if 0 1328 callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc); 1329 #endif 1330 return 1; 1331 1332 case SEEKCOMPLETE: 1333 /* Make sure seek really happened */ 1334 DPRINTF(("fdcintr: SEEKCOMPLETE: FDC status = %x\n", 1335 bus_space_read_1(fdc->sc_iot, fdc->sc_ioh, fdsts))); 1336 out_fdc(iot, ioh, NE7CMD_SENSEI); 1337 tmp = fdcresult(fdc); 1338 if ((st0 & 0xf8) == 0xc0) { 1339 DPRINTF(("fdcintr: first seek!\n")); 1340 fdc->sc_state = DORECAL; 1341 goto loop; 1342 } else if (tmp != 2 || 1343 (st0 & 0xf8) != 0x20 || 1344 cyl != bp->b_cylinder) { 1345 #ifdef FDDEBUG 1346 fdcstatus(&fd->sc_dev, 2, "seek failed"); 1347 #endif 1348 fdcretry(fdc); 1349 goto loop; 1350 } 1351 fd->sc_cylin = bp->b_cylinder; 1352 goto doio; 1353 1354 case IOTIMEDOUT: 1355 #if 0 1356 isa_dmaabort(fdc->sc_drq); 1357 #endif 1358 case SEEKTIMEDOUT: 1359 case RECALTIMEDOUT: 1360 case RESETTIMEDOUT: 1361 fdcretry(fdc); 1362 goto loop; 1363 1364 case IOCOMPLETE: /* IO DONE, post-analyze */ 1365 callout_stop(&fdc->sc_timo_ch); 1366 DPRINTF(("fdcintr: in IOCOMPLETE\n")); 1367 if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) { 1368 printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0); 1369 #if 0 1370 isa_dmaabort(fdc->sc_drq); 1371 #endif 1372 fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ? 1373 "read failed" : "write failed"); 1374 printf("blkno %d nblks %d\n", 1375 fd->sc_blkno, fd->sc_nblks); 1376 fdcretry(fdc); 1377 goto loop; 1378 } 1379 #if 0 1380 isa_dmadone(bp->b_flags & B_READ, bp->b_data + fd->sc_skip, 1381 nblks * FDC_BSIZE, fdc->sc_drq); 1382 #endif 1383 iocomplete2: 1384 if (fdc->sc_errors) { 1385 diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF, 1386 fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL); 1387 printf("\n"); 1388 fdc->sc_errors = 0; 1389 } 1390 fd->sc_blkno += fd->sc_nblks; 1391 fd->sc_skip += fd->sc_nbytes; 1392 fd->sc_bcount -= fd->sc_nbytes; 1393 DPRINTF(("fd->sc_bcount = %d\n", fd->sc_bcount)); 1394 if (fd->sc_bcount > 0) { 1395 bp->b_cylinder = fd->sc_blkno 1396 / (fd->sc_type->seccyl 1397 * (1 << (fd->sc_type->secsize - 2))); 1398 goto doseek; 1399 } 1400 fdfinish(fd, bp); 1401 goto loop; 1402 1403 case COPYCOMPLETE: /* IO DONE, post-analyze */ 1404 DPRINTF(("fdcintr: COPYCOMPLETE:")); 1405 callout_stop(&fdc->sc_timo_ch); 1406 if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) { 1407 printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0); 1408 #if 0 1409 isa_dmaabort(fdc->sc_drq); 1410 #endif 1411 fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ? 1412 "read failed" : "write failed"); 1413 printf("blkno %d nblks %d\n", 1414 fd->sc_blkno, fd->sc_nblks); 1415 fdcretry(fdc); 1416 goto loop; 1417 } 1418 goto doiohalf; 1419 1420 case DORESET: 1421 DPRINTF(("fdcintr: in DORESET\n")); 1422 /* try a reset, keep motor on */ 1423 fd_set_motor(fdc, 1); 1424 DELAY(100); 1425 fd_set_motor(fdc, 0); 1426 fdc->sc_state = RESETCOMPLETE; 1427 callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc); 1428 return 1; /* will return later */ 1429 1430 case RESETCOMPLETE: 1431 DPRINTF(("fdcintr: in RESETCOMPLETE\n")); 1432 callout_stop(&fdc->sc_timo_ch); 1433 /* clear the controller output buffer */ 1434 for (i = 0; i < 4; i++) { 1435 out_fdc(iot, ioh, NE7CMD_SENSEI); 1436 (void) fdcresult(fdc); 1437 } 1438 1439 /* fall through */ 1440 case DORECAL: 1441 DPRINTF(("fdcintr: in DORECAL\n")); 1442 out_fdc(iot, ioh, NE7CMD_RECAL); /* recalibrate function */ 1443 out_fdc(iot, ioh, fd->sc_drive); 1444 fdc->sc_state = RECALWAIT; 1445 callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc); 1446 return 1; /* will return later */ 1447 1448 case RECALWAIT: 1449 DPRINTF(("fdcintr: in RECALWAIT\n")); 1450 callout_stop(&fdc->sc_timo_ch); 1451 fdc->sc_state = RECALCOMPLETE; 1452 /* allow 1/30 second for heads to settle */ 1453 #if 0 1454 callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc); 1455 #endif 1456 return 1; /* will return later */ 1457 1458 case RECALCOMPLETE: 1459 DPRINTF(("fdcintr: in RECALCOMPLETE\n")); 1460 out_fdc(iot, ioh, NE7CMD_SENSEI); 1461 tmp = fdcresult(fdc); 1462 if ((st0 & 0xf8) == 0xc0) { 1463 DPRINTF(("fdcintr: first seek!\n")); 1464 fdc->sc_state = DORECAL; 1465 goto loop; 1466 } else if (tmp != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) { 1467 #ifdef FDDEBUG 1468 fdcstatus(&fd->sc_dev, 2, "recalibrate failed"); 1469 #endif 1470 fdcretry(fdc); 1471 goto loop; 1472 } 1473 fd->sc_cylin = 0; 1474 goto doseek; 1475 1476 case MOTORWAIT: 1477 if (fd->sc_flags & FD_MOTOR_WAIT) 1478 return 1; /* time's not up yet */ 1479 goto doseek; 1480 1481 default: 1482 fdcstatus(&fd->sc_dev, 0, "stray interrupt"); 1483 return 1; 1484 } 1485 #ifdef DIAGNOSTIC 1486 panic("fdcintr: impossible"); 1487 #endif 1488 #undef st0 1489 #undef cyl 1490 } 1491 1492 void 1493 fdcretry(fdc) 1494 struct fdc_softc *fdc; 1495 { 1496 struct fd_softc *fd; 1497 struct buf *bp; 1498 char bits[64]; 1499 1500 DPRINTF(("fdcretry:\n")); 1501 fd = fdc->sc_drives.tqh_first; 1502 bp = BUFQ_FIRST(&fd->sc_q); 1503 1504 switch (fdc->sc_errors) { 1505 case 0: 1506 /* try again */ 1507 fdc->sc_state = SEEKCOMPLETE; 1508 break; 1509 1510 case 1: case 2: case 3: 1511 /* didn't work; try recalibrating */ 1512 fdc->sc_state = DORECAL; 1513 break; 1514 1515 case 4: 1516 /* still no go; reset the bastard */ 1517 fdc->sc_state = DORESET; 1518 break; 1519 1520 default: 1521 diskerr(bp, "fd", "hard error", LOG_PRINTF, 1522 fd->sc_skip, (struct disklabel *)NULL); 1523 printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0], 1524 NE7_ST0BITS, bits, 1525 sizeof(bits))); 1526 printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1], 1527 NE7_ST1BITS, bits, 1528 sizeof(bits))); 1529 printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2], 1530 NE7_ST2BITS, bits, 1531 sizeof(bits))); 1532 printf(" cyl %d head %d sec %d)\n", 1533 fdc->sc_status[3], 1534 fdc->sc_status[4], 1535 fdc->sc_status[5]); 1536 1537 bp->b_flags |= B_ERROR; 1538 bp->b_error = EIO; 1539 fdfinish(fd, bp); 1540 } 1541 fdc->sc_errors++; 1542 } 1543 1544 int 1545 fdsize(dev) 1546 dev_t dev; 1547 { 1548 1549 /* Swapping to floppies would not make sense. */ 1550 return -1; 1551 } 1552 1553 int 1554 fddump(dev, blkno, va, size) 1555 dev_t dev; 1556 daddr_t blkno; 1557 caddr_t va; 1558 size_t size; 1559 { 1560 1561 /* Not implemented. */ 1562 return ENXIO; 1563 } 1564 1565 int 1566 fdioctl(dev, cmd, addr, flag, p) 1567 dev_t dev; 1568 u_long cmd; 1569 caddr_t addr; 1570 int flag; 1571 struct proc *p; 1572 { 1573 struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)]; 1574 struct fdc_softc *fdc = (void*) fd->sc_dev.dv_parent; 1575 int unit = FDUNIT(dev); 1576 int part = DISKPART(dev); 1577 struct disklabel buffer; 1578 int error; 1579 1580 DPRINTF(("fdioctl:\n")); 1581 switch (cmd) { 1582 case DIOCGDINFO: 1583 #if 1 1584 *(struct disklabel *)addr = *(fd->sc_dk.dk_label); 1585 return(0); 1586 #else 1587 memset(&buffer, 0, sizeof(buffer)); 1588 1589 buffer.d_secpercyl = fd->sc_type->seccyl; 1590 buffer.d_type = DTYPE_FLOPPY; 1591 buffer.d_secsize = 128 << fd->sc_type->secsize; 1592 1593 if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL) 1594 return EINVAL; 1595 1596 *(struct disklabel *)addr = buffer; 1597 return 0; 1598 #endif 1599 1600 case DIOCGPART: 1601 ((struct partinfo *)addr)->disklab = fd->sc_dk.dk_label; 1602 ((struct partinfo *)addr)->part = 1603 &fd->sc_dk.dk_label->d_partitions[part]; 1604 return(0); 1605 1606 case DIOCWLABEL: 1607 if ((flag & FWRITE) == 0) 1608 return EBADF; 1609 /* XXX do something */ 1610 return 0; 1611 1612 case DIOCWDINFO: 1613 if ((flag & FWRITE) == 0) 1614 return EBADF; 1615 1616 error = setdisklabel(&buffer, (struct disklabel *)addr, 0, NULL); 1617 if (error) 1618 return error; 1619 1620 error = writedisklabel(dev, fdstrategy, &buffer, NULL); 1621 return error; 1622 1623 case DIOCLOCK: 1624 /* 1625 * Nothing to do here, really. 1626 */ 1627 return 0; /* XXX */ 1628 1629 case DIOCEJECT: 1630 if (*(int *)addr == 0) { 1631 /* 1632 * Don't force eject: check that we are the only 1633 * partition open. If so, unlock it. 1634 */ 1635 if ((fd->sc_dk.dk_openmask & ~(1 << part)) != 0 || 1636 fd->sc_dk.dk_bopenmask + fd->sc_dk.dk_copenmask != 1637 fd->sc_dk.dk_openmask) { 1638 return (EBUSY); 1639 } 1640 } 1641 /* FALLTHROUGH */ 1642 case ODIOCEJECT: 1643 fd_do_eject(fdc, unit); 1644 return 0; 1645 1646 default: 1647 return ENOTTY; 1648 } 1649 1650 #ifdef DIAGNOSTIC 1651 panic("fdioctl: impossible"); 1652 #endif 1653 } 1654 1655 void 1656 fd_do_eject(fdc, unit) 1657 struct fdc_softc *fdc; 1658 int unit; 1659 { 1660 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 1661 0x20 | ( 1 << unit)); 1662 DELAY(1); /* XXX */ 1663 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0x20); 1664 } 1665 1666 /* 1667 * Build disk label. For now we only create a label from what we know 1668 * from 'sc'. 1669 */ 1670 static int 1671 fdgetdisklabel(sc, dev) 1672 struct fd_softc *sc; 1673 dev_t dev; 1674 { 1675 struct disklabel *lp; 1676 int part; 1677 1678 DPRINTF(("fdgetdisklabel()\n")); 1679 1680 part = DISKPART(dev); 1681 lp = sc->sc_dk.dk_label; 1682 bzero(lp, sizeof(struct disklabel)); 1683 1684 lp->d_secsize = 128 << sc->sc_type->secsize; 1685 lp->d_ntracks = sc->sc_type->heads; 1686 lp->d_nsectors = sc->sc_type->sectrac; 1687 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 1688 lp->d_ncylinders = sc->sc_type->size / lp->d_secpercyl; 1689 lp->d_secperunit = sc->sc_type->size; 1690 1691 lp->d_type = DTYPE_FLOPPY; 1692 lp->d_rpm = 300; /* XXX */ 1693 lp->d_interleave = 1; /* FIXME: is this OK? */ 1694 lp->d_bbsize = 0; 1695 lp->d_sbsize = 0; 1696 lp->d_npartitions = part + 1; 1697 #define STEP_DELAY 6000 /* 6ms (6000us) delay after stepping */ 1698 lp->d_trkseek = STEP_DELAY; /* XXX */ 1699 lp->d_magic = DISKMAGIC; 1700 lp->d_magic2 = DISKMAGIC; 1701 lp->d_checksum = dkcksum(lp); 1702 lp->d_partitions[part].p_size = lp->d_secperunit; 1703 lp->d_partitions[part].p_fstype = FS_UNUSED; 1704 lp->d_partitions[part].p_fsize = 1024; 1705 lp->d_partitions[part].p_frag = 8; 1706 1707 return(0); 1708 } 1709 1710 #include <dev/cons.h> 1711 1712 /* 1713 * Mountroot hook: prompt the user to enter the root file system 1714 * floppy. 1715 */ 1716 void 1717 fd_mountroot_hook(dev) 1718 struct device *dev; 1719 { 1720 struct fd_softc *fd = (void*) dev; 1721 struct fdc_softc *fdc = (void*) fd->sc_dev.dv_parent; 1722 int c; 1723 1724 fd_do_eject(fdc, dev->dv_unit); 1725 printf("Insert filesystem floppy and press return."); 1726 for (;;) { 1727 c = cngetc(); 1728 if ((c == '\r') || (c == '\n')) { 1729 printf("\n"); 1730 break; 1731 } 1732 } 1733 } 1734