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