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