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