1 /* $NetBSD: fd.c,v 1.52 2006/10/14 08:11:16 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.52 2006/10/14 08:11:16 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 /* 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 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() softintr_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 = (caddr_t)bus_mapin(ca->ca_bustype, ca->ca_paddr, 406 sizeof(union fdreg)); 407 408 callout_init(&fdc->sc_timo_ch); 409 callout_init(&fdc->sc_intr_ch); 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 = softintr_establish(IPL_SOFTFD, fdcswintr, fdc); 445 printf(": (softpri %d) chip 8207%c\n", FDC_SOFTPRI, code); 446 447 #ifdef FD_DEBUG 448 if (out_fdc(fdc, NE7CMD_VERSION) == 0 && 449 fdcresult(fdc) == 1 && fdc->sc_status[0] == 0x90) { 450 if (fdc_debug) 451 printf("[version cmd]"); 452 } 453 #endif 454 455 fdc_reset(fdc); 456 /* 457 * Configure controller; enable FIFO, Implied seek, no POLL mode?. 458 * Note: CFG_EFIFO is active-low, initial threshold value: 8 459 */ 460 fdc->sc_cfg = CFG_EIS|/*CFG_EFIFO|*/CFG_POLL|(8 & CFG_THRHLD_MASK); 461 fdconf(fdc); 462 463 evcnt_attach_dynamic(&fdc->sc_intrcnt, EVCNT_TYPE_INTR, NULL, 464 fdc->sc_dev.dv_xname, "intr"); 465 466 /* physical limit: four drives per controller. */ 467 for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) { 468 fa.fa_deftype = NULL; /* unknown */ 469 fa.fa_deftype = &fd_types[0]; /* XXX */ 470 (void)config_found(self, (void *)&fa, fdprint); 471 } 472 } 473 474 int 475 fdmatch(struct device *parent, struct cfdata *match, void *aux) 476 { 477 struct fdc_softc *fdc = (void *)parent; 478 struct fdc_attach_args *fa = aux; 479 int drive = fa->fa_drive; 480 int n, ok; 481 482 if (drive > 0) 483 /* XXX - for now, punt > 1 drives */ 484 return (0); 485 486 /* select drive and turn on motor */ 487 fdc->sc_fcr |= FCR_DSEL(drive) | FCR_MTRON; 488 FCR_REG_SYNC(); 489 /* wait for motor to spin up */ 490 delay(250000); 491 492 fdc->sc_nstat = 0; 493 out_fdc(fdc, NE7CMD_RECAL); 494 out_fdc(fdc, drive); 495 /* wait for recalibrate */ 496 for (n = 0; n < 10000; n++) { 497 delay(1000); 498 if ((*fdc->sc_reg_msr & (NE7_RQM|NE7_DIO|NE7_CB)) == NE7_RQM) { 499 /* wait a bit longer till device *really* is ready */ 500 delay(100000); 501 if (out_fdc(fdc, NE7CMD_SENSEI)) 502 break; 503 if (fdcresult(fdc) == 1 && fdc->sc_status[0] == 0x80) 504 /* 505 * Got `invalid command'; we interpret it 506 * to mean that the re-calibrate hasn't in 507 * fact finished yet 508 */ 509 continue; 510 break; 511 } 512 } 513 n = fdc->sc_nstat; 514 #ifdef FD_DEBUG 515 if (fdc_debug) { 516 int i; 517 printf("fdprobe: %d stati:", n); 518 for (i = 0; i < n; i++) 519 printf(" %x", fdc->sc_status[i]); 520 printf("\n"); 521 } 522 #endif 523 ok = (n == 2 && (fdc->sc_status[0] & 0xf8) == 0x20) ? 1 : 0; 524 525 /* turn off motor */ 526 fdc->sc_fcr &= ~(FCR_DSEL(drive)|FCR_MTRON); 527 FCR_REG_SYNC(); 528 529 return (ok); 530 } 531 532 /* 533 * Controller is working, and drive responded. Attach it. 534 */ 535 void 536 fdattach(struct device *parent, struct device *self, void *aux) 537 { 538 struct fdc_softc *fdc = (void *)parent; 539 struct fd_softc *fd = (void *)self; 540 struct fdc_attach_args *fa = aux; 541 struct fd_type *type = fa->fa_deftype; 542 int drive = fa->fa_drive; 543 544 callout_init(&fd->sc_motoron_ch); 545 callout_init(&fd->sc_motoroff_ch); 546 547 /* XXX Allow `flags' to override device type? */ 548 549 if (type) 550 printf(": %s %d cyl, %d head, %d sec\n", type->name, 551 type->tracks, type->heads, type->sectrac); 552 else 553 printf(": density unknown\n"); 554 555 bufq_alloc(&fd->sc_q, "disksort", BUFQ_SORT_CYLINDER); 556 fd->sc_cylin = -1; 557 fd->sc_drive = drive; 558 fd->sc_deftype = type; 559 fdc->sc_fd[drive] = fd; 560 561 /* 562 * Initialize and attach the disk structure. 563 */ 564 fd->sc_dk.dk_name = fd->sc_dv.dv_xname; 565 fd->sc_dk.dk_driver = &fddkdriver; 566 disk_attach(&fd->sc_dk); 567 568 #ifdef sparc 569 /* 570 * We're told if we're the boot device in fdcattach(). 571 */ 572 if (fa->fa_bootpath) 573 fa->fa_bootpath->dev = &fd->sc_dv; 574 #endif 575 #define OUT_FDC(sc, c) { \ 576 if (out_fdc((sc), (c))) \ 577 printf("fdc: specify command failed.\n");\ 578 } 579 /* specify command */ 580 OUT_FDC(fdc, NE7CMD_SPECIFY); 581 OUT_FDC(fdc, type->steprate); 582 /* 583 * The '|1' in the following statement turns on the 'Non-DMA' bit 584 * specifier in the last byte of the SPECIFY command as described in the 585 * datasheet I have. This is necessary for the driver to work on the 586 * sun3x, because the system will not respond to the chip's requests 587 * for DMA; there is no hardware on the motherboard to support it. 588 * By enabling this bit, we will force the chip to interrupt when its 589 * FIFO is full, at which point the interrupt handler will empty it and 590 * continue. This is ``pseudo-DMA''. 591 * -J 592 */ 593 OUT_FDC(fdc, 6|1); /* XXX head load time == 6ms */ 594 #undef OUT_FDC 595 596 /* 597 * Establish a mountroot_hook anyway in case we booted 598 * with RB_ASKNAME and get selected as the boot device. 599 */ 600 mountroothook_establish(fd_mountroot_hook, &fd->sc_dv); 601 602 /* Make sure the drive motor gets turned off at shutdown time. */ 603 fd->sc_sdhook = shutdownhook_establish(fd_motor_off, fd); 604 } 605 606 inline struct fd_type * 607 fd_dev_to_type(struct fd_softc *fd, dev_t dev) 608 { 609 int type = FDTYPE(dev); 610 611 if (type > (sizeof(fd_types) / sizeof(fd_types[0]))) 612 return (NULL); 613 return (type ? &fd_types[type - 1] : fd->sc_deftype); 614 } 615 616 void 617 fdstrategy(struct buf *bp /* IO operation to perform */) 618 { 619 struct fd_softc *fd; 620 int unit = FDUNIT(bp->b_dev); 621 int sz; 622 int s; 623 624 /* Valid unit, controller, and request? */ 625 if (unit >= fd_cd.cd_ndevs || 626 (fd = fd_cd.cd_devs[unit]) == 0 || 627 bp->b_blkno < 0 || 628 ((bp->b_bcount % FDC_BSIZE) != 0 && 629 (bp->b_flags & B_FORMAT) == 0)) { 630 bp->b_error = EINVAL; 631 goto bad; 632 } 633 634 /* If it's a null transfer, return immediately. */ 635 if (bp->b_bcount == 0) 636 goto done; 637 638 sz = howmany(bp->b_bcount, FDC_BSIZE); 639 640 if (bp->b_blkno + sz > fd->sc_type->size) { 641 sz = fd->sc_type->size - bp->b_blkno; 642 if (sz == 0) { 643 /* If exactly at end of disk, return EOF. */ 644 bp->b_resid = bp->b_bcount; 645 goto done; 646 } 647 if (sz < 0) { 648 /* If past end of disk, return EINVAL. */ 649 bp->b_error = EINVAL; 650 goto bad; 651 } 652 /* Otherwise, truncate request. */ 653 bp->b_bcount = sz << DEV_BSHIFT; 654 } 655 656 bp->b_rawblkno = bp->b_blkno; 657 bp->b_cylinder = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE) / fd->sc_type->seccyl; 658 659 #ifdef FD_DEBUG 660 if (fdc_debug > 1) 661 printf("fdstrategy: b_blkno %d b_bcount %d blkno %d cylin %d\n", 662 (int)bp->b_blkno, bp->b_bcount, (int)fd->sc_blkno, bp->b_cylinder); 663 #endif 664 665 /* Queue transfer on drive, activate drive and controller if idle. */ 666 s = splbio(); 667 BUFQ_PUT(fd->sc_q, bp); 668 callout_stop(&fd->sc_motoroff_ch); /* a good idea */ 669 if (fd->sc_active == 0) 670 fdstart(fd); 671 #ifdef DIAGNOSTIC 672 else { 673 struct fdc_softc *fdc = (void *)device_parent(&fd->sc_dv); 674 if (fdc->sc_state == DEVIDLE) { 675 printf("fdstrategy: controller inactive\n"); 676 fdcstart(fdc); 677 } 678 } 679 #endif 680 splx(s); 681 return; 682 683 bad: 684 bp->b_flags |= B_ERROR; 685 done: 686 /* Toss transfer; we're done early. */ 687 biodone(bp); 688 } 689 690 void 691 fdstart(struct fd_softc *fd) 692 { 693 struct fdc_softc *fdc = (void *)device_parent(&fd->sc_dv); 694 int active = fdc->sc_drives.tqh_first != 0; 695 696 /* Link into controller queue. */ 697 fd->sc_active = 1; 698 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain); 699 700 /* If controller not already active, start it. */ 701 if (!active) 702 fdcstart(fdc); 703 } 704 705 void 706 fdfinish(struct fd_softc *fd, struct buf *bp) 707 { 708 struct fdc_softc *fdc = (void *)device_parent(&fd->sc_dv); 709 710 /* 711 * Move this drive to the end of the queue to give others a `fair' 712 * chance. We only force a switch if N operations are completed while 713 * another drive is waiting to be serviced, since there is a long motor 714 * startup delay whenever we switch. 715 */ 716 (void)BUFQ_GET(fd->sc_q); 717 if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) { 718 fd->sc_ops = 0; 719 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain); 720 if (BUFQ_PEEK(fd->sc_q) != NULL) { 721 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain); 722 } else 723 fd->sc_active = 0; 724 } 725 bp->b_resid = fd->sc_bcount; 726 fd->sc_skip = 0; 727 728 biodone(bp); 729 /* turn off motor 5s from now */ 730 callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd); 731 fdc->sc_state = DEVIDLE; 732 } 733 734 void 735 fdc_reset(struct fdc_softc *fdc) 736 { 737 fdc->sc_fcr = 0; 738 FCR_REG_SYNC(); 739 740 *fdc->sc_reg_drs = DRS_RESET; 741 delay(10); 742 *fdc->sc_reg_drs = 0; 743 744 #ifdef FD_DEBUG 745 if (fdc_debug) 746 printf("fdc reset\n"); 747 #endif 748 } 749 750 void 751 fd_set_motor(struct fdc_softc *fdc) 752 { 753 struct fd_softc *fd; 754 int n; 755 756 int on = 0; 757 758 for (n = 0; n < 4; n++) 759 if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR)) 760 on = 1; 761 if (on) { 762 fdc->sc_fcr |= FCR_DSEL(0)|FCR_MTRON; /* XXX */ 763 } else { 764 fdc->sc_fcr &= ~(FCR_DSEL(0)|FCR_MTRON); /* XXX */ 765 } 766 FCR_REG_SYNC(); 767 } 768 769 void 770 fd_motor_off(void *arg) 771 { 772 struct fd_softc *fd = arg; 773 int s; 774 775 s = splbio(); 776 fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT); 777 fd_set_motor((struct fdc_softc *)device_parent(&fd->sc_dv)); 778 splx(s); 779 } 780 781 void 782 fd_motor_on(void *arg) 783 { 784 struct fd_softc *fd = arg; 785 struct fdc_softc *fdc = (void *)device_parent(&fd->sc_dv); 786 int s; 787 788 s = splbio(); 789 fd->sc_flags &= ~FD_MOTOR_WAIT; 790 if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT)) 791 (void) fdcstate(fdc); 792 splx(s); 793 } 794 795 int 796 fdcresult(struct fdc_softc *fdc) 797 { 798 u_char i; 799 int j = 100000, 800 n = 0; 801 802 for (; j; j--) { 803 i = *fdc->sc_reg_msr & (NE7_DIO | NE7_RQM | NE7_CB); 804 if (i == NE7_RQM) 805 return (fdc->sc_nstat = n); 806 if (i == (NE7_DIO | NE7_RQM | NE7_CB)) { 807 if (n >= sizeof(fdc->sc_status)) { 808 log(LOG_ERR, "fdcresult: overrun\n"); 809 return (-1); 810 } 811 fdc->sc_status[n++] = *fdc->sc_reg_fifo; 812 } else 813 delay(10); 814 } 815 log(LOG_ERR, "fdcresult: timeout\n"); 816 return (fdc->sc_nstat = -1); 817 } 818 819 int 820 out_fdc(struct fdc_softc *fdc, u_char x) 821 { 822 int i = 100000; 823 824 while (((*fdc->sc_reg_msr & (NE7_DIO|NE7_RQM)) != NE7_RQM) && i-- > 0) 825 delay(1); 826 if (i <= 0) 827 return (-1); 828 829 *fdc->sc_reg_fifo = x; 830 return (0); 831 } 832 833 int 834 fdopen(dev_t dev, int flags, int fmt, struct lwp *l) 835 { 836 int unit, pmask; 837 struct fd_softc *fd; 838 struct fd_type *type; 839 840 unit = FDUNIT(dev); 841 if (unit >= fd_cd.cd_ndevs) 842 return (ENXIO); 843 fd = fd_cd.cd_devs[unit]; 844 if (fd == 0) 845 return (ENXIO); 846 type = fd_dev_to_type(fd, dev); 847 if (type == NULL) 848 return (ENXIO); 849 850 if ((fd->sc_flags & FD_OPEN) != 0 && 851 fd->sc_type != type) 852 return (EBUSY); 853 854 fd->sc_type = type; 855 fd->sc_cylin = -1; 856 fd->sc_flags |= FD_OPEN; 857 858 /* 859 * Only update the disklabel if we're not open anywhere else. 860 */ 861 if (fd->sc_dk.dk_openmask == 0) 862 fdgetdisklabel(dev); 863 864 pmask = (1 << DISKPART(dev)); 865 866 switch (fmt) { 867 case S_IFCHR: 868 fd->sc_dk.dk_copenmask |= pmask; 869 break; 870 871 case S_IFBLK: 872 fd->sc_dk.dk_bopenmask |= pmask; 873 break; 874 } 875 fd->sc_dk.dk_openmask = 876 fd->sc_dk.dk_copenmask | fd->sc_dk.dk_bopenmask; 877 878 return (0); 879 } 880 881 int 882 fdclose(dev_t dev, int flags, int fmt, struct lwp *l) 883 { 884 struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)]; 885 int pmask = (1 << DISKPART(dev)); 886 887 fd->sc_flags &= ~FD_OPEN; 888 fd->sc_opts &= ~(FDOPT_NORETRY|FDOPT_SILENT); 889 890 switch (fmt) { 891 case S_IFCHR: 892 fd->sc_dk.dk_copenmask &= ~pmask; 893 break; 894 895 case S_IFBLK: 896 fd->sc_dk.dk_bopenmask &= ~pmask; 897 break; 898 } 899 fd->sc_dk.dk_openmask = 900 fd->sc_dk.dk_copenmask | fd->sc_dk.dk_bopenmask; 901 902 return (0); 903 } 904 905 int 906 fdread(dev_t dev, struct uio *uio, int flag) 907 { 908 909 return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio)); 910 } 911 912 int 913 fdwrite(dev_t dev, struct uio *uio, int flag) 914 { 915 916 return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio)); 917 } 918 919 void 920 fdcstart(struct fdc_softc *fdc) 921 { 922 923 #ifdef DIAGNOSTIC 924 /* only got here if controller's drive queue was inactive; should 925 be in idle state */ 926 if (fdc->sc_state != DEVIDLE) { 927 printf("fdcstart: not idle\n"); 928 return; 929 } 930 #endif 931 (void) fdcstate(fdc); 932 } 933 934 void 935 fdcstatus(struct device *dv, int n, const char *s) 936 { 937 struct fdc_softc *fdc = (void *)device_parent(dv); 938 char bits[64]; 939 #if 0 940 /* 941 * A 82072 seems to return <invalid command> on 942 * gratuitous Sense Interrupt commands. 943 */ 944 if (n == 0 && (fdc->sc_flags & FDC_82077)) { 945 out_fdc(fdc, NE7CMD_SENSEI); 946 (void) fdcresult(fdc); 947 n = 2; 948 } 949 #endif 950 951 /* Just print last status */ 952 n = fdc->sc_nstat; 953 954 printf("%s: %s: state %d", dv->dv_xname, s, fdc->sc_state); 955 956 switch (n) { 957 case 0: 958 printf("\n"); 959 break; 960 case 2: 961 printf(" (st0 %s cyl %d)\n", 962 bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS, 963 bits, sizeof(bits)), fdc->sc_status[1]); 964 break; 965 case 7: 966 printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0], 967 NE7_ST0BITS, bits, sizeof(bits))); 968 printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1], 969 NE7_ST1BITS, bits, sizeof(bits))); 970 printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2], 971 NE7_ST2BITS, bits, sizeof(bits))); 972 printf(" cyl %d head %d sec %d)\n", 973 fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]); 974 break; 975 #ifdef DIAGNOSTIC 976 default: 977 printf(" fdcstatus: weird size: %d\n", n); 978 break; 979 #endif 980 } 981 } 982 983 void 984 fdctimeout(void *arg) 985 { 986 struct fdc_softc *fdc = arg; 987 struct fd_softc *fd = fdc->sc_drives.tqh_first; 988 int s; 989 990 s = splbio(); 991 fdcstatus(&fd->sc_dv, 0, "timeout"); 992 993 if (BUFQ_PEEK(fd->sc_q) != NULL) 994 fdc->sc_state++; 995 else 996 fdc->sc_state = DEVIDLE; 997 998 (void) fdcstate(fdc); 999 splx(s); 1000 } 1001 1002 void 1003 fdcpseudointr(void *arg) 1004 { 1005 struct fdc_softc *fdc = arg; 1006 int s; 1007 1008 /* Just ensure it has the right spl. */ 1009 s = splbio(); 1010 (void) fdcstate(fdc); 1011 splx(s); 1012 } 1013 1014 1015 /* 1016 * hardware interrupt entry point: must be converted to `fast' 1017 * (in-window) handler. 1018 */ 1019 int 1020 fdchwintr(void *arg) 1021 { 1022 struct fdc_softc *fdc = arg; 1023 1024 /* 1025 * This code was reverse engineered from the SPARC bsd_fdintr.s. 1026 */ 1027 switch (fdc->sc_istate) { 1028 case ISTATE_IDLE: 1029 return (0); 1030 case ISTATE_SENSEI: 1031 out_fdc(fdc, NE7CMD_SENSEI); 1032 fdcresult(fdc); 1033 fdc->sc_istate = ISTATE_DONE; 1034 FD_SET_SWINTR(); 1035 return (1); 1036 case ISTATE_DMA: 1037 break; 1038 default: 1039 log(LOG_ERR, "fdc: stray hard interrupt.\n"); 1040 fdc->sc_fcr &= ~(FCR_DSEL(0)); /* Does this help? */ 1041 fdc->sc_istate = ISTATE_SPURIOUS; 1042 FD_SET_SWINTR(); 1043 return (1); 1044 } 1045 1046 for (;;) { 1047 int msr; 1048 1049 msr = *fdc->sc_reg_msr; 1050 1051 if ((msr & NE7_RQM) == 0) 1052 break; 1053 1054 if ((msr & NE7_NDM) == 0) { 1055 fdcresult(fdc); 1056 fdc->sc_istate = ISTATE_DONE; 1057 FD_SET_SWINTR(); 1058 log(LOG_ERR, "fdc: overrun: tc = %d\n", fdc->sc_tc); 1059 break; 1060 } 1061 1062 if (msr & NE7_DIO) { 1063 *fdc->sc_data++ = *fdc->sc_reg_fifo; 1064 } else { 1065 *fdc->sc_reg_fifo = *fdc->sc_data++; 1066 } 1067 if (--fdc->sc_tc == 0) { 1068 fdc->sc_fcr |= FCR_TC; 1069 FCR_REG_SYNC(); 1070 fdc->sc_istate = ISTATE_DONE; 1071 delay(10); 1072 fdc->sc_fcr &= ~FCR_TC; 1073 FCR_REG_SYNC(); 1074 fdcresult(fdc); 1075 FD_SET_SWINTR(); 1076 break; 1077 } 1078 } 1079 return (1); 1080 } 1081 1082 void 1083 fdcswintr(void *arg) 1084 { 1085 struct fdc_softc *fdc = arg; 1086 int s; 1087 1088 if (fdc->sc_istate != ISTATE_DONE) 1089 return; 1090 1091 fdc->sc_istate = ISTATE_IDLE; 1092 s = splbio(); 1093 fdcstate(fdc); 1094 splx(s); 1095 return; 1096 } 1097 1098 int 1099 fdcstate(struct fdc_softc *fdc) 1100 { 1101 #define st0 fdc->sc_status[0] 1102 #define st1 fdc->sc_status[1] 1103 #define cyl fdc->sc_status[1] 1104 #define OUT_FDC(fdc, c, s) \ 1105 do { if (out_fdc(fdc, (c))) { (fdc)->sc_state = (s); goto loop; } } while(0) 1106 1107 struct fd_softc *fd; 1108 struct buf *bp; 1109 int read, head, sec, nblks; 1110 struct fd_type *type; 1111 struct ne7_fd_formb *finfo = NULL; 1112 1113 1114 if (fdc->sc_istate != ISTATE_IDLE) { 1115 /* Trouble... */ 1116 printf("fdc: spurious interrupt: state %d, istate=%d\n", 1117 fdc->sc_state, fdc->sc_istate); 1118 fdc->sc_istate = ISTATE_IDLE; 1119 if (fdc->sc_state == RESETCOMPLETE || 1120 fdc->sc_state == RESETTIMEDOUT) { 1121 panic("fdcintr: spurious interrupt can't be cleared"); 1122 } 1123 goto doreset; 1124 } 1125 1126 loop: 1127 /* Is there a drive for the controller to do a transfer with? */ 1128 fd = fdc->sc_drives.tqh_first; 1129 if (fd == NULL) { 1130 fdc->sc_state = DEVIDLE; 1131 return (0); 1132 } 1133 1134 /* Is there a transfer to this drive? If not, deactivate drive. */ 1135 bp = BUFQ_PEEK(fd->sc_q); 1136 if (bp == NULL) { 1137 fd->sc_ops = 0; 1138 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain); 1139 fd->sc_active = 0; 1140 goto loop; 1141 } 1142 1143 if (bp->b_flags & B_FORMAT) 1144 finfo = (struct ne7_fd_formb *)bp->b_data; 1145 1146 switch (fdc->sc_state) { 1147 case DEVIDLE: 1148 fdc->sc_errors = 0; 1149 fd->sc_skip = 0; 1150 fd->sc_bcount = bp->b_bcount; 1151 fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE); 1152 callout_stop(&fd->sc_motoroff_ch); 1153 if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) { 1154 fdc->sc_state = MOTORWAIT; 1155 return (1); 1156 } 1157 if ((fd->sc_flags & FD_MOTOR) == 0) { 1158 /* Turn on the motor, being careful about pairing. */ 1159 struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1]; 1160 if (ofd && ofd->sc_flags & FD_MOTOR) { 1161 callout_stop(&ofd->sc_motoroff_ch); 1162 ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT); 1163 } 1164 fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT; 1165 fd_set_motor(fdc); 1166 fdc->sc_state = MOTORWAIT; 1167 if (fdc->sc_flags & FDC_82077) { /* XXX */ 1168 /* Allow .25s for motor to stabilize. */ 1169 callout_reset(&fd->sc_motoron_ch, hz / 4, 1170 fd_motor_on, fd); 1171 } else { 1172 fd->sc_flags &= ~FD_MOTOR_WAIT; 1173 goto loop; 1174 } 1175 return (1); 1176 } 1177 /* Make sure the right drive is selected. */ 1178 fd_set_motor(fdc); 1179 1180 /*FALLTHROUGH*/ 1181 case DOSEEK: 1182 doseek: 1183 if ((fdc->sc_flags & FDC_EIS) && 1184 (bp->b_flags & B_FORMAT) == 0) { 1185 fd->sc_cylin = bp->b_cylinder; 1186 /* We use implied seek */ 1187 goto doio; 1188 } 1189 1190 if (fd->sc_cylin == bp->b_cylinder) 1191 goto doio; 1192 1193 /* specify command */ 1194 OUT_FDC(fdc, NE7CMD_SPECIFY, SEEKTIMEDOUT); 1195 OUT_FDC(fdc, fd->sc_type->steprate, SEEKTIMEDOUT); 1196 OUT_FDC(fdc, 6|1, SEEKTIMEDOUT); /* XXX head load time == 6ms */ 1197 1198 fdc->sc_istate = ISTATE_SENSEI; 1199 /* seek function */ 1200 OUT_FDC(fdc, NE7CMD_SEEK, SEEKTIMEDOUT); 1201 OUT_FDC(fdc, fd->sc_drive, SEEKTIMEDOUT); /* drive number */ 1202 OUT_FDC(fdc, bp->b_cylinder * fd->sc_type->step, SEEKTIMEDOUT); 1203 1204 fd->sc_cylin = -1; 1205 fdc->sc_state = SEEKWAIT; 1206 fdc->sc_nstat = 0; 1207 1208 iostat_seek(fd->sc_dk.dk_stats); 1209 disk_busy(&fd->sc_dk); 1210 1211 callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc); 1212 return (1); 1213 1214 case DOIO: 1215 doio: 1216 #ifdef NOTYET 1217 /* Check to see if the disk has changed */ 1218 if (fdc->sc_reg_dir & FDI_DCHG) { 1219 /* 1220 * The disk in the drive has changed since 1221 * the last transfer. We need to see if its geometry 1222 * has changed. 1223 */ 1224 } 1225 #endif /* NOTYET */ 1226 1227 if (finfo) 1228 fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) - 1229 (char *)finfo; 1230 type = fd->sc_type; 1231 sec = fd->sc_blkno % type->seccyl; 1232 nblks = type->seccyl - sec; 1233 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE); 1234 nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE); 1235 fd->sc_nblks = nblks; 1236 fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FDC_BSIZE; 1237 head = sec / type->sectrac; 1238 sec -= head * type->sectrac; 1239 #ifdef DIAGNOSTIC 1240 {int block; 1241 block = (fd->sc_cylin * type->heads + head) * type->sectrac + sec; 1242 if (block != fd->sc_blkno) { 1243 printf("fdcintr: block %d != blkno %" PRIu64 "\n", 1244 block, fd->sc_blkno); 1245 #ifdef DDB 1246 Debugger(); 1247 #endif 1248 }} 1249 #endif 1250 read = bp->b_flags & B_READ; 1251 1252 /* Setup for pseudo DMA */ 1253 fdc->sc_data = bp->b_data + fd->sc_skip; 1254 fdc->sc_tc = fd->sc_nbytes; 1255 1256 *fdc->sc_reg_drs = type->rate; 1257 #ifdef FD_DEBUG 1258 if (fdc_debug > 1) 1259 printf("fdcintr: %s drive %d track %d head %d sec %d nblks %d\n", 1260 read ? "read" : "write", fd->sc_drive, 1261 fd->sc_cylin, head, sec, nblks); 1262 #endif 1263 fdc->sc_state = IOCOMPLETE; 1264 fdc->sc_istate = ISTATE_DMA; 1265 fdc->sc_nstat = 0; 1266 if (finfo) { 1267 /* formatting */ 1268 OUT_FDC(fdc, NE7CMD_FORMAT, IOTIMEDOUT); 1269 OUT_FDC(fdc, (head << 2) | fd->sc_drive, IOTIMEDOUT); 1270 OUT_FDC(fdc, finfo->fd_formb_secshift, IOTIMEDOUT); 1271 OUT_FDC(fdc, finfo->fd_formb_nsecs, IOTIMEDOUT); 1272 OUT_FDC(fdc, finfo->fd_formb_gaplen, IOTIMEDOUT); 1273 OUT_FDC(fdc, finfo->fd_formb_fillbyte, IOTIMEDOUT); 1274 } else { 1275 if (read) 1276 OUT_FDC(fdc, NE7CMD_READ, IOTIMEDOUT); 1277 else 1278 OUT_FDC(fdc, NE7CMD_WRITE, IOTIMEDOUT); 1279 OUT_FDC(fdc, (head << 2) | fd->sc_drive, IOTIMEDOUT); 1280 OUT_FDC(fdc, fd->sc_cylin, IOTIMEDOUT); /*track*/ 1281 OUT_FDC(fdc, head, IOTIMEDOUT); 1282 OUT_FDC(fdc, sec + 1, IOTIMEDOUT); /*sector+1*/ 1283 OUT_FDC(fdc, type->secsize, IOTIMEDOUT);/*sector size*/ 1284 OUT_FDC(fdc, type->sectrac, IOTIMEDOUT);/*secs/track*/ 1285 OUT_FDC(fdc, type->gap1, IOTIMEDOUT); /*gap1 size*/ 1286 OUT_FDC(fdc, type->datalen, IOTIMEDOUT);/*data length*/ 1287 } 1288 1289 disk_busy(&fd->sc_dk); 1290 1291 /* allow 2 seconds for operation */ 1292 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc); 1293 return (1); /* will return later */ 1294 1295 case SEEKWAIT: 1296 callout_stop(&fdc->sc_timo_ch); 1297 fdc->sc_state = SEEKCOMPLETE; 1298 if (fdc->sc_flags & FDC_NEEDHEADSETTLE) { 1299 /* allow 1/50 second for heads to settle */ 1300 callout_reset(&fdc->sc_intr_ch, hz / 50, 1301 fdcpseudointr, fdc); 1302 return (1); /* will return later */ 1303 } 1304 /*FALLTHROUGH*/ 1305 case SEEKCOMPLETE: 1306 /* no data on seek */ 1307 disk_unbusy(&fd->sc_dk, 0, 0); 1308 1309 /* Make sure seek really happened. */ 1310 if (fdc->sc_nstat != 2 || (st0 & 0xf8) != 0x20 || 1311 cyl != bp->b_cylinder * fd->sc_type->step) { 1312 #ifdef FD_DEBUG 1313 if (fdc_debug) 1314 fdcstatus(&fd->sc_dv, 2, "seek failed"); 1315 #endif 1316 fdcretry(fdc); 1317 goto loop; 1318 } 1319 fd->sc_cylin = bp->b_cylinder; 1320 goto doio; 1321 1322 case IOTIMEDOUT: 1323 fdc->sc_fcr |= FCR_TC; 1324 FCR_REG_SYNC(); 1325 delay(10); 1326 fdc->sc_fcr &= ~FCR_TC; 1327 FCR_REG_SYNC(); 1328 (void)fdcresult(fdc); 1329 /*FALLTHROUGH*/ 1330 case SEEKTIMEDOUT: 1331 case RECALTIMEDOUT: 1332 case RESETTIMEDOUT: 1333 fdcretry(fdc); 1334 goto loop; 1335 1336 case IOCOMPLETE: /* IO DONE, post-analyze */ 1337 callout_stop(&fdc->sc_timo_ch); 1338 1339 disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid), 1340 (bp->b_flags & B_READ)); 1341 1342 if (fdc->sc_nstat != 7 || (st0 & 0xf8) != 0 || st1 != 0) { 1343 #ifdef FD_DEBUG 1344 if (fdc_debug) { 1345 fdcstatus(&fd->sc_dv, 7, 1346 bp->b_flags & B_READ 1347 ? "read failed" : "write failed"); 1348 printf("blkno %d nblks %d tc %d\n", 1349 (int)fd->sc_blkno, fd->sc_nblks, fdc->sc_tc); 1350 } 1351 #endif 1352 if (fdc->sc_nstat == 7 && 1353 (st1 & ST1_OVERRUN) == ST1_OVERRUN) { 1354 1355 /* 1356 * Silently retry overruns if no other 1357 * error bit is set. Adjust threshold. 1358 */ 1359 int thr = fdc->sc_cfg & CFG_THRHLD_MASK; 1360 if (thr < 15) { 1361 thr++; 1362 fdc->sc_cfg &= ~CFG_THRHLD_MASK; 1363 fdc->sc_cfg |= (thr & CFG_THRHLD_MASK); 1364 #ifdef FD_DEBUG 1365 if (fdc_debug) 1366 printf("fdc: %d -> threshold\n", thr); 1367 #endif 1368 fdconf(fdc); 1369 fdc->sc_overruns = 0; 1370 } 1371 if (++fdc->sc_overruns < 3) { 1372 fdc->sc_state = DOIO; 1373 goto loop; 1374 } 1375 } 1376 fdcretry(fdc); 1377 goto loop; 1378 } 1379 if (fdc->sc_errors) { 1380 diskerr(bp, "fd", "soft error", LOG_PRINTF, 1381 fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL); 1382 printf("\n"); 1383 fdc->sc_errors = 0; 1384 } else { 1385 if (--fdc->sc_overruns < -20) { 1386 int thr = fdc->sc_cfg & CFG_THRHLD_MASK; 1387 if (thr > 0) { 1388 thr--; 1389 fdc->sc_cfg &= ~CFG_THRHLD_MASK; 1390 fdc->sc_cfg |= (thr & CFG_THRHLD_MASK); 1391 #ifdef FD_DEBUG 1392 if (fdc_debug) 1393 printf("fdc: %d -> threshold\n", thr); 1394 #endif 1395 fdconf(fdc); 1396 } 1397 fdc->sc_overruns = 0; 1398 } 1399 } 1400 fd->sc_blkno += fd->sc_nblks; 1401 fd->sc_skip += fd->sc_nbytes; 1402 fd->sc_bcount -= fd->sc_nbytes; 1403 if (!finfo && fd->sc_bcount > 0) { 1404 bp->b_cylinder = fd->sc_blkno / fd->sc_type->seccyl; 1405 goto doseek; 1406 } 1407 fdfinish(fd, bp); 1408 goto loop; 1409 1410 case DORESET: 1411 doreset: 1412 /* try a reset, keep motor on */ 1413 fd_set_motor(fdc); 1414 delay(100); 1415 fdc_reset(fdc); 1416 fdc->sc_nstat = 0; 1417 fdc->sc_istate = ISTATE_SENSEI; 1418 fdc->sc_state = RESETCOMPLETE; 1419 callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc); 1420 return (1); /* will return later */ 1421 1422 case RESETCOMPLETE: 1423 callout_stop(&fdc->sc_timo_ch); 1424 fdconf(fdc); 1425 1426 /* fall through */ 1427 case DORECAL: 1428 fdc->sc_state = RECALWAIT; 1429 fdc->sc_istate = ISTATE_SENSEI; 1430 fdc->sc_nstat = 0; 1431 /* recalibrate function */ 1432 OUT_FDC(fdc, NE7CMD_RECAL, RECALTIMEDOUT); 1433 OUT_FDC(fdc, fd->sc_drive, RECALTIMEDOUT); 1434 callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc); 1435 return (1); /* will return later */ 1436 1437 case RECALWAIT: 1438 callout_stop(&fdc->sc_timo_ch); 1439 fdc->sc_state = RECALCOMPLETE; 1440 if (fdc->sc_flags & FDC_NEEDHEADSETTLE) { 1441 /* allow 1/30 second for heads to settle */ 1442 callout_reset(&fdc->sc_intr_ch, hz / 30, 1443 fdcpseudointr, fdc); 1444 return (1); /* will return later */ 1445 } 1446 1447 case RECALCOMPLETE: 1448 if (fdc->sc_nstat != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) { 1449 #ifdef FD_DEBUG 1450 if (fdc_debug) 1451 fdcstatus(&fd->sc_dv, 2, "recalibrate failed"); 1452 #endif 1453 fdcretry(fdc); 1454 goto loop; 1455 } 1456 fd->sc_cylin = 0; 1457 goto doseek; 1458 1459 case MOTORWAIT: 1460 if (fd->sc_flags & FD_MOTOR_WAIT) 1461 return (1); /* time's not up yet */ 1462 goto doseek; 1463 1464 default: 1465 fdcstatus(&fd->sc_dv, 0, "stray interrupt"); 1466 return (1); 1467 } 1468 #ifdef DIAGNOSTIC 1469 panic("fdcintr: impossible"); 1470 #endif 1471 #undef st0 1472 #undef st1 1473 #undef cyl 1474 } 1475 1476 void 1477 fdcretry(struct fdc_softc *fdc) 1478 { 1479 char bits[64]; 1480 struct fd_softc *fd; 1481 struct buf *bp; 1482 1483 fd = fdc->sc_drives.tqh_first; 1484 bp = BUFQ_PEEK(fd->sc_q); 1485 1486 fdc->sc_overruns = 0; 1487 if (fd->sc_opts & FDOPT_NORETRY) 1488 goto fail; 1489 1490 switch (fdc->sc_errors) { 1491 case 0: 1492 /* try again */ 1493 fdc->sc_state = 1494 (fdc->sc_flags & FDC_EIS) ? DOIO : DOSEEK; 1495 break; 1496 1497 case 1: case 2: case 3: 1498 /* didn't work; try recalibrating */ 1499 fdc->sc_state = DORECAL; 1500 break; 1501 1502 case 4: 1503 /* still no go; reset the bastard */ 1504 fdc->sc_state = DORESET; 1505 break; 1506 1507 default: 1508 fail: 1509 if ((fd->sc_opts & FDOPT_SILENT) == 0) { 1510 diskerr(bp, "fd", "hard error", LOG_PRINTF, 1511 fd->sc_skip / FDC_BSIZE, 1512 (struct disklabel *)NULL); 1513 1514 printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0], 1515 NE7_ST0BITS, bits, sizeof(bits))); 1516 printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1], 1517 NE7_ST1BITS, bits, sizeof(bits))); 1518 printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2], 1519 NE7_ST2BITS, bits, sizeof(bits))); 1520 printf(" cyl %d head %d sec %d)\n", 1521 fdc->sc_status[3], fdc->sc_status[4], 1522 fdc->sc_status[5]); 1523 } 1524 1525 bp->b_flags |= B_ERROR; 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, caddr_t 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 = (caddr_t)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((caddr_t)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 } 1816 if (bp->b_flags & B_ERROR) { 1817 rv = bp->b_error; 1818 } 1819 free(bp, M_TEMP); 1820 return (rv); 1821 } 1822 1823 void 1824 fdgetdisklabel(dev_t dev) 1825 { 1826 int unit = FDUNIT(dev), i; 1827 struct fd_softc *fd = fd_cd.cd_devs[unit]; 1828 struct disklabel *lp = fd->sc_dk.dk_label; 1829 struct cpu_disklabel *clp = fd->sc_dk.dk_cpulabel; 1830 1831 memset(lp, 0, sizeof(struct disklabel)); 1832 memset(lp, 0, sizeof(struct cpu_disklabel)); 1833 1834 lp->d_type = DTYPE_FLOPPY; 1835 lp->d_secsize = FDC_BSIZE; 1836 lp->d_secpercyl = fd->sc_type->seccyl; 1837 lp->d_nsectors = fd->sc_type->sectrac; 1838 lp->d_ncylinders = fd->sc_type->tracks; 1839 lp->d_ntracks = fd->sc_type->heads; /* Go figure... */ 1840 lp->d_rpm = 3600; /* XXX like it matters... */ 1841 1842 strncpy(lp->d_typename, "floppy", sizeof(lp->d_typename)); 1843 strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname)); 1844 lp->d_interleave = 1; 1845 1846 lp->d_partitions[RAW_PART].p_offset = 0; 1847 lp->d_partitions[RAW_PART].p_size = lp->d_secpercyl * lp->d_ncylinders; 1848 lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED; 1849 lp->d_npartitions = RAW_PART + 1; 1850 1851 lp->d_magic = DISKMAGIC; 1852 lp->d_magic2 = DISKMAGIC; 1853 lp->d_checksum = dkcksum(lp); 1854 1855 /* 1856 * Call the generic disklabel extraction routine. If there's 1857 * not a label there, fake it. 1858 */ 1859 if (readdisklabel(dev, fdstrategy, lp, clp) != NULL) { 1860 strncpy(lp->d_packname, "default label", 1861 sizeof(lp->d_packname)); 1862 /* 1863 * Reset the partition info; it might have gotten 1864 * trashed in readdisklabel(). 1865 * 1866 * XXX Why do we have to do this? readdisklabel() 1867 * should be safe... 1868 */ 1869 for (i = 0; i < MAXPARTITIONS; ++i) { 1870 lp->d_partitions[i].p_offset = 0; 1871 if (i == RAW_PART) { 1872 lp->d_partitions[i].p_size = 1873 lp->d_secpercyl * lp->d_ncylinders; 1874 lp->d_partitions[i].p_fstype = FS_BSDFFS; 1875 } else { 1876 lp->d_partitions[i].p_size = 0; 1877 lp->d_partitions[i].p_fstype = FS_UNUSED; 1878 } 1879 } 1880 lp->d_npartitions = RAW_PART + 1; 1881 } 1882 } 1883 1884 void 1885 fd_do_eject(struct fdc_softc *fdc, int unit) 1886 { 1887 fdc->sc_fcr |= FCR_DSEL(unit)|FCR_EJECT; 1888 FCR_REG_SYNC(); 1889 delay(10); 1890 fdc->sc_fcr &= ~(FCR_DSEL(unit)|FCR_EJECT); 1891 FCR_REG_SYNC(); 1892 } 1893 1894 #ifdef MEMORY_DISK_HOOKS_sun3x_not_yet 1895 int fd_read_md_image(size_t *, caddr_t *); 1896 #endif 1897 1898 /* ARGSUSED */ 1899 void 1900 fd_mountroot_hook(struct device *dev) 1901 { 1902 int c; 1903 1904 fd_do_eject(fdc_cd.cd_devs[0], 0); /* XXX - doesn't check ``dev'' */ 1905 printf("Insert filesystem floppy and press return."); 1906 for (;;) { 1907 c = cngetc(); 1908 if ((c == '\r') || (c == '\n')) { 1909 printf("\n"); 1910 break; 1911 } 1912 } 1913 #ifdef MEMORY_DISK_HOOKS_sun3x_not_yet 1914 { 1915 extern int (*md_read_image)(size_t *, caddr_t *); 1916 md_read_image = fd_read_md_image; 1917 } 1918 #endif 1919 } 1920 1921 #ifdef MEMORY_DISK_HOOKS_sun3x_not_yet 1922 1923 #define FDMICROROOTSIZE ((2*18*80) << DEV_BSHIFT) 1924 1925 int 1926 fd_read_md_image(size_t *sizep, caddr_t *addrp) 1927 { 1928 struct buf buf, *bp = &buf; 1929 dev_t dev; 1930 off_t offset; 1931 caddr_t addr; 1932 1933 dev = makedev(54,0); /* XXX */ 1934 1935 MALLOC(addr, caddr_t, FDMICROROOTSIZE, M_DEVBUF, M_WAITOK); 1936 *addrp = addr; 1937 1938 if (fdopen(dev, 0, S_IFCHR, NULL)) 1939 panic("fd: mountroot: fdopen"); 1940 1941 offset = 0; 1942 1943 for (;;) { 1944 bp->b_dev = dev; 1945 bp->b_error = 0; 1946 bp->b_resid = 0; 1947 bp->b_proc = NULL; 1948 bp->b_flags = B_BUSY | B_PHYS | B_RAW | B_READ; 1949 bp->b_blkno = btodb(offset); 1950 bp->b_bcount = DEV_BSIZE; 1951 bp->b_data = addr; 1952 fdstrategy(bp); 1953 while ((bp->b_flags & B_DONE) == 0) { 1954 tsleep((caddr_t)bp, PRIBIO + 1, "physio", 0); 1955 } 1956 if (bp->b_error) 1957 panic("fd: mountroot: fdread error %d", bp->b_error); 1958 1959 if (bp->b_resid != 0) 1960 break; 1961 1962 addr += DEV_BSIZE; 1963 offset += DEV_BSIZE; 1964 if (offset + DEV_BSIZE > FDMICROROOTSIZE) 1965 break; 1966 } 1967 (void)fdclose(dev, 0, S_IFCHR, NULL); 1968 *sizep = offset; 1969 fd_do_eject(fdc_cd.cd_devs[0], FDUNIT(dev)); /* XXX */ 1970 return (0); 1971 } 1972 #endif 1973