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