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