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