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