1 /* $NetBSD: fd.c,v 1.48 2006/04/19 06:16:00 he 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.48 2006/04/19 06:16:00 he 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 /* XXX misuse a flag to identify format operation */ 126 #define B_FORMAT B_XXX 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 caddr_t 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 }; 183 184 /* controller driver configuration */ 185 int fdcmatch(struct device *, struct cfdata *, void *); 186 void fdcattach(struct device *, struct device *, void *); 187 188 CFATTACH_DECL(fdc, sizeof(struct fdc_softc), 189 fdcmatch, fdcattach, NULL, NULL); 190 191 extern struct cfdriver fdc_cd; 192 193 inline struct fd_type *fd_dev_to_type(struct fd_softc *, dev_t); 194 195 /* 196 * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how 197 * we tell them apart. 198 */ 199 struct fd_type { 200 int sectrac; /* sectors per track */ 201 int heads; /* number of heads */ 202 int seccyl; /* sectors per cylinder */ 203 int secsize; /* size code for sectors */ 204 int datalen; /* data len when secsize = 0 */ 205 int steprate; /* step rate and head unload time */ 206 int gap1; /* gap len between sectors */ 207 int gap2; /* formatting gap */ 208 int tracks; /* total num of tracks */ 209 int size; /* size of disk in sectors */ 210 int step; /* steps per cylinder */ 211 int rate; /* transfer speed code */ 212 int fillbyte; /* format fill byte */ 213 int interleave; /* interleave factor (formatting) */ 214 const char *name; 215 }; 216 217 /* The order of entries in the following table is important -- BEWARE! */ 218 struct fd_type fd_types[] = { 219 { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS,0xf6,1, "1.44MB" }, /* 1.44MB diskette */ 220 { 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS,0xf6,1, "1.2MB" }, /* 1.2 MB AT-diskettes */ 221 { 9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS,0xf6,1, "360KB/AT" }, /* 360kB in 1.2MB drive */ 222 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS,0xf6,1, "360KB/PC" }, /* 360kB PC diskettes */ 223 { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS,0xf6,1, "720KB" }, /* 3.5" 720kB diskette */ 224 { 9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS,0xf6,1, "720KB/x" }, /* 720kB in 1.2MB drive */ 225 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS,0xf6,1, "360KB/x" }, /* 360kB in 720kB drive */ 226 }; 227 228 /* software state, per disk (with up to 4 disks per ctlr) */ 229 struct fd_softc { 230 struct device sc_dv; /* generic device info */ 231 struct disk sc_dk; /* generic disk info */ 232 233 struct fd_type *sc_deftype; /* default type descriptor */ 234 struct fd_type *sc_type; /* current type descriptor */ 235 236 struct callout sc_motoron_ch; 237 struct callout sc_motoroff_ch; 238 239 daddr_t sc_blkno; /* starting block number */ 240 int sc_bcount; /* byte count left */ 241 int sc_skip; /* bytes already transferred */ 242 int sc_nblks; /* number of blocks currently transferring */ 243 int sc_nbytes; /* number of bytes currently transferring */ 244 245 int sc_drive; /* physical unit number */ 246 int sc_flags; 247 #define FD_OPEN 0x01 /* it's open */ 248 #define FD_MOTOR 0x02 /* motor should be on */ 249 #define FD_MOTOR_WAIT 0x04 /* motor coming up */ 250 int sc_cylin; /* where we think the head is */ 251 int sc_opts; /* user-set options */ 252 253 void *sc_sdhook; /* shutdownhook cookie */ 254 255 TAILQ_ENTRY(fd_softc) sc_drivechain; 256 int sc_ops; /* I/O ops since last switch */ 257 struct bufq_state *sc_q;/* pending I/O requests */ 258 int sc_active; /* number of active I/O operations */ 259 }; 260 261 /* floppy driver configuration */ 262 int fdmatch(struct device *, struct cfdata *, void *); 263 void fdattach(struct device *, struct device *, void *); 264 265 CFATTACH_DECL(fd, sizeof(struct fd_softc), 266 fdmatch, fdattach, NULL, NULL); 267 268 extern struct cfdriver fd_cd; 269 270 dev_type_open(fdopen); 271 dev_type_close(fdclose); 272 dev_type_read(fdread); 273 dev_type_write(fdwrite); 274 dev_type_ioctl(fdioctl); 275 dev_type_strategy(fdstrategy); 276 277 const struct bdevsw fd_bdevsw = { 278 fdopen, fdclose, fdstrategy, fdioctl, nodump, nosize, D_DISK 279 }; 280 281 const struct cdevsw fd_cdevsw = { 282 fdopen, fdclose, fdread, fdwrite, fdioctl, 283 nostop, notty, nopoll, nommap, nokqfilter, D_DISK 284 }; 285 286 void fdgetdisklabel(dev_t); 287 int fd_get_parms(struct fd_softc *); 288 void fdstart(struct fd_softc *); 289 int fdprint(void *, const char *); 290 291 struct dkdriver fddkdriver = { fdstrategy }; 292 293 struct fd_type *fd_nvtotype(char *, int, int); 294 void fd_set_motor(struct fdc_softc *); 295 void fd_motor_off(void *); 296 void fd_motor_on(void *); 297 int fdcresult(struct fdc_softc *); 298 int out_fdc(struct fdc_softc *, u_char); 299 void fdcstart(struct fdc_softc *); 300 void fdcstatus(struct device *, int, const char *); 301 void fdc_reset(struct fdc_softc *); 302 void fdctimeout(void *); 303 void fdcpseudointr(void *); 304 int fdchwintr(void *); 305 int fdcswintr(void *); 306 int fdcstate(struct fdc_softc *); 307 void fdcretry(struct fdc_softc *); 308 void fdfinish(struct fd_softc *, struct buf *); 309 int fdformat(dev_t, struct ne7_fd_formb *, struct proc *); 310 void fd_do_eject(struct fdc_softc *, int); 311 void fd_mountroot_hook(struct device *); 312 static void fdconf(struct fdc_softc *); 313 314 static int fdc_softpend = 0; 315 #ifndef FDC_SOFTPRI 316 #define FDC_SOFTPRI 2 317 #endif 318 #define FD_SET_SWINTR() { fdc_softpend = 1; isr_soft_request(FDC_SOFTPRI); } 319 320 /* 321 * The Floppy Control Register on the sun3x, not to be confused with the 322 * Floppy ControllER Registers that this driver mostly insterfaces with, 323 * controls some of the auxillary functions of the floppy drive. These 324 * include asserting the floppy eject and terminal data count (or TC) pins 325 * of the floppy drive and controller chip respectively. 326 * 327 * Often it is necessary to toggle individual bits within this register 328 * while keeping the others untouched. However, the register does not 329 * present its latched data to the processor when read. This prevents the 330 * use of a read-modify-write cycle that would normally be used to modify 331 * individual bits. To get around this we must keep a copy of register's 332 * current value and always insure that when we wish to modify the register, 333 * we actually modify the copy and synchronize the register to it. 334 */ 335 #define FCR_REG_SYNC() (*fdc->sc_reg_fcr = fdc->sc_fcr) 336 337 int 338 fdcmatch(struct device *parent, struct cfdata *match, void *aux) 339 { 340 struct confargs *ca = aux; 341 342 if (bus_peek(ca->ca_bustype, ca->ca_paddr, sizeof(u_char)) == -1) 343 return (0); 344 345 return (1); 346 } 347 348 /* 349 * Arguments passed between fdcattach and fdprobe. 350 */ 351 struct fdc_attach_args { 352 int fa_drive; 353 struct bootpath *fa_bootpath; 354 struct fd_type *fa_deftype; 355 }; 356 357 /* 358 * Print the location of a disk drive (called just before attaching the 359 * the drive). If `fdc' is not NULL, the drive was found but was not 360 * in the system config file; print the drive name as well. 361 * Return QUIET (config_find ignores this if the device was configured) to 362 * avoid printing `fdN not configured' messages. 363 */ 364 int 365 fdprint(void *aux, const char *fdc) 366 { 367 struct fdc_attach_args *fa = aux; 368 369 if (!fdc) 370 aprint_normal(" drive %d", fa->fa_drive); 371 return (QUIET); 372 } 373 374 static void 375 fdconf(struct fdc_softc *fdc) 376 { 377 int vroom; 378 379 if (out_fdc(fdc, NE7CMD_DUMPREG) || fdcresult(fdc) != 10) 380 return; 381 382 /* 383 * dumpreg[7] seems to be a motor-off timeout; set it to whatever 384 * the PROM thinks is appropriate. 385 */ 386 if ((vroom = fdc->sc_status[7]) == 0) 387 vroom = 0x64; 388 389 /* Configure controller to use FIFO and Implied Seek */ 390 out_fdc(fdc, NE7CMD_CFG); 391 out_fdc(fdc, vroom); 392 out_fdc(fdc, fdc->sc_cfg); 393 out_fdc(fdc, 0); /* PRETRK */ 394 /* No result phase */ 395 } 396 397 void 398 fdcattach(struct device *parent, struct device *self, void *aux) 399 { 400 struct confargs *ca = aux; 401 struct fdc_softc *fdc = (void *)self; 402 struct fdc_attach_args fa; 403 int pri, vec; 404 char code; 405 406 fdc->sc_reg = (caddr_t)bus_mapin(ca->ca_bustype, ca->ca_paddr, 407 sizeof(union fdreg)); 408 409 callout_init(&fdc->sc_timo_ch); 410 callout_init(&fdc->sc_intr_ch); 411 412 fdc->sc_state = DEVIDLE; 413 fdc->sc_istate = ISTATE_IDLE; 414 fdc->sc_flags |= FDC_EIS; 415 TAILQ_INIT(&fdc->sc_drives); 416 417 /* Assume a 82072 */ 418 code = '2'; 419 420 if (code == '7') { 421 panic("no 82077 fdc in this kernel"); 422 /* NOTREACHED */ 423 } else { 424 fdc->sc_reg_msr = &((struct fdreg_72 *)fdc->sc_reg)->fd_msr; 425 fdc->sc_reg_fifo = &((struct fdreg_72 *)fdc->sc_reg)->fd_fifo; 426 427 fdc->sc_reg_fcr = ((volatile uint8_t *) fdc->sc_reg) 428 + FDC_FCR_OFFSET; 429 fdc->sc_reg_fvr = ((volatile uint8_t *) fdc->sc_reg) 430 + FDC_FVR_OFFSET; 431 } 432 433 isr_add_autovect(fdcswintr, fdc, FDC_SOFTPRI); 434 pri = ca->ca_intpri; 435 vec = ca->ca_intvec; 436 if (vec == -1) { 437 /* Tell the FDC to fake an autovector. */ 438 vec = 0x18 + pri; /* XXX */ 439 isr_add_autovect(fdchwintr, fdc, pri); 440 } else { 441 /* An OBIO bus with vectors? Weird exception. */ 442 isr_add_vectored(fdchwintr, fdc, pri, vec); 443 } 444 *fdc->sc_reg_fvr = vec; /* Program controller w/ interrupt vector */ 445 446 printf(": (softpri %d) chip 8207%c\n", FDC_SOFTPRI, code); 447 448 #ifdef FD_DEBUG 449 if (out_fdc(fdc, NE7CMD_VERSION) == 0 && 450 fdcresult(fdc) == 1 && fdc->sc_status[0] == 0x90) { 451 if (fdc_debug) 452 printf("[version cmd]"); 453 } 454 #endif 455 456 fdc_reset(fdc); 457 /* 458 * Configure controller; enable FIFO, Implied seek, no POLL mode?. 459 * Note: CFG_EFIFO is active-low, initial threshold value: 8 460 */ 461 fdc->sc_cfg = CFG_EIS|/*CFG_EFIFO|*/CFG_POLL|(8 & CFG_THRHLD_MASK); 462 fdconf(fdc); 463 464 evcnt_attach_dynamic(&fdc->sc_intrcnt, EVCNT_TYPE_INTR, NULL, 465 fdc->sc_dev.dv_xname, "intr"); 466 467 /* physical limit: four drives per controller. */ 468 for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) { 469 fa.fa_deftype = NULL; /* unknown */ 470 fa.fa_deftype = &fd_types[0]; /* XXX */ 471 (void)config_found(self, (void *)&fa, fdprint); 472 } 473 } 474 475 int 476 fdmatch(struct device *parent, struct cfdata *match, void *aux) 477 { 478 struct fdc_softc *fdc = (void *)parent; 479 struct fdc_attach_args *fa = aux; 480 int drive = fa->fa_drive; 481 int n, ok; 482 483 if (drive > 0) 484 /* XXX - for now, punt > 1 drives */ 485 return (0); 486 487 /* select drive and turn on motor */ 488 fdc->sc_fcr |= FCR_DSEL(drive) | FCR_MTRON; 489 FCR_REG_SYNC(); 490 /* wait for motor to spin up */ 491 delay(250000); 492 493 fdc->sc_nstat = 0; 494 out_fdc(fdc, NE7CMD_RECAL); 495 out_fdc(fdc, drive); 496 /* wait for recalibrate */ 497 for (n = 0; n < 10000; n++) { 498 delay(1000); 499 if ((*fdc->sc_reg_msr & (NE7_RQM|NE7_DIO|NE7_CB)) == NE7_RQM) { 500 /* wait a bit longer till device *really* is ready */ 501 delay(100000); 502 if (out_fdc(fdc, NE7CMD_SENSEI)) 503 break; 504 if (fdcresult(fdc) == 1 && fdc->sc_status[0] == 0x80) 505 /* 506 * Got `invalid command'; we interpret it 507 * to mean that the re-calibrate hasn't in 508 * fact finished yet 509 */ 510 continue; 511 break; 512 } 513 } 514 n = fdc->sc_nstat; 515 #ifdef FD_DEBUG 516 if (fdc_debug) { 517 int i; 518 printf("fdprobe: %d stati:", n); 519 for (i = 0; i < n; i++) 520 printf(" %x", fdc->sc_status[i]); 521 printf("\n"); 522 } 523 #endif 524 ok = (n == 2 && (fdc->sc_status[0] & 0xf8) == 0x20) ? 1 : 0; 525 526 /* turn off motor */ 527 fdc->sc_fcr &= ~(FCR_DSEL(drive)|FCR_MTRON); 528 FCR_REG_SYNC(); 529 530 return (ok); 531 } 532 533 /* 534 * Controller is working, and drive responded. Attach it. 535 */ 536 void 537 fdattach(struct device *parent, struct device *self, void *aux) 538 { 539 struct fdc_softc *fdc = (void *)parent; 540 struct fd_softc *fd = (void *)self; 541 struct fdc_attach_args *fa = aux; 542 struct fd_type *type = fa->fa_deftype; 543 int drive = fa->fa_drive; 544 545 callout_init(&fd->sc_motoron_ch); 546 callout_init(&fd->sc_motoroff_ch); 547 548 /* XXX Allow `flags' to override device type? */ 549 550 if (type) 551 printf(": %s %d cyl, %d head, %d sec\n", type->name, 552 type->tracks, type->heads, type->sectrac); 553 else 554 printf(": density unknown\n"); 555 556 bufq_alloc(&fd->sc_q, "disksort", BUFQ_SORT_CYLINDER); 557 fd->sc_cylin = -1; 558 fd->sc_drive = drive; 559 fd->sc_deftype = type; 560 fdc->sc_fd[drive] = fd; 561 562 /* 563 * Initialize and attach the disk structure. 564 */ 565 fd->sc_dk.dk_name = fd->sc_dv.dv_xname; 566 fd->sc_dk.dk_driver = &fddkdriver; 567 disk_attach(&fd->sc_dk); 568 569 #ifdef sparc 570 /* 571 * We're told if we're the boot device in fdcattach(). 572 */ 573 if (fa->fa_bootpath) 574 fa->fa_bootpath->dev = &fd->sc_dv; 575 #endif 576 #define OUT_FDC(sc, c) { \ 577 if (out_fdc((sc), (c))) \ 578 printf("fdc: specify command failed.\n");\ 579 } 580 /* specify command */ 581 OUT_FDC(fdc, NE7CMD_SPECIFY); 582 OUT_FDC(fdc, type->steprate); 583 /* 584 * The '|1' in the following statement turns on the 'Non-DMA' bit 585 * specifier in the last byte of the SPECIFY command as described in the 586 * datasheet I have. This is necessary for the driver to work on the 587 * sun3x, because the system will not respond to the chip's requests 588 * for DMA; there is no hardware on the motherboard to support it. 589 * By enabling this bit, we will force the chip to interrupt when its 590 * FIFO is full, at which point the interrupt handler will empty it and 591 * continue. This is ``pseudo-DMA''. 592 * -J 593 */ 594 OUT_FDC(fdc, 6|1); /* XXX head load time == 6ms */ 595 #undef OUT_FDC 596 597 /* 598 * Establish a mountroot_hook anyway in case we booted 599 * with RB_ASKNAME and get selected as the boot device. 600 */ 601 mountroothook_establish(fd_mountroot_hook, &fd->sc_dv); 602 603 /* Make sure the drive motor gets turned off at shutdown time. */ 604 fd->sc_sdhook = shutdownhook_establish(fd_motor_off, fd); 605 } 606 607 inline struct fd_type * 608 fd_dev_to_type(struct fd_softc *fd, dev_t dev) 609 { 610 int type = FDTYPE(dev); 611 612 if (type > (sizeof(fd_types) / sizeof(fd_types[0]))) 613 return (NULL); 614 return (type ? &fd_types[type - 1] : fd->sc_deftype); 615 } 616 617 void 618 fdstrategy(struct buf *bp /* IO operation to perform */) 619 { 620 struct fd_softc *fd; 621 int unit = FDUNIT(bp->b_dev); 622 int sz; 623 int s; 624 625 /* Valid unit, controller, and request? */ 626 if (unit >= fd_cd.cd_ndevs || 627 (fd = fd_cd.cd_devs[unit]) == 0 || 628 bp->b_blkno < 0 || 629 ((bp->b_bcount % FDC_BSIZE) != 0 && 630 (bp->b_flags & B_FORMAT) == 0)) { 631 bp->b_error = EINVAL; 632 goto bad; 633 } 634 635 /* If it's a null transfer, return immediately. */ 636 if (bp->b_bcount == 0) 637 goto done; 638 639 sz = howmany(bp->b_bcount, FDC_BSIZE); 640 641 if (bp->b_blkno + sz > fd->sc_type->size) { 642 sz = fd->sc_type->size - bp->b_blkno; 643 if (sz == 0) { 644 /* If exactly at end of disk, return EOF. */ 645 bp->b_resid = bp->b_bcount; 646 goto done; 647 } 648 if (sz < 0) { 649 /* If past end of disk, return EINVAL. */ 650 bp->b_error = EINVAL; 651 goto bad; 652 } 653 /* Otherwise, truncate request. */ 654 bp->b_bcount = sz << DEV_BSHIFT; 655 } 656 657 bp->b_rawblkno = bp->b_blkno; 658 bp->b_cylinder = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE) / fd->sc_type->seccyl; 659 660 #ifdef FD_DEBUG 661 if (fdc_debug > 1) 662 printf("fdstrategy: b_blkno %d b_bcount %ld blkno %d cylin %ld\n", 663 bp->b_blkno, bp->b_bcount, fd->sc_blkno, bp->b_cylinder); 664 #endif 665 666 /* Queue transfer on drive, activate drive and controller if idle. */ 667 s = splbio(); 668 BUFQ_PUT(fd->sc_q, bp); 669 callout_stop(&fd->sc_motoroff_ch); /* a good idea */ 670 if (fd->sc_active == 0) 671 fdstart(fd); 672 #ifdef DIAGNOSTIC 673 else { 674 struct fdc_softc *fdc = (void *)device_parent(&fd->sc_dv); 675 if (fdc->sc_state == DEVIDLE) { 676 printf("fdstrategy: controller inactive\n"); 677 fdcstart(fdc); 678 } 679 } 680 #endif 681 splx(s); 682 return; 683 684 bad: 685 bp->b_flags |= B_ERROR; 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 int 1084 fdcswintr(void *arg) 1085 { 1086 struct fdc_softc *fdc = arg; 1087 int s; 1088 1089 if (fdc_softpend == 0) 1090 return (0); 1091 1092 isr_soft_clear(FDC_SOFTPRI); 1093 fdc_softpend = 0; 1094 1095 if (fdc->sc_istate != ISTATE_DONE) 1096 return (0); 1097 1098 fdc->sc_istate = ISTATE_IDLE; 1099 s = splbio(); 1100 fdcstate(fdc); 1101 splx(s); 1102 return (1); 1103 } 1104 1105 int 1106 fdcstate(struct fdc_softc *fdc) 1107 { 1108 #define st0 fdc->sc_status[0] 1109 #define st1 fdc->sc_status[1] 1110 #define cyl fdc->sc_status[1] 1111 #define OUT_FDC(fdc, c, s) \ 1112 do { if (out_fdc(fdc, (c))) { (fdc)->sc_state = (s); goto loop; } } while(0) 1113 1114 struct fd_softc *fd; 1115 struct buf *bp; 1116 int read, head, sec, nblks; 1117 struct fd_type *type; 1118 struct ne7_fd_formb *finfo = NULL; 1119 1120 1121 if (fdc->sc_istate != ISTATE_IDLE) { 1122 /* Trouble... */ 1123 printf("fdc: spurious interrupt: state %d, istate=%d\n", 1124 fdc->sc_state, fdc->sc_istate); 1125 fdc->sc_istate = ISTATE_IDLE; 1126 if (fdc->sc_state == RESETCOMPLETE || 1127 fdc->sc_state == RESETTIMEDOUT) { 1128 panic("fdcintr: spurious interrupt can't be cleared"); 1129 } 1130 goto doreset; 1131 } 1132 1133 loop: 1134 /* Is there a drive for the controller to do a transfer with? */ 1135 fd = fdc->sc_drives.tqh_first; 1136 if (fd == NULL) { 1137 fdc->sc_state = DEVIDLE; 1138 return (0); 1139 } 1140 1141 /* Is there a transfer to this drive? If not, deactivate drive. */ 1142 bp = BUFQ_PEEK(fd->sc_q); 1143 if (bp == NULL) { 1144 fd->sc_ops = 0; 1145 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain); 1146 fd->sc_active = 0; 1147 goto loop; 1148 } 1149 1150 if (bp->b_flags & B_FORMAT) 1151 finfo = (struct ne7_fd_formb *)bp->b_data; 1152 1153 switch (fdc->sc_state) { 1154 case DEVIDLE: 1155 fdc->sc_errors = 0; 1156 fd->sc_skip = 0; 1157 fd->sc_bcount = bp->b_bcount; 1158 fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE); 1159 callout_stop(&fd->sc_motoroff_ch); 1160 if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) { 1161 fdc->sc_state = MOTORWAIT; 1162 return (1); 1163 } 1164 if ((fd->sc_flags & FD_MOTOR) == 0) { 1165 /* Turn on the motor, being careful about pairing. */ 1166 struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1]; 1167 if (ofd && ofd->sc_flags & FD_MOTOR) { 1168 callout_stop(&ofd->sc_motoroff_ch); 1169 ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT); 1170 } 1171 fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT; 1172 fd_set_motor(fdc); 1173 fdc->sc_state = MOTORWAIT; 1174 if (fdc->sc_flags & FDC_82077) { /* XXX */ 1175 /* Allow .25s for motor to stabilize. */ 1176 callout_reset(&fd->sc_motoron_ch, hz / 4, 1177 fd_motor_on, fd); 1178 } else { 1179 fd->sc_flags &= ~FD_MOTOR_WAIT; 1180 goto loop; 1181 } 1182 return (1); 1183 } 1184 /* Make sure the right drive is selected. */ 1185 fd_set_motor(fdc); 1186 1187 /*FALLTHROUGH*/ 1188 case DOSEEK: 1189 doseek: 1190 if ((fdc->sc_flags & FDC_EIS) && 1191 (bp->b_flags & B_FORMAT) == 0) { 1192 fd->sc_cylin = bp->b_cylinder; 1193 /* We use implied seek */ 1194 goto doio; 1195 } 1196 1197 if (fd->sc_cylin == bp->b_cylinder) 1198 goto doio; 1199 1200 /* specify command */ 1201 OUT_FDC(fdc, NE7CMD_SPECIFY, SEEKTIMEDOUT); 1202 OUT_FDC(fdc, fd->sc_type->steprate, SEEKTIMEDOUT); 1203 OUT_FDC(fdc, 6|1, SEEKTIMEDOUT); /* XXX head load time == 6ms */ 1204 1205 fdc->sc_istate = ISTATE_SENSEI; 1206 /* seek function */ 1207 OUT_FDC(fdc, NE7CMD_SEEK, SEEKTIMEDOUT); 1208 OUT_FDC(fdc, fd->sc_drive, SEEKTIMEDOUT); /* drive number */ 1209 OUT_FDC(fdc, bp->b_cylinder * fd->sc_type->step, SEEKTIMEDOUT); 1210 1211 fd->sc_cylin = -1; 1212 fdc->sc_state = SEEKWAIT; 1213 fdc->sc_nstat = 0; 1214 1215 iostat_seek(fd->sc_dk.dk_stats); 1216 disk_busy(&fd->sc_dk); 1217 1218 callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc); 1219 return (1); 1220 1221 case DOIO: 1222 doio: 1223 #ifdef NOTYET 1224 /* Check to see if the disk has changed */ 1225 if (fdc->sc_reg_dir & FDI_DCHG) { 1226 /* 1227 * The disk in the drive has changed since 1228 * the last transfer. We need to see if its geometry 1229 * has changed. 1230 */ 1231 } 1232 #endif /* NOTYET */ 1233 1234 if (finfo) 1235 fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) - 1236 (char *)finfo; 1237 type = fd->sc_type; 1238 sec = fd->sc_blkno % type->seccyl; 1239 nblks = type->seccyl - sec; 1240 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE); 1241 nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE); 1242 fd->sc_nblks = nblks; 1243 fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FDC_BSIZE; 1244 head = sec / type->sectrac; 1245 sec -= head * type->sectrac; 1246 #ifdef DIAGNOSTIC 1247 {int block; 1248 block = (fd->sc_cylin * type->heads + head) * type->sectrac + sec; 1249 if (block != fd->sc_blkno) { 1250 printf("fdcintr: block %d != blkno %" PRIu64 "\n", 1251 block, fd->sc_blkno); 1252 #ifdef DDB 1253 Debugger(); 1254 #endif 1255 }} 1256 #endif 1257 read = bp->b_flags & B_READ; 1258 1259 /* Setup for pseudo DMA */ 1260 fdc->sc_data = bp->b_data + fd->sc_skip; 1261 fdc->sc_tc = fd->sc_nbytes; 1262 1263 *fdc->sc_reg_drs = type->rate; 1264 #ifdef FD_DEBUG 1265 if (fdc_debug > 1) 1266 printf("fdcintr: %s drive %d track %d head %d sec %d nblks %d\n", 1267 read ? "read" : "write", fd->sc_drive, 1268 fd->sc_cylin, head, sec, nblks); 1269 #endif 1270 fdc->sc_state = IOCOMPLETE; 1271 fdc->sc_istate = ISTATE_DMA; 1272 fdc->sc_nstat = 0; 1273 if (finfo) { 1274 /* formatting */ 1275 OUT_FDC(fdc, NE7CMD_FORMAT, IOTIMEDOUT); 1276 OUT_FDC(fdc, (head << 2) | fd->sc_drive, IOTIMEDOUT); 1277 OUT_FDC(fdc, finfo->fd_formb_secshift, IOTIMEDOUT); 1278 OUT_FDC(fdc, finfo->fd_formb_nsecs, IOTIMEDOUT); 1279 OUT_FDC(fdc, finfo->fd_formb_gaplen, IOTIMEDOUT); 1280 OUT_FDC(fdc, finfo->fd_formb_fillbyte, IOTIMEDOUT); 1281 } else { 1282 if (read) 1283 OUT_FDC(fdc, NE7CMD_READ, IOTIMEDOUT); 1284 else 1285 OUT_FDC(fdc, NE7CMD_WRITE, IOTIMEDOUT); 1286 OUT_FDC(fdc, (head << 2) | fd->sc_drive, IOTIMEDOUT); 1287 OUT_FDC(fdc, fd->sc_cylin, IOTIMEDOUT); /*track*/ 1288 OUT_FDC(fdc, head, IOTIMEDOUT); 1289 OUT_FDC(fdc, sec + 1, IOTIMEDOUT); /*sector+1*/ 1290 OUT_FDC(fdc, type->secsize, IOTIMEDOUT);/*sector size*/ 1291 OUT_FDC(fdc, type->sectrac, IOTIMEDOUT);/*secs/track*/ 1292 OUT_FDC(fdc, type->gap1, IOTIMEDOUT); /*gap1 size*/ 1293 OUT_FDC(fdc, type->datalen, IOTIMEDOUT);/*data length*/ 1294 } 1295 1296 disk_busy(&fd->sc_dk); 1297 1298 /* allow 2 seconds for operation */ 1299 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc); 1300 return (1); /* will return later */ 1301 1302 case SEEKWAIT: 1303 callout_stop(&fdc->sc_timo_ch); 1304 fdc->sc_state = SEEKCOMPLETE; 1305 if (fdc->sc_flags & FDC_NEEDHEADSETTLE) { 1306 /* allow 1/50 second for heads to settle */ 1307 callout_reset(&fdc->sc_intr_ch, hz / 50, 1308 fdcpseudointr, fdc); 1309 return (1); /* will return later */ 1310 } 1311 /*FALLTHROUGH*/ 1312 case SEEKCOMPLETE: 1313 /* no data on seek */ 1314 disk_unbusy(&fd->sc_dk, 0, 0); 1315 1316 /* Make sure seek really happened. */ 1317 if (fdc->sc_nstat != 2 || (st0 & 0xf8) != 0x20 || 1318 cyl != bp->b_cylinder * fd->sc_type->step) { 1319 #ifdef FD_DEBUG 1320 if (fdc_debug) 1321 fdcstatus(&fd->sc_dv, 2, "seek failed"); 1322 #endif 1323 fdcretry(fdc); 1324 goto loop; 1325 } 1326 fd->sc_cylin = bp->b_cylinder; 1327 goto doio; 1328 1329 case IOTIMEDOUT: 1330 fdc->sc_fcr |= FCR_TC; 1331 FCR_REG_SYNC(); 1332 delay(10); 1333 fdc->sc_fcr &= ~FCR_TC; 1334 FCR_REG_SYNC(); 1335 (void)fdcresult(fdc); 1336 /*FALLTHROUGH*/ 1337 case SEEKTIMEDOUT: 1338 case RECALTIMEDOUT: 1339 case RESETTIMEDOUT: 1340 fdcretry(fdc); 1341 goto loop; 1342 1343 case IOCOMPLETE: /* IO DONE, post-analyze */ 1344 callout_stop(&fdc->sc_timo_ch); 1345 1346 disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid), 1347 (bp->b_flags & B_READ)); 1348 1349 if (fdc->sc_nstat != 7 || (st0 & 0xf8) != 0 || st1 != 0) { 1350 #ifdef FD_DEBUG 1351 if (fdc_debug) { 1352 fdcstatus(&fd->sc_dv, 7, 1353 bp->b_flags & B_READ 1354 ? "read failed" : "write failed"); 1355 printf("blkno %d nblks %d tc %d\n", 1356 fd->sc_blkno, fd->sc_nblks, fdc->sc_tc); 1357 } 1358 #endif 1359 if (fdc->sc_nstat == 7 && 1360 (st1 & ST1_OVERRUN) == ST1_OVERRUN) { 1361 1362 /* 1363 * Silently retry overruns if no other 1364 * error bit is set. Adjust threshold. 1365 */ 1366 int thr = fdc->sc_cfg & CFG_THRHLD_MASK; 1367 if (thr < 15) { 1368 thr++; 1369 fdc->sc_cfg &= ~CFG_THRHLD_MASK; 1370 fdc->sc_cfg |= (thr & CFG_THRHLD_MASK); 1371 #ifdef FD_DEBUG 1372 if (fdc_debug) 1373 printf("fdc: %d -> threshold\n", thr); 1374 #endif 1375 fdconf(fdc); 1376 fdc->sc_overruns = 0; 1377 } 1378 if (++fdc->sc_overruns < 3) { 1379 fdc->sc_state = DOIO; 1380 goto loop; 1381 } 1382 } 1383 fdcretry(fdc); 1384 goto loop; 1385 } 1386 if (fdc->sc_errors) { 1387 diskerr(bp, "fd", "soft error", LOG_PRINTF, 1388 fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL); 1389 printf("\n"); 1390 fdc->sc_errors = 0; 1391 } else { 1392 if (--fdc->sc_overruns < -20) { 1393 int thr = fdc->sc_cfg & CFG_THRHLD_MASK; 1394 if (thr > 0) { 1395 thr--; 1396 fdc->sc_cfg &= ~CFG_THRHLD_MASK; 1397 fdc->sc_cfg |= (thr & CFG_THRHLD_MASK); 1398 #ifdef FD_DEBUG 1399 if (fdc_debug) 1400 printf("fdc: %d -> threshold\n", thr); 1401 #endif 1402 fdconf(fdc); 1403 } 1404 fdc->sc_overruns = 0; 1405 } 1406 } 1407 fd->sc_blkno += fd->sc_nblks; 1408 fd->sc_skip += fd->sc_nbytes; 1409 fd->sc_bcount -= fd->sc_nbytes; 1410 if (!finfo && fd->sc_bcount > 0) { 1411 bp->b_cylinder = fd->sc_blkno / fd->sc_type->seccyl; 1412 goto doseek; 1413 } 1414 fdfinish(fd, bp); 1415 goto loop; 1416 1417 case DORESET: 1418 doreset: 1419 /* try a reset, keep motor on */ 1420 fd_set_motor(fdc); 1421 delay(100); 1422 fdc_reset(fdc); 1423 fdc->sc_nstat = 0; 1424 fdc->sc_istate = ISTATE_SENSEI; 1425 fdc->sc_state = RESETCOMPLETE; 1426 callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc); 1427 return (1); /* will return later */ 1428 1429 case RESETCOMPLETE: 1430 callout_stop(&fdc->sc_timo_ch); 1431 fdconf(fdc); 1432 1433 /* fall through */ 1434 case DORECAL: 1435 fdc->sc_state = RECALWAIT; 1436 fdc->sc_istate = ISTATE_SENSEI; 1437 fdc->sc_nstat = 0; 1438 /* recalibrate function */ 1439 OUT_FDC(fdc, NE7CMD_RECAL, RECALTIMEDOUT); 1440 OUT_FDC(fdc, fd->sc_drive, RECALTIMEDOUT); 1441 callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc); 1442 return (1); /* will return later */ 1443 1444 case RECALWAIT: 1445 callout_stop(&fdc->sc_timo_ch); 1446 fdc->sc_state = RECALCOMPLETE; 1447 if (fdc->sc_flags & FDC_NEEDHEADSETTLE) { 1448 /* allow 1/30 second for heads to settle */ 1449 callout_reset(&fdc->sc_intr_ch, hz / 30, 1450 fdcpseudointr, fdc); 1451 return (1); /* will return later */ 1452 } 1453 1454 case RECALCOMPLETE: 1455 if (fdc->sc_nstat != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) { 1456 #ifdef FD_DEBUG 1457 if (fdc_debug) 1458 fdcstatus(&fd->sc_dv, 2, "recalibrate failed"); 1459 #endif 1460 fdcretry(fdc); 1461 goto loop; 1462 } 1463 fd->sc_cylin = 0; 1464 goto doseek; 1465 1466 case MOTORWAIT: 1467 if (fd->sc_flags & FD_MOTOR_WAIT) 1468 return (1); /* time's not up yet */ 1469 goto doseek; 1470 1471 default: 1472 fdcstatus(&fd->sc_dv, 0, "stray interrupt"); 1473 return (1); 1474 } 1475 #ifdef DIAGNOSTIC 1476 panic("fdcintr: impossible"); 1477 #endif 1478 #undef st0 1479 #undef st1 1480 #undef cyl 1481 } 1482 1483 void 1484 fdcretry(struct fdc_softc *fdc) 1485 { 1486 char bits[64]; 1487 struct fd_softc *fd; 1488 struct buf *bp; 1489 1490 fd = fdc->sc_drives.tqh_first; 1491 bp = BUFQ_PEEK(fd->sc_q); 1492 1493 fdc->sc_overruns = 0; 1494 if (fd->sc_opts & FDOPT_NORETRY) 1495 goto fail; 1496 1497 switch (fdc->sc_errors) { 1498 case 0: 1499 /* try again */ 1500 fdc->sc_state = 1501 (fdc->sc_flags & FDC_EIS) ? DOIO : DOSEEK; 1502 break; 1503 1504 case 1: case 2: case 3: 1505 /* didn't work; try recalibrating */ 1506 fdc->sc_state = DORECAL; 1507 break; 1508 1509 case 4: 1510 /* still no go; reset the bastard */ 1511 fdc->sc_state = DORESET; 1512 break; 1513 1514 default: 1515 fail: 1516 if ((fd->sc_opts & FDOPT_SILENT) == 0) { 1517 diskerr(bp, "fd", "hard error", LOG_PRINTF, 1518 fd->sc_skip / FDC_BSIZE, 1519 (struct disklabel *)NULL); 1520 1521 printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0], 1522 NE7_ST0BITS, bits, sizeof(bits))); 1523 printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1], 1524 NE7_ST1BITS, bits, sizeof(bits))); 1525 printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2], 1526 NE7_ST2BITS, bits, sizeof(bits))); 1527 printf(" cyl %d head %d sec %d)\n", 1528 fdc->sc_status[3], fdc->sc_status[4], 1529 fdc->sc_status[5]); 1530 } 1531 1532 bp->b_flags |= B_ERROR; 1533 bp->b_error = EIO; 1534 fdfinish(fd, bp); 1535 } 1536 fdc->sc_errors++; 1537 } 1538 1539 int 1540 fdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct lwp *l) 1541 { 1542 struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)]; 1543 struct fdformat_parms *form_parms; 1544 struct fdformat_cmd *form_cmd; 1545 struct ne7_fd_formb *fd_formb; 1546 int il[FD_MAX_NSEC + 1]; 1547 int i, j; 1548 int error; 1549 1550 switch (cmd) { 1551 case DIOCGDINFO: 1552 *(struct disklabel *)addr = *(fd->sc_dk.dk_label); 1553 return 0; 1554 1555 case DIOCWLABEL: 1556 if ((flag & FWRITE) == 0) 1557 return EBADF; 1558 /* XXX do something */ 1559 return (0); 1560 1561 case DIOCWDINFO: 1562 if ((flag & FWRITE) == 0) 1563 return (EBADF); 1564 1565 error = setdisklabel(fd->sc_dk.dk_label, 1566 (struct disklabel *)addr, 0, 1567 fd->sc_dk.dk_cpulabel); 1568 if (error) 1569 return (error); 1570 1571 error = writedisklabel(dev, fdstrategy, 1572 fd->sc_dk.dk_label, 1573 fd->sc_dk.dk_cpulabel); 1574 return (error); 1575 1576 case DIOCLOCK: 1577 /* 1578 * Nothing to do here, really. 1579 */ 1580 return (0); 1581 1582 case DIOCEJECT: 1583 if (*(int *)addr == 0) { 1584 int part = DISKPART(dev); 1585 /* 1586 * Don't force eject: check that we are the only 1587 * partition open. If so, unlock it. 1588 */ 1589 if ((fd->sc_dk.dk_openmask & ~(1 << part)) != 0 || 1590 fd->sc_dk.dk_bopenmask + fd->sc_dk.dk_copenmask != 1591 fd->sc_dk.dk_openmask) { 1592 return (EBUSY); 1593 } 1594 } 1595 /* FALLTHROUGH */ 1596 case ODIOCEJECT: 1597 fd_do_eject((void *)device_parent(&fd->sc_dv), fd->sc_drive); 1598 return (0); 1599 1600 case FDIOCGETFORMAT: 1601 form_parms = (struct fdformat_parms *)addr; 1602 form_parms->fdformat_version = FDFORMAT_VERSION; 1603 form_parms->nbps = 128 * (1 << fd->sc_type->secsize); 1604 form_parms->ncyl = fd->sc_type->tracks; 1605 form_parms->nspt = fd->sc_type->sectrac; 1606 form_parms->ntrk = fd->sc_type->heads; 1607 form_parms->stepspercyl = fd->sc_type->step; 1608 form_parms->gaplen = fd->sc_type->gap2; 1609 form_parms->fillbyte = fd->sc_type->fillbyte; 1610 form_parms->interleave = fd->sc_type->interleave; 1611 switch (fd->sc_type->rate) { 1612 case FDC_500KBPS: 1613 form_parms->xfer_rate = 500 * 1024; 1614 break; 1615 case FDC_300KBPS: 1616 form_parms->xfer_rate = 300 * 1024; 1617 break; 1618 case FDC_250KBPS: 1619 form_parms->xfer_rate = 250 * 1024; 1620 break; 1621 default: 1622 return (EINVAL); 1623 } 1624 return (0); 1625 1626 case FDIOCSETFORMAT: 1627 if ((flag & FWRITE) == 0) 1628 return (EBADF); /* must be opened for writing */ 1629 1630 form_parms = (struct fdformat_parms *)addr; 1631 if (form_parms->fdformat_version != FDFORMAT_VERSION) 1632 return (EINVAL);/* wrong version of formatting prog */ 1633 1634 i = form_parms->nbps >> 7; 1635 if ((form_parms->nbps & 0x7f) || ffs(i) == 0 || 1636 i & ~(1 << (ffs(i)-1))) 1637 /* not a power-of-two multiple of 128 */ 1638 return (EINVAL); 1639 1640 switch (form_parms->xfer_rate) { 1641 case 500 * 1024: 1642 fd->sc_type->rate = FDC_500KBPS; 1643 break; 1644 case 300 * 1024: 1645 fd->sc_type->rate = FDC_300KBPS; 1646 break; 1647 case 250 * 1024: 1648 fd->sc_type->rate = FDC_250KBPS; 1649 break; 1650 default: 1651 return (EINVAL); 1652 } 1653 1654 if (form_parms->nspt > FD_MAX_NSEC || 1655 form_parms->fillbyte > 0xff || 1656 form_parms->interleave > 0xff) 1657 return EINVAL; 1658 fd->sc_type->sectrac = form_parms->nspt; 1659 if (form_parms->ntrk != 2 && form_parms->ntrk != 1) 1660 return EINVAL; 1661 fd->sc_type->heads = form_parms->ntrk; 1662 fd->sc_type->seccyl = form_parms->nspt * form_parms->ntrk; 1663 fd->sc_type->secsize = ffs(i)-1; 1664 fd->sc_type->gap2 = form_parms->gaplen; 1665 fd->sc_type->tracks = form_parms->ncyl; 1666 fd->sc_type->size = fd->sc_type->seccyl * form_parms->ncyl * 1667 form_parms->nbps / DEV_BSIZE; 1668 fd->sc_type->step = form_parms->stepspercyl; 1669 fd->sc_type->fillbyte = form_parms->fillbyte; 1670 fd->sc_type->interleave = form_parms->interleave; 1671 return (0); 1672 1673 case FDIOCFORMAT_TRACK: 1674 if((flag & FWRITE) == 0) 1675 /* must be opened for writing */ 1676 return (EBADF); 1677 form_cmd = (struct fdformat_cmd *)addr; 1678 if (form_cmd->formatcmd_version != FDFORMAT_VERSION) 1679 /* wrong version of formatting prog */ 1680 return (EINVAL); 1681 1682 if (form_cmd->head >= fd->sc_type->heads || 1683 form_cmd->cylinder >= fd->sc_type->tracks) { 1684 return (EINVAL); 1685 } 1686 1687 fd_formb = malloc(sizeof(struct ne7_fd_formb), 1688 M_TEMP, M_NOWAIT); 1689 if (fd_formb == 0) 1690 return (ENOMEM); 1691 1692 fd_formb->head = form_cmd->head; 1693 fd_formb->cyl = form_cmd->cylinder; 1694 fd_formb->transfer_rate = fd->sc_type->rate; 1695 fd_formb->fd_formb_secshift = fd->sc_type->secsize; 1696 fd_formb->fd_formb_nsecs = fd->sc_type->sectrac; 1697 fd_formb->fd_formb_gaplen = fd->sc_type->gap2; 1698 fd_formb->fd_formb_fillbyte = fd->sc_type->fillbyte; 1699 1700 memset(il, 0, sizeof(il)); 1701 for (j = 0, i = 1; i <= fd_formb->fd_formb_nsecs; i++) { 1702 while (il[(j%fd_formb->fd_formb_nsecs) + 1]) 1703 j++; 1704 il[(j%fd_formb->fd_formb_nsecs) + 1] = i; 1705 j += fd->sc_type->interleave; 1706 } 1707 for (i = 0; i < fd_formb->fd_formb_nsecs; i++) { 1708 fd_formb->fd_formb_cylno(i) = form_cmd->cylinder; 1709 fd_formb->fd_formb_headno(i) = form_cmd->head; 1710 fd_formb->fd_formb_secno(i) = il[i+1]; 1711 fd_formb->fd_formb_secsize(i) = fd->sc_type->secsize; 1712 } 1713 1714 error = fdformat(dev, fd_formb, l->l_proc); 1715 free(fd_formb, M_TEMP); 1716 return (error); 1717 1718 case FDIOCGETOPTS: /* get drive options */ 1719 *(int *)addr = fd->sc_opts; 1720 return (0); 1721 1722 case FDIOCSETOPTS: /* set drive options */ 1723 fd->sc_opts = *(int *)addr; 1724 return (0); 1725 1726 #ifdef DEBUG 1727 case _IO('f', 100): 1728 { 1729 int i; 1730 struct fdc_softc *fdc = (struct fdc_softc *) 1731 device_parent(&fd->sc_dv); 1732 1733 out_fdc(fdc, NE7CMD_DUMPREG); 1734 fdcresult(fdc); 1735 printf("dumpreg(%d regs): <", fdc->sc_nstat); 1736 for (i = 0; i < fdc->sc_nstat; i++) 1737 printf(" %x", fdc->sc_status[i]); 1738 printf(">\n"); 1739 } 1740 1741 return (0); 1742 case _IOW('f', 101, int): 1743 ((struct fdc_softc *)device_parent(&fd->sc_dv))->sc_cfg &= 1744 ~CFG_THRHLD_MASK; 1745 ((struct fdc_softc *)device_parent(&fd->sc_dv))->sc_cfg |= 1746 (*(int *)addr & CFG_THRHLD_MASK); 1747 fdconf((struct fdc_softc *)device_parent(&fd->sc_dv)); 1748 return (0); 1749 case _IO('f', 102): 1750 { 1751 int i; 1752 struct fdc_softc *fdc = (struct fdc_softc *) 1753 device_parent(&fd->sc_dv); 1754 out_fdc(fdc, NE7CMD_SENSEI); 1755 fdcresult(fdc); 1756 printf("sensei(%d regs): <", fdc->sc_nstat); 1757 for (i=0; i< fdc->sc_nstat; i++) 1758 printf(" 0x%x", fdc->sc_status[i]); 1759 } 1760 printf(">\n"); 1761 return (0); 1762 #endif 1763 default: 1764 return (ENOTTY); 1765 } 1766 1767 #ifdef DIAGNOSTIC 1768 panic("fdioctl: impossible"); 1769 #endif 1770 } 1771 1772 int 1773 fdformat(dev_t dev, struct ne7_fd_formb *finfo, struct proc *p) 1774 { 1775 int rv = 0, s; 1776 struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)]; 1777 struct fd_type *type = fd->sc_type; 1778 struct buf *bp; 1779 1780 /* set up a buffer header for fdstrategy() */ 1781 bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT); 1782 if (bp == 0) 1783 return (ENOBUFS); 1784 1785 memset((void *)bp, 0, sizeof(struct buf)); 1786 bp->b_flags = B_BUSY | B_PHYS | B_FORMAT; 1787 bp->b_proc = p; 1788 bp->b_dev = dev; 1789 1790 /* 1791 * Calculate a fake blkno, so fdstrategy() would initiate a 1792 * seek to the requested cylinder. 1793 */ 1794 bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads) 1795 + finfo->head * type->sectrac) * FDC_BSIZE / DEV_BSIZE; 1796 1797 bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs; 1798 bp->b_data = (caddr_t)finfo; 1799 1800 #ifdef FD_DEBUG 1801 if (fdc_debug) 1802 printf("fdformat: blkno %x count %ld\n", 1803 bp->b_blkno, bp->b_bcount); 1804 #endif 1805 1806 /* now do the format */ 1807 fdstrategy(bp); 1808 1809 /* ...and wait for it to complete */ 1810 s = splbio(); 1811 while (!(bp->b_flags & B_DONE)) { 1812 rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 20 * hz); 1813 if (rv == EWOULDBLOCK) 1814 break; 1815 } 1816 splx(s); 1817 1818 if (rv == EWOULDBLOCK) { 1819 /* timed out */ 1820 rv = EIO; 1821 biodone(bp); 1822 } 1823 if (bp->b_flags & B_ERROR) { 1824 rv = bp->b_error; 1825 } 1826 free(bp, M_TEMP); 1827 return (rv); 1828 } 1829 1830 void 1831 fdgetdisklabel(dev_t dev) 1832 { 1833 int unit = FDUNIT(dev), i; 1834 struct fd_softc *fd = fd_cd.cd_devs[unit]; 1835 struct disklabel *lp = fd->sc_dk.dk_label; 1836 struct cpu_disklabel *clp = fd->sc_dk.dk_cpulabel; 1837 1838 memset(lp, 0, sizeof(struct disklabel)); 1839 memset(lp, 0, sizeof(struct cpu_disklabel)); 1840 1841 lp->d_type = DTYPE_FLOPPY; 1842 lp->d_secsize = FDC_BSIZE; 1843 lp->d_secpercyl = fd->sc_type->seccyl; 1844 lp->d_nsectors = fd->sc_type->sectrac; 1845 lp->d_ncylinders = fd->sc_type->tracks; 1846 lp->d_ntracks = fd->sc_type->heads; /* Go figure... */ 1847 lp->d_rpm = 3600; /* XXX like it matters... */ 1848 1849 strncpy(lp->d_typename, "floppy", sizeof(lp->d_typename)); 1850 strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname)); 1851 lp->d_interleave = 1; 1852 1853 lp->d_partitions[RAW_PART].p_offset = 0; 1854 lp->d_partitions[RAW_PART].p_size = lp->d_secpercyl * lp->d_ncylinders; 1855 lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED; 1856 lp->d_npartitions = RAW_PART + 1; 1857 1858 lp->d_magic = DISKMAGIC; 1859 lp->d_magic2 = DISKMAGIC; 1860 lp->d_checksum = dkcksum(lp); 1861 1862 /* 1863 * Call the generic disklabel extraction routine. If there's 1864 * not a label there, fake it. 1865 */ 1866 if (readdisklabel(dev, fdstrategy, lp, clp) != NULL) { 1867 strncpy(lp->d_packname, "default label", 1868 sizeof(lp->d_packname)); 1869 /* 1870 * Reset the partition info; it might have gotten 1871 * trashed in readdisklabel(). 1872 * 1873 * XXX Why do we have to do this? readdisklabel() 1874 * should be safe... 1875 */ 1876 for (i = 0; i < MAXPARTITIONS; ++i) { 1877 lp->d_partitions[i].p_offset = 0; 1878 if (i == RAW_PART) { 1879 lp->d_partitions[i].p_size = 1880 lp->d_secpercyl * lp->d_ncylinders; 1881 lp->d_partitions[i].p_fstype = FS_BSDFFS; 1882 } else { 1883 lp->d_partitions[i].p_size = 0; 1884 lp->d_partitions[i].p_fstype = FS_UNUSED; 1885 } 1886 } 1887 lp->d_npartitions = RAW_PART + 1; 1888 } 1889 } 1890 1891 void 1892 fd_do_eject(struct fdc_softc *fdc, int unit) 1893 { 1894 fdc->sc_fcr |= FCR_DSEL(unit)|FCR_EJECT; 1895 FCR_REG_SYNC(); 1896 delay(10); 1897 fdc->sc_fcr &= ~(FCR_DSEL(unit)|FCR_EJECT); 1898 FCR_REG_SYNC(); 1899 } 1900 1901 #ifdef MEMORY_DISK_HOOKS_sun3x_not_yet 1902 int fd_read_md_image(size_t *, caddr_t *); 1903 #endif 1904 1905 /* ARGSUSED */ 1906 void 1907 fd_mountroot_hook(struct device *dev) 1908 { 1909 int c; 1910 1911 fd_do_eject(fdc_cd.cd_devs[0], 0); /* XXX - doesn't check ``dev'' */ 1912 printf("Insert filesystem floppy and press return."); 1913 for (;;) { 1914 c = cngetc(); 1915 if ((c == '\r') || (c == '\n')) { 1916 printf("\n"); 1917 break; 1918 } 1919 } 1920 #ifdef MEMORY_DISK_HOOKS_sun3x_not_yet 1921 { 1922 extern int (*md_read_image)(size_t *, caddr_t *); 1923 md_read_image = fd_read_md_image; 1924 } 1925 #endif 1926 } 1927 1928 #ifdef MEMORY_DISK_HOOKS_sun3x_not_yet 1929 1930 #define FDMICROROOTSIZE ((2*18*80) << DEV_BSHIFT) 1931 1932 int 1933 fd_read_md_image(size_t *sizep, caddr_t *addrp) 1934 { 1935 struct buf buf, *bp = &buf; 1936 dev_t dev; 1937 off_t offset; 1938 caddr_t addr; 1939 1940 dev = makedev(54,0); /* XXX */ 1941 1942 MALLOC(addr, caddr_t, FDMICROROOTSIZE, M_DEVBUF, M_WAITOK); 1943 *addrp = addr; 1944 1945 if (fdopen(dev, 0, S_IFCHR, NULL)) 1946 panic("fd: mountroot: fdopen"); 1947 1948 offset = 0; 1949 1950 for (;;) { 1951 bp->b_dev = dev; 1952 bp->b_error = 0; 1953 bp->b_resid = 0; 1954 bp->b_proc = NULL; 1955 bp->b_flags = B_BUSY | B_PHYS | B_RAW | B_READ; 1956 bp->b_blkno = btodb(offset); 1957 bp->b_bcount = DEV_BSIZE; 1958 bp->b_data = addr; 1959 fdstrategy(bp); 1960 while ((bp->b_flags & B_DONE) == 0) { 1961 tsleep((caddr_t)bp, PRIBIO + 1, "physio", 0); 1962 } 1963 if (bp->b_error) 1964 panic("fd: mountroot: fdread error %d", bp->b_error); 1965 1966 if (bp->b_resid != 0) 1967 break; 1968 1969 addr += DEV_BSIZE; 1970 offset += DEV_BSIZE; 1971 if (offset + DEV_BSIZE > FDMICROROOTSIZE) 1972 break; 1973 } 1974 (void)fdclose(dev, 0, S_IFCHR, NULL); 1975 *sizep = offset; 1976 fd_do_eject(fdc_cd.cd_devs[0], FDUNIT(dev)); /* XXX */ 1977 return (0); 1978 } 1979 #endif 1980