1 /* $OpenBSD: fd.c,v 1.53 2024/05/13 01:15:50 jsg Exp $ */ 2 /* $NetBSD: fd.c,v 1.112 2003/08/07 16:29:35 agc Exp $ */ 3 4 /*- 5 * Copyright (c) 2000 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Paul Kranenburg. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /*- 34 * Copyright (c) 1990 The Regents of the University of California. 35 * All rights reserved. 36 * 37 * This code is derived from software contributed to Berkeley by 38 * Don Ahn. 39 * 40 * Redistribution and use in source and binary forms, with or without 41 * modification, are permitted provided that the following conditions 42 * are met: 43 * 1. Redistributions of source code must retain the above copyright 44 * notice, this list of conditions and the following disclaimer. 45 * 2. Redistributions in binary form must reproduce the above copyright 46 * notice, this list of conditions and the following disclaimer in the 47 * documentation and/or other materials provided with the distribution. 48 * 3. Neither the name of the University nor the names of its contributors 49 * may be used to endorse or promote products derived from this software 50 * without specific prior written permission. 51 * 52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 62 * SUCH DAMAGE. 63 * 64 * @(#)fd.c 7.4 (Berkeley) 5/25/91 65 */ 66 67 /*- 68 * Copyright (c) 1993, 1994, 1995 Charles M. Hannum. 69 * Copyright (c) 1995 Paul Kranenburg. 70 * 71 * This code is derived from software contributed to Berkeley by 72 * Don Ahn. 73 * 74 * Redistribution and use in source and binary forms, with or without 75 * modification, are permitted provided that the following conditions 76 * are met: 77 * 1. Redistributions of source code must retain the above copyright 78 * notice, this list of conditions and the following disclaimer. 79 * 2. Redistributions in binary form must reproduce the above copyright 80 * notice, this list of conditions and the following disclaimer in the 81 * documentation and/or other materials provided with the distribution. 82 * 3. All advertising materials mentioning features or use of this software 83 * must display the following acknowledgement: 84 * This product includes software developed by the University of 85 * California, Berkeley and its contributors. 86 * 4. Neither the name of the University nor the names of its contributors 87 * may be used to endorse or promote products derived from this software 88 * without specific prior written permission. 89 * 90 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 91 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 92 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 93 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 94 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 95 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 96 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 97 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 98 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 99 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 100 * SUCH DAMAGE. 101 * 102 * @(#)fd.c 7.4 (Berkeley) 5/25/91 103 */ 104 105 #include <sys/param.h> 106 #include <sys/systm.h> 107 #include <sys/timeout.h> 108 #include <sys/kernel.h> 109 #include <sys/fcntl.h> 110 #include <sys/ioctl.h> 111 #include <sys/conf.h> 112 #include <sys/device.h> 113 #include <sys/disklabel.h> 114 #include <sys/disk.h> 115 #include <sys/buf.h> 116 #include <sys/malloc.h> 117 #include <sys/proc.h> 118 #include <sys/uio.h> 119 #include <sys/mtio.h> 120 #include <sys/stat.h> 121 #include <sys/syslog.h> 122 #include <sys/queue.h> 123 #include <sys/dkio.h> 124 125 #include <dev/cons.h> 126 127 #include <uvm/uvm_extern.h> 128 129 #include <machine/autoconf.h> 130 #include <machine/conf.h> 131 #include <machine/intr.h> 132 #include <machine/ioctl_fd.h> 133 134 #include <sparc64/dev/auxioreg.h> 135 #include <sparc64/dev/auxiovar.h> 136 #include <sparc64/dev/ebusreg.h> 137 #include <sparc64/dev/ebusvar.h> 138 #include <sparc64/dev/fdreg.h> 139 #include <sparc64/dev/fdvar.h> 140 141 #define FDUNIT(dev) ((minor(dev) / MAXPARTITIONS) / 8) 142 #define FDTYPE(dev) ((minor(dev) / MAXPARTITIONS) % 8) 143 144 #define FTC_FLIP \ 145 do { \ 146 auxio_fd_control(AUXIO_LED_FTC); \ 147 auxio_fd_control(0); \ 148 } while (0) 149 150 /* XXX misuse a flag to identify format operation */ 151 #define B_FORMAT B_XXX 152 153 #ifdef FD_DEBUG 154 int fdc_debug = 0; 155 #endif 156 157 enum fdc_state { 158 DEVIDLE = 0, 159 MOTORWAIT, /* 1 */ 160 DOSEEK, /* 2 */ 161 SEEKWAIT, /* 3 */ 162 SEEKTIMEDOUT, /* 4 */ 163 SEEKCOMPLETE, /* 5 */ 164 DOIO, /* 6 */ 165 IOCOMPLETE, /* 7 */ 166 IOTIMEDOUT, /* 8 */ 167 IOCLEANUPWAIT, /* 9 */ 168 IOCLEANUPTIMEDOUT,/*10 */ 169 DORESET, /* 11 */ 170 RESETCOMPLETE, /* 12 */ 171 RESETTIMEDOUT, /* 13 */ 172 DORECAL, /* 14 */ 173 RECALWAIT, /* 15 */ 174 RECALTIMEDOUT, /* 16 */ 175 RECALCOMPLETE, /* 17 */ 176 DODSKCHG, /* 18 */ 177 DSKCHGWAIT, /* 19 */ 178 DSKCHGTIMEDOUT, /* 20 */ 179 }; 180 181 /* software state, per controller */ 182 struct fdc_softc { 183 struct device sc_dev; /* boilerplate */ 184 bus_space_tag_t sc_bustag; 185 186 struct timeout fdctimeout_to; 187 struct timeout fdcpseudointr_to; 188 189 struct fd_softc *sc_fd[4]; /* pointers to children */ 190 TAILQ_HEAD(drivehead, fd_softc) sc_drives; 191 enum fdc_state sc_state; 192 int sc_flags; 193 #define FDC_EBUS 0x01 194 #define FDC_NEEDHEADSETTLE 0x02 195 #define FDC_EIS 0x04 196 #define FDC_NEEDMOTORWAIT 0x08 197 #define FDC_NOEJECT 0x10 198 int sc_errors; /* number of retries so far */ 199 int sc_overruns; /* number of DMA overruns */ 200 int sc_cfg; /* current configuration */ 201 struct fdcio sc_io; 202 #define sc_handle sc_io.fdcio_handle 203 #define sc_itask sc_io.fdcio_itask 204 #define sc_istatus sc_io.fdcio_istatus 205 #define sc_data sc_io.fdcio_data 206 #define sc_tc sc_io.fdcio_tc 207 #define sc_nstat sc_io.fdcio_nstat 208 #define sc_status sc_io.fdcio_status 209 210 void *sc_sicookie; /* softintr(9) cookie */ 211 }; 212 213 /* controller driver configuration */ 214 int fdcmatch_sbus(struct device *, void *, void *); 215 int fdcmatch_ebus(struct device *, void *, void *); 216 void fdcattach_sbus(struct device *, struct device *, void *); 217 void fdcattach_ebus(struct device *, struct device *, void *); 218 219 int fdcattach(struct fdc_softc *, int); 220 221 const struct cfattach fdc_sbus_ca = { 222 sizeof(struct fdc_softc), fdcmatch_sbus, fdcattach_sbus 223 }; 224 225 const struct cfattach fdc_ebus_ca = { 226 sizeof(struct fdc_softc), fdcmatch_ebus, fdcattach_ebus 227 }; 228 229 struct cfdriver fdc_cd = { 230 NULL, "fdc", DV_DULL 231 }; 232 233 __inline struct fd_type *fd_dev_to_type(struct fd_softc *, dev_t); 234 235 /* The order of entries in the following table is important -- BEWARE! */ 236 struct fd_type fd_types[] = { 237 { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS, "1.44MB" }, /* 1.44MB diskette */ 238 { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS, "720KB" }, /* 3.5" 720kB diskette */ 239 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS, "360KB/x" }, /* 360kB in 720kB drive */ 240 { 8,2,16,3,0xff,0xdf,0x35,0x74,77,1232,1,FDC_500KBPS, "1.2MB/NEC" } /* 1.2 MB japanese format */ 241 }; 242 243 /* software state, per disk (with up to 4 disks per ctlr) */ 244 struct fd_softc { 245 struct device sc_dv; /* generic device info */ 246 struct disk sc_dk; /* generic disk info */ 247 248 struct fd_type *sc_deftype; /* default type descriptor */ 249 struct fd_type *sc_type; /* current type descriptor */ 250 251 struct timeout sc_motoron_to; 252 struct timeout sc_motoroff_to; 253 254 daddr_t sc_blkno; /* starting block number */ 255 int sc_bcount; /* byte count left */ 256 int sc_skip; /* bytes already transferred */ 257 int sc_nblks; /* number of blocks currently transferring */ 258 int sc_nbytes; /* number of bytes currently transferring */ 259 260 int sc_drive; /* physical unit number */ 261 int sc_flags; 262 #define FD_OPEN 0x01 /* it's open */ 263 #define FD_MOTOR 0x02 /* motor should be on */ 264 #define FD_MOTOR_WAIT 0x04 /* motor coming up */ 265 int sc_cylin; /* where we think the head is */ 266 int sc_opts; /* user-set options */ 267 268 TAILQ_ENTRY(fd_softc) sc_drivechain; 269 int sc_ops; /* I/O ops since last switch */ 270 struct bufq sc_bufq; /* pending I/O requests */ 271 struct buf *sc_bp; /* current I/O */ 272 }; 273 274 /* floppy driver configuration */ 275 int fdmatch(struct device *, void *, void *); 276 void fdattach(struct device *, struct device *, void *); 277 int fdactivate(struct device *, int); 278 279 const struct cfattach fd_ca = { 280 sizeof(struct fd_softc), fdmatch, fdattach, 281 NULL, fdactivate 282 }; 283 284 struct cfdriver fd_cd = { 285 NULL, "fd", DV_DISK 286 }; 287 288 int fdgetdisklabel(dev_t, struct fd_softc *, struct disklabel *, int); 289 void fdstrategy(struct buf *); 290 void fdstart(struct fd_softc *); 291 int fdprint(void *, const char *); 292 293 struct fd_type *fd_nvtotype(char *, int, int); 294 void fd_set_motor(struct fdc_softc *fdc); 295 void fd_motor_off(void *arg); 296 void fd_motor_on(void *arg); 297 int fdcresult(struct fdc_softc *fdc); 298 int fdc_wrfifo(struct fdc_softc *fdc, u_char x); 299 void fdcstart(struct fdc_softc *fdc); 300 void fdcstatus(struct fdc_softc *fdc, char *s); 301 void fdc_reset(struct fdc_softc *fdc); 302 int fdc_diskchange(struct fdc_softc *fdc); 303 void fdctimeout(void *arg); 304 void fdcpseudointr(void *arg); 305 int fdchwintr(void *); 306 void fdcswintr(void *); 307 int fdcstate(struct fdc_softc *); 308 void fdcretry(struct fdc_softc *fdc); 309 void fdfinish(struct fd_softc *fd, struct buf *bp); 310 int fdformat(dev_t, struct fd_formb *, struct proc *); 311 void fd_do_eject(struct fd_softc *); 312 static int fdconf(struct fdc_softc *); 313 314 int 315 fdcmatch_sbus(struct device *parent, void *match, void *aux) 316 { 317 struct sbus_attach_args *sa = aux; 318 319 return (strcmp("SUNW,fdtwo", sa->sa_name) == 0); 320 } 321 322 void 323 fdcattach_sbus(struct device *parent, struct device *self, void *aux) 324 { 325 struct fdc_softc *fdc = (void *)self; 326 struct sbus_attach_args *sa = aux; 327 328 if (sa->sa_nintr == 0) { 329 printf(": no interrupt line configured\n"); 330 return; 331 } 332 333 if (auxio_fd_control(0) != 0) { 334 printf(": can't attach before auxio\n"); 335 return; 336 } 337 338 fdc->sc_bustag = sa->sa_bustag; 339 340 if (sbus_bus_map(sa->sa_bustag, 341 sa->sa_slot, sa->sa_offset, sa->sa_size, 342 BUS_SPACE_MAP_LINEAR, 0, &fdc->sc_handle) != 0) { 343 printf(": cannot map control registers\n"); 344 return; 345 } 346 347 if (strcmp(getpropstring(sa->sa_node, "status"), "disabled") == 0) { 348 printf(": no drives attached\n"); 349 return; 350 } 351 352 if (getproplen(sa->sa_node, "manual") >= 0) 353 fdc->sc_flags |= FDC_NOEJECT; 354 355 if (fdcattach(fdc, sa->sa_pri) != 0) 356 bus_space_unmap(sa->sa_bustag, fdc->sc_handle, sa->sa_size); 357 } 358 359 int 360 fdcmatch_ebus(struct device *parent, void *match, void *aux) 361 { 362 struct ebus_attach_args *ea = aux; 363 364 return (strcmp("fdthree", ea->ea_name) == 0); 365 } 366 367 void 368 fdcattach_ebus(struct device *parent, struct device *self, void *aux) 369 { 370 struct fdc_softc *fdc = (void *)self; 371 struct ebus_attach_args *ea = aux; 372 373 if (ea->ea_nintrs == 0) { 374 printf(": no interrupt line configured\n"); 375 return; 376 } 377 378 if (ea->ea_nregs < 3) { 379 printf(": expected 3 registers, only got %d\n", 380 ea->ea_nregs); 381 return; 382 } 383 384 if (ea->ea_nvaddrs > 0) { 385 if (bus_space_map(ea->ea_memtag, ea->ea_vaddrs[0], 0, 386 BUS_SPACE_MAP_PROMADDRESS, &fdc->sc_handle) != 0) { 387 printf(": can't map control registers\n"); 388 return; 389 } 390 fdc->sc_bustag = ea->ea_memtag; 391 } else if (ebus_bus_map(ea->ea_memtag, 0, 392 EBUS_PADDR_FROM_REG(&ea->ea_regs[0]), 393 ea->ea_regs[0].size, 0, 0, &fdc->sc_handle) == 0) { 394 fdc->sc_bustag = ea->ea_memtag; 395 } else if (ebus_bus_map(ea->ea_iotag, 0, 396 EBUS_PADDR_FROM_REG(&ea->ea_regs[0]), 397 ea->ea_regs[0].size, 0, 0, &fdc->sc_handle) == 0) { 398 fdc->sc_bustag = ea->ea_iotag; 399 } else { 400 printf(": can't map control registers\n"); 401 return; 402 } 403 404 if (strcmp(getpropstring(ea->ea_node, "status"), "disabled") == 0) { 405 printf(": no drives attached\n"); 406 return; 407 } 408 409 fdc->sc_flags |= FDC_EBUS; 410 411 if (getproplen(ea->ea_node, "manual") >= 0) 412 fdc->sc_flags |= FDC_NOEJECT; 413 414 /* XXX unmapping if it fails */ 415 fdcattach(fdc, ea->ea_intrs[0]); 416 } 417 418 /* 419 * Arguments passed between fdcattach and fdprobe. 420 */ 421 struct fdc_attach_args { 422 int fa_drive; 423 struct fd_type *fa_deftype; 424 }; 425 426 /* 427 * Print the location of a disk drive (called just before attaching the 428 * the drive). If `fdc' is not NULL, the drive was found but was not 429 * in the system config file; print the drive name as well. 430 * Return QUIET (config_find ignores this if the device was configured) to 431 * avoid printing `fdN not configured' messages. 432 */ 433 int 434 fdprint(void *aux, const char *fdc) 435 { 436 register struct fdc_attach_args *fa = aux; 437 438 if (!fdc) 439 printf(" drive %d", fa->fa_drive); 440 return (QUIET); 441 } 442 443 /* 444 * Configure several parameters and features on the FDC. 445 * Return 0 on success. 446 */ 447 static int 448 fdconf(struct fdc_softc *fdc) 449 { 450 int vroom; 451 452 if (fdc_wrfifo(fdc, NE7CMD_DUMPREG) || fdcresult(fdc) != 10) 453 return (-1); 454 455 /* 456 * dumpreg[7] seems to be a motor-off timeout; set it to whatever 457 * the PROM thinks is appropriate. 458 */ 459 if ((vroom = fdc->sc_status[7]) == 0) 460 vroom = 0x64; 461 462 /* Configure controller to use FIFO and Implied Seek */ 463 if (fdc_wrfifo(fdc, NE7CMD_CFG) != 0) 464 return (-1); 465 if (fdc_wrfifo(fdc, vroom) != 0) 466 return (-1); 467 if (fdc_wrfifo(fdc, fdc->sc_cfg) != 0) 468 return (-1); 469 if (fdc_wrfifo(fdc, 0) != 0) /* PRETRK */ 470 return (-1); 471 /* No result phase for the NE7CMD_CFG command */ 472 473 /* Lock configuration across soft resets. */ 474 if (fdc_wrfifo(fdc, NE7CMD_LOCK | CFG_LOCK) != 0 || 475 fdcresult(fdc) != 1) { 476 #ifdef FD_DEBUG 477 printf("fdconf: CFGLOCK failed"); 478 #endif 479 return (-1); 480 } 481 482 return (0); 483 #if 0 484 if (fdc_wrfifo(fdc, NE7CMD_VERSION) == 0 && 485 fdcresult(fdc) == 1 && fdc->sc_status[0] == 0x90) { 486 if (fdc_debug) 487 printf("[version cmd]"); 488 } 489 #endif 490 } 491 492 int 493 fdcattach(struct fdc_softc *fdc, int pri) 494 { 495 struct fdc_attach_args fa; 496 int drive_attached; 497 498 timeout_set(&fdc->fdctimeout_to, fdctimeout, fdc); 499 timeout_set(&fdc->fdcpseudointr_to, fdcpseudointr, fdc); 500 501 fdc->sc_state = DEVIDLE; 502 fdc->sc_itask = FDC_ITASK_NONE; 503 fdc->sc_istatus = FDC_ISTATUS_NONE; 504 fdc->sc_flags |= FDC_EIS | FDC_NEEDMOTORWAIT; 505 TAILQ_INIT(&fdc->sc_drives); 506 507 /* 508 * Configure controller; enable FIFO, Implied seek, no POLL mode?. 509 * Note: CFG_EFIFO is active-low, initial threshold value: 8 510 */ 511 fdc->sc_cfg = CFG_EIS|/*CFG_EFIFO|*/CFG_POLL|(8 & CFG_THRHLD_MASK); 512 if (fdconf(fdc) != 0) { 513 printf("\n%s: no drives attached\n", fdc->sc_dev.dv_xname); 514 return (-1); 515 } 516 517 if (bus_intr_establish(fdc->sc_bustag, pri, IPL_BIO, 518 0, fdchwintr, fdc, fdc->sc_dev.dv_xname) == NULL) { 519 printf("\n%s: cannot register interrupt handler\n", 520 fdc->sc_dev.dv_xname); 521 return (-1); 522 } 523 524 fdc->sc_sicookie = softintr_establish(IPL_BIO, fdcswintr, fdc); 525 if (fdc->sc_sicookie == NULL) { 526 printf("\n%s: cannot register soft interrupt handler\n", 527 fdc->sc_dev.dv_xname); 528 return (-1); 529 } 530 531 if (fdc->sc_flags & FDC_NOEJECT) 532 printf(": manual eject"); 533 printf("\n"); 534 535 /* physical limit: four drives per controller. */ 536 drive_attached = 0; 537 for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) { 538 fa.fa_deftype = NULL; /* unknown */ 539 fa.fa_deftype = &fd_types[0]; /* XXX */ 540 if (config_found(&fdc->sc_dev, (void *)&fa, fdprint) != NULL) 541 drive_attached = 1; 542 } 543 544 if (drive_attached == 0) { 545 /* XXX - dis-establish interrupts here */ 546 /* return (-1); */ 547 } 548 549 return (0); 550 } 551 552 int 553 fdmatch(struct device *parent, void *match, void *aux) 554 { 555 struct fdc_softc *fdc = (void *)parent; 556 bus_space_tag_t t = fdc->sc_bustag; 557 bus_space_handle_t h = fdc->sc_handle; 558 struct fdc_attach_args *fa = aux; 559 int drive = fa->fa_drive; 560 int n, ok; 561 562 if (drive > 0) 563 /* XXX - for now, punt on more than one drive */ 564 return (0); 565 566 /* select drive and turn on motor */ 567 bus_space_write_1(t, h, FDREG77_DOR, 568 drive | FDO_FRST | FDO_MOEN(drive)); 569 /* wait for motor to spin up */ 570 delay(250000); 571 572 fdc->sc_nstat = 0; 573 fdc_wrfifo(fdc, NE7CMD_RECAL); 574 fdc_wrfifo(fdc, drive); 575 576 /* Wait for recalibration to complete */ 577 for (n = 0; n < 10000; n++) { 578 u_int8_t v; 579 580 delay(1000); 581 v = bus_space_read_1(t, h, FDREG77_MSR); 582 if ((v & (NE7_RQM|NE7_DIO|NE7_CB)) == NE7_RQM) { 583 /* wait a bit longer till device *really* is ready */ 584 delay(100000); 585 if (fdc_wrfifo(fdc, NE7CMD_SENSEI)) 586 break; 587 if (fdcresult(fdc) == 1 && fdc->sc_status[0] == 0x80) 588 /* 589 * Got `invalid command'; we interpret it 590 * to mean that the re-calibrate hasn't in 591 * fact finished yet 592 */ 593 continue; 594 break; 595 } 596 } 597 n = fdc->sc_nstat; 598 #ifdef FD_DEBUG 599 if (fdc_debug) { 600 int i; 601 printf("fdprobe: %d stati:", n); 602 for (i = 0; i < n; i++) 603 printf(" 0x%x", fdc->sc_status[i]); 604 printf("\n"); 605 } 606 #endif 607 ok = (n == 2 && (fdc->sc_status[0] & 0xf8) == 0x20) ? 1 : 0; 608 609 /* deselect drive and turn motor off */ 610 bus_space_write_1(t, h, FDREG77_DOR, FDO_FRST | FDO_DS); 611 612 return (ok); 613 } 614 615 /* 616 * Controller is working, and drive responded. Attach it. 617 */ 618 void 619 fdattach(struct device *parent, struct device *self, void *aux) 620 { 621 struct fdc_softc *fdc = (void *)parent; 622 struct fd_softc *fd = (void *)self; 623 struct fdc_attach_args *fa = aux; 624 struct fd_type *type = fa->fa_deftype; 625 int drive = fa->fa_drive; 626 627 timeout_set(&fd->sc_motoron_to, fd_motor_on, fd); 628 timeout_set(&fd->sc_motoroff_to, fd_motor_off, fd); 629 630 /* XXX Allow `flags' to override device type? */ 631 632 if (type) 633 printf(": %s %d cyl, %d head, %d sec\n", type->name, 634 type->tracks, type->heads, type->sectrac); 635 else 636 printf(": density unknown\n"); 637 638 fd->sc_cylin = -1; 639 fd->sc_drive = drive; 640 fd->sc_deftype = type; 641 fdc->sc_fd[drive] = fd; 642 643 fdc_wrfifo(fdc, NE7CMD_SPECIFY); 644 fdc_wrfifo(fdc, type->steprate); 645 /* XXX head load time == 6ms */ 646 fdc_wrfifo(fdc, 6 | NE7_SPECIFY_NODMA); 647 648 /* 649 * Initialize and attach the disk structure. 650 */ 651 fd->sc_dk.dk_flags = DKF_NOLABELREAD; 652 fd->sc_dk.dk_name = fd->sc_dv.dv_xname; 653 bufq_init(&fd->sc_bufq, BUFQ_DEFAULT); 654 disk_attach(&fd->sc_dv, &fd->sc_dk); 655 } 656 657 int 658 fdactivate(struct device *self, int act) 659 { 660 int ret = 0; 661 662 switch (act) { 663 case DVACT_POWERDOWN: 664 /* Make sure the drive motor gets turned off at shutdown time. */ 665 fd_motor_off(self); 666 break; 667 } 668 669 return (ret); 670 } 671 672 __inline struct fd_type * 673 fd_dev_to_type(struct fd_softc *fd, dev_t dev) 674 { 675 int type = FDTYPE(dev); 676 677 if (type > (sizeof(fd_types) / sizeof(fd_types[0]))) 678 return (NULL); 679 return (type ? &fd_types[type - 1] : fd->sc_deftype); 680 } 681 682 void 683 fdstrategy(struct buf *bp) 684 { 685 struct fd_softc *fd; 686 int unit = FDUNIT(bp->b_dev); 687 int sz; 688 int s; 689 690 /* Valid unit, controller, and request? */ 691 if (unit >= fd_cd.cd_ndevs || 692 (fd = fd_cd.cd_devs[unit]) == 0 || 693 bp->b_blkno < 0 || 694 (((bp->b_bcount % FD_BSIZE(fd)) != 0 || 695 (bp->b_blkno * DEV_BSIZE) % FD_BSIZE(fd) != 0) && 696 (bp->b_flags & B_FORMAT) == 0)) { 697 bp->b_error = EINVAL; 698 goto bad; 699 } 700 701 /* If it's a null transfer, return immediately. */ 702 if (bp->b_bcount == 0) 703 goto done; 704 705 bp->b_resid = bp->b_bcount; 706 sz = howmany(bp->b_bcount, DEV_BSIZE); 707 708 if (bp->b_blkno + sz > (fd->sc_type->size * DEV_BSIZE) / FD_BSIZE(fd)) { 709 sz = (fd->sc_type->size * DEV_BSIZE) / FD_BSIZE(fd) 710 - bp->b_blkno; 711 if (sz == 0) { 712 /* If exactly at end of disk, return EOF. */ 713 goto done; 714 } 715 if (sz < 0) { 716 /* If past end of disk, return EINVAL. */ 717 bp->b_error = EINVAL; 718 goto bad; 719 } 720 /* Otherwise, truncate request. */ 721 bp->b_bcount = sz << DEV_BSHIFT; 722 } 723 724 #ifdef FD_DEBUG 725 if (fdc_debug > 1) 726 printf("fdstrategy: b_blkno %lld b_bcount %d blkno %lld\n", 727 (long long)bp->b_blkno, bp->b_bcount, 728 (long long)fd->sc_blkno); 729 #endif 730 731 /* Queue transfer */ 732 bufq_queue(&fd->sc_bufq, bp); 733 734 /* Queue transfer on drive, activate drive and controller if idle. */ 735 s = splbio(); 736 timeout_del(&fd->sc_motoroff_to); /* a good idea */ 737 if (fd->sc_bp == NULL) 738 fdstart(fd); 739 #ifdef DIAGNOSTIC 740 else { 741 struct fdc_softc *fdc = (void *)fd->sc_dv.dv_parent; 742 if (fdc->sc_state == DEVIDLE) { 743 printf("fdstrategy: controller inactive\n"); 744 fdcstart(fdc); 745 } 746 } 747 #endif 748 splx(s); 749 return; 750 751 bad: 752 bp->b_flags |= B_ERROR; 753 done: 754 /* Toss transfer; we're done early. */ 755 s = splbio(); 756 biodone(bp); 757 splx(s); 758 } 759 760 void 761 fdstart(struct fd_softc *fd) 762 { 763 struct fdc_softc *fdc = (void *)fd->sc_dv.dv_parent; 764 int active = !TAILQ_EMPTY(&fdc->sc_drives); 765 766 /* Link into controller queue. */ 767 fd->sc_bp = bufq_dequeue(&fd->sc_bufq); 768 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain); 769 770 /* If controller not already active, start it. */ 771 if (!active) 772 fdcstart(fdc); 773 } 774 775 void 776 fdfinish(struct fd_softc *fd, struct buf *bp) 777 { 778 struct fdc_softc *fdc = (void *)fd->sc_dv.dv_parent; 779 780 fd->sc_skip = 0; 781 fd->sc_bp = bufq_dequeue(&fd->sc_bufq); 782 783 /* 784 * Move this drive to the end of the queue to give others a `fair' 785 * chance. We only force a switch if N operations are completed while 786 * another drive is waiting to be serviced, since there is a long motor 787 * startup delay whenever we switch. 788 */ 789 if (TAILQ_NEXT(fd, sc_drivechain) != NULL && ++fd->sc_ops >= 8) { 790 fd->sc_ops = 0; 791 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain); 792 if (fd->sc_bp != NULL) 793 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain); 794 } 795 796 biodone(bp); 797 /* turn off motor 5s from now */ 798 timeout_add_sec(&fd->sc_motoroff_to, 5); 799 fdc->sc_state = DEVIDLE; 800 } 801 802 void 803 fdc_reset(struct fdc_softc *fdc) 804 { 805 bus_space_tag_t t = fdc->sc_bustag; 806 bus_space_handle_t h = fdc->sc_handle; 807 808 bus_space_write_1(t, h, FDREG77_DOR, FDO_FDMAEN | FDO_MOEN(0)); 809 810 bus_space_write_1(t, h, FDREG77_DRS, DRS_RESET); 811 delay(10); 812 bus_space_write_1(t, h, FDREG77_DRS, 0); 813 814 bus_space_write_1(t, h, FDREG77_DOR, 815 FDO_FRST | FDO_FDMAEN | FDO_DS); 816 #ifdef FD_DEBUG 817 if (fdc_debug) 818 printf("fdc reset\n"); 819 #endif 820 } 821 822 void 823 fd_set_motor(struct fdc_softc *fdc) 824 { 825 struct fd_softc *fd; 826 u_char status; 827 int n; 828 829 status = FDO_FRST | FDO_FDMAEN; 830 if ((fd = TAILQ_FIRST(&fdc->sc_drives)) != NULL) 831 status |= fd->sc_drive; 832 833 for (n = 0; n < 4; n++) 834 if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR)) 835 status |= FDO_MOEN(n); 836 bus_space_write_1(fdc->sc_bustag, fdc->sc_handle, 837 FDREG77_DOR, status); 838 } 839 840 void 841 fd_motor_off(void *arg) 842 { 843 struct fd_softc *fd = arg; 844 int s; 845 846 s = splbio(); 847 fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT); 848 fd_set_motor((struct fdc_softc *)fd->sc_dv.dv_parent); 849 splx(s); 850 } 851 852 void 853 fd_motor_on(void *arg) 854 { 855 struct fd_softc *fd = arg; 856 struct fdc_softc *fdc = (void *)fd->sc_dv.dv_parent; 857 int s; 858 859 s = splbio(); 860 fd->sc_flags &= ~FD_MOTOR_WAIT; 861 if (fd == TAILQ_FIRST(&fdc->sc_drives) && fdc->sc_state == MOTORWAIT) 862 (void) fdcstate(fdc); 863 splx(s); 864 } 865 866 /* 867 * Get status bytes off the FDC after a command has finished 868 * Returns the number of status bytes read; -1 on error. 869 * The return value is also stored in `sc_nstat'. 870 */ 871 int 872 fdcresult(struct fdc_softc *fdc) 873 { 874 bus_space_tag_t t = fdc->sc_bustag; 875 bus_space_handle_t h = fdc->sc_handle; 876 int j, n = 0; 877 878 for (j = 100000; j; j--) { 879 u_int8_t v = bus_space_read_1(t, h, FDREG77_MSR); 880 v &= (NE7_DIO | NE7_RQM | NE7_CB); 881 if (v == NE7_RQM) 882 return (fdc->sc_nstat = n); 883 if (v == (NE7_DIO | NE7_RQM | NE7_CB)) { 884 if (n >= sizeof(fdc->sc_status)) { 885 log(LOG_ERR, "fdcresult: overrun\n"); 886 return (-1); 887 } 888 fdc->sc_status[n++] = 889 bus_space_read_1(t, h, FDREG77_FIFO); 890 } else 891 delay(1); 892 } 893 894 log(LOG_ERR, "fdcresult: timeout\n"); 895 return (fdc->sc_nstat = -1); 896 } 897 898 /* 899 * Write a command byte to the FDC. 900 * Returns 0 on success; -1 on failure (i.e. timeout) 901 */ 902 int 903 fdc_wrfifo(struct fdc_softc *fdc, u_int8_t x) 904 { 905 bus_space_tag_t t = fdc->sc_bustag; 906 bus_space_handle_t h = fdc->sc_handle; 907 int i; 908 909 for (i = 100000; i-- != 0;) { 910 u_int8_t v = bus_space_read_1(t, h, FDREG77_MSR); 911 if ((v & (NE7_DIO|NE7_RQM)) == NE7_RQM) { 912 /* The chip is ready */ 913 bus_space_write_1(t, h, FDREG77_FIFO, x); 914 return (0); 915 } 916 delay(1); 917 } 918 return (-1); 919 } 920 921 int 922 fdc_diskchange(struct fdc_softc *fdc) 923 { 924 bus_space_tag_t t = fdc->sc_bustag; 925 bus_space_handle_t h = fdc->sc_handle; 926 927 u_int8_t v = bus_space_read_1(t, h, FDREG77_DIR); 928 return ((v & FDI_DCHG) != 0); 929 } 930 931 int 932 fdopen(dev_t dev, int flags, int fmt, struct proc *p) 933 { 934 int unit, pmask; 935 struct fd_softc *fd; 936 struct fd_type *type; 937 938 unit = FDUNIT(dev); 939 if (unit >= fd_cd.cd_ndevs) 940 return (ENXIO); 941 fd = fd_cd.cd_devs[unit]; 942 if (fd == NULL) 943 return (ENXIO); 944 type = fd_dev_to_type(fd, dev); 945 if (type == NULL) 946 return (ENXIO); 947 948 if ((fd->sc_flags & FD_OPEN) != 0 && 949 fd->sc_type != type) 950 return (EBUSY); 951 952 fd->sc_type = type; 953 fd->sc_cylin = -1; 954 fd->sc_flags |= FD_OPEN; 955 956 /* 957 * Only update the disklabel if we're not open anywhere else. 958 */ 959 if (fd->sc_dk.dk_openmask == 0) 960 fdgetdisklabel(dev, fd, fd->sc_dk.dk_label, 0); 961 962 pmask = (1 << DISKPART(dev)); 963 964 switch (fmt) { 965 case S_IFCHR: 966 fd->sc_dk.dk_copenmask |= pmask; 967 break; 968 969 case S_IFBLK: 970 fd->sc_dk.dk_bopenmask |= pmask; 971 break; 972 } 973 fd->sc_dk.dk_openmask = 974 fd->sc_dk.dk_copenmask | fd->sc_dk.dk_bopenmask; 975 976 return (0); 977 } 978 979 int 980 fdclose(dev_t dev, int flags, int fmt, struct proc *p) 981 { 982 struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)]; 983 int pmask = (1 << DISKPART(dev)); 984 985 fd->sc_flags &= ~FD_OPEN; 986 fd->sc_opts &= ~(FDOPT_NORETRY|FDOPT_SILENT); 987 988 switch (fmt) { 989 case S_IFCHR: 990 fd->sc_dk.dk_copenmask &= ~pmask; 991 break; 992 993 case S_IFBLK: 994 fd->sc_dk.dk_bopenmask &= ~pmask; 995 break; 996 } 997 fd->sc_dk.dk_openmask = 998 fd->sc_dk.dk_copenmask | fd->sc_dk.dk_bopenmask; 999 1000 return (0); 1001 } 1002 1003 int 1004 fdread(dev_t dev, struct uio *uio, int flag) 1005 { 1006 1007 return (physio(fdstrategy, dev, B_READ, minphys, uio)); 1008 } 1009 1010 int 1011 fdwrite(dev_t dev, struct uio *uio, int flag) 1012 { 1013 1014 return (physio(fdstrategy, dev, B_WRITE, minphys, uio)); 1015 } 1016 1017 void 1018 fdcstart(struct fdc_softc *fdc) 1019 { 1020 1021 #ifdef DIAGNOSTIC 1022 /* only got here if controller's drive queue was inactive; should 1023 be in idle state */ 1024 if (fdc->sc_state != DEVIDLE) { 1025 printf("fdcstart: not idle\n"); 1026 return; 1027 } 1028 #endif 1029 (void) fdcstate(fdc); 1030 } 1031 1032 void 1033 fdcstatus(struct fdc_softc *fdc, char *s) 1034 { 1035 struct fd_softc *fd = TAILQ_FIRST(&fdc->sc_drives); 1036 int n; 1037 1038 /* Just print last status */ 1039 n = fdc->sc_nstat; 1040 1041 #if 0 1042 if (n == 0) { 1043 fdc_wrfifo(fdc, NE7CMD_SENSEI); 1044 (void) fdcresult(fdc); 1045 n = 2; 1046 } 1047 #endif 1048 1049 printf("%s: %s: state %d", 1050 fd ? fd->sc_dv.dv_xname : "fdc", s, fdc->sc_state); 1051 1052 switch (n) { 1053 case 0: 1054 printf("\n"); 1055 break; 1056 case 2: 1057 printf(" (st0 %b cyl %d)\n", 1058 fdc->sc_status[0], NE7_ST0BITS, 1059 fdc->sc_status[1]); 1060 break; 1061 case 7: 1062 printf(" (st0 %b st1 %b st2 %b cyl %d head %d sec %d)\n", 1063 fdc->sc_status[0], NE7_ST0BITS, 1064 fdc->sc_status[1], NE7_ST1BITS, 1065 fdc->sc_status[2], NE7_ST2BITS, 1066 fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]); 1067 break; 1068 #ifdef DIAGNOSTIC 1069 default: 1070 printf(" fdcstatus: weird size: %d\n", n); 1071 break; 1072 #endif 1073 } 1074 } 1075 1076 void 1077 fdctimeout(void *arg) 1078 { 1079 struct fdc_softc *fdc = arg; 1080 struct fd_softc *fd; 1081 int s; 1082 1083 s = splbio(); 1084 fd = TAILQ_FIRST(&fdc->sc_drives); 1085 if (fd == NULL) { 1086 printf("%s: timeout but no I/O pending: state %d, istatus=%d\n", 1087 fdc->sc_dev.dv_xname, fdc->sc_state, fdc->sc_istatus); 1088 fdc->sc_state = DEVIDLE; 1089 goto out; 1090 } 1091 1092 if (fd->sc_bp != NULL) 1093 fdc->sc_state++; 1094 else 1095 fdc->sc_state = DEVIDLE; 1096 1097 (void) fdcstate(fdc); 1098 out: 1099 splx(s); 1100 1101 } 1102 1103 void 1104 fdcpseudointr(void *arg) 1105 { 1106 struct fdc_softc *fdc = arg; 1107 int s; 1108 1109 /* Just ensure it has the right spl. */ 1110 s = splbio(); 1111 (void) fdcstate(fdc); 1112 splx(s); 1113 } 1114 1115 1116 /* 1117 * Hardware interrupt entry point. 1118 * Unfortunately, we have no reliable way to determine that the 1119 * interrupt really came from the floppy controller; just hope 1120 * that the other devices that share this interrupt can do better.. 1121 */ 1122 int 1123 fdchwintr(void *arg) 1124 { 1125 struct fdc_softc *fdc = arg; 1126 bus_space_tag_t t = fdc->sc_bustag; 1127 bus_space_handle_t h = fdc->sc_handle; 1128 1129 switch (fdc->sc_itask) { 1130 case FDC_ITASK_NONE: 1131 return (0); 1132 case FDC_ITASK_SENSEI: 1133 if (fdc_wrfifo(fdc, NE7CMD_SENSEI) != 0 || fdcresult(fdc) == -1) 1134 fdc->sc_istatus = FDC_ISTATUS_ERROR; 1135 else 1136 fdc->sc_istatus = FDC_ISTATUS_DONE; 1137 softintr_schedule(fdc->sc_sicookie); 1138 return (1); 1139 case FDC_ITASK_RESULT: 1140 if (fdcresult(fdc) == -1) 1141 fdc->sc_istatus = FDC_ISTATUS_ERROR; 1142 else 1143 fdc->sc_istatus = FDC_ISTATUS_DONE; 1144 softintr_schedule(fdc->sc_sicookie); 1145 return (1); 1146 case FDC_ITASK_DMA: 1147 /* Proceed with pseudo-DMA below */ 1148 break; 1149 default: 1150 printf("fdc: stray hard interrupt: itask=%d\n", fdc->sc_itask); 1151 fdc->sc_istatus = FDC_ISTATUS_SPURIOUS; 1152 softintr_schedule(fdc->sc_sicookie); 1153 return (1); 1154 } 1155 1156 /* 1157 * Pseudo DMA in progress 1158 */ 1159 for (;;) { 1160 u_int8_t msr; 1161 1162 msr = bus_space_read_1(t, h, FDREG77_MSR); 1163 1164 if ((msr & NE7_RQM) == 0) 1165 /* That's all this round */ 1166 break; 1167 1168 if ((msr & NE7_NDM) == 0) { 1169 fdcresult(fdc); 1170 fdc->sc_istatus = FDC_ISTATUS_DONE; 1171 softintr_schedule(fdc->sc_sicookie); 1172 #ifdef FD_DEBUG 1173 if (fdc_debug > 1) 1174 printf("fdc: overrun: msr = %x, tc = %d\n", 1175 msr, fdc->sc_tc); 1176 #endif 1177 break; 1178 } 1179 1180 /* Another byte can be transferred */ 1181 if ((msr & NE7_DIO) != 0) 1182 *fdc->sc_data = 1183 bus_space_read_1(t, h, FDREG77_FIFO); 1184 else 1185 bus_space_write_1(t, h, FDREG77_FIFO, 1186 *fdc->sc_data); 1187 1188 fdc->sc_data++; 1189 if (--fdc->sc_tc == 0) { 1190 fdc->sc_istatus = FDC_ISTATUS_DONE; 1191 FTC_FLIP; 1192 fdcresult(fdc); 1193 softintr_schedule(fdc->sc_sicookie); 1194 break; 1195 } 1196 } 1197 return (1); 1198 } 1199 1200 void 1201 fdcswintr(void *arg) 1202 { 1203 struct fdc_softc *fdc = arg; 1204 int s; 1205 1206 if (fdc->sc_istatus == FDC_ISTATUS_NONE) 1207 /* This (software) interrupt is not for us */ 1208 return; 1209 1210 switch (fdc->sc_istatus) { 1211 case FDC_ISTATUS_ERROR: 1212 printf("fdc: ierror status: state %d\n", fdc->sc_state); 1213 break; 1214 case FDC_ISTATUS_SPURIOUS: 1215 printf("fdc: spurious interrupt: state %d\n", fdc->sc_state); 1216 break; 1217 } 1218 1219 s = splbio(); 1220 fdcstate(fdc); 1221 splx(s); 1222 return; 1223 } 1224 1225 int 1226 fdcstate(struct fdc_softc *fdc) 1227 { 1228 #define st0 fdc->sc_status[0] 1229 #define st1 fdc->sc_status[1] 1230 #define cyl fdc->sc_status[1] 1231 #define FDC_WRFIFO(fdc, c) \ 1232 do { \ 1233 if (fdc_wrfifo(fdc, (c))) { \ 1234 goto xxx; \ 1235 } \ 1236 } while(0) 1237 1238 struct fd_softc *fd; 1239 struct buf *bp; 1240 int read, head, sec, nblks, cylin; 1241 struct fd_type *type; 1242 struct fd_formb *finfo = NULL; 1243 1244 if (fdc->sc_istatus == FDC_ISTATUS_ERROR) { 1245 /* Prevent loop if the reset sequence produces errors */ 1246 if (fdc->sc_state != RESETCOMPLETE && 1247 fdc->sc_state != RECALWAIT && 1248 fdc->sc_state != RECALCOMPLETE) 1249 fdc->sc_state = DORESET; 1250 } 1251 1252 /* Clear I task/status field */ 1253 fdc->sc_istatus = FDC_ISTATUS_NONE; 1254 fdc->sc_itask = FDC_ITASK_NONE; 1255 1256 loop: 1257 /* Is there a drive for the controller to do a transfer with? */ 1258 fd = TAILQ_FIRST(&fdc->sc_drives); 1259 if (fd == NULL) { 1260 fdc->sc_state = DEVIDLE; 1261 return (0); 1262 } 1263 1264 /* Is there a transfer to this drive? If not, deactivate drive. */ 1265 bp = fd->sc_bp; 1266 if (bp == NULL) { 1267 fd->sc_ops = 0; 1268 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain); 1269 goto loop; 1270 } 1271 1272 if (bp->b_flags & B_FORMAT) 1273 finfo = (struct fd_formb *)bp->b_data; 1274 1275 cylin = ((bp->b_blkno * DEV_BSIZE) - (bp->b_bcount - bp->b_resid)) / 1276 (FD_BSIZE(fd) * fd->sc_type->seccyl); 1277 1278 switch (fdc->sc_state) { 1279 case DEVIDLE: 1280 fdc->sc_errors = 0; 1281 fd->sc_skip = 0; 1282 fd->sc_bcount = bp->b_bcount; 1283 fd->sc_blkno = (bp->b_blkno * DEV_BSIZE) / FD_BSIZE(fd); 1284 timeout_del(&fd->sc_motoroff_to); 1285 if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) { 1286 fdc->sc_state = MOTORWAIT; 1287 return (1); 1288 } 1289 if ((fd->sc_flags & FD_MOTOR) == 0) { 1290 /* Turn on the motor, being careful about pairing. */ 1291 struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1]; 1292 if (ofd && ofd->sc_flags & FD_MOTOR) { 1293 timeout_del(&ofd->sc_motoroff_to); 1294 ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT); 1295 } 1296 fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT; 1297 fd_set_motor(fdc); 1298 fdc->sc_state = MOTORWAIT; 1299 if ((fdc->sc_flags & FDC_NEEDMOTORWAIT) != 0) { /*XXX*/ 1300 /* Allow .25s for motor to stabilize. */ 1301 timeout_add_msec(&fd->sc_motoron_to, 250); 1302 } else { 1303 fd->sc_flags &= ~FD_MOTOR_WAIT; 1304 goto loop; 1305 } 1306 return (1); 1307 } 1308 /* Make sure the right drive is selected. */ 1309 fd_set_motor(fdc); 1310 1311 if (fdc_diskchange(fdc)) 1312 goto dodskchg; 1313 1314 /*FALLTHROUGH*/ 1315 case DOSEEK: 1316 doseek: 1317 if ((fdc->sc_flags & FDC_EIS) && 1318 (bp->b_flags & B_FORMAT) == 0) { 1319 fd->sc_cylin = cylin; 1320 /* We use implied seek */ 1321 goto doio; 1322 } 1323 1324 if (fd->sc_cylin == cylin) 1325 goto doio; 1326 1327 fd->sc_cylin = -1; 1328 fdc->sc_state = SEEKWAIT; 1329 fdc->sc_nstat = 0; 1330 1331 fd->sc_dk.dk_seek++; 1332 1333 disk_busy(&fd->sc_dk); 1334 timeout_add_sec(&fdc->fdctimeout_to, 4); 1335 1336 /* specify command */ 1337 FDC_WRFIFO(fdc, NE7CMD_SPECIFY); 1338 FDC_WRFIFO(fdc, fd->sc_type->steprate); 1339 /* XXX head load time == 6ms */ 1340 FDC_WRFIFO(fdc, 6 | NE7_SPECIFY_NODMA); 1341 1342 fdc->sc_itask = FDC_ITASK_SENSEI; 1343 /* seek function */ 1344 FDC_WRFIFO(fdc, NE7CMD_SEEK); 1345 FDC_WRFIFO(fdc, fd->sc_drive); /* drive number */ 1346 FDC_WRFIFO(fdc, cylin * fd->sc_type->step); 1347 return (1); 1348 1349 case DODSKCHG: 1350 dodskchg: 1351 /* 1352 * Disk change: force a seek operation by going to cyl 1 1353 * followed by a recalibrate. 1354 */ 1355 disk_busy(&fd->sc_dk); 1356 timeout_add_sec(&fdc->fdctimeout_to, 4); 1357 fd->sc_cylin = -1; 1358 fdc->sc_nstat = 0; 1359 fdc->sc_state = DSKCHGWAIT; 1360 1361 fdc->sc_itask = FDC_ITASK_SENSEI; 1362 /* seek function */ 1363 FDC_WRFIFO(fdc, NE7CMD_SEEK); 1364 FDC_WRFIFO(fdc, fd->sc_drive); /* drive number */ 1365 FDC_WRFIFO(fdc, 1 * fd->sc_type->step); 1366 return (1); 1367 1368 case DSKCHGWAIT: 1369 timeout_del(&fdc->fdctimeout_to); 1370 disk_unbusy(&fd->sc_dk, 0, 0, 0); 1371 if (fdc->sc_nstat != 2 || (st0 & 0xf8) != 0x20 || 1372 cyl != 1 * fd->sc_type->step) { 1373 fdcstatus(fdc, "dskchg seek failed"); 1374 fdc->sc_state = DORESET; 1375 } else 1376 fdc->sc_state = DORECAL; 1377 1378 if (fdc_diskchange(fdc)) { 1379 printf("%s: cannot clear disk change status\n", 1380 fdc->sc_dev.dv_xname); 1381 fdc->sc_state = DORESET; 1382 } 1383 goto loop; 1384 1385 case DOIO: 1386 doio: 1387 if (finfo != NULL) 1388 fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) - 1389 (char *)finfo; 1390 type = fd->sc_type; 1391 sec = fd->sc_blkno % type->seccyl; 1392 nblks = type->seccyl - sec; 1393 nblks = min(nblks, fd->sc_bcount / FD_BSIZE(fd)); 1394 nblks = min(nblks, FDC_MAXIOSIZE / FD_BSIZE(fd)); 1395 fd->sc_nblks = nblks; 1396 fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FD_BSIZE(fd); 1397 head = sec / type->sectrac; 1398 sec -= head * type->sectrac; 1399 #ifdef DIAGNOSTIC 1400 { 1401 daddr_t block; 1402 1403 block = (fd->sc_cylin * type->heads + head) * 1404 type->sectrac + sec; 1405 if (block != fd->sc_blkno) { 1406 printf("fdcintr: block %lld != blkno %lld\n", 1407 (long long)block, (long long)fd->sc_blkno); 1408 #if defined(FD_DEBUG) && defined(DDB) 1409 db_enter(); 1410 #endif 1411 } 1412 } 1413 #endif 1414 read = bp->b_flags & B_READ; 1415 1416 /* Setup for pseudo DMA */ 1417 fdc->sc_data = bp->b_data + fd->sc_skip; 1418 fdc->sc_tc = fd->sc_nbytes; 1419 1420 bus_space_write_1(fdc->sc_bustag, fdc->sc_handle, 1421 FDREG77_DRS, type->rate); 1422 #ifdef FD_DEBUG 1423 if (fdc_debug > 1) 1424 printf("fdcstate: doio: %s drive %d " 1425 "track %d head %d sec %d nblks %d\n", 1426 finfo ? "format" : 1427 (read ? "read" : "write"), 1428 fd->sc_drive, fd->sc_cylin, head, sec, nblks); 1429 #endif 1430 fdc->sc_state = IOCOMPLETE; 1431 fdc->sc_itask = FDC_ITASK_DMA; 1432 fdc->sc_nstat = 0; 1433 1434 disk_busy(&fd->sc_dk); 1435 1436 /* allow 3 seconds for operation */ 1437 timeout_add_sec(&fdc->fdctimeout_to, 3); 1438 1439 if (finfo != NULL) { 1440 /* formatting */ 1441 FDC_WRFIFO(fdc, NE7CMD_FORMAT); 1442 FDC_WRFIFO(fdc, (head << 2) | fd->sc_drive); 1443 FDC_WRFIFO(fdc, finfo->fd_formb_secshift); 1444 FDC_WRFIFO(fdc, finfo->fd_formb_nsecs); 1445 FDC_WRFIFO(fdc, finfo->fd_formb_gaplen); 1446 FDC_WRFIFO(fdc, finfo->fd_formb_fillbyte); 1447 } else { 1448 if (read) 1449 FDC_WRFIFO(fdc, NE7CMD_READ); 1450 else 1451 FDC_WRFIFO(fdc, NE7CMD_WRITE); 1452 FDC_WRFIFO(fdc, (head << 2) | fd->sc_drive); 1453 FDC_WRFIFO(fdc, fd->sc_cylin); /*track*/ 1454 FDC_WRFIFO(fdc, head); 1455 FDC_WRFIFO(fdc, sec + 1); /*sector+1*/ 1456 FDC_WRFIFO(fdc, type->secsize); /*sector size*/ 1457 FDC_WRFIFO(fdc, type->sectrac); /*secs/track*/ 1458 FDC_WRFIFO(fdc, type->gap1); /*gap1 size*/ 1459 FDC_WRFIFO(fdc, type->datalen); /*data length*/ 1460 } 1461 1462 return (1); /* will return later */ 1463 1464 case SEEKWAIT: 1465 timeout_del(&fdc->fdctimeout_to); 1466 fdc->sc_state = SEEKCOMPLETE; 1467 if (fdc->sc_flags & FDC_NEEDHEADSETTLE) { 1468 /* allow 1/50 second for heads to settle */ 1469 timeout_add_msec(&fdc->fdcpseudointr_to, 20); 1470 return (1); /* will return later */ 1471 } 1472 /*FALLTHROUGH*/ 1473 case SEEKCOMPLETE: 1474 /* no data on seek */ 1475 disk_unbusy(&fd->sc_dk, 0, 0, 0); 1476 1477 /* Make sure seek really happened. */ 1478 if (fdc->sc_nstat != 2 || (st0 & 0xf8) != 0x20 || 1479 cyl != cylin * fd->sc_type->step) { 1480 #ifdef FD_DEBUG 1481 if (fdc_debug) 1482 fdcstatus(fdc, "seek failed"); 1483 #endif 1484 fdcretry(fdc); 1485 goto loop; 1486 } 1487 fd->sc_cylin = cylin; 1488 goto doio; 1489 1490 case IOTIMEDOUT: 1491 /* 1492 * Try to abort the I/O operation without resetting 1493 * the chip first. Poke TC and arrange to pick up 1494 * the timed out I/O command's status. 1495 */ 1496 fdc->sc_itask = FDC_ITASK_RESULT; 1497 fdc->sc_state = IOCLEANUPWAIT; 1498 fdc->sc_nstat = 0; 1499 /* 1/10 second should be enough */ 1500 timeout_add_msec(&fdc->fdctimeout_to, 100); 1501 return (1); 1502 1503 case IOCLEANUPTIMEDOUT: 1504 case SEEKTIMEDOUT: 1505 case RECALTIMEDOUT: 1506 case RESETTIMEDOUT: 1507 case DSKCHGTIMEDOUT: 1508 fdcstatus(fdc, "timeout"); 1509 1510 /* All other timeouts always roll through to a chip reset */ 1511 fdcretry(fdc); 1512 1513 /* Force reset, no matter what fdcretry() says */ 1514 fdc->sc_state = DORESET; 1515 goto loop; 1516 1517 case IOCLEANUPWAIT: /* IO FAILED, cleanup succeeded */ 1518 timeout_del(&fdc->fdctimeout_to); 1519 disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid), 1520 bp->b_blkno, (bp->b_flags & B_READ)); 1521 fdcretry(fdc); 1522 goto loop; 1523 1524 case IOCOMPLETE: /* IO DONE, post-analyze */ 1525 timeout_del(&fdc->fdctimeout_to); 1526 1527 disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid), 1528 bp->b_blkno, (bp->b_flags & B_READ)); 1529 1530 if (fdc->sc_nstat != 7 || st1 != 0 || 1531 ((st0 & 0xf8) != 0 && 1532 ((st0 & 0xf8) != 0x20 || (fdc->sc_cfg & CFG_EIS) == 0))) { 1533 #ifdef FD_DEBUG 1534 if (fdc_debug) { 1535 fdcstatus(fdc, 1536 bp->b_flags & B_READ 1537 ? "read failed" : "write failed"); 1538 printf("blkno %lld nblks %d nstat %d tc %d\n", 1539 (long long)fd->sc_blkno, fd->sc_nblks, 1540 fdc->sc_nstat, fdc->sc_tc); 1541 } 1542 #endif 1543 if (fdc->sc_nstat == 7 && 1544 (st1 & ST1_OVERRUN) == ST1_OVERRUN) { 1545 1546 /* 1547 * Silently retry overruns if no other 1548 * error bit is set. Adjust threshold. 1549 */ 1550 int thr = fdc->sc_cfg & CFG_THRHLD_MASK; 1551 if (thr < 15) { 1552 thr++; 1553 fdc->sc_cfg &= ~CFG_THRHLD_MASK; 1554 fdc->sc_cfg |= (thr & CFG_THRHLD_MASK); 1555 #ifdef FD_DEBUG 1556 if (fdc_debug) 1557 printf("fdc: %d -> threshold\n", thr); 1558 #endif 1559 fdconf(fdc); 1560 fdc->sc_overruns = 0; 1561 } 1562 if (++fdc->sc_overruns < 3) { 1563 fdc->sc_state = DOIO; 1564 goto loop; 1565 } 1566 } 1567 fdcretry(fdc); 1568 goto loop; 1569 } 1570 if (fdc->sc_errors) { 1571 diskerr(bp, "fd", "soft error", LOG_PRINTF, 1572 fd->sc_skip / FD_BSIZE(fd), 1573 (struct disklabel *)NULL); 1574 printf("\n"); 1575 fdc->sc_errors = 0; 1576 } else { 1577 if (--fdc->sc_overruns < -20) { 1578 int thr = fdc->sc_cfg & CFG_THRHLD_MASK; 1579 if (thr > 0) { 1580 thr--; 1581 fdc->sc_cfg &= ~CFG_THRHLD_MASK; 1582 fdc->sc_cfg |= (thr & CFG_THRHLD_MASK); 1583 #ifdef FD_DEBUG 1584 if (fdc_debug) 1585 printf("fdc: %d -> threshold\n", thr); 1586 #endif 1587 fdconf(fdc); 1588 } 1589 fdc->sc_overruns = 0; 1590 } 1591 } 1592 fd->sc_blkno += fd->sc_nblks; 1593 fd->sc_skip += fd->sc_nbytes; 1594 fd->sc_bcount -= fd->sc_nbytes; 1595 bp->b_resid -= fd->sc_nbytes; 1596 if (finfo == NULL && fd->sc_bcount > 0) { 1597 cylin = fd->sc_blkno / fd->sc_type->seccyl; 1598 goto doseek; 1599 } 1600 fdfinish(fd, bp); 1601 goto loop; 1602 1603 case DORESET: 1604 /* try a reset, keep motor on */ 1605 fd_set_motor(fdc); 1606 delay(100); 1607 fdc->sc_nstat = 0; 1608 fdc->sc_itask = FDC_ITASK_SENSEI; 1609 fdc->sc_state = RESETCOMPLETE; 1610 timeout_add_msec(&fdc->fdctimeout_to, 500); 1611 fdc_reset(fdc); 1612 return (1); /* will return later */ 1613 1614 case RESETCOMPLETE: 1615 timeout_del(&fdc->fdctimeout_to); 1616 fdconf(fdc); 1617 1618 /* FALLTHROUGH */ 1619 case DORECAL: 1620 fdc->sc_state = RECALWAIT; 1621 fdc->sc_itask = FDC_ITASK_SENSEI; 1622 fdc->sc_nstat = 0; 1623 timeout_add_sec(&fdc->fdctimeout_to, 5); 1624 /* recalibrate function */ 1625 FDC_WRFIFO(fdc, NE7CMD_RECAL); 1626 FDC_WRFIFO(fdc, fd->sc_drive); 1627 return (1); /* will return later */ 1628 1629 case RECALWAIT: 1630 timeout_del(&fdc->fdctimeout_to); 1631 fdc->sc_state = RECALCOMPLETE; 1632 if (fdc->sc_flags & FDC_NEEDHEADSETTLE) { 1633 /* allow 1/30 second for heads to settle */ 1634 timeout_add_msec(&fdc->fdcpseudointr_to, 1000 / 30); 1635 return (1); /* will return later */ 1636 } 1637 1638 case RECALCOMPLETE: 1639 if (fdc->sc_nstat != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) { 1640 #ifdef FD_DEBUG 1641 if (fdc_debug) 1642 fdcstatus(fdc, "recalibrate failed"); 1643 #endif 1644 fdcretry(fdc); 1645 goto loop; 1646 } 1647 fd->sc_cylin = 0; 1648 goto doseek; 1649 1650 case MOTORWAIT: 1651 if (fd->sc_flags & FD_MOTOR_WAIT) 1652 return (1); /* time's not up yet */ 1653 goto doseek; 1654 1655 default: 1656 fdcstatus(fdc, "stray interrupt"); 1657 return (1); 1658 } 1659 #ifdef DIAGNOSTIC 1660 panic("fdcintr: impossible"); 1661 #endif 1662 1663 xxx: 1664 /* 1665 * We get here if the chip locks up in FDC_WRFIFO() 1666 * Cancel any operation and schedule a reset 1667 */ 1668 timeout_del(&fdc->fdctimeout_to); 1669 fdcretry(fdc); 1670 fdc->sc_state = DORESET; 1671 goto loop; 1672 1673 #undef st0 1674 #undef st1 1675 #undef cyl 1676 } 1677 1678 void 1679 fdcretry(struct fdc_softc *fdc) 1680 { 1681 struct fd_softc *fd; 1682 struct buf *bp; 1683 int error = EIO; 1684 1685 fd = TAILQ_FIRST(&fdc->sc_drives); 1686 bp = fd->sc_bp; 1687 1688 fdc->sc_overruns = 0; 1689 if (fd->sc_opts & FDOPT_NORETRY) 1690 goto fail; 1691 1692 switch (fdc->sc_errors) { 1693 case 0: 1694 if (fdc->sc_nstat == 7 && 1695 (fdc->sc_status[0] & 0xd8) == 0x40 && 1696 (fdc->sc_status[1] & 0x2) == 0x2) { 1697 printf("%s: read-only medium\n", fd->sc_dv.dv_xname); 1698 error = EROFS; 1699 goto failsilent; 1700 } 1701 /* try again */ 1702 fdc->sc_state = 1703 (fdc->sc_flags & FDC_EIS) ? DOIO : DOSEEK; 1704 break; 1705 1706 case 1: case 2: case 3: 1707 /* didn't work; try recalibrating */ 1708 fdc->sc_state = DORECAL; 1709 break; 1710 1711 case 4: 1712 if (fdc->sc_nstat == 7 && 1713 fdc->sc_status[0] == 0 && 1714 fdc->sc_status[1] == 0 && 1715 fdc->sc_status[2] == 0) { 1716 /* 1717 * We've retried a few times and we've got 1718 * valid status and all three status bytes 1719 * are zero. Assume this condition is the 1720 * result of no disk loaded into the drive. 1721 */ 1722 printf("%s: no medium?\n", fd->sc_dv.dv_xname); 1723 error = ENODEV; 1724 goto failsilent; 1725 } 1726 1727 /* still no go; reset the bastard */ 1728 fdc->sc_state = DORESET; 1729 break; 1730 1731 default: 1732 fail: 1733 if ((fd->sc_opts & FDOPT_SILENT) == 0) { 1734 diskerr(bp, "fd", "hard error", LOG_PRINTF, 1735 fd->sc_skip / FD_BSIZE(fd), 1736 (struct disklabel *)NULL); 1737 printf("\n"); 1738 fdcstatus(fdc, "controller status"); 1739 } 1740 1741 failsilent: 1742 bp->b_flags |= B_ERROR; 1743 bp->b_error = error; 1744 bp->b_resid = bp->b_bcount; 1745 fdfinish(fd, bp); 1746 } 1747 fdc->sc_errors++; 1748 } 1749 1750 daddr_t 1751 fdsize(dev_t dev) 1752 { 1753 1754 /* Swapping to floppies would not make sense. */ 1755 return (-1); 1756 } 1757 1758 int 1759 fddump(dev_t dev, daddr_t blkno, caddr_t va, size_t size) 1760 { 1761 1762 /* Not implemented. */ 1763 return (EINVAL); 1764 } 1765 1766 int 1767 fdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) 1768 { 1769 struct fd_softc *fd; 1770 struct fdc_softc *fdc; 1771 struct disklabel *lp; 1772 int unit; 1773 int error; 1774 #ifdef FD_DEBUG 1775 int i; 1776 #endif 1777 1778 unit = FDUNIT(dev); 1779 if (unit >= fd_cd.cd_ndevs) 1780 return (ENXIO); 1781 1782 fd = fd_cd.cd_devs[FDUNIT(dev)]; 1783 fdc = (struct fdc_softc *)fd->sc_dv.dv_parent; 1784 1785 switch (cmd) { 1786 case DIOCRLDINFO: 1787 lp = malloc(sizeof(*lp), M_TEMP, M_WAITOK); 1788 fdgetdisklabel(dev, fd, lp, 0); 1789 bcopy(lp, fd->sc_dk.dk_label, sizeof(*lp)); 1790 free(lp, M_TEMP, 0); 1791 return 0; 1792 1793 case DIOCGPDINFO: 1794 fdgetdisklabel(dev, fd, (struct disklabel *)addr, 1); 1795 return 0; 1796 1797 case DIOCGDINFO: 1798 *(struct disklabel *)addr = *(fd->sc_dk.dk_label); 1799 return 0; 1800 1801 case DIOCGPART: 1802 ((struct partinfo *)addr)->disklab = fd->sc_dk.dk_label; 1803 ((struct partinfo *)addr)->part = 1804 &fd->sc_dk.dk_label->d_partitions[DISKPART(dev)]; 1805 return 0; 1806 1807 case DIOCWDINFO: 1808 case DIOCSDINFO: 1809 if ((flag & FWRITE) == 0) 1810 return (EBADF); 1811 1812 error = setdisklabel(fd->sc_dk.dk_label, 1813 (struct disklabel *)addr, 0); 1814 if (error == 0) { 1815 if (cmd == DIOCWDINFO) 1816 error = writedisklabel(DISKLABELDEV(dev), 1817 fdstrategy, fd->sc_dk.dk_label); 1818 } 1819 return (error); 1820 1821 case DIOCLOCK: 1822 /* 1823 * Nothing to do here, really. 1824 */ 1825 return (0); 1826 1827 case MTIOCTOP: 1828 if (((struct mtop *)addr)->mt_op != MTOFFL) 1829 return (EIO); 1830 /* FALLTHROUGH */ 1831 case DIOCEJECT: 1832 if (fdc->sc_flags & FDC_NOEJECT) 1833 return (ENODEV); 1834 fd_do_eject(fd); 1835 return (0); 1836 1837 case FD_FORM: 1838 if ((flag & FWRITE) == 0) 1839 return (EBADF); /* must be opened for writing */ 1840 else if (((struct fd_formb *)addr)->format_version != 1841 FD_FORMAT_VERSION) 1842 return (EINVAL);/* wrong version of formatting prog */ 1843 else 1844 return fdformat(dev, (struct fd_formb *)addr, p); 1845 break; 1846 1847 case FD_GTYPE: /* get drive options */ 1848 *(struct fd_type *)addr = *fd->sc_type; 1849 return (0); 1850 1851 case FD_GOPTS: /* get drive options */ 1852 *(int *)addr = fd->sc_opts; 1853 return (0); 1854 1855 case FD_SOPTS: /* set drive options */ 1856 fd->sc_opts = *(int *)addr; 1857 return (0); 1858 1859 #ifdef FD_DEBUG 1860 case _IO('f', 100): 1861 fdc_wrfifo(fdc, NE7CMD_DUMPREG); 1862 fdcresult(fdc); 1863 printf("fdc: dumpreg(%d regs): <", fdc->sc_nstat); 1864 for (i = 0; i < fdc->sc_nstat; i++) 1865 printf(" 0x%x", fdc->sc_status[i]); 1866 printf(">\n"); 1867 return (0); 1868 1869 case _IOW('f', 101, int): 1870 fdc->sc_cfg &= ~CFG_THRHLD_MASK; 1871 fdc->sc_cfg |= (*(int *)addr & CFG_THRHLD_MASK); 1872 fdconf(fdc); 1873 return (0); 1874 1875 case _IO('f', 102): 1876 fdc_wrfifo(fdc, NE7CMD_SENSEI); 1877 fdcresult(fdc); 1878 printf("fdc: sensei(%d regs): <", fdc->sc_nstat); 1879 for (i=0; i< fdc->sc_nstat; i++) 1880 printf(" 0x%x", fdc->sc_status[i]); 1881 printf(">\n"); 1882 return (0); 1883 #endif 1884 default: 1885 return (ENOTTY); 1886 } 1887 } 1888 1889 int 1890 fdformat(dev_t dev, struct fd_formb *finfo, struct proc *p) 1891 { 1892 int rv = 0; 1893 struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)]; 1894 struct fd_type *type = fd->sc_type; 1895 struct buf *bp; 1896 1897 /* set up a buffer header for fdstrategy() */ 1898 bp = malloc(sizeof(*bp), M_TEMP, M_NOWAIT | M_ZERO); 1899 if (bp == NULL) 1900 return (ENOBUFS); 1901 1902 bp->b_flags = B_BUSY | B_PHYS | B_FORMAT | B_RAW; 1903 bp->b_proc = p; 1904 bp->b_dev = dev; 1905 1906 /* 1907 * Calculate a fake blkno, so fdstrategy() would initiate a 1908 * seek to the requested cylinder. 1909 */ 1910 bp->b_blkno = ((finfo->cyl * (type->sectrac * type->heads) 1911 + finfo->head * type->sectrac) * FD_BSIZE(fd)) 1912 / DEV_BSIZE; 1913 1914 bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs; 1915 bp->b_data = (caddr_t)finfo; 1916 1917 #ifdef FD_DEBUG 1918 if (fdc_debug) { 1919 int i; 1920 1921 printf("fdformat: blkno 0x%llx count %ld\n", 1922 (unsigned long long)bp->b_blkno, bp->b_bcount); 1923 1924 printf("\tcyl:\t%d\n", finfo->cyl); 1925 printf("\thead:\t%d\n", finfo->head); 1926 printf("\tnsecs:\t%d\n", finfo->fd_formb_nsecs); 1927 printf("\tsshft:\t%d\n", finfo->fd_formb_secshift); 1928 printf("\tgaplen:\t%d\n", finfo->fd_formb_gaplen); 1929 printf("\ttrack data:"); 1930 for (i = 0; i < finfo->fd_formb_nsecs; i++) { 1931 printf(" [c%d h%d s%d]", 1932 finfo->fd_formb_cylno(i), 1933 finfo->fd_formb_headno(i), 1934 finfo->fd_formb_secno(i) ); 1935 if (finfo->fd_formb_secsize(i) != 2) 1936 printf("<sz:%d>", finfo->fd_formb_secsize(i)); 1937 } 1938 printf("\n"); 1939 } 1940 #endif 1941 1942 /* now do the format */ 1943 fdstrategy(bp); 1944 1945 /* ...and wait for it to complete */ 1946 rv = biowait(bp); 1947 free(bp, M_TEMP, 0); 1948 return (rv); 1949 } 1950 1951 int 1952 fdgetdisklabel(dev_t dev, struct fd_softc *fd, struct disklabel *lp, 1953 int spoofonly) 1954 { 1955 bzero(lp, sizeof(struct disklabel)); 1956 1957 lp->d_type = DTYPE_FLOPPY; 1958 lp->d_secsize = FD_BSIZE(fd); 1959 lp->d_secpercyl = fd->sc_type->seccyl; 1960 lp->d_nsectors = fd->sc_type->sectrac; 1961 lp->d_ncylinders = fd->sc_type->tracks; 1962 lp->d_ntracks = fd->sc_type->heads; /* Go figure... */ 1963 DL_SETDSIZE(lp, (u_int64_t)lp->d_secpercyl * lp->d_ncylinders); 1964 1965 strncpy(lp->d_typename, "floppy disk", sizeof(lp->d_typename)); 1966 strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname)); 1967 lp->d_version = 1; 1968 1969 lp->d_magic = DISKMAGIC; 1970 lp->d_magic2 = DISKMAGIC; 1971 lp->d_checksum = dkcksum(lp); 1972 1973 /* 1974 * Call the generic disklabel extraction routine. If there's 1975 * not a label there, fake it. 1976 */ 1977 return readdisklabel(DISKLABELDEV(dev), fdstrategy, lp, spoofonly); 1978 } 1979 1980 void 1981 fd_do_eject(struct fd_softc *fd) 1982 { 1983 struct fdc_softc *fdc = (void *)fd->sc_dv.dv_parent; 1984 bus_space_tag_t t = fdc->sc_bustag; 1985 bus_space_handle_t h = fdc->sc_handle; 1986 u_int8_t dor = FDO_FRST | FDO_FDMAEN | FDO_MOEN(0); 1987 1988 bus_space_write_1(t, h, FDREG77_DOR, dor | FDO_EJ); 1989 delay(10); 1990 bus_space_write_1(t, h, FDREG77_DOR, FDO_FRST | FDO_DS); 1991 } 1992