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