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