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