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