1 /* $NetBSD: fd.c,v 1.89 2024/12/21 17:40:11 tsutsui Exp $ */ 2 3 /*- 4 * Copyright (c) 1990 The Regents of the University of California. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Don Ahn. 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. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * @(#)fd.c 7.4 (Berkeley) 5/25/91 35 */ 36 37 /*- 38 * Copyright (c) 1993, 1994, 1995 Charles M. Hannum. 39 * 40 * This code is derived from software contributed to Berkeley by 41 * Don Ahn. 42 * 43 * Redistribution and use in source and binary forms, with or without 44 * modification, are permitted provided that the following conditions 45 * are met: 46 * 1. Redistributions of source code must retain the above copyright 47 * notice, this list of conditions and the following disclaimer. 48 * 2. Redistributions in binary form must reproduce the above copyright 49 * notice, this list of conditions and the following disclaimer in the 50 * documentation and/or other materials provided with the distribution. 51 * 3. All advertising materials mentioning features or use of this software 52 * must display the following acknowledgement: 53 * This product includes software developed by the University of 54 * California, Berkeley and its contributors. 55 * 4. Neither the name of the University nor the names of its contributors 56 * may be used to endorse or promote products derived from this software 57 * without specific prior written permission. 58 * 59 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 60 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 61 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 62 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 63 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 64 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 65 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 66 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 67 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 68 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 69 * SUCH DAMAGE. 70 * 71 * @(#)fd.c 7.4 (Berkeley) 5/25/91 72 */ 73 74 #include <sys/cdefs.h> 75 __KERNEL_RCSID(0, "$NetBSD: fd.c,v 1.89 2024/12/21 17:40:11 tsutsui Exp $"); 76 77 #include "opt_ddb.h" 78 79 #include <sys/param.h> 80 #include <sys/systm.h> 81 #include <sys/callout.h> 82 #include <sys/kernel.h> 83 #include <sys/file.h> 84 #include <sys/ioctl.h> 85 #include <sys/device.h> 86 #include <sys/disklabel.h> 87 #include <sys/disk.h> 88 #include <sys/fdio.h> 89 #include <sys/buf.h> 90 #include <sys/bufq.h> 91 #include <sys/kmem.h> 92 #include <sys/proc.h> 93 #include <sys/uio.h> 94 #include <sys/stat.h> 95 #include <sys/syslog.h> 96 #include <sys/queue.h> 97 #include <sys/conf.h> 98 99 #include <dev/cons.h> 100 101 #include <uvm/uvm_extern.h> 102 103 #include <machine/cpu.h> 104 #include <machine/autoconf.h> 105 106 #include <sun3/dev/fdreg.h> 107 #include <sun3/dev/fdvar.h> 108 109 #include "ioconf.h" 110 111 /* 112 * Print a complaint when no fd children were specified 113 * in the config file. Better than a link error... 114 * 115 * XXX: Some folks say this driver should be split in two, 116 * but that seems pointless with ONLY one type of child. 117 * (Thankfully, no 3/80 boxes have floppy tapes!:) 118 */ 119 #include "fdc.h" 120 #if NFD == 0 121 #error "fdc but no fd?" 122 #endif 123 124 #define FDUNIT(dev) (minor(dev) / 8) 125 #define FDTYPE(dev) (minor(dev) % 8) 126 127 /* (mis)use device use flag to identify format operation */ 128 #define B_FORMAT B_DEVPRIVATE 129 130 #ifdef FD_DEBUG 131 int fdc_debug = 0; 132 #endif 133 134 enum fdc_state { 135 DEVIDLE = 0, 136 MOTORWAIT, 137 DOSEEK, 138 SEEKWAIT, 139 SEEKTIMEDOUT, 140 SEEKCOMPLETE, 141 DOIO, 142 IOCOMPLETE, 143 IOTIMEDOUT, 144 DORESET, 145 RESETCOMPLETE, 146 RESETTIMEDOUT, 147 DORECAL, 148 RECALWAIT, 149 RECALTIMEDOUT, 150 RECALCOMPLETE, 151 }; 152 153 /* software state, per controller */ 154 struct fdc_softc { 155 device_t sc_dev; /* boilerplate */ 156 void * sc_reg; 157 158 struct callout sc_timo_ch; /* timeout callout */ 159 struct callout sc_intr_ch; /* pseudo-intr callout */ 160 161 struct fd_softc *sc_fd[4]; /* pointers to children */ 162 TAILQ_HEAD(drivehead, fd_softc) sc_drives; 163 enum fdc_state sc_state; 164 int sc_flags; 165 #define FDC_82077 0x01 166 #define FDC_NEEDHEADSETTLE 0x02 167 #define FDC_EIS 0x04 168 int sc_errors; /* number of retries so far */ 169 int sc_overruns; /* number of DMA overruns */ 170 int sc_cfg; /* current configuration */ 171 int sc_fcr; /* current image of floppy ctrlr reg. */ 172 struct fdcio sc_io; 173 #define sc_reg_msr sc_io.fdcio_reg_msr 174 #define sc_reg_fifo sc_io.fdcio_reg_fifo 175 #define sc_reg_fcr sc_io.fdcio_reg_fcr 176 #define sc_reg_fvr sc_io.fdcio_reg_fvr 177 #define sc_reg_drs sc_io.fdcio_reg_msr 178 #define sc_istate sc_io.fdcio_istate 179 #define sc_data sc_io.fdcio_data 180 #define sc_tc sc_io.fdcio_tc 181 #define sc_nstat sc_io.fdcio_nstat 182 #define sc_status sc_io.fdcio_status 183 #define sc_intrcnt sc_io.fdcio_intrcnt 184 void *sc_si; /* softintr cookie */ 185 }; 186 187 /* controller driver configuration */ 188 static int fdcmatch(device_t, cfdata_t, void *); 189 static void fdcattach(device_t, device_t, void *); 190 191 CFATTACH_DECL_NEW(fdc, sizeof(struct fdc_softc), 192 fdcmatch, fdcattach, NULL, NULL); 193 194 static struct fd_type *fd_dev_to_type(struct fd_softc *, dev_t); 195 196 /* 197 * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how 198 * we tell them apart. 199 */ 200 struct fd_type { 201 int sectrac; /* sectors per track */ 202 int heads; /* number of heads */ 203 int seccyl; /* sectors per cylinder */ 204 int secsize; /* size code for sectors */ 205 int datalen; /* data len when secsize = 0 */ 206 int steprate; /* step rate and head unload time */ 207 int gap1; /* gap len between sectors */ 208 int gap2; /* formatting gap */ 209 int tracks; /* total num of tracks */ 210 int size; /* size of disk in sectors */ 211 int step; /* steps per cylinder */ 212 int rate; /* transfer speed code */ 213 int fillbyte; /* format fill byte */ 214 int interleave; /* interleave factor (formatting) */ 215 const char *name; 216 }; 217 218 /* The order of entries in the following table is important -- BEWARE! */ 219 static struct fd_type fd_types[] = { 220 { 18, 2, 36, 2, 0xff, 0xcf, 0x18, 0x50, 80, 2880, 1, 221 FDC_500KBPS, 0xf6, 1, "1.44MB" }, /* 1.44MB diskette */ 222 { 15, 2, 30, 2, 0xff, 0xdf, 0x1b, 0x54, 80, 2400, 1, 223 FDC_500KBPS, 0xf6, 1, "1.2MB" }, /* 1.2 MB AT-diskettes */ 224 { 9, 2, 18, 2, 0xff, 0xdf, 0x23, 0x50, 40, 720, 2, 225 FDC_300KBPS, 0xf6, 1, "360KB/AT" }, /* 360kB in 1.2MB drive */ 226 { 9, 2, 18, 2, 0xff, 0xdf, 0x2a, 0x50, 40, 720, 1, 227 FDC_250KBPS, 0xf6, 1, "360KB/PC" }, /* 360kB PC diskettes */ 228 { 9, 2, 18, 2, 0xff, 0xdf, 0x2a, 0x50, 80, 1440, 1, 229 FDC_250KBPS, 0xf6, 1, "720KB" }, /* 3.5" 720kB diskette */ 230 { 9, 2, 18, 2, 0xff, 0xdf, 0x23, 0x50, 80, 1440, 1, 231 FDC_300KBPS, 0xf6, 1, "720KB/x" }, /* 720kB in 1.2MB drive */ 232 { 9, 2, 18, 2, 0xff, 0xdf, 0x2a, 0x50, 40, 720, 2, 233 FDC_250KBPS,0xf6,1, "360KB/x" }, /* 360kB in 720kB drive */ 234 }; 235 236 /* software state, per disk (with up to 4 disks per ctlr) */ 237 struct fd_softc { 238 device_t sc_dv; /* generic device info */ 239 struct disk sc_dk; /* generic disk info */ 240 241 struct fd_type *sc_deftype; /* default type descriptor */ 242 struct fd_type *sc_type; /* current type descriptor */ 243 244 struct callout sc_motoron_ch; 245 struct callout sc_motoroff_ch; 246 247 daddr_t sc_blkno; /* starting block number */ 248 int sc_bcount; /* byte count left */ 249 int sc_skip; /* bytes already transferred */ 250 int sc_nblks; /* number of blocks currently transferring */ 251 int sc_nbytes; /* number of bytes currently transferring */ 252 253 int sc_drive; /* physical unit number */ 254 int sc_flags; 255 #define FD_OPEN 0x01 /* it's open */ 256 #define FD_MOTOR 0x02 /* motor should be on */ 257 #define FD_MOTOR_WAIT 0x04 /* motor coming up */ 258 int sc_cylin; /* where we think the head is */ 259 int sc_opts; /* user-set options */ 260 261 TAILQ_ENTRY(fd_softc) sc_drivechain; 262 int sc_ops; /* I/O ops since last switch */ 263 struct bufq_state *sc_q;/* pending I/O requests */ 264 int sc_active; /* number of active I/O operations */ 265 }; 266 267 /* floppy driver configuration */ 268 static int fdmatch(device_t, cfdata_t, void *); 269 static void fdattach(device_t, device_t, void *); 270 271 CFATTACH_DECL_NEW(fd, sizeof(struct fd_softc), 272 fdmatch, fdattach, NULL, NULL); 273 274 static dev_type_open(fdopen); 275 static dev_type_close(fdclose); 276 static dev_type_read(fdread); 277 static dev_type_write(fdwrite); 278 static dev_type_ioctl(fdioctl); 279 static dev_type_strategy(fdstrategy); 280 281 const struct bdevsw fd_bdevsw = { 282 .d_open = fdopen, 283 .d_close = fdclose, 284 .d_strategy = fdstrategy, 285 .d_ioctl = fdioctl, 286 .d_dump = nodump, 287 .d_psize = nosize, 288 .d_discard = nodiscard, 289 .d_flag = D_DISK 290 }; 291 292 const struct cdevsw fd_cdevsw = { 293 .d_open = fdopen, 294 .d_close = fdclose, 295 .d_read = fdread, 296 .d_write = fdwrite, 297 .d_ioctl = fdioctl, 298 .d_stop = nostop, 299 .d_tty = notty, 300 .d_poll = nopoll, 301 .d_mmap = nommap, 302 .d_kqfilter = nokqfilter, 303 .d_discard = nodiscard, 304 .d_flag = D_DISK 305 }; 306 307 static bool fd_shutdown(device_t, int); 308 static void fdgetdisklabel(dev_t); 309 static void fdstart(struct fd_softc *); 310 static int fdprint(void *, const char *); 311 312 struct dkdriver fddkdriver = { 313 .d_strategy = fdstrategy 314 }; 315 316 static void fd_set_motor(struct fdc_softc *); 317 static void fd_motor_off(void *); 318 static void fd_motor_on(void *); 319 static int fdcresult(struct fdc_softc *); 320 static int out_fdc(struct fdc_softc *, u_char); 321 static void fdcstart(struct fdc_softc *); 322 static void fdcstatus(device_t, int, const char *); 323 static void fdc_reset(struct fdc_softc *); 324 static void fdctimeout(void *); 325 static void fdcpseudointr(void *); 326 static int fdchwintr(void *); 327 static void fdcswintr(void *); 328 static int fdcstate(struct fdc_softc *); 329 static void fdcretry(struct fdc_softc *); 330 static void fdfinish(struct fd_softc *, struct buf *); 331 static int fdformat(dev_t, struct ne7_fd_formb *, struct proc *); 332 static void fd_do_eject(struct fdc_softc *, int); 333 static void fd_mountroot_hook(device_t); 334 static void fdconf(struct fdc_softc *); 335 336 #define IPL_SOFTFD IPL_BIO 337 #define FDC_SOFTPRI 2 338 #define FD_SET_SWINTR() softint_schedule(fdc->sc_si); 339 340 /* 341 * The Floppy Control Register on the sun3x, not to be confused with the 342 * Floppy ControllER Registers that this driver mostly insterfaces with, 343 * controls some of the auxiliary functions of the floppy drive. These 344 * include asserting the floppy eject and terminal data count (or TC) pins 345 * of the floppy drive and controller chip respectively. 346 * 347 * Often it is necessary to toggle individual bits within this register 348 * while keeping the others untouched. However, the register does not 349 * present its latched data to the processor when read. This prevents the 350 * use of a read-modify-write cycle that would normally be used to modify 351 * individual bits. To get around this we must keep a copy of register's 352 * current value and always insure that when we wish to modify the register, 353 * we actually modify the copy and synchronize the register to it. 354 */ 355 #define FCR_REG_SYNC() (*fdc->sc_reg_fcr = fdc->sc_fcr) 356 357 int 358 fdcmatch(device_t parent, cfdata_t cf, void *aux) 359 { 360 struct confargs *ca = aux; 361 362 if (bus_peek(ca->ca_bustype, ca->ca_paddr, sizeof(uint8_t)) == -1) 363 return 0; 364 365 return 1; 366 } 367 368 /* 369 * Arguments passed between fdcattach and fdprobe. 370 */ 371 struct fdc_attach_args { 372 int fa_drive; 373 struct bootpath *fa_bootpath; 374 struct fd_type *fa_deftype; 375 }; 376 377 /* 378 * Print the location of a disk drive (called just before attaching the 379 * the drive). If `fdc' is not NULL, the drive was found but was not 380 * in the system config file; print the drive name as well. 381 * Return QUIET (config_find ignores this if the device was configured) to 382 * avoid printing `fdN not configured' messages. 383 */ 384 int 385 fdprint(void *aux, const char *fdc) 386 { 387 struct fdc_attach_args *fa = aux; 388 389 if (fdc == NULL) 390 aprint_normal(" drive %d", fa->fa_drive); 391 return QUIET; 392 } 393 394 static void 395 fdconf(struct fdc_softc *fdc) 396 { 397 int vroom; 398 399 if (out_fdc(fdc, NE7CMD_DUMPREG) || fdcresult(fdc) != 10) 400 return; 401 402 /* 403 * dumpreg[7] seems to be a motor-off timeout; set it to whatever 404 * the PROM thinks is appropriate. 405 */ 406 if ((vroom = fdc->sc_status[7]) == 0) 407 vroom = 0x64; 408 409 /* Configure controller to use FIFO and Implied Seek */ 410 out_fdc(fdc, NE7CMD_CFG); 411 out_fdc(fdc, vroom); 412 out_fdc(fdc, fdc->sc_cfg); 413 out_fdc(fdc, 0); /* PRETRK */ 414 /* No result phase */ 415 } 416 417 void 418 fdcattach(device_t parent, device_t self, void *aux) 419 { 420 struct confargs *ca = aux; 421 struct fdc_softc *fdc = device_private(self); 422 struct fdc_attach_args fa; 423 int pri, vec; 424 char code; 425 426 fdc->sc_dev = self; 427 428 fdc->sc_reg = (void *)bus_mapin(ca->ca_bustype, ca->ca_paddr, 429 sizeof(union fdreg)); 430 431 callout_init(&fdc->sc_timo_ch, 0); 432 callout_init(&fdc->sc_intr_ch, 0); 433 434 fdc->sc_state = DEVIDLE; 435 fdc->sc_istate = ISTATE_IDLE; 436 fdc->sc_flags |= FDC_EIS; 437 TAILQ_INIT(&fdc->sc_drives); 438 439 /* Assume a 82072 */ 440 code = '2'; 441 442 if (code == '7') { 443 panic("no 82077 fdc in this kernel"); 444 /* NOTREACHED */ 445 } else { 446 fdc->sc_reg_msr = &((struct fdreg_72 *)fdc->sc_reg)->fd_msr; 447 fdc->sc_reg_fifo = &((struct fdreg_72 *)fdc->sc_reg)->fd_fifo; 448 449 fdc->sc_reg_fcr = ((volatile uint8_t *)fdc->sc_reg) 450 + FDC_FCR_OFFSET; 451 fdc->sc_reg_fvr = ((volatile uint8_t *)fdc->sc_reg) 452 + FDC_FVR_OFFSET; 453 } 454 455 pri = ca->ca_intpri; 456 vec = ca->ca_intvec; 457 if (vec == -1) { 458 /* Tell the FDC to fake an autovector. */ 459 vec = 0x18 + pri; /* XXX */ 460 isr_add_autovect(fdchwintr, fdc, pri); 461 } else { 462 /* An OBIO bus with vectors? Weird exception. */ 463 isr_add_vectored(fdchwintr, fdc, pri, vec); 464 } 465 *fdc->sc_reg_fvr = vec; /* Program controller w/ interrupt vector */ 466 467 fdc->sc_si = softint_establish(SOFTINT_BIO, fdcswintr, fdc); 468 #if 0 469 aprint_normal(": (softpri %d) chip 8207%c\n", FDC_SOFTPRI, code); 470 #else 471 aprint_normal(": chip 8207%c\n", code); 472 #endif 473 474 #ifdef FD_DEBUG 475 if (out_fdc(fdc, NE7CMD_VERSION) == 0 && 476 fdcresult(fdc) == 1 && fdc->sc_status[0] == 0x90) { 477 if (fdc_debug) 478 aprint_debug("[version cmd]"); 479 } 480 #endif 481 482 fdc_reset(fdc); 483 /* 484 * Configure controller; enable FIFO, Implied seek, no POLL mode?. 485 * Note: CFG_EFIFO is active-low, initial threshold value: 8 486 */ 487 fdc->sc_cfg = CFG_EIS|/*CFG_EFIFO|*/CFG_POLL|(8 & CFG_THRHLD_MASK); 488 fdconf(fdc); 489 490 evcnt_attach_dynamic(&fdc->sc_intrcnt, EVCNT_TYPE_INTR, NULL, 491 device_xname(self), "intr"); 492 493 /* physical limit: four drives per controller. */ 494 for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) { 495 fa.fa_deftype = NULL; /* unknown */ 496 fa.fa_deftype = &fd_types[0]; /* XXX */ 497 (void)config_found(self, (void *)&fa, fdprint, CFARGS_NONE); 498 } 499 } 500 501 int 502 fdmatch(device_t parent, cfdata_t cf, void *aux) 503 { 504 struct fdc_softc *fdc = device_private(parent); 505 struct fdc_attach_args *fa = aux; 506 int drive = fa->fa_drive; 507 int n, ok; 508 509 if (drive > 0) 510 /* XXX - for now, punt > 1 drives */ 511 return 0; 512 513 /* select drive and turn on motor */ 514 fdc->sc_fcr |= FCR_DSEL(drive) | FCR_MTRON; 515 FCR_REG_SYNC(); 516 /* wait for motor to spin up */ 517 delay(250000); 518 519 fdc->sc_nstat = 0; 520 out_fdc(fdc, NE7CMD_RECAL); 521 out_fdc(fdc, drive); 522 /* wait for recalibrate */ 523 for (n = 0; n < 10000; n++) { 524 delay(1000); 525 if ((*fdc->sc_reg_msr & (NE7_RQM|NE7_DIO|NE7_CB)) == NE7_RQM) { 526 /* wait a bit longer till device *really* is ready */ 527 delay(100000); 528 if (out_fdc(fdc, NE7CMD_SENSEI)) 529 break; 530 if (fdcresult(fdc) == 1 && fdc->sc_status[0] == 0x80) 531 /* 532 * Got `invalid command'; we interpret it 533 * to mean that the re-calibrate hasn't in 534 * fact finished yet 535 */ 536 continue; 537 break; 538 } 539 } 540 n = fdc->sc_nstat; 541 #ifdef FD_DEBUG 542 if (fdc_debug) { 543 int i; 544 aprint_debug("%s: %d stati:", __func__, n); 545 for (i = 0; i < n; i++) 546 aprint_debug(" %x", fdc->sc_status[i]); 547 aprint_debug("\n"); 548 } 549 #endif 550 ok = (n == 2 && (fdc->sc_status[0] & 0xf8) == 0x20) ? 1 : 0; 551 552 /* turn off motor */ 553 fdc->sc_fcr &= ~(FCR_DSEL(drive)|FCR_MTRON); 554 FCR_REG_SYNC(); 555 556 return ok; 557 } 558 559 /* 560 * Controller is working, and drive responded. Attach it. 561 */ 562 void 563 fdattach(device_t parent, device_t self, void *aux) 564 { 565 struct fdc_softc *fdc = device_private(parent); 566 struct fd_softc *fd = device_private(self); 567 struct fdc_attach_args *fa = aux; 568 struct fd_type *type = fa->fa_deftype; 569 int drive = fa->fa_drive; 570 571 fd->sc_dv = self; 572 573 callout_init(&fd->sc_motoron_ch, 0); 574 callout_init(&fd->sc_motoroff_ch, 0); 575 576 /* XXX Allow `flags' to override device type? */ 577 578 if (type) 579 aprint_normal(": %s %d cyl, %d head, %d sec\n", type->name, 580 type->tracks, type->heads, type->sectrac); 581 else 582 aprint_normal(": density unknown\n"); 583 584 bufq_alloc(&fd->sc_q, "disksort", BUFQ_SORT_CYLINDER); 585 fd->sc_cylin = -1; 586 fd->sc_drive = drive; 587 fd->sc_deftype = type; 588 fdc->sc_fd[drive] = fd; 589 590 /* 591 * Initialize and attach the disk structure. 592 */ 593 disk_init(&fd->sc_dk, device_xname(self), &fddkdriver); 594 disk_attach(&fd->sc_dk); 595 596 #ifdef sparc 597 /* 598 * We're told if we're the boot device in fdcattach(). 599 */ 600 if (fa->fa_bootpath) 601 fa->fa_bootpath->dev = self; 602 #endif 603 #define OUT_FDC(sc, c) do { \ 604 if (out_fdc((sc), (c)) != 0) \ 605 printf("fdc: specify command failed.\n"); \ 606 } while (/* CONSTCOND */ 0) 607 608 /* specify command */ 609 OUT_FDC(fdc, NE7CMD_SPECIFY); 610 OUT_FDC(fdc, type->steprate); 611 /* 612 * The '|1' in the following statement turns on the 'Non-DMA' bit 613 * specifier in the last byte of the SPECIFY command as described in the 614 * datasheet I have. This is necessary for the driver to work on the 615 * sun3x, because the system will not respond to the chip's requests 616 * for DMA; there is no hardware on the motherboard to support it. 617 * By enabling this bit, we will force the chip to interrupt when its 618 * FIFO is full, at which point the interrupt handler will empty it and 619 * continue. This is ``pseudo-DMA''. 620 * -J 621 */ 622 OUT_FDC(fdc, 6|1); /* XXX head load time == 6ms */ 623 #undef OUT_FDC 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, self); 630 631 /* Make sure the drive motor gets turned off at shutdown time. */ 632 if (!pmf_device_register1(self, NULL, NULL, fd_shutdown)) 633 aprint_error_dev(self, "couldn't establish power handler\n"); 634 } 635 636 bool 637 fd_shutdown(device_t self, int howto) 638 { 639 struct fd_softc *fd; 640 641 fd = device_private(self); 642 fd_motor_off(fd); 643 644 return true; 645 } 646 647 static struct fd_type * 648 fd_dev_to_type(struct fd_softc *fd, dev_t dev) 649 { 650 int type = FDTYPE(dev); 651 652 if (type > (sizeof(fd_types) / sizeof(fd_types[0]))) 653 return NULL; 654 return type ? &fd_types[type - 1] : fd->sc_deftype; 655 } 656 657 static void 658 fdstrategy(struct buf *bp) 659 { 660 struct fd_softc *fd; 661 int unit = FDUNIT(bp->b_dev); 662 int sz; 663 int s; 664 665 /* Valid unit, controller, and request? */ 666 if ((fd = device_lookup_private(&fd_cd, unit)) == 0 || 667 bp->b_blkno < 0 || 668 ((bp->b_bcount % FDC_BSIZE) != 0 && 669 (bp->b_flags & B_FORMAT) == 0)) { 670 bp->b_error = EINVAL; 671 goto done; 672 } 673 674 /* If it's a null transfer, return immediately. */ 675 if (bp->b_bcount == 0) 676 goto done; 677 678 sz = howmany(bp->b_bcount, FDC_BSIZE); 679 680 if (bp->b_blkno + sz > fd->sc_type->size) { 681 sz = fd->sc_type->size - bp->b_blkno; 682 if (sz == 0) { 683 /* If exactly at end of disk, return EOF. */ 684 bp->b_resid = bp->b_bcount; 685 goto done; 686 } 687 if (sz < 0) { 688 /* If past end of disk, return EINVAL. */ 689 bp->b_error = EINVAL; 690 goto done; 691 } 692 /* Otherwise, truncate request. */ 693 bp->b_bcount = sz << DEV_BSHIFT; 694 } 695 696 bp->b_rawblkno = bp->b_blkno; 697 bp->b_cylinder = 698 bp->b_blkno / (FDC_BSIZE / DEV_BSIZE) / fd->sc_type->seccyl; 699 700 #ifdef FD_DEBUG 701 if (fdc_debug > 1) 702 printf("%s: b_blkno %d b_bcount %d blkno %d cylin %d\n", 703 __func__, (int)bp->b_blkno, bp->b_bcount, 704 (int)fd->sc_blkno, bp->b_cylinder); 705 #endif 706 707 /* Queue transfer on drive, activate drive and controller if idle. */ 708 s = splbio(); 709 bufq_put(fd->sc_q, bp); 710 callout_stop(&fd->sc_motoroff_ch); /* a good idea */ 711 if (fd->sc_active == 0) 712 fdstart(fd); 713 #ifdef DIAGNOSTIC 714 else { 715 struct fdc_softc *fdc; 716 717 fdc = device_private(device_parent(fd->sc_dv)); 718 if (fdc->sc_state == DEVIDLE) { 719 printf("%s: controller inactive\n", __func__); 720 fdcstart(fdc); 721 } 722 } 723 #endif 724 splx(s); 725 return; 726 727 done: 728 /* Toss transfer; we're done early. */ 729 biodone(bp); 730 } 731 732 void 733 fdstart(struct fd_softc *fd) 734 { 735 struct fdc_softc *fdc = device_private(device_parent(fd->sc_dv)); 736 bool active = fdc->sc_drives.tqh_first != 0; 737 738 /* Link into controller queue. */ 739 fd->sc_active = 1; 740 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain); 741 742 /* If controller not already active, start it. */ 743 if (!active) 744 fdcstart(fdc); 745 } 746 747 void 748 fdfinish(struct fd_softc *fd, struct buf *bp) 749 { 750 struct fdc_softc *fdc = device_private(device_parent(fd->sc_dv)); 751 752 /* 753 * Move this drive to the end of the queue to give others a `fair' 754 * chance. We only force a switch if N operations are completed while 755 * another drive is waiting to be serviced, since there is a long motor 756 * startup delay whenever we switch. 757 */ 758 (void)bufq_get(fd->sc_q); 759 if (TAILQ_NEXT(fd, sc_drivechain) && ++fd->sc_ops >= 8) { 760 fd->sc_ops = 0; 761 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain); 762 if (bufq_peek(fd->sc_q) != NULL) { 763 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain); 764 } else 765 fd->sc_active = 0; 766 } 767 bp->b_resid = fd->sc_bcount; 768 fd->sc_skip = 0; 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 void 777 fdc_reset(struct fdc_softc *fdc) 778 { 779 780 fdc->sc_fcr = 0; 781 FCR_REG_SYNC(); 782 783 *fdc->sc_reg_drs = DRS_RESET; 784 delay(10); 785 *fdc->sc_reg_drs = 0; 786 787 #ifdef FD_DEBUG 788 if (fdc_debug) 789 printf("fdc reset\n"); 790 #endif 791 } 792 793 void 794 fd_set_motor(struct fdc_softc *fdc) 795 { 796 struct fd_softc *fd; 797 int n; 798 799 int on = 0; 800 801 for (n = 0; n < 4; n++) 802 if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR)) 803 on = 1; 804 if (on) { 805 fdc->sc_fcr |= FCR_DSEL(0)|FCR_MTRON; /* XXX */ 806 } else { 807 fdc->sc_fcr &= ~(FCR_DSEL(0)|FCR_MTRON); /* XXX */ 808 } 809 FCR_REG_SYNC(); 810 } 811 812 void 813 fd_motor_off(void *arg) 814 { 815 struct fd_softc *fd = arg; 816 int s; 817 818 s = splbio(); 819 fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT); 820 fd_set_motor(device_private(device_parent(fd->sc_dv))); 821 splx(s); 822 } 823 824 void 825 fd_motor_on(void *arg) 826 { 827 struct fd_softc *fd = arg; 828 struct fdc_softc *fdc = device_private(device_parent(fd->sc_dv)); 829 int s; 830 831 s = splbio(); 832 fd->sc_flags &= ~FD_MOTOR_WAIT; 833 if ((TAILQ_FIRST(&fdc->sc_drives) == fd) && 834 (fdc->sc_state == MOTORWAIT)) 835 (void)fdcstate(fdc); 836 splx(s); 837 } 838 839 int 840 fdcresult(struct fdc_softc *fdc) 841 { 842 uint8_t i; 843 int j, n = 0; 844 845 for (j = 100000; j; j--) { 846 i = *fdc->sc_reg_msr & (NE7_DIO | NE7_RQM | NE7_CB); 847 if (i == NE7_RQM) { 848 fdc->sc_nstat = n; 849 return n; 850 } 851 if (i == (NE7_DIO | NE7_RQM | NE7_CB)) { 852 if (n >= sizeof(fdc->sc_status)) { 853 log(LOG_ERR, "fdcresult: overrun\n"); 854 return -1; 855 } 856 fdc->sc_status[n++] = *fdc->sc_reg_fifo; 857 } else 858 delay(10); 859 } 860 log(LOG_ERR, "fdcresult: timeout\n"); 861 fdc->sc_nstat = -1; 862 return -1; 863 } 864 865 int 866 out_fdc(struct fdc_softc *fdc, u_char x) 867 { 868 int i = 100000; 869 870 while (((*fdc->sc_reg_msr & (NE7_DIO|NE7_RQM)) != NE7_RQM) && i-- > 0) 871 delay(1); 872 if (i <= 0) 873 return -1; 874 875 *fdc->sc_reg_fifo = x; 876 return 0; 877 } 878 879 static int 880 fdopen(dev_t dev, int flags, int fmt, struct lwp *l) 881 { 882 int unit, pmask; 883 struct fd_softc *fd; 884 struct fd_type *type; 885 886 unit = FDUNIT(dev); 887 fd = device_lookup_private(&fd_cd, unit); 888 if (fd == NULL) 889 return ENXIO; 890 type = fd_dev_to_type(fd, dev); 891 if (type == NULL) 892 return ENXIO; 893 894 if ((fd->sc_flags & FD_OPEN) != 0 && 895 fd->sc_type != type) 896 return EBUSY; 897 898 fd->sc_type = type; 899 fd->sc_cylin = -1; 900 fd->sc_flags |= FD_OPEN; 901 902 /* 903 * Only update the disklabel if we're not open anywhere else. 904 */ 905 if (fd->sc_dk.dk_openmask == 0) 906 fdgetdisklabel(dev); 907 908 pmask = (1 << DISKPART(dev)); 909 910 switch (fmt) { 911 case S_IFCHR: 912 fd->sc_dk.dk_copenmask |= pmask; 913 break; 914 915 case S_IFBLK: 916 fd->sc_dk.dk_bopenmask |= pmask; 917 break; 918 } 919 fd->sc_dk.dk_openmask = 920 fd->sc_dk.dk_copenmask | fd->sc_dk.dk_bopenmask; 921 922 return 0; 923 } 924 925 static int 926 fdclose(dev_t dev, int flags, int fmt, struct lwp *l) 927 { 928 struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(dev)); 929 int pmask = (1 << DISKPART(dev)); 930 931 fd->sc_flags &= ~FD_OPEN; 932 fd->sc_opts &= ~(FDOPT_NORETRY|FDOPT_SILENT); 933 934 switch (fmt) { 935 case S_IFCHR: 936 fd->sc_dk.dk_copenmask &= ~pmask; 937 break; 938 939 case S_IFBLK: 940 fd->sc_dk.dk_bopenmask &= ~pmask; 941 break; 942 } 943 fd->sc_dk.dk_openmask = 944 fd->sc_dk.dk_copenmask | fd->sc_dk.dk_bopenmask; 945 946 return 0; 947 } 948 949 static int 950 fdread(dev_t dev, struct uio *uio, int flag) 951 { 952 953 return physio(fdstrategy, NULL, dev, B_READ, minphys, uio); 954 } 955 956 static int 957 fdwrite(dev_t dev, struct uio *uio, int flag) 958 { 959 960 return physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio); 961 } 962 963 void 964 fdcstart(struct fdc_softc *fdc) 965 { 966 967 #ifdef DIAGNOSTIC 968 /* only got here if controller's drive queue was inactive; should 969 be in idle state */ 970 if (fdc->sc_state != DEVIDLE) { 971 printf("%s: not idle\n", __func__); 972 return; 973 } 974 #endif 975 (void)fdcstate(fdc); 976 } 977 978 static void 979 fdcpstatus(int n, struct fdc_softc *fdc) 980 { 981 char bits[64]; 982 983 switch (n) { 984 case 0: 985 printf("\n"); 986 break; 987 case 2: 988 snprintb(bits, sizeof(bits), NE7_ST0BITS, fdc->sc_status[0]); 989 printf(" (st0 %s cyl %d)\n", bits, fdc->sc_status[1]); 990 break; 991 case 7: 992 snprintb(bits, sizeof(bits), NE7_ST0BITS, fdc->sc_status[0]); 993 printf(" (st0 %s", bits); 994 snprintb(bits, sizeof(bits), NE7_ST1BITS, fdc->sc_status[1]); 995 printf(" st1 %s", bits); 996 snprintb(bits, sizeof(bits), NE7_ST2BITS, fdc->sc_status[2]); 997 printf(" st2 %s", bits); 998 printf(" cyl %d head %d sec %d)\n", 999 fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]); 1000 break; 1001 #ifdef DIAGNOSTIC 1002 default: 1003 printf("\nfdcstatus: weird size"); 1004 break; 1005 #endif 1006 } 1007 } 1008 1009 void 1010 fdcstatus(device_t dv, int n, const char *s) 1011 { 1012 struct fdc_softc *fdc = device_private(device_parent(dv)); 1013 #if 0 1014 /* 1015 * A 82072 seems to return <invalid command> on 1016 * gratuitous Sense Interrupt commands. 1017 */ 1018 if (n == 0 && (fdc->sc_flags & FDC_82077)) { 1019 out_fdc(fdc, NE7CMD_SENSEI); 1020 (void)fdcresult(fdc); 1021 n = 2; 1022 } 1023 #endif 1024 1025 /* Just print last status */ 1026 n = fdc->sc_nstat; 1027 1028 printf("%s: %s: state %d", device_xname(dv), s, fdc->sc_state); 1029 1030 fdcpstatus(n, fdc); 1031 } 1032 1033 void 1034 fdctimeout(void *arg) 1035 { 1036 struct fdc_softc *fdc = arg; 1037 struct fd_softc *fd = TAILQ_FIRST(&fdc->sc_drives); 1038 int s; 1039 1040 s = splbio(); 1041 fdcstatus(fd->sc_dv, 0, "timeout"); 1042 1043 if (bufq_peek(fd->sc_q) != NULL) 1044 fdc->sc_state++; 1045 else 1046 fdc->sc_state = DEVIDLE; 1047 1048 (void)fdcstate(fdc); 1049 splx(s); 1050 } 1051 1052 void 1053 fdcpseudointr(void *arg) 1054 { 1055 struct fdc_softc *fdc = arg; 1056 int s; 1057 1058 /* Just ensure it has the right spl. */ 1059 s = splbio(); 1060 (void)fdcstate(fdc); 1061 splx(s); 1062 } 1063 1064 1065 /* 1066 * hardware interrupt entry point: must be converted to `fast' 1067 * (in-window) handler. 1068 */ 1069 int 1070 fdchwintr(void *arg) 1071 { 1072 struct fdc_softc *fdc = arg; 1073 1074 /* 1075 * This code was reverse engineered from the SPARC bsd_fdintr.s. 1076 */ 1077 switch (fdc->sc_istate) { 1078 case ISTATE_IDLE: 1079 return 0; 1080 case ISTATE_SENSEI: 1081 out_fdc(fdc, NE7CMD_SENSEI); 1082 fdcresult(fdc); 1083 fdc->sc_istate = ISTATE_DONE; 1084 FD_SET_SWINTR(); 1085 return 1; 1086 case ISTATE_DMA: 1087 break; 1088 default: 1089 log(LOG_ERR, "fdc: stray hard interrupt.\n"); 1090 fdc->sc_fcr &= ~(FCR_DSEL(0)); /* Does this help? */ 1091 fdc->sc_istate = ISTATE_SPURIOUS; 1092 FD_SET_SWINTR(); 1093 return 1; 1094 } 1095 1096 for (;;) { 1097 int msr; 1098 1099 msr = *fdc->sc_reg_msr; 1100 1101 if ((msr & NE7_RQM) == 0) 1102 break; 1103 1104 if ((msr & NE7_NDM) == 0) { 1105 /* Execution phase finished, get result. */ 1106 fdcresult(fdc); 1107 fdc->sc_istate = ISTATE_DONE; 1108 FD_SET_SWINTR(); 1109 #ifdef FD_DEBUG 1110 if (fdc_debug) 1111 log(LOG_ERR, "fdc: overrun: tc = %d\n", 1112 fdc->sc_tc); 1113 #endif 1114 break; 1115 } 1116 1117 if (msr & NE7_DIO) { 1118 *fdc->sc_data++ = *fdc->sc_reg_fifo; 1119 } else { 1120 *fdc->sc_reg_fifo = *fdc->sc_data++; 1121 } 1122 if (--fdc->sc_tc == 0) { 1123 fdc->sc_fcr |= FCR_TC; 1124 FCR_REG_SYNC(); 1125 delay(10); 1126 fdc->sc_fcr &= ~FCR_TC; 1127 FCR_REG_SYNC(); 1128 break; 1129 } 1130 } 1131 return 1; 1132 } 1133 1134 void 1135 fdcswintr(void *arg) 1136 { 1137 struct fdc_softc *fdc = arg; 1138 int s; 1139 1140 if (fdc->sc_istate != ISTATE_DONE) 1141 return; 1142 1143 fdc->sc_istate = ISTATE_IDLE; 1144 s = splbio(); 1145 fdcstate(fdc); 1146 splx(s); 1147 } 1148 1149 int 1150 fdcstate(struct fdc_softc *fdc) 1151 { 1152 #define st0 fdc->sc_status[0] 1153 #define st1 fdc->sc_status[1] 1154 #define cyl fdc->sc_status[1] 1155 #define OUT_FDC(fdc, c, s) \ 1156 do { \ 1157 if (out_fdc(fdc, (c))) { \ 1158 (fdc)->sc_state = (s); \ 1159 goto loop; \ 1160 } \ 1161 } while (/* CONSTCOND */ 0) 1162 1163 struct fd_softc *fd; 1164 struct buf *bp; 1165 int read, head, sec, nblks; 1166 struct fd_type *type; 1167 struct ne7_fd_formb *finfo = NULL; 1168 1169 1170 if (fdc->sc_istate != ISTATE_IDLE) { 1171 /* Trouble... */ 1172 printf("fdc: spurious interrupt: state %d, istate=%d\n", 1173 fdc->sc_state, fdc->sc_istate); 1174 fdc->sc_istate = ISTATE_IDLE; 1175 if (fdc->sc_state == RESETCOMPLETE || 1176 fdc->sc_state == RESETTIMEDOUT) { 1177 panic("%s: spurious interrupt can't be cleared", 1178 __func__); 1179 } 1180 goto doreset; 1181 } 1182 1183 loop: 1184 /* Is there a drive for the controller to do a transfer with? */ 1185 fd = TAILQ_FIRST(&fdc->sc_drives); 1186 if (fd == NULL) { 1187 fdc->sc_state = DEVIDLE; 1188 return 0; 1189 } 1190 1191 /* Is there a transfer to this drive? If not, deactivate drive. */ 1192 bp = bufq_peek(fd->sc_q); 1193 if (bp == NULL) { 1194 fd->sc_ops = 0; 1195 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain); 1196 fd->sc_active = 0; 1197 goto loop; 1198 } 1199 1200 if (bp->b_flags & B_FORMAT) 1201 finfo = (struct ne7_fd_formb *)bp->b_data; 1202 1203 switch (fdc->sc_state) { 1204 case DEVIDLE: 1205 fdc->sc_errors = 0; 1206 fd->sc_skip = 0; 1207 fd->sc_bcount = bp->b_bcount; 1208 fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE); 1209 callout_stop(&fd->sc_motoroff_ch); 1210 if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) { 1211 fdc->sc_state = MOTORWAIT; 1212 return 1; 1213 } 1214 if ((fd->sc_flags & FD_MOTOR) == 0) { 1215 /* Turn on the motor, being careful about pairing. */ 1216 struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1]; 1217 if (ofd && ofd->sc_flags & FD_MOTOR) { 1218 callout_stop(&ofd->sc_motoroff_ch); 1219 ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT); 1220 } 1221 fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT; 1222 fd_set_motor(fdc); 1223 fdc->sc_state = MOTORWAIT; 1224 if (fdc->sc_flags & FDC_82077) { /* XXX */ 1225 /* Allow .25s for motor to stabilize. */ 1226 callout_reset(&fd->sc_motoron_ch, hz / 4, 1227 fd_motor_on, fd); 1228 } else { 1229 fd->sc_flags &= ~FD_MOTOR_WAIT; 1230 goto loop; 1231 } 1232 return 1; 1233 } 1234 /* Make sure the right drive is selected. */ 1235 fd_set_motor(fdc); 1236 1237 /*FALLTHROUGH*/ 1238 case DOSEEK: 1239 doseek: 1240 if ((fdc->sc_flags & FDC_EIS) && 1241 (bp->b_flags & B_FORMAT) == 0) { 1242 fd->sc_cylin = bp->b_cylinder; 1243 /* We use implied seek */ 1244 goto doio; 1245 } 1246 1247 if (fd->sc_cylin == bp->b_cylinder) 1248 goto doio; 1249 1250 /* specify command */ 1251 OUT_FDC(fdc, NE7CMD_SPECIFY, SEEKTIMEDOUT); 1252 OUT_FDC(fdc, fd->sc_type->steprate, SEEKTIMEDOUT); 1253 OUT_FDC(fdc, 6|1, SEEKTIMEDOUT); /* XXX head load time == 6ms */ 1254 1255 fdc->sc_istate = ISTATE_SENSEI; 1256 /* seek function */ 1257 OUT_FDC(fdc, NE7CMD_SEEK, SEEKTIMEDOUT); 1258 OUT_FDC(fdc, fd->sc_drive, SEEKTIMEDOUT); /* drive number */ 1259 OUT_FDC(fdc, bp->b_cylinder * fd->sc_type->step, SEEKTIMEDOUT); 1260 1261 fd->sc_cylin = -1; 1262 fdc->sc_state = SEEKWAIT; 1263 fdc->sc_nstat = 0; 1264 1265 iostat_seek(fd->sc_dk.dk_stats); 1266 disk_busy(&fd->sc_dk); 1267 1268 callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc); 1269 return 1; 1270 1271 case DOIO: 1272 doio: 1273 #ifdef NOTYET 1274 /* Check to see if the disk has changed */ 1275 if (fdc->sc_reg_dir & FDI_DCHG) { 1276 /* 1277 * The disk in the drive has changed since 1278 * the last transfer. We need to see if its geometry 1279 * has changed. 1280 */ 1281 } 1282 #endif /* NOTYET */ 1283 1284 if (finfo) 1285 fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) - 1286 (char *)finfo; 1287 type = fd->sc_type; 1288 sec = fd->sc_blkno % type->seccyl; 1289 nblks = type->seccyl - sec; 1290 nblks = uimin(nblks, fd->sc_bcount / FDC_BSIZE); 1291 nblks = uimin(nblks, FDC_MAXIOSIZE / FDC_BSIZE); 1292 fd->sc_nblks = nblks; 1293 fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FDC_BSIZE; 1294 head = sec / type->sectrac; 1295 sec -= head * type->sectrac; 1296 #ifdef DIAGNOSTIC 1297 { 1298 int block; 1299 1300 block = (fd->sc_cylin * type->heads + head) * 1301 type->sectrac + sec; 1302 if (block != fd->sc_blkno) { 1303 printf("%s: block %d != blkno %" PRIu64 "\n", 1304 device_xname(fdc->sc_dev), block, 1305 fd->sc_blkno); 1306 #ifdef DDB 1307 Debugger(); 1308 #endif 1309 } 1310 } 1311 #endif 1312 read = bp->b_flags & B_READ; 1313 1314 /* Setup for pseudo DMA */ 1315 fdc->sc_data = (char *)bp->b_data + fd->sc_skip; 1316 fdc->sc_tc = fd->sc_nbytes; 1317 1318 *fdc->sc_reg_drs = type->rate; 1319 #ifdef FD_DEBUG 1320 if (fdc_debug > 1) 1321 printf("%s: %s drive %d track %d head %d sec %d " 1322 "nblks %d\n", __func__, 1323 read ? "read" : "write", fd->sc_drive, 1324 fd->sc_cylin, head, sec, nblks); 1325 #endif 1326 fdc->sc_state = IOCOMPLETE; 1327 fdc->sc_istate = ISTATE_DMA; 1328 fdc->sc_nstat = 0; 1329 if (finfo) { 1330 /* formatting */ 1331 OUT_FDC(fdc, NE7CMD_FORMAT, IOTIMEDOUT); 1332 OUT_FDC(fdc, (head << 2) | fd->sc_drive, IOTIMEDOUT); 1333 OUT_FDC(fdc, finfo->fd_formb_secshift, IOTIMEDOUT); 1334 OUT_FDC(fdc, finfo->fd_formb_nsecs, IOTIMEDOUT); 1335 OUT_FDC(fdc, finfo->fd_formb_gaplen, IOTIMEDOUT); 1336 OUT_FDC(fdc, finfo->fd_formb_fillbyte, IOTIMEDOUT); 1337 } else { 1338 if (read) 1339 OUT_FDC(fdc, NE7CMD_READ, IOTIMEDOUT); 1340 else 1341 OUT_FDC(fdc, NE7CMD_WRITE, IOTIMEDOUT); 1342 OUT_FDC(fdc, (head << 2) | fd->sc_drive, IOTIMEDOUT); 1343 OUT_FDC(fdc, fd->sc_cylin, IOTIMEDOUT); /*track*/ 1344 OUT_FDC(fdc, head, IOTIMEDOUT); 1345 OUT_FDC(fdc, sec + 1, IOTIMEDOUT); /*sector+1*/ 1346 OUT_FDC(fdc, type->secsize, IOTIMEDOUT);/*sector size*/ 1347 OUT_FDC(fdc, type->sectrac, IOTIMEDOUT);/*secs/track*/ 1348 OUT_FDC(fdc, type->gap1, IOTIMEDOUT); /*gap1 size*/ 1349 OUT_FDC(fdc, type->datalen, IOTIMEDOUT);/*data length*/ 1350 } 1351 1352 disk_busy(&fd->sc_dk); 1353 1354 /* allow 2 seconds for operation */ 1355 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc); 1356 return 1; /* will return later */ 1357 1358 case SEEKWAIT: 1359 callout_stop(&fdc->sc_timo_ch); 1360 fdc->sc_state = SEEKCOMPLETE; 1361 if (fdc->sc_flags & FDC_NEEDHEADSETTLE) { 1362 /* allow 1/50 second for heads to settle */ 1363 callout_reset(&fdc->sc_intr_ch, hz / 50, 1364 fdcpseudointr, fdc); 1365 return 1; /* will return later */ 1366 } 1367 /*FALLTHROUGH*/ 1368 case SEEKCOMPLETE: 1369 /* no data on seek */ 1370 disk_unbusy(&fd->sc_dk, 0, 0); 1371 1372 /* Make sure seek really happened. */ 1373 if (fdc->sc_nstat != 2 || (st0 & 0xf8) != 0x20 || 1374 cyl != bp->b_cylinder * fd->sc_type->step) { 1375 #ifdef FD_DEBUG 1376 if (fdc_debug) 1377 fdcstatus(fd->sc_dv, 2, "seek failed"); 1378 #endif 1379 fdcretry(fdc); 1380 goto loop; 1381 } 1382 fd->sc_cylin = bp->b_cylinder; 1383 goto doio; 1384 1385 case IOTIMEDOUT: 1386 fdc->sc_fcr |= FCR_TC; 1387 FCR_REG_SYNC(); 1388 delay(10); 1389 fdc->sc_fcr &= ~FCR_TC; 1390 FCR_REG_SYNC(); 1391 (void)fdcresult(fdc); 1392 /* FALLTHROUGH */ 1393 case SEEKTIMEDOUT: 1394 case RECALTIMEDOUT: 1395 case RESETTIMEDOUT: 1396 fdcretry(fdc); 1397 goto loop; 1398 1399 case IOCOMPLETE: /* IO DONE, post-analyze */ 1400 callout_stop(&fdc->sc_timo_ch); 1401 1402 disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid), 1403 (bp->b_flags & B_READ)); 1404 1405 if (fdc->sc_nstat != 7 || (st0 & 0xf8) != 0 || st1 != 0) { 1406 #ifdef FD_DEBUG 1407 if (fdc_debug) { 1408 fdcstatus(fd->sc_dv, 7, 1409 bp->b_flags & B_READ 1410 ? "read failed" : "write failed"); 1411 printf("blkno %d nblks %d tc %d\n", 1412 (int)fd->sc_blkno, fd->sc_nblks, 1413 fdc->sc_tc); 1414 } 1415 #endif 1416 if (fdc->sc_nstat == 7 && 1417 (st1 & ST1_OVERRUN) == ST1_OVERRUN) { 1418 1419 /* 1420 * Silently retry overruns if no other 1421 * error bit is set. Adjust threshold. 1422 */ 1423 int thr = fdc->sc_cfg & CFG_THRHLD_MASK; 1424 if (thr < 15) { 1425 thr++; 1426 fdc->sc_cfg &= ~CFG_THRHLD_MASK; 1427 fdc->sc_cfg |= (thr & CFG_THRHLD_MASK); 1428 #ifdef FD_DEBUG 1429 if (fdc_debug) 1430 printf("fdc: %d -> threshold\n", 1431 thr); 1432 #endif 1433 fdconf(fdc); 1434 fdc->sc_overruns = 0; 1435 } 1436 if (++fdc->sc_overruns < 3) { 1437 fdc->sc_state = DOIO; 1438 goto loop; 1439 } 1440 } 1441 fdcretry(fdc); 1442 goto loop; 1443 } 1444 if (fdc->sc_errors) { 1445 diskerr(bp, "fd", "soft error", LOG_PRINTF, 1446 fd->sc_skip / FDC_BSIZE, NULL); 1447 printf("\n"); 1448 fdc->sc_errors = 0; 1449 } else { 1450 if (--fdc->sc_overruns < -20) { 1451 int thr = fdc->sc_cfg & CFG_THRHLD_MASK; 1452 if (thr > 0) { 1453 thr--; 1454 fdc->sc_cfg &= ~CFG_THRHLD_MASK; 1455 fdc->sc_cfg |= (thr & CFG_THRHLD_MASK); 1456 #ifdef FD_DEBUG 1457 if (fdc_debug) 1458 printf("fdc: %d -> threshold\n", 1459 thr); 1460 #endif 1461 fdconf(fdc); 1462 } 1463 fdc->sc_overruns = 0; 1464 } 1465 } 1466 fd->sc_blkno += fd->sc_nblks; 1467 fd->sc_skip += fd->sc_nbytes; 1468 fd->sc_bcount -= fd->sc_nbytes; 1469 if (!finfo && fd->sc_bcount > 0) { 1470 bp->b_cylinder = fd->sc_blkno / fd->sc_type->seccyl; 1471 goto doseek; 1472 } 1473 fdfinish(fd, bp); 1474 goto loop; 1475 1476 case DORESET: 1477 doreset: 1478 /* try a reset, keep motor on */ 1479 fd_set_motor(fdc); 1480 delay(100); 1481 fdc_reset(fdc); 1482 fdc->sc_nstat = 0; 1483 fdc->sc_istate = ISTATE_SENSEI; 1484 fdc->sc_state = RESETCOMPLETE; 1485 callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc); 1486 return 1; /* will return later */ 1487 1488 case RESETCOMPLETE: 1489 callout_stop(&fdc->sc_timo_ch); 1490 fdconf(fdc); 1491 1492 /* FALLTHROUGH */ 1493 case DORECAL: 1494 fdc->sc_state = RECALWAIT; 1495 fdc->sc_istate = ISTATE_SENSEI; 1496 fdc->sc_nstat = 0; 1497 /* recalibrate function */ 1498 OUT_FDC(fdc, NE7CMD_RECAL, RECALTIMEDOUT); 1499 OUT_FDC(fdc, fd->sc_drive, RECALTIMEDOUT); 1500 callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc); 1501 return 1; /* will return later */ 1502 1503 case RECALWAIT: 1504 callout_stop(&fdc->sc_timo_ch); 1505 fdc->sc_state = RECALCOMPLETE; 1506 if (fdc->sc_flags & FDC_NEEDHEADSETTLE) { 1507 /* allow 1/30 second for heads to settle */ 1508 callout_reset(&fdc->sc_intr_ch, hz / 30, 1509 fdcpseudointr, fdc); 1510 return 1; /* will return later */ 1511 } 1512 1513 case RECALCOMPLETE: 1514 if (fdc->sc_nstat != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) { 1515 #ifdef FD_DEBUG 1516 if (fdc_debug) 1517 fdcstatus(fd->sc_dv, 2, "recalibrate failed"); 1518 #endif 1519 fdcretry(fdc); 1520 goto loop; 1521 } 1522 fd->sc_cylin = 0; 1523 goto doseek; 1524 1525 case MOTORWAIT: 1526 if (fd->sc_flags & FD_MOTOR_WAIT) 1527 return 1; /* time's not up yet */ 1528 goto doseek; 1529 1530 default: 1531 fdcstatus(fd->sc_dv, 0, "stray interrupt"); 1532 return 1; 1533 } 1534 #ifdef DIAGNOSTIC 1535 panic("%s: impossible", __func__); 1536 #endif 1537 #undef st0 1538 #undef st1 1539 #undef cyl 1540 } 1541 1542 void 1543 fdcretry(struct fdc_softc *fdc) 1544 { 1545 struct fd_softc *fd; 1546 struct buf *bp; 1547 1548 fd = fdc->sc_drives.tqh_first; 1549 bp = bufq_peek(fd->sc_q); 1550 1551 fdc->sc_overruns = 0; 1552 if (fd->sc_opts & FDOPT_NORETRY) 1553 goto fail; 1554 1555 switch (fdc->sc_errors) { 1556 case 0: 1557 /* try again */ 1558 fdc->sc_state = 1559 (fdc->sc_flags & FDC_EIS) ? DOIO : DOSEEK; 1560 break; 1561 1562 case 1: 1563 case 2: 1564 case 3: 1565 /* didn't work; try recalibrating */ 1566 fdc->sc_state = DORECAL; 1567 break; 1568 1569 case 4: 1570 /* still no go; reset the bastard */ 1571 fdc->sc_state = DORESET; 1572 break; 1573 1574 default: 1575 fail: 1576 if ((fd->sc_opts & FDOPT_SILENT) == 0) { 1577 diskerr(bp, "fd", "hard error", LOG_PRINTF, 1578 fd->sc_skip / FDC_BSIZE, NULL); 1579 1580 fdcpstatus(7, fdc); 1581 } 1582 1583 bp->b_error = EIO; 1584 fdfinish(fd, bp); 1585 } 1586 fdc->sc_errors++; 1587 } 1588 1589 static int 1590 fdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) 1591 { 1592 struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(dev)); 1593 struct fdformat_parms *form_parms; 1594 struct fdformat_cmd *form_cmd; 1595 struct ne7_fd_formb *fd_formb; 1596 int il[FD_MAX_NSEC + 1]; 1597 int i, j; 1598 int error; 1599 1600 switch (cmd) { 1601 case DIOCGDINFO: 1602 *(struct disklabel *)addr = *(fd->sc_dk.dk_label); 1603 return 0; 1604 1605 case DIOCWLABEL: 1606 if ((flag & FWRITE) == 0) 1607 return EBADF; 1608 /* XXX do something */ 1609 return 0; 1610 1611 case DIOCWDINFO: 1612 if ((flag & FWRITE) == 0) 1613 return EBADF; 1614 1615 error = setdisklabel(fd->sc_dk.dk_label, 1616 (struct disklabel *)addr, 0, fd->sc_dk.dk_cpulabel); 1617 if (error) 1618 return error; 1619 1620 error = writedisklabel(dev, fdstrategy, fd->sc_dk.dk_label, 1621 fd->sc_dk.dk_cpulabel); 1622 return error; 1623 1624 case DIOCLOCK: 1625 /* 1626 * Nothing to do here, really. 1627 */ 1628 return 0; 1629 1630 case DIOCEJECT: 1631 if (*(int *)addr == 0) { 1632 int part = DISKPART(dev); 1633 /* 1634 * Don't force eject: check that we are the only 1635 * partition open. If so, unlock it. 1636 */ 1637 if ((fd->sc_dk.dk_openmask & ~(1 << part)) != 0 || 1638 fd->sc_dk.dk_bopenmask + fd->sc_dk.dk_copenmask != 1639 fd->sc_dk.dk_openmask) { 1640 return EBUSY; 1641 } 1642 } 1643 /* FALLTHROUGH */ 1644 case ODIOCEJECT: 1645 fd_do_eject(device_private(device_parent(fd->sc_dv)), 1646 fd->sc_drive); 1647 return 0; 1648 1649 case FDIOCGETFORMAT: 1650 form_parms = (struct fdformat_parms *)addr; 1651 form_parms->fdformat_version = FDFORMAT_VERSION; 1652 form_parms->nbps = 128 * (1 << fd->sc_type->secsize); 1653 form_parms->ncyl = fd->sc_type->tracks; 1654 form_parms->nspt = fd->sc_type->sectrac; 1655 form_parms->ntrk = fd->sc_type->heads; 1656 form_parms->stepspercyl = fd->sc_type->step; 1657 form_parms->gaplen = fd->sc_type->gap2; 1658 form_parms->fillbyte = fd->sc_type->fillbyte; 1659 form_parms->interleave = fd->sc_type->interleave; 1660 switch (fd->sc_type->rate) { 1661 case FDC_500KBPS: 1662 form_parms->xfer_rate = 500 * 1024; 1663 break; 1664 case FDC_300KBPS: 1665 form_parms->xfer_rate = 300 * 1024; 1666 break; 1667 case FDC_250KBPS: 1668 form_parms->xfer_rate = 250 * 1024; 1669 break; 1670 default: 1671 return EINVAL; 1672 } 1673 return 0; 1674 1675 case FDIOCSETFORMAT: 1676 if ((flag & FWRITE) == 0) 1677 return EBADF; /* must be opened for writing */ 1678 1679 form_parms = (struct fdformat_parms *)addr; 1680 if (form_parms->fdformat_version != FDFORMAT_VERSION) 1681 return EINVAL; /* wrong version of formatting prog */ 1682 1683 i = form_parms->nbps >> 7; 1684 if ((form_parms->nbps & 0x7f) || ffs(i) == 0 || 1685 i & ~(1 << (ffs(i) - 1))) 1686 /* not a power-of-two multiple of 128 */ 1687 return EINVAL; 1688 1689 switch (form_parms->xfer_rate) { 1690 case 500 * 1024: 1691 fd->sc_type->rate = FDC_500KBPS; 1692 break; 1693 case 300 * 1024: 1694 fd->sc_type->rate = FDC_300KBPS; 1695 break; 1696 case 250 * 1024: 1697 fd->sc_type->rate = FDC_250KBPS; 1698 break; 1699 default: 1700 return EINVAL; 1701 } 1702 1703 if (form_parms->nspt > FD_MAX_NSEC || 1704 form_parms->fillbyte > 0xff || 1705 form_parms->interleave > 0xff) 1706 return EINVAL; 1707 fd->sc_type->sectrac = form_parms->nspt; 1708 if (form_parms->ntrk != 2 && form_parms->ntrk != 1) 1709 return EINVAL; 1710 fd->sc_type->heads = form_parms->ntrk; 1711 fd->sc_type->seccyl = form_parms->nspt * form_parms->ntrk; 1712 fd->sc_type->secsize = ffs(i) - 1; 1713 fd->sc_type->gap2 = form_parms->gaplen; 1714 fd->sc_type->tracks = form_parms->ncyl; 1715 fd->sc_type->size = fd->sc_type->seccyl * form_parms->ncyl * 1716 form_parms->nbps / DEV_BSIZE; 1717 fd->sc_type->step = form_parms->stepspercyl; 1718 fd->sc_type->fillbyte = form_parms->fillbyte; 1719 fd->sc_type->interleave = form_parms->interleave; 1720 return 0; 1721 1722 case FDIOCFORMAT_TRACK: 1723 if((flag & FWRITE) == 0) 1724 /* must be opened for writing */ 1725 return EBADF; 1726 form_cmd = (struct fdformat_cmd *)addr; 1727 if (form_cmd->formatcmd_version != FDFORMAT_VERSION) 1728 /* wrong version of formatting prog */ 1729 return EINVAL; 1730 1731 if (form_cmd->head >= fd->sc_type->heads || 1732 form_cmd->cylinder >= fd->sc_type->tracks) { 1733 return EINVAL; 1734 } 1735 1736 fd_formb = kmem_alloc(sizeof(*fd_formb), KM_SLEEP); 1737 fd_formb->head = form_cmd->head; 1738 fd_formb->cyl = form_cmd->cylinder; 1739 fd_formb->transfer_rate = fd->sc_type->rate; 1740 fd_formb->fd_formb_secshift = fd->sc_type->secsize; 1741 fd_formb->fd_formb_nsecs = fd->sc_type->sectrac; 1742 fd_formb->fd_formb_gaplen = fd->sc_type->gap2; 1743 fd_formb->fd_formb_fillbyte = fd->sc_type->fillbyte; 1744 1745 memset(il, 0, sizeof(il)); 1746 for (j = 0, i = 1; i <= fd_formb->fd_formb_nsecs; i++) { 1747 while (il[(j%fd_formb->fd_formb_nsecs) + 1]) 1748 j++; 1749 il[(j % fd_formb->fd_formb_nsecs) + 1] = i; 1750 j += fd->sc_type->interleave; 1751 } 1752 for (i = 0; i < fd_formb->fd_formb_nsecs; i++) { 1753 fd_formb->fd_formb_cylno(i) = form_cmd->cylinder; 1754 fd_formb->fd_formb_headno(i) = form_cmd->head; 1755 fd_formb->fd_formb_secno(i) = il[i+1]; 1756 fd_formb->fd_formb_secsize(i) = fd->sc_type->secsize; 1757 } 1758 1759 error = fdformat(dev, fd_formb, l->l_proc); 1760 kmem_free(fd_formb, sizeof(*fd_formb)); 1761 return error; 1762 1763 case FDIOCGETOPTS: /* get drive options */ 1764 *(int *)addr = fd->sc_opts; 1765 return 0; 1766 1767 case FDIOCSETOPTS: /* set drive options */ 1768 fd->sc_opts = *(int *)addr; 1769 return 0; 1770 1771 #ifdef DEBUG 1772 case _IO('f', 100): 1773 { 1774 int k; 1775 struct fdc_softc *fdc = 1776 device_private(device_parent(fd->sc_dv)); 1777 1778 out_fdc(fdc, NE7CMD_DUMPREG); 1779 fdcresult(fdc); 1780 printf("dumpreg(%d regs): <", fdc->sc_nstat); 1781 for (k = 0; k < fdc->sc_nstat; k++) 1782 printf(" %x", fdc->sc_status[k]); 1783 printf(">\n"); 1784 return 0; 1785 } 1786 1787 case _IOW('f', 101, int): 1788 { 1789 struct fdc_softc *fdc = 1790 device_private(device_parent(fd->sc_dv)); 1791 1792 fdc->sc_cfg &= ~CFG_THRHLD_MASK; 1793 fdc->sc_cfg |= (*(int *)addr & CFG_THRHLD_MASK); 1794 fdconf(fdc); 1795 return 0; 1796 } 1797 1798 case _IO('f', 102): 1799 { 1800 int k; 1801 struct fdc_softc *fdc = 1802 device_private(device_parent(fd->sc_dv)); 1803 1804 out_fdc(fdc, NE7CMD_SENSEI); 1805 fdcresult(fdc); 1806 printf("sensei(%d regs): <", fdc->sc_nstat); 1807 for (k=0; k < fdc->sc_nstat; k++) 1808 printf(" 0x%x", fdc->sc_status[k]); 1809 printf(">\n"); 1810 return 0; 1811 } 1812 #endif 1813 1814 default: 1815 return ENOTTY; 1816 } 1817 1818 #ifdef DIAGNOSTIC 1819 panic("%s: impossible", __func__); 1820 #endif 1821 } 1822 1823 int 1824 fdformat(dev_t dev, struct ne7_fd_formb *finfo, struct proc *p) 1825 { 1826 int rv = 0; 1827 struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(dev)); 1828 struct fd_type *type = fd->sc_type; 1829 struct buf *bp; 1830 1831 /* set up a buffer header for fdstrategy() */ 1832 bp = getiobuf(NULL, false); 1833 if (bp == NULL) 1834 return ENOBUFS; 1835 1836 bp->b_vp = NULL; 1837 bp->b_cflags = BC_BUSY; 1838 bp->b_flags = B_PHYS | B_FORMAT; 1839 bp->b_proc = p; 1840 bp->b_dev = dev; 1841 1842 /* 1843 * Calculate a fake blkno, so fdstrategy() would initiate a 1844 * seek to the requested cylinder. 1845 */ 1846 bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads) 1847 + finfo->head * type->sectrac) * FDC_BSIZE / DEV_BSIZE; 1848 1849 bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs; 1850 bp->b_data = (void *)finfo; 1851 1852 #ifdef FD_DEBUG 1853 if (fdc_debug) 1854 printf("%s: blkno %x count %d\n", 1855 __func__, (int)bp->b_blkno, bp->b_bcount); 1856 #endif 1857 1858 /* now do the format */ 1859 fdstrategy(bp); 1860 1861 /* ...and wait for it to complete */ 1862 rv = biowait(bp); 1863 putiobuf(bp); 1864 return rv; 1865 } 1866 1867 void 1868 fdgetdisklabel(dev_t dev) 1869 { 1870 int unit = FDUNIT(dev), i; 1871 struct fd_softc *fd = device_lookup_private(&fd_cd, unit); 1872 struct disklabel *lp = fd->sc_dk.dk_label; 1873 struct cpu_disklabel *clp = fd->sc_dk.dk_cpulabel; 1874 1875 memset(lp, 0, sizeof(struct disklabel)); 1876 memset(clp, 0, sizeof(struct cpu_disklabel)); 1877 1878 lp->d_type = DKTYPE_FLOPPY; 1879 lp->d_secsize = FDC_BSIZE; 1880 lp->d_secpercyl = fd->sc_type->seccyl; 1881 lp->d_nsectors = fd->sc_type->sectrac; 1882 lp->d_ncylinders = fd->sc_type->tracks; 1883 lp->d_ntracks = fd->sc_type->heads; /* Go figure... */ 1884 lp->d_rpm = 3600; /* XXX like it matters... */ 1885 1886 strncpy(lp->d_typename, "floppy", sizeof(lp->d_typename)); 1887 strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname)); 1888 lp->d_interleave = 1; 1889 1890 lp->d_partitions[RAW_PART].p_offset = 0; 1891 lp->d_partitions[RAW_PART].p_size = lp->d_secpercyl * lp->d_ncylinders; 1892 lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED; 1893 lp->d_npartitions = RAW_PART + 1; 1894 1895 lp->d_magic = DISKMAGIC; 1896 lp->d_magic2 = DISKMAGIC; 1897 lp->d_checksum = dkcksum(lp); 1898 1899 /* 1900 * Call the generic disklabel extraction routine. If there's 1901 * not a label there, fake it. 1902 */ 1903 if (readdisklabel(dev, fdstrategy, lp, clp) != NULL) { 1904 strncpy(lp->d_packname, "default label", 1905 sizeof(lp->d_packname)); 1906 /* 1907 * Reset the partition info; it might have gotten 1908 * trashed in readdisklabel(). 1909 * 1910 * XXX Why do we have to do this? readdisklabel() 1911 * should be safe... 1912 */ 1913 for (i = 0; i < MAXPARTITIONS; ++i) { 1914 lp->d_partitions[i].p_offset = 0; 1915 if (i == RAW_PART) { 1916 lp->d_partitions[i].p_size = 1917 lp->d_secpercyl * lp->d_ncylinders; 1918 lp->d_partitions[i].p_fstype = FS_BSDFFS; 1919 } else { 1920 lp->d_partitions[i].p_size = 0; 1921 lp->d_partitions[i].p_fstype = FS_UNUSED; 1922 } 1923 } 1924 lp->d_npartitions = RAW_PART + 1; 1925 } 1926 } 1927 1928 void 1929 fd_do_eject(struct fdc_softc *fdc, int unit) 1930 { 1931 1932 fdc->sc_fcr |= FCR_DSEL(unit)|FCR_EJECT; 1933 FCR_REG_SYNC(); 1934 delay(10); 1935 fdc->sc_fcr &= ~(FCR_DSEL(unit)|FCR_EJECT); 1936 FCR_REG_SYNC(); 1937 } 1938 1939 #ifdef MEMORY_DISK_HOOKS_sun3x_not_yet 1940 int fd_read_md_image(size_t *, void **); 1941 #endif 1942 1943 /* ARGSUSED */ 1944 void 1945 fd_mountroot_hook(device_t dev) 1946 { 1947 struct fd_softc *fd; 1948 struct fdc_softc *fdc; 1949 int c; 1950 1951 fd = device_private(dev); 1952 fdc = device_private(device_parent(dev)); 1953 fd_do_eject(fdc, fd->sc_drive); 1954 printf("Insert filesystem floppy and press return."); 1955 for (;;) { 1956 c = cngetc(); 1957 if ((c == '\r') || (c == '\n')) { 1958 printf("\n"); 1959 break; 1960 } 1961 } 1962 #ifdef MEMORY_DISK_HOOKS_sun3x_not_yet 1963 { 1964 extern int (*md_read_image)(size_t *, void **); 1965 1966 md_read_image = fd_read_md_image; 1967 } 1968 #endif 1969 } 1970 1971 #ifdef MEMORY_DISK_HOOKS_sun3x_not_yet 1972 1973 #define FDMICROROOTSIZE ((2*18*80) << DEV_BSHIFT) 1974 1975 int 1976 fd_read_md_image(size_t *sizep, void **addrp) 1977 { 1978 struct fdc_softc *fdc; 1979 struct fd_softc *fd; 1980 struct buf buf, *bp = &buf; 1981 dev_t dev; 1982 off_t offset; 1983 void *addr; 1984 1985 dev = makedev(cdevsw_lookup_major(&fd_cdevsw), 0); /* XXX */ 1986 1987 addr = kmem_alloc(FDMICROROOTSIZE, KM_SLEEP); 1988 *addrp = addr; 1989 1990 if (fdopen(dev, 0, S_IFCHR, NULL)) 1991 panic("fd: mountroot: fdopen"); 1992 1993 offset = 0; 1994 1995 for (;;) { 1996 bp->b_dev = dev; 1997 bp->b_error = 0; 1998 bp->b_resid = 0; 1999 bp->b_proc = NULL; 2000 bp->b_flags = B_PHYS | B_RAW | B_READ; 2001 bp->b_cflags = BC_BUSY; 2002 bp->b_blkno = btodb(offset); 2003 bp->b_bcount = DEV_BSIZE; 2004 bp->b_data = addr; 2005 fdstrategy(bp); 2006 biowait(bp); 2007 if (bp->b_error) 2008 panic("fd: mountroot: fdread error %d", bp->b_error); 2009 2010 if (bp->b_resid != 0) 2011 break; 2012 2013 addr += DEV_BSIZE; 2014 offset += DEV_BSIZE; 2015 if (offset + DEV_BSIZE > FDMICROROOTSIZE) 2016 break; 2017 } 2018 (void)fdclose(dev, 0, S_IFCHR, NULL); 2019 *sizep = offset; 2020 fd = device_lookup_private(&fd_cd, 0); 2021 fdc = device_private(device_parent(fd->sc_dv)); 2022 fd_do_eject(fdc, 0); /* XXX */ 2023 return 0; 2024 } 2025 #endif 2026