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