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