1 /* $NetBSD: fd.c,v 1.31 2002/11/01 11:31:57 mrg Exp $ */ 2 3 /*- 4 * Copyright (c) 1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Charles M. Hannum. 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. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /*- 40 * Copyright (c) 1990 The Regents of the University of California. 41 * All rights reserved. 42 * 43 * This code is derived from software contributed to Berkeley by 44 * Don Ahn. 45 * 46 * Redistribution and use in source and binary forms, with or without 47 * modification, are permitted provided that the following conditions 48 * are met: 49 * 1. Redistributions of source code must retain the above copyright 50 * notice, this list of conditions and the following disclaimer. 51 * 2. Redistributions in binary form must reproduce the above copyright 52 * notice, this list of conditions and the following disclaimer in the 53 * documentation and/or other materials provided with the distribution. 54 * 3. All advertising materials mentioning features or use of this software 55 * must display the following acknowledgement: 56 * This product includes software developed by the University of 57 * California, Berkeley and its contributors. 58 * 4. Neither the name of the University nor the names of its contributors 59 * may be used to endorse or promote products derived from this software 60 * without specific prior written permission. 61 * 62 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 63 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 64 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 65 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 66 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 67 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 68 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 69 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 70 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 71 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 72 * SUCH DAMAGE. 73 * 74 * @(#)fd.c 7.4 (Berkeley) 5/25/91 75 */ 76 77 /* 78 * Floppy formatting facilities merged from FreeBSD fd.c driver: 79 * Id: fd.c,v 1.53 1995/03/12 22:40:56 joerg Exp 80 * which carries the same copyright/redistribution notice as shown above with 81 * the addition of the following statement before the "Redistribution and 82 * use ..." clause: 83 * 84 * Copyright (c) 1993, 1994 by 85 * jc@irbs.UUCP (John Capo) 86 * vak@zebub.msk.su (Serge Vakulenko) 87 * ache@astral.msk.su (Andrew A. Chernov) 88 * 89 * Copyright (c) 1993, 1994, 1995 by 90 * joerg_wunsch@uriah.sax.de (Joerg Wunsch) 91 * dufault@hda.com (Peter Dufault) 92 */ 93 94 #include <sys/cdefs.h> 95 __KERNEL_RCSID(0, "$NetBSD: fd.c,v 1.31 2002/11/01 11:31:57 mrg Exp $"); 96 97 #include "rnd.h" 98 #include "opt_ddb.h" 99 100 /* 101 * XXX This driver should be properly MI'd some day, but this allows us 102 * XXX to eliminate a lot of code duplication for now. 103 */ 104 #if !defined(alpha) && !defined(algor) && !defined(atari) && \ 105 !defined(bebox) && !defined(evbmips) && !defined(i386) && \ 106 !defined(prep) && !defined(sandpoint) && !defined(x86_64) 107 #error platform not supported by this driver, yet 108 #endif 109 110 #include <sys/param.h> 111 #include <sys/systm.h> 112 #include <sys/callout.h> 113 #include <sys/kernel.h> 114 #include <sys/file.h> 115 #include <sys/ioctl.h> 116 #include <sys/device.h> 117 #include <sys/disklabel.h> 118 #include <sys/dkstat.h> 119 #include <sys/disk.h> 120 #include <sys/buf.h> 121 #include <sys/malloc.h> 122 #include <sys/uio.h> 123 #include <sys/syslog.h> 124 #include <sys/queue.h> 125 #include <sys/proc.h> 126 #include <sys/fdio.h> 127 #include <sys/conf.h> 128 #if NRND > 0 129 #include <sys/rnd.h> 130 #endif 131 132 #include <uvm/uvm_extern.h> 133 134 #include <dev/cons.h> 135 136 #include <machine/cpu.h> 137 #include <machine/bus.h> 138 139 #if defined(atari) 140 /* 141 * On the atari, it is configured as fdcisa 142 */ 143 #define FDCCF_DRIVE FDCISACF_DRIVE 144 #define FDCCF_DRIVE_DEFAULT FDCISACF_DRIVE_DEFAULT 145 146 #define fd_cd fdisa_cd 147 #define fd_ca fdisa_ca 148 #endif /* atari */ 149 150 #include <machine/intr.h> 151 152 #include <dev/isa/isavar.h> 153 #include <dev/isa/isadmavar.h> 154 155 #include <dev/isa/fdreg.h> 156 #include <dev/isa/fdcvar.h> 157 158 #if defined(i386) 159 160 #include <dev/ic/mc146818reg.h> /* for NVRAM access */ 161 #include <i386/isa/nvram.h> 162 163 #include "mca.h" 164 #if NMCA > 0 165 #include <machine/mca_machdep.h> /* for MCA_system */ 166 #endif 167 168 #endif /* i386 */ 169 170 #define FDUNIT(dev) (minor(dev) / 8) 171 #define FDTYPE(dev) (minor(dev) % 8) 172 173 /* XXX misuse a flag to identify format operation */ 174 #define B_FORMAT B_XXX 175 176 /* controller driver configuration */ 177 int fdprint __P((void *, const char *)); 178 179 /* 180 * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how 181 * we tell them apart. 182 */ 183 struct fd_type { 184 int sectrac; /* sectors per track */ 185 int heads; /* number of heads */ 186 int seccyl; /* sectors per cylinder */ 187 int secsize; /* size code for sectors */ 188 int datalen; /* data len when secsize = 0 */ 189 int steprate; /* step rate and head unload time */ 190 int gap1; /* gap len between sectors */ 191 int gap2; /* formatting gap */ 192 int cyls; /* total num of cylinders */ 193 int size; /* size of disk in sectors */ 194 int step; /* steps per cylinder */ 195 int rate; /* transfer speed code */ 196 u_char fillbyte; /* format fill byte */ 197 u_char interleave; /* interleave factor (formatting) */ 198 const char *name; 199 }; 200 201 #if NMCA > 0 202 /* MCA - specific entries */ 203 const struct fd_type mca_fd_types[] = { 204 { 18,2,36,2,0xff,0x0f,0x1b,0x6c,80,2880,1,FDC_500KBPS,0xf6,1, "1.44MB" }, /* 1.44MB diskette - XXX try 16ms step rate */ 205 { 9,2,18,2,0xff,0x4f,0x2a,0x50,80,1440,1,FDC_250KBPS,0xf6,1, "720KB" }, /* 3.5 inch 720kB diskette - XXX try 24ms step rate */ 206 }; 207 #endif /* NMCA > 0 */ 208 209 /* The order of entries in the following table is important -- BEWARE! */ 210 211 #if defined(atari) 212 const struct fd_type fd_types[] = { 213 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS,0xf6,1, "360KB/PC" }, /* 360kB PC diskettes */ 214 { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS,0xf6,1, "720KB" }, /* 3.5 inch 720kB diskette */ 215 { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS,0xf6,1, "1.44MB" }, /* 1.44MB diskette */ 216 }; 217 #else 218 const struct fd_type fd_types[] = { 219 { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS,0xf6,1, "1.44MB" }, /* 1.44MB diskette */ 220 { 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS,0xf6,1, "1.2MB" }, /* 1.2 MB AT-diskettes */ 221 { 9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS,0xf6,1, "360KB/AT" }, /* 360kB in 1.2MB drive */ 222 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS,0xf6,1, "360KB/PC" }, /* 360kB PC diskettes */ 223 { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS,0xf6,1, "720KB" }, /* 3.5 inch 720kB diskette */ 224 { 9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS,0xf6,1, "720KB/x" }, /* 720kB in 1.2MB drive */ 225 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS,0xf6,1, "360KB/x" }, /* 360kB in 720kB drive */ 226 }; 227 #endif /* defined(atari) */ 228 229 /* software state, per disk (with up to 4 disks per ctlr) */ 230 struct fd_softc { 231 struct device sc_dev; 232 struct disk sc_dk; 233 234 const struct fd_type *sc_deftype; /* default type descriptor */ 235 struct fd_type *sc_type; /* current type descriptor */ 236 struct fd_type sc_type_copy; /* copy for fiddling when formatting */ 237 238 struct callout sc_motoron_ch; 239 struct callout sc_motoroff_ch; 240 241 daddr_t sc_blkno; /* starting block number */ 242 int sc_bcount; /* byte count left */ 243 int sc_opts; /* user-set options */ 244 int sc_skip; /* bytes already transferred */ 245 int sc_nblks; /* number of blocks currently transferring */ 246 int sc_nbytes; /* number of bytes currently transferring */ 247 248 int sc_drive; /* physical unit number */ 249 int sc_flags; 250 #define FD_OPEN 0x01 /* it's open */ 251 #define FD_MOTOR 0x02 /* motor should be on */ 252 #define FD_MOTOR_WAIT 0x04 /* motor coming up */ 253 int sc_cylin; /* where we think the head is */ 254 255 void *sc_sdhook; /* saved shutdown hook for drive. */ 256 257 TAILQ_ENTRY(fd_softc) sc_drivechain; 258 int sc_ops; /* I/O ops since last switch */ 259 struct bufq_state sc_q; /* pending I/O requests */ 260 int sc_active; /* number of active I/O operations */ 261 262 #if NRND > 0 263 rndsource_element_t rnd_source; 264 #endif 265 }; 266 267 int fdprobe __P((struct device *, struct cfdata *, void *)); 268 void fdattach __P((struct device *, struct device *, void *)); 269 270 extern struct cfdriver fd_cd; 271 272 CFATTACH_DECL(fd, sizeof(struct fd_softc), 273 fdprobe, fdattach, NULL, NULL); 274 275 dev_type_open(fdopen); 276 dev_type_close(fdclose); 277 dev_type_read(fdread); 278 dev_type_write(fdwrite); 279 dev_type_ioctl(fdioctl); 280 dev_type_strategy(fdstrategy); 281 282 const struct bdevsw fd_bdevsw = { 283 fdopen, fdclose, fdstrategy, fdioctl, nodump, nosize, D_DISK 284 }; 285 286 const struct cdevsw fd_cdevsw = { 287 fdopen, fdclose, fdread, fdwrite, fdioctl, 288 nostop, notty, nopoll, nommap, nokqfilter, D_DISK 289 }; 290 291 void fdgetdisklabel __P((struct fd_softc *)); 292 int fd_get_parms __P((struct fd_softc *)); 293 void fdstart __P((struct fd_softc *)); 294 295 struct dkdriver fddkdriver = { fdstrategy }; 296 297 #if defined(i386) 298 const struct fd_type *fd_nvtotype __P((char *, int, int)); 299 #endif /* i386 */ 300 void fd_set_motor __P((struct fdc_softc *fdc, int reset)); 301 void fd_motor_off __P((void *arg)); 302 void fd_motor_on __P((void *arg)); 303 int fdcresult __P((struct fdc_softc *fdc)); 304 void fdcstart __P((struct fdc_softc *fdc)); 305 void fdcstatus __P((struct device *dv, int n, char *s)); 306 void fdctimeout __P((void *arg)); 307 void fdcpseudointr __P((void *arg)); 308 void fdcretry __P((struct fdc_softc *fdc)); 309 void fdfinish __P((struct fd_softc *fd, struct buf *bp)); 310 __inline const struct fd_type *fd_dev_to_type __P((struct fd_softc *, dev_t)); 311 int fdformat __P((dev_t, struct ne7_fd_formb *, struct proc *)); 312 313 void fd_mountroot_hook __P((struct device *)); 314 315 /* 316 * Arguments passed between fdcattach and fdprobe. 317 */ 318 struct fdc_attach_args { 319 int fa_drive; 320 const struct fd_type *fa_deftype; 321 }; 322 323 /* 324 * Print the location of a disk drive (called just before attaching the 325 * the drive). If `fdc' is not NULL, the drive was found but was not 326 * in the system config file; print the drive name as well. 327 * Return QUIET (config_find ignores this if the device was configured) to 328 * avoid printing `fdN not configured' messages. 329 */ 330 int 331 fdprint(aux, fdc) 332 void *aux; 333 const char *fdc; 334 { 335 register struct fdc_attach_args *fa = aux; 336 337 if (!fdc) 338 printf(" drive %d", fa->fa_drive); 339 return QUIET; 340 } 341 342 void 343 fdcattach(fdc) 344 struct fdc_softc *fdc; 345 { 346 struct fdc_attach_args fa; 347 bus_space_tag_t iot; 348 bus_space_handle_t ioh; 349 #if defined(i386) 350 int type; 351 #endif 352 353 iot = fdc->sc_iot; 354 ioh = fdc->sc_ioh; 355 callout_init(&fdc->sc_timo_ch); 356 callout_init(&fdc->sc_intr_ch); 357 358 fdc->sc_state = DEVIDLE; 359 TAILQ_INIT(&fdc->sc_drives); 360 361 fdc->sc_maxiosize = isa_dmamaxsize(fdc->sc_ic, fdc->sc_drq); 362 363 if (isa_dmamap_create(fdc->sc_ic, fdc->sc_drq, fdc->sc_maxiosize, 364 BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW)) { 365 printf("%s: can't set up ISA DMA map\n", 366 fdc->sc_dev.dv_xname); 367 return; 368 } 369 370 /* 371 * Reset the controller to get it into a known state. Not all 372 * probes necessarily need do this to discover the controller up 373 * front, so don't assume anything. 374 */ 375 376 bus_space_write_1(iot, ioh, fdout, 0); 377 delay(100); 378 bus_space_write_1(iot, ioh, fdout, FDO_FRST); 379 380 /* see if it can handle a command */ 381 if (out_fdc(iot, ioh, NE7CMD_SPECIFY) < 0) { 382 printf ("%s: can't reset controller\n", fdc->sc_dev.dv_xname); 383 return; 384 } 385 out_fdc(iot, ioh, 0xdf); 386 out_fdc(iot, ioh, 2); 387 388 #if defined(i386) 389 /* 390 * The NVRAM info only tells us about the first two disks on the 391 * `primary' floppy controller. 392 */ 393 if (fdc->sc_dev.dv_unit == 0) 394 type = mc146818_read(NULL, NVRAM_DISKETTE); /* XXX softc */ 395 else 396 type = -1; 397 #endif /* i386 */ 398 399 /* physical limit: four drives per controller. */ 400 for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) { 401 #if defined(i386) 402 if (type >= 0 && fa.fa_drive < 2) 403 fa.fa_deftype = fd_nvtotype(fdc->sc_dev.dv_xname, 404 type, fa.fa_drive); 405 else 406 fa.fa_deftype = NULL; /* unknown */ 407 #elif defined(atari) 408 /* 409 * Atari has a different ordening, defaults to 1.44 410 */ 411 fa.fa_deftype = &fd_types[2]; 412 #else 413 /* 414 * Default to 1.44MB on Alpha and BeBox. How do we tell 415 * on these platforms? 416 */ 417 fa.fa_deftype = &fd_types[0]; 418 #endif /* i386 */ 419 (void)config_found(&fdc->sc_dev, (void *)&fa, fdprint); 420 } 421 } 422 423 int 424 fdprobe(parent, match, aux) 425 struct device *parent; 426 struct cfdata *match; 427 void *aux; 428 { 429 struct fdc_softc *fdc = (void *)parent; 430 struct cfdata *cf = match; 431 struct fdc_attach_args *fa = aux; 432 int drive = fa->fa_drive; 433 bus_space_tag_t iot = fdc->sc_iot; 434 bus_space_handle_t ioh = fdc->sc_ioh; 435 int n; 436 437 if (cf->cf_loc[FDCCF_DRIVE] != FDCCF_DRIVE_DEFAULT && 438 cf->cf_loc[FDCCF_DRIVE] != drive) 439 return 0; 440 /* 441 * XXX 442 * This is to work around some odd interactions between this driver 443 * and SMC Ethernet cards. 444 */ 445 if (cf->cf_loc[FDCCF_DRIVE] == FDCCF_DRIVE_DEFAULT && drive >= 2) 446 return 0; 447 448 /* select drive and turn on motor */ 449 bus_space_write_1(iot, ioh, fdout, drive | FDO_FRST | FDO_MOEN(drive)); 450 /* wait for motor to spin up */ 451 delay(250000); 452 out_fdc(iot, ioh, NE7CMD_RECAL); 453 out_fdc(iot, ioh, drive); 454 /* wait for recalibrate */ 455 delay(2000000); 456 out_fdc(iot, ioh, NE7CMD_SENSEI); 457 n = fdcresult(fdc); 458 #ifdef FD_DEBUG 459 { 460 int i; 461 printf("fdprobe: status"); 462 for (i = 0; i < n; i++) 463 printf(" %x", fdc->sc_status[i]); 464 printf("\n"); 465 } 466 #endif 467 /* turn off motor */ 468 bus_space_write_1(iot, ioh, fdout, FDO_FRST); 469 470 #if defined(bebox) /* XXX What is this about? --thorpej@netbsd.org */ 471 if (n != 2 || (fdc->sc_status[1] != 0)) 472 return 0; 473 #else 474 if (n != 2 || (fdc->sc_status[0] & 0xf8) != 0x20) 475 return 0; 476 #endif /* bebox */ 477 478 return 1; 479 } 480 481 /* 482 * Controller is working, and drive responded. Attach it. 483 */ 484 void 485 fdattach(parent, self, aux) 486 struct device *parent, *self; 487 void *aux; 488 { 489 struct fdc_softc *fdc = (void *)parent; 490 struct fd_softc *fd = (void *)self; 491 struct fdc_attach_args *fa = aux; 492 const struct fd_type *type = fa->fa_deftype; 493 int drive = fa->fa_drive; 494 495 callout_init(&fd->sc_motoron_ch); 496 callout_init(&fd->sc_motoroff_ch); 497 498 /* XXX Allow `flags' to override device type? */ 499 500 if (type) 501 printf(": %s, %d cyl, %d head, %d sec\n", type->name, 502 type->cyls, type->heads, type->sectrac); 503 else 504 printf(": density unknown\n"); 505 506 bufq_alloc(&fd->sc_q, BUFQ_DISKSORT|BUFQ_SORT_CYLINDER); 507 fd->sc_cylin = -1; 508 fd->sc_drive = drive; 509 fd->sc_deftype = type; 510 fdc->sc_fd[drive] = fd; 511 512 /* 513 * Initialize and attach the disk structure. 514 */ 515 fd->sc_dk.dk_name = fd->sc_dev.dv_xname; 516 fd->sc_dk.dk_driver = &fddkdriver; 517 disk_attach(&fd->sc_dk); 518 519 /* 520 * Establish a mountroot hook. 521 */ 522 mountroothook_establish(fd_mountroot_hook, &fd->sc_dev); 523 524 /* Needed to power off if the motor is on when we halt. */ 525 fd->sc_sdhook = shutdownhook_establish(fd_motor_off, fd); 526 527 #if NRND > 0 528 rnd_attach_source(&fd->rnd_source, fd->sc_dev.dv_xname, 529 RND_TYPE_DISK, 0); 530 #endif 531 } 532 533 #if defined(i386) 534 /* 535 * Translate nvram type into internal data structure. Return NULL for 536 * none/unknown/unusable. 537 */ 538 const struct fd_type * 539 fd_nvtotype(fdc, nvraminfo, drive) 540 char *fdc; 541 int nvraminfo, drive; 542 { 543 int type; 544 545 type = (drive == 0 ? nvraminfo : nvraminfo << 4) & 0xf0; 546 switch (type) { 547 case NVRAM_DISKETTE_NONE: 548 return NULL; 549 case NVRAM_DISKETTE_12M: 550 return &fd_types[1]; 551 case NVRAM_DISKETTE_TYPE5: 552 case NVRAM_DISKETTE_TYPE6: 553 /* XXX We really ought to handle 2.88MB format. */ 554 case NVRAM_DISKETTE_144M: 555 #if NMCA > 0 556 if (MCA_system) 557 return &mca_fd_types[0]; 558 else 559 #endif /* NMCA > 0 */ 560 return &fd_types[0]; 561 case NVRAM_DISKETTE_360K: 562 return &fd_types[3]; 563 case NVRAM_DISKETTE_720K: 564 #if NMCA > 0 565 if (MCA_system) 566 return &mca_fd_types[1]; 567 else 568 #endif /* NMCA > 0 */ 569 return &fd_types[4]; 570 default: 571 printf("%s: drive %d: unknown device type 0x%x\n", 572 fdc, drive, type); 573 return NULL; 574 } 575 } 576 #endif /* i386 */ 577 578 __inline const struct fd_type * 579 fd_dev_to_type(fd, dev) 580 struct fd_softc *fd; 581 dev_t dev; 582 { 583 u_int type = FDTYPE(dev); 584 585 if (type > (sizeof(fd_types) / sizeof(fd_types[0]))) 586 return NULL; 587 return type ? &fd_types[type - 1] : fd->sc_deftype; 588 } 589 590 void 591 fdstrategy(bp) 592 register struct buf *bp; /* IO operation to perform */ 593 { 594 struct fd_softc *fd = device_lookup(&fd_cd, FDUNIT(bp->b_dev)); 595 int sz; 596 int s; 597 598 /* Valid unit, controller, and request? */ 599 if (bp->b_blkno < 0 || 600 ((bp->b_bcount % FDC_BSIZE) != 0 && 601 (bp->b_flags & B_FORMAT) == 0)) { 602 bp->b_error = EINVAL; 603 goto bad; 604 } 605 606 /* If it's a null transfer, return immediately. */ 607 if (bp->b_bcount == 0) 608 goto done; 609 610 sz = howmany(bp->b_bcount, FDC_BSIZE); 611 612 if (bp->b_blkno + sz > fd->sc_type->size) { 613 sz = fd->sc_type->size - bp->b_blkno; 614 if (sz == 0) { 615 /* If exactly at end of disk, return EOF. */ 616 goto done; 617 } 618 if (sz < 0) { 619 /* If past end of disk, return EINVAL. */ 620 bp->b_error = EINVAL; 621 goto bad; 622 } 623 /* Otherwise, truncate request. */ 624 bp->b_bcount = sz << DEV_BSHIFT; 625 } 626 627 bp->b_rawblkno = bp->b_blkno; 628 bp->b_cylinder = 629 bp->b_blkno / (FDC_BSIZE / DEV_BSIZE) / fd->sc_type->seccyl; 630 631 #ifdef FD_DEBUG 632 printf("fdstrategy: b_blkno %d b_bcount %ld blkno %d cylin %ld sz %d\n", 633 bp->b_blkno, bp->b_bcount, fd->sc_blkno, bp->b_cylinder, sz); 634 #endif 635 636 /* Queue transfer on drive, activate drive and controller if idle. */ 637 s = splbio(); 638 BUFQ_PUT(&fd->sc_q, bp); 639 callout_stop(&fd->sc_motoroff_ch); /* a good idea */ 640 if (fd->sc_active == 0) 641 fdstart(fd); 642 #ifdef DIAGNOSTIC 643 else { 644 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; 645 if (fdc->sc_state == DEVIDLE) { 646 printf("fdstrategy: controller inactive\n"); 647 fdcstart(fdc); 648 } 649 } 650 #endif 651 splx(s); 652 return; 653 654 bad: 655 bp->b_flags |= B_ERROR; 656 done: 657 /* Toss transfer; we're done early. */ 658 bp->b_resid = bp->b_bcount; 659 biodone(bp); 660 } 661 662 void 663 fdstart(fd) 664 struct fd_softc *fd; 665 { 666 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; 667 int active = !TAILQ_EMPTY(&fdc->sc_drives); 668 669 /* Link into controller queue. */ 670 fd->sc_active = 1; 671 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain); 672 673 /* If controller not already active, start it. */ 674 if (!active) 675 fdcstart(fdc); 676 } 677 678 void 679 fdfinish(fd, bp) 680 struct fd_softc *fd; 681 struct buf *bp; 682 { 683 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; 684 685 /* 686 * Move this drive to the end of the queue to give others a `fair' 687 * chance. We only force a switch if N operations are completed while 688 * another drive is waiting to be serviced, since there is a long motor 689 * startup delay whenever we switch. 690 */ 691 (void)BUFQ_GET(&fd->sc_q); 692 if (TAILQ_NEXT(fd, sc_drivechain) && ++fd->sc_ops >= 8) { 693 fd->sc_ops = 0; 694 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain); 695 if (BUFQ_PEEK(&fd->sc_q) != NULL) 696 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain); 697 else 698 fd->sc_active = 0; 699 } 700 bp->b_resid = fd->sc_bcount; 701 fd->sc_skip = 0; 702 703 #if NRND > 0 704 rnd_add_uint32(&fd->rnd_source, bp->b_blkno); 705 #endif 706 707 biodone(bp); 708 /* turn off motor 5s from now */ 709 callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd); 710 fdc->sc_state = DEVIDLE; 711 } 712 713 int 714 fdread(dev, uio, flags) 715 dev_t dev; 716 struct uio *uio; 717 int flags; 718 { 719 720 return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio)); 721 } 722 723 int 724 fdwrite(dev, uio, flags) 725 dev_t dev; 726 struct uio *uio; 727 int flags; 728 { 729 730 return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio)); 731 } 732 733 void 734 fd_set_motor(fdc, reset) 735 struct fdc_softc *fdc; 736 int reset; 737 { 738 struct fd_softc *fd; 739 u_char status; 740 int n; 741 742 if ((fd = TAILQ_FIRST(&fdc->sc_drives)) != NULL) 743 status = fd->sc_drive; 744 else 745 status = 0; 746 if (!reset) 747 status |= FDO_FRST | FDO_FDMAEN; 748 for (n = 0; n < 4; n++) 749 if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR)) 750 status |= FDO_MOEN(n); 751 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, status); 752 } 753 754 void 755 fd_motor_off(arg) 756 void *arg; 757 { 758 struct fd_softc *fd = arg; 759 int s; 760 761 s = splbio(); 762 fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT); 763 fd_set_motor((struct fdc_softc *)fd->sc_dev.dv_parent, 0); 764 splx(s); 765 } 766 767 void 768 fd_motor_on(arg) 769 void *arg; 770 { 771 struct fd_softc *fd = arg; 772 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; 773 int s; 774 775 s = splbio(); 776 fd->sc_flags &= ~FD_MOTOR_WAIT; 777 if ((TAILQ_FIRST(&fdc->sc_drives) == fd) &&(fdc->sc_state == MOTORWAIT)) 778 (void) fdcintr(fdc); 779 splx(s); 780 } 781 782 int 783 fdcresult(fdc) 784 struct fdc_softc *fdc; 785 { 786 bus_space_tag_t iot = fdc->sc_iot; 787 bus_space_handle_t ioh = fdc->sc_ioh; 788 u_char i; 789 u_int j = 100000, 790 n = 0; 791 792 for (; j; j--) { 793 i = bus_space_read_1(iot, ioh, fdsts) & 794 (NE7_DIO | NE7_RQM | NE7_CB); 795 if (i == NE7_RQM) 796 return n; 797 if (i == (NE7_DIO | NE7_RQM | NE7_CB)) { 798 if (n >= sizeof(fdc->sc_status)) { 799 log(LOG_ERR, "fdcresult: overrun\n"); 800 return -1; 801 } 802 fdc->sc_status[n++] = 803 bus_space_read_1(iot, ioh, fddata); 804 } 805 delay(10); 806 } 807 log(LOG_ERR, "fdcresult: timeout\n"); 808 return -1; 809 } 810 811 int 812 out_fdc(iot, ioh, x) 813 bus_space_tag_t iot; 814 bus_space_handle_t ioh; 815 u_char x; 816 { 817 int i = 100000; 818 819 while ((bus_space_read_1(iot, ioh, fdsts) & NE7_DIO) && i-- > 0); 820 if (i <= 0) 821 return -1; 822 while ((bus_space_read_1(iot, ioh, fdsts) & NE7_RQM) == 0 && i-- > 0); 823 if (i <= 0) 824 return -1; 825 bus_space_write_1(iot, ioh, fddata, x); 826 return 0; 827 } 828 829 int 830 fdopen(dev, flags, mode, p) 831 dev_t dev; 832 int flags; 833 int mode; 834 struct proc *p; 835 { 836 struct fd_softc *fd; 837 const struct fd_type *type; 838 839 fd = device_lookup(&fd_cd, FDUNIT(dev)); 840 if (fd == NULL) 841 return (ENXIO); 842 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 memcmp(fd->sc_type, type, sizeof(*type))) 849 return EBUSY; 850 851 fd->sc_type_copy = *type; 852 fd->sc_type = &fd->sc_type_copy; 853 fd->sc_cylin = -1; 854 fd->sc_flags |= FD_OPEN; 855 856 return 0; 857 } 858 859 int 860 fdclose(dev, flags, mode, p) 861 dev_t dev; 862 int flags; 863 int mode; 864 struct proc *p; 865 { 866 struct fd_softc *fd = device_lookup(&fd_cd, FDUNIT(dev)); 867 868 fd->sc_flags &= ~FD_OPEN; 869 fd->sc_opts &= ~(FDOPT_NORETRY|FDOPT_SILENT); 870 return 0; 871 } 872 873 void 874 fdcstart(fdc) 875 struct fdc_softc *fdc; 876 { 877 878 #ifdef DIAGNOSTIC 879 /* only got here if controller's drive queue was inactive; should 880 be in idle state */ 881 if (fdc->sc_state != DEVIDLE) { 882 printf("fdcstart: not idle\n"); 883 return; 884 } 885 #endif 886 (void) fdcintr(fdc); 887 } 888 889 void 890 fdcstatus(dv, n, s) 891 struct device *dv; 892 int n; 893 char *s; 894 { 895 struct fdc_softc *fdc = (void *)dv->dv_parent; 896 char bits[64]; 897 898 if (n == 0) { 899 out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI); 900 (void) fdcresult(fdc); 901 n = 2; 902 } 903 904 printf("%s: %s", dv->dv_xname, s); 905 906 switch (n) { 907 case 0: 908 printf("\n"); 909 break; 910 case 2: 911 printf(" (st0 %s cyl %d)\n", 912 bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS, 913 bits, sizeof(bits)), fdc->sc_status[1]); 914 break; 915 case 7: 916 printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0], 917 NE7_ST0BITS, bits, sizeof(bits))); 918 printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1], 919 NE7_ST1BITS, bits, sizeof(bits))); 920 printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2], 921 NE7_ST2BITS, bits, sizeof(bits))); 922 printf(" cyl %d head %d sec %d)\n", 923 fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]); 924 break; 925 #ifdef DIAGNOSTIC 926 default: 927 printf("\nfdcstatus: weird size"); 928 break; 929 #endif 930 } 931 } 932 933 void 934 fdctimeout(arg) 935 void *arg; 936 { 937 struct fdc_softc *fdc = arg; 938 struct fd_softc *fd = TAILQ_FIRST(&fdc->sc_drives); 939 int s; 940 941 s = splbio(); 942 #ifdef DEBUG 943 log(LOG_ERR, "fdctimeout: state %d\n", fdc->sc_state); 944 #endif 945 fdcstatus(&fd->sc_dev, 0, "timeout"); 946 947 if (BUFQ_PEEK(&fd->sc_q) != NULL) 948 fdc->sc_state++; 949 else 950 fdc->sc_state = DEVIDLE; 951 952 (void) fdcintr(fdc); 953 splx(s); 954 } 955 956 void 957 fdcpseudointr(arg) 958 void *arg; 959 { 960 int s; 961 962 /* Just ensure it has the right spl. */ 963 s = splbio(); 964 (void) fdcintr(arg); 965 splx(s); 966 } 967 968 int 969 fdcintr(arg) 970 void *arg; 971 { 972 struct fdc_softc *fdc = arg; 973 #define st0 fdc->sc_status[0] 974 #define cyl fdc->sc_status[1] 975 struct fd_softc *fd; 976 struct buf *bp; 977 bus_space_tag_t iot = fdc->sc_iot; 978 bus_space_handle_t ioh = fdc->sc_ioh; 979 int read, head, sec, i, nblks; 980 struct fd_type *type; 981 struct ne7_fd_formb *finfo = NULL; 982 983 loop: 984 /* Is there a drive for the controller to do a transfer with? */ 985 fd = TAILQ_FIRST(&fdc->sc_drives); 986 if (fd == NULL) { 987 fdc->sc_state = DEVIDLE; 988 return 1; 989 } 990 991 /* Is there a transfer to this drive? If not, deactivate drive. */ 992 bp = BUFQ_PEEK(&fd->sc_q); 993 if (bp == NULL) { 994 fd->sc_ops = 0; 995 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain); 996 fd->sc_active = 0; 997 goto loop; 998 } 999 1000 if (bp->b_flags & B_FORMAT) 1001 finfo = (struct ne7_fd_formb *)bp->b_data; 1002 1003 switch (fdc->sc_state) { 1004 case DEVIDLE: 1005 fdc->sc_errors = 0; 1006 fd->sc_skip = 0; 1007 fd->sc_bcount = bp->b_bcount; 1008 fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE); 1009 callout_stop(&fd->sc_motoroff_ch); 1010 if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) { 1011 fdc->sc_state = MOTORWAIT; 1012 return 1; 1013 } 1014 if ((fd->sc_flags & FD_MOTOR) == 0) { 1015 /* Turn on the motor, being careful about pairing. */ 1016 struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1]; 1017 if (ofd && ofd->sc_flags & FD_MOTOR) { 1018 callout_stop(&ofd->sc_motoroff_ch); 1019 ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT); 1020 } 1021 fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT; 1022 fd_set_motor(fdc, 0); 1023 fdc->sc_state = MOTORWAIT; 1024 /* Allow .25s for motor to stabilize. */ 1025 callout_reset(&fd->sc_motoron_ch, hz / 4, 1026 fd_motor_on, fd); 1027 return 1; 1028 } 1029 /* Make sure the right drive is selected. */ 1030 fd_set_motor(fdc, 0); 1031 1032 /* fall through */ 1033 case DOSEEK: 1034 doseek: 1035 if (fd->sc_cylin == bp->b_cylinder) 1036 goto doio; 1037 1038 out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */ 1039 out_fdc(iot, ioh, fd->sc_type->steprate); 1040 out_fdc(iot, ioh, 6); /* XXX head load time == 6ms */ 1041 1042 out_fdc(iot, ioh, NE7CMD_SEEK); /* seek function */ 1043 out_fdc(iot, ioh, fd->sc_drive); /* drive number */ 1044 out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step); 1045 1046 fd->sc_cylin = -1; 1047 fdc->sc_state = SEEKWAIT; 1048 1049 fd->sc_dk.dk_seek++; 1050 disk_busy(&fd->sc_dk); 1051 1052 callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc); 1053 return 1; 1054 1055 case DOIO: 1056 doio: 1057 type = fd->sc_type; 1058 if (finfo) 1059 fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) - 1060 (char *)finfo; 1061 sec = fd->sc_blkno % type->seccyl; 1062 nblks = type->seccyl - sec; 1063 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE); 1064 nblks = min(nblks, fdc->sc_maxiosize / FDC_BSIZE); 1065 fd->sc_nblks = nblks; 1066 fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FDC_BSIZE; 1067 head = sec / type->sectrac; 1068 sec -= head * type->sectrac; 1069 #ifdef DIAGNOSTIC 1070 { 1071 int block; 1072 block = (fd->sc_cylin * type->heads + head) 1073 * type->sectrac + sec; 1074 if (block != fd->sc_blkno) { 1075 printf("fdcintr: block %d != blkno %d\n", 1076 block, fd->sc_blkno); 1077 #ifdef DDB 1078 Debugger(); 1079 #endif 1080 } 1081 } 1082 #endif 1083 read = bp->b_flags & B_READ ? DMAMODE_READ : DMAMODE_WRITE; 1084 isa_dmastart(fdc->sc_ic, fdc->sc_drq, 1085 bp->b_data + fd->sc_skip, fd->sc_nbytes, 1086 NULL, read | DMAMODE_DEMAND, BUS_DMA_NOWAIT); 1087 bus_space_write_1(iot, fdc->sc_fdctlioh, 0, type->rate); 1088 #ifdef FD_DEBUG 1089 printf("fdcintr: %s drive %d track %d head %d sec %d nblks %d\n", 1090 read ? "read" : "write", fd->sc_drive, fd->sc_cylin, 1091 head, sec, nblks); 1092 #endif 1093 if (finfo) { 1094 /* formatting */ 1095 if (out_fdc(iot, ioh, NE7CMD_FORMAT) < 0) { 1096 fdc->sc_errors = 4; 1097 fdcretry(fdc); 1098 goto loop; 1099 } 1100 out_fdc(iot, ioh, (head << 2) | fd->sc_drive); 1101 out_fdc(iot, ioh, finfo->fd_formb_secshift); 1102 out_fdc(iot, ioh, finfo->fd_formb_nsecs); 1103 out_fdc(iot, ioh, finfo->fd_formb_gaplen); 1104 out_fdc(iot, ioh, finfo->fd_formb_fillbyte); 1105 } else { 1106 if (read) 1107 out_fdc(iot, ioh, NE7CMD_READ); /* READ */ 1108 else 1109 out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */ 1110 out_fdc(iot, ioh, (head << 2) | fd->sc_drive); 1111 out_fdc(iot, ioh, fd->sc_cylin); /* track */ 1112 out_fdc(iot, ioh, head); 1113 out_fdc(iot, ioh, sec + 1); /* sector +1 */ 1114 out_fdc(iot, ioh, type->secsize);/* sector size */ 1115 out_fdc(iot, ioh, type->sectrac);/* sectors/track */ 1116 out_fdc(iot, ioh, type->gap1); /* gap1 size */ 1117 out_fdc(iot, ioh, type->datalen);/* data length */ 1118 } 1119 fdc->sc_state = IOCOMPLETE; 1120 1121 disk_busy(&fd->sc_dk); 1122 1123 /* allow 2 seconds for operation */ 1124 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc); 1125 return 1; /* will return later */ 1126 1127 case SEEKWAIT: 1128 callout_stop(&fdc->sc_timo_ch); 1129 fdc->sc_state = SEEKCOMPLETE; 1130 /* allow 1/50 second for heads to settle */ 1131 callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc); 1132 return 1; 1133 1134 case SEEKCOMPLETE: 1135 /* no data on seek */ 1136 disk_unbusy(&fd->sc_dk, 0, 0); 1137 1138 /* Make sure seek really happened. */ 1139 out_fdc(iot, ioh, NE7CMD_SENSEI); 1140 if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || 1141 cyl != bp->b_cylinder * fd->sc_type->step) { 1142 #ifdef FD_DEBUG 1143 fdcstatus(&fd->sc_dev, 2, "seek failed"); 1144 #endif 1145 fdcretry(fdc); 1146 goto loop; 1147 } 1148 fd->sc_cylin = bp->b_cylinder; 1149 goto doio; 1150 1151 case IOTIMEDOUT: 1152 isa_dmaabort(fdc->sc_ic, fdc->sc_drq); 1153 case SEEKTIMEDOUT: 1154 case RECALTIMEDOUT: 1155 case RESETTIMEDOUT: 1156 fdcretry(fdc); 1157 goto loop; 1158 1159 case IOCOMPLETE: /* IO DONE, post-analyze */ 1160 callout_stop(&fdc->sc_timo_ch); 1161 1162 disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid), 1163 (bp->b_flags & B_READ)); 1164 1165 if (fdcresult(fdc) != 7 || (st0 & 0xf8) != 0) { 1166 isa_dmaabort(fdc->sc_ic, fdc->sc_drq); 1167 #ifdef FD_DEBUG 1168 fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ? 1169 "read failed" : "write failed"); 1170 printf("blkno %d nblks %d\n", 1171 fd->sc_blkno, fd->sc_nblks); 1172 #endif 1173 fdcretry(fdc); 1174 goto loop; 1175 } 1176 isa_dmadone(fdc->sc_ic, fdc->sc_drq); 1177 if (fdc->sc_errors) { 1178 diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF, 1179 fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL); 1180 printf("\n"); 1181 fdc->sc_errors = 0; 1182 } 1183 fd->sc_blkno += fd->sc_nblks; 1184 fd->sc_skip += fd->sc_nbytes; 1185 fd->sc_bcount -= fd->sc_nbytes; 1186 if (!finfo && fd->sc_bcount > 0) { 1187 bp->b_cylinder = fd->sc_blkno / fd->sc_type->seccyl; 1188 goto doseek; 1189 } 1190 fdfinish(fd, bp); 1191 goto loop; 1192 1193 case DORESET: 1194 /* try a reset, keep motor on */ 1195 fd_set_motor(fdc, 1); 1196 delay(100); 1197 fd_set_motor(fdc, 0); 1198 fdc->sc_state = RESETCOMPLETE; 1199 callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc); 1200 return 1; /* will return later */ 1201 1202 case RESETCOMPLETE: 1203 callout_stop(&fdc->sc_timo_ch); 1204 /* clear the controller output buffer */ 1205 for (i = 0; i < 4; i++) { 1206 out_fdc(iot, ioh, NE7CMD_SENSEI); 1207 (void) fdcresult(fdc); 1208 } 1209 1210 /* fall through */ 1211 case DORECAL: 1212 out_fdc(iot, ioh, NE7CMD_RECAL); /* recalibrate function */ 1213 out_fdc(iot, ioh, fd->sc_drive); 1214 fdc->sc_state = RECALWAIT; 1215 callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc); 1216 return 1; /* will return later */ 1217 1218 case RECALWAIT: 1219 callout_stop(&fdc->sc_timo_ch); 1220 fdc->sc_state = RECALCOMPLETE; 1221 /* allow 1/30 second for heads to settle */ 1222 callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc); 1223 return 1; /* will return later */ 1224 1225 case RECALCOMPLETE: 1226 out_fdc(iot, ioh, NE7CMD_SENSEI); 1227 if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) { 1228 #ifdef FD_DEBUG 1229 fdcstatus(&fd->sc_dev, 2, "recalibrate failed"); 1230 #endif 1231 fdcretry(fdc); 1232 goto loop; 1233 } 1234 fd->sc_cylin = 0; 1235 goto doseek; 1236 1237 case MOTORWAIT: 1238 if (fd->sc_flags & FD_MOTOR_WAIT) 1239 return 1; /* time's not up yet */ 1240 goto doseek; 1241 1242 default: 1243 fdcstatus(&fd->sc_dev, 0, "stray interrupt"); 1244 return 1; 1245 } 1246 #ifdef DIAGNOSTIC 1247 panic("fdcintr: impossible"); 1248 #endif 1249 #undef st0 1250 #undef cyl 1251 } 1252 1253 void 1254 fdcretry(fdc) 1255 struct fdc_softc *fdc; 1256 { 1257 char bits[64]; 1258 struct fd_softc *fd; 1259 struct buf *bp; 1260 1261 fd = TAILQ_FIRST(&fdc->sc_drives); 1262 bp = BUFQ_PEEK(&fd->sc_q); 1263 1264 if (fd->sc_opts & FDOPT_NORETRY) 1265 goto fail; 1266 switch (fdc->sc_errors) { 1267 case 0: 1268 /* try again */ 1269 fdc->sc_state = DOSEEK; 1270 break; 1271 1272 case 1: case 2: case 3: 1273 /* didn't work; try recalibrating */ 1274 fdc->sc_state = DORECAL; 1275 break; 1276 1277 case 4: 1278 /* still no go; reset the bastard */ 1279 fdc->sc_state = DORESET; 1280 break; 1281 1282 default: 1283 fail: 1284 if ((fd->sc_opts & FDOPT_SILENT) == 0) { 1285 diskerr(bp, "fd", "hard error", LOG_PRINTF, 1286 fd->sc_skip / FDC_BSIZE, 1287 (struct disklabel *)NULL); 1288 1289 printf(" (st0 %s", 1290 bitmask_snprintf(fdc->sc_status[0], 1291 NE7_ST0BITS, bits, 1292 sizeof(bits))); 1293 printf(" st1 %s", 1294 bitmask_snprintf(fdc->sc_status[1], 1295 NE7_ST1BITS, bits, 1296 sizeof(bits))); 1297 printf(" st2 %s", 1298 bitmask_snprintf(fdc->sc_status[2], 1299 NE7_ST2BITS, bits, 1300 sizeof(bits))); 1301 printf(" cyl %d head %d sec %d)\n", 1302 fdc->sc_status[3], 1303 fdc->sc_status[4], 1304 fdc->sc_status[5]); 1305 } 1306 1307 bp->b_flags |= B_ERROR; 1308 bp->b_error = EIO; 1309 fdfinish(fd, bp); 1310 } 1311 fdc->sc_errors++; 1312 } 1313 1314 int 1315 fdioctl(dev, cmd, addr, flag, p) 1316 dev_t dev; 1317 u_long cmd; 1318 caddr_t addr; 1319 int flag; 1320 struct proc *p; 1321 { 1322 struct fd_softc *fd = device_lookup(&fd_cd, FDUNIT(dev)); 1323 struct fdformat_parms *form_parms; 1324 struct fdformat_cmd *form_cmd; 1325 struct ne7_fd_formb *fd_formb; 1326 struct disklabel buffer; 1327 int error; 1328 unsigned int scratch; 1329 int il[FD_MAX_NSEC + 1]; 1330 register int i, j; 1331 #ifdef __HAVE_OLD_DISKLABEL 1332 struct disklabel newlabel; 1333 #endif 1334 1335 switch (cmd) { 1336 case DIOCGDINFO: 1337 #ifdef __HAVE_OLD_DISKLABEL 1338 case ODIOCGDINFO: 1339 #endif 1340 memset(&buffer, 0, sizeof(buffer)); 1341 1342 buffer.d_secpercyl = fd->sc_type->seccyl; 1343 buffer.d_type = DTYPE_FLOPPY; 1344 buffer.d_secsize = FDC_BSIZE; 1345 1346 if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL) 1347 return EINVAL; 1348 1349 #ifdef __HAVE_OLD_DISKLABEL 1350 if (cmd == ODIOCGDINFO) { 1351 if (buffer.d_npartitions > OLDMAXPARTITIONS) 1352 return ENOTTY; 1353 memcpy(addr, &buffer, sizeof (struct olddisklabel)); 1354 } else 1355 #endif 1356 *(struct disklabel *)addr = buffer; 1357 return 0; 1358 1359 case DIOCWLABEL: 1360 if ((flag & FWRITE) == 0) 1361 return EBADF; 1362 /* XXX do something */ 1363 return 0; 1364 1365 case DIOCWDINFO: 1366 #ifdef __HAVE_OLD_DISKLABEL 1367 case ODIOCWDINFO: 1368 #endif 1369 { 1370 struct disklabel *lp; 1371 1372 if ((flag & FWRITE) == 0) 1373 return EBADF; 1374 #ifdef __HAVE_OLD_DISKLABEL 1375 if (cmd == ODIOCWDINFO) { 1376 memset(&newlabel, 0, sizeof newlabel); 1377 memcpy(&newlabel, addr, sizeof (struct olddisklabel)); 1378 lp = &newlabel; 1379 } else 1380 #endif 1381 lp = (struct disklabel *)addr; 1382 1383 error = setdisklabel(&buffer, lp, 0, NULL); 1384 if (error) 1385 return error; 1386 1387 error = writedisklabel(dev, fdstrategy, &buffer, NULL); 1388 return error; 1389 } 1390 1391 case FDIOCGETFORMAT: 1392 form_parms = (struct fdformat_parms *)addr; 1393 form_parms->fdformat_version = FDFORMAT_VERSION; 1394 form_parms->nbps = 128 * (1 << fd->sc_type->secsize); 1395 form_parms->ncyl = fd->sc_type->cyls; 1396 form_parms->nspt = fd->sc_type->sectrac; 1397 form_parms->ntrk = fd->sc_type->heads; 1398 form_parms->stepspercyl = fd->sc_type->step; 1399 form_parms->gaplen = fd->sc_type->gap2; 1400 form_parms->fillbyte = fd->sc_type->fillbyte; 1401 form_parms->interleave = fd->sc_type->interleave; 1402 switch (fd->sc_type->rate) { 1403 case FDC_500KBPS: 1404 form_parms->xfer_rate = 500 * 1024; 1405 break; 1406 case FDC_300KBPS: 1407 form_parms->xfer_rate = 300 * 1024; 1408 break; 1409 case FDC_250KBPS: 1410 form_parms->xfer_rate = 250 * 1024; 1411 break; 1412 default: 1413 return EINVAL; 1414 } 1415 return 0; 1416 1417 case FDIOCSETFORMAT: 1418 if((flag & FWRITE) == 0) 1419 return EBADF; /* must be opened for writing */ 1420 form_parms = (struct fdformat_parms *)addr; 1421 if (form_parms->fdformat_version != FDFORMAT_VERSION) 1422 return EINVAL; /* wrong version of formatting prog */ 1423 1424 scratch = form_parms->nbps >> 7; 1425 if ((form_parms->nbps & 0x7f) || ffs(scratch) == 0 || 1426 scratch & ~(1 << (ffs(scratch)-1))) 1427 /* not a power-of-two multiple of 128 */ 1428 return EINVAL; 1429 1430 switch (form_parms->xfer_rate) { 1431 case 500 * 1024: 1432 fd->sc_type->rate = FDC_500KBPS; 1433 break; 1434 case 300 * 1024: 1435 fd->sc_type->rate = FDC_300KBPS; 1436 break; 1437 case 250 * 1024: 1438 fd->sc_type->rate = FDC_250KBPS; 1439 break; 1440 default: 1441 return EINVAL; 1442 } 1443 1444 if (form_parms->nspt > FD_MAX_NSEC || 1445 form_parms->fillbyte > 0xff || 1446 form_parms->interleave > 0xff) 1447 return EINVAL; 1448 fd->sc_type->sectrac = form_parms->nspt; 1449 if (form_parms->ntrk != 2 && form_parms->ntrk != 1) 1450 return EINVAL; 1451 fd->sc_type->heads = form_parms->ntrk; 1452 fd->sc_type->seccyl = form_parms->nspt * form_parms->ntrk; 1453 fd->sc_type->secsize = ffs(scratch)-1; 1454 fd->sc_type->gap2 = form_parms->gaplen; 1455 fd->sc_type->cyls = form_parms->ncyl; 1456 fd->sc_type->size = fd->sc_type->seccyl * form_parms->ncyl * 1457 form_parms->nbps / DEV_BSIZE; 1458 fd->sc_type->step = form_parms->stepspercyl; 1459 fd->sc_type->fillbyte = form_parms->fillbyte; 1460 fd->sc_type->interleave = form_parms->interleave; 1461 return 0; 1462 1463 case FDIOCFORMAT_TRACK: 1464 if((flag & FWRITE) == 0) 1465 return EBADF; /* must be opened for writing */ 1466 form_cmd = (struct fdformat_cmd *)addr; 1467 if (form_cmd->formatcmd_version != FDFORMAT_VERSION) 1468 return EINVAL; /* wrong version of formatting prog */ 1469 1470 if (form_cmd->head >= fd->sc_type->heads || 1471 form_cmd->cylinder >= fd->sc_type->cyls) { 1472 return EINVAL; 1473 } 1474 1475 fd_formb = malloc(sizeof(struct ne7_fd_formb), 1476 M_TEMP, M_NOWAIT); 1477 if (fd_formb == 0) 1478 return ENOMEM; 1479 1480 fd_formb->head = form_cmd->head; 1481 fd_formb->cyl = form_cmd->cylinder; 1482 fd_formb->transfer_rate = fd->sc_type->rate; 1483 fd_formb->fd_formb_secshift = fd->sc_type->secsize; 1484 fd_formb->fd_formb_nsecs = fd->sc_type->sectrac; 1485 fd_formb->fd_formb_gaplen = fd->sc_type->gap2; 1486 fd_formb->fd_formb_fillbyte = fd->sc_type->fillbyte; 1487 1488 memset(il, 0, sizeof il); 1489 for (j = 0, i = 1; i <= fd_formb->fd_formb_nsecs; i++) { 1490 while (il[(j%fd_formb->fd_formb_nsecs)+1]) 1491 j++; 1492 il[(j%fd_formb->fd_formb_nsecs)+1] = i; 1493 j += fd->sc_type->interleave; 1494 } 1495 for (i = 0; i < fd_formb->fd_formb_nsecs; i++) { 1496 fd_formb->fd_formb_cylno(i) = form_cmd->cylinder; 1497 fd_formb->fd_formb_headno(i) = form_cmd->head; 1498 fd_formb->fd_formb_secno(i) = il[i+1]; 1499 fd_formb->fd_formb_secsize(i) = fd->sc_type->secsize; 1500 } 1501 1502 error = fdformat(dev, fd_formb, p); 1503 free(fd_formb, M_TEMP); 1504 return error; 1505 1506 case FDIOCGETOPTS: /* get drive options */ 1507 *(int *)addr = fd->sc_opts; 1508 return 0; 1509 1510 case FDIOCSETOPTS: /* set drive options */ 1511 fd->sc_opts = *(int *)addr; 1512 return 0; 1513 1514 default: 1515 return ENOTTY; 1516 } 1517 1518 #ifdef DIAGNOSTIC 1519 panic("fdioctl: impossible"); 1520 #endif 1521 } 1522 1523 int 1524 fdformat(dev, finfo, p) 1525 dev_t dev; 1526 struct ne7_fd_formb *finfo; 1527 struct proc *p; 1528 { 1529 int rv = 0, s; 1530 struct fd_softc *fd = device_lookup(&fd_cd, FDUNIT(dev)); 1531 struct fd_type *type = fd->sc_type; 1532 struct buf *bp; 1533 1534 /* set up a buffer header for fdstrategy() */ 1535 bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT|M_ZERO); 1536 if(bp == 0) 1537 return ENOBUFS; 1538 bp->b_flags = B_BUSY | B_PHYS | B_FORMAT; 1539 bp->b_proc = p; 1540 bp->b_dev = dev; 1541 1542 /* 1543 * calculate a fake blkno, so fdstrategy() would initiate a 1544 * seek to the requested cylinder 1545 */ 1546 bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads) 1547 + finfo->head * type->sectrac) * FDC_BSIZE / DEV_BSIZE; 1548 1549 bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs; 1550 bp->b_data = (caddr_t)finfo; 1551 1552 #ifdef DEBUG 1553 printf("fdformat: blkno %x count %lx\n", bp->b_blkno, bp->b_bcount); 1554 #endif 1555 1556 /* now do the format */ 1557 fdstrategy(bp); 1558 1559 /* ...and wait for it to complete */ 1560 s = splbio(); 1561 while (!(bp->b_flags & B_DONE)) { 1562 rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 20 * hz); 1563 if (rv == EWOULDBLOCK) 1564 break; 1565 } 1566 splx(s); 1567 1568 if (rv == EWOULDBLOCK) { 1569 /* timed out */ 1570 rv = EIO; 1571 biodone(bp); 1572 } 1573 if(bp->b_flags & B_ERROR) { 1574 rv = bp->b_error; 1575 } 1576 free(bp, M_TEMP); 1577 return rv; 1578 } 1579 1580 /* 1581 * Mountroot hook: prompt the user to enter the root file system 1582 * floppy. 1583 */ 1584 void 1585 fd_mountroot_hook(dev) 1586 struct device *dev; 1587 { 1588 int c; 1589 1590 printf("Insert filesystem floppy and press return."); 1591 cnpollc(1); 1592 for (;;) { 1593 c = cngetc(); 1594 if ((c == '\r') || (c == '\n')) { 1595 printf("\n"); 1596 break; 1597 } 1598 } 1599 cnpollc(0); 1600 } 1601