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