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