fdc.c revision 12359
1/*- 2 * Copyright (c) 1990 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Don Ahn. 7 * 8 * Copyright (c) 1993, 1994 by 9 * jc@irbs.UUCP (John Capo) 10 * vak@zebub.msk.su (Serge Vakulenko) 11 * ache@astral.msk.su (Andrew A. Chernov) 12 * 13 * Copyright (c) 1993, 1994, 1995 by 14 * joerg_wunsch@uriah.sax.de (Joerg Wunsch) 15 * dufault@hda.com (Peter Dufault) 16 * 17 * Redistribution and use in source and binary forms, with or without 18 * modification, are permitted provided that the following conditions 19 * are met: 20 * 1. Redistributions of source code must retain the above copyright 21 * notice, this list of conditions and the following disclaimer. 22 * 2. Redistributions in binary form must reproduce the above copyright 23 * notice, this list of conditions and the following disclaimer in the 24 * documentation and/or other materials provided with the distribution. 25 * 3. All advertising materials mentioning features or use of this software 26 * must display the following acknowledgement: 27 * This product includes software developed by the University of 28 * California, Berkeley and its contributors. 29 * 4. Neither the name of the University nor the names of its contributors 30 * may be used to endorse or promote products derived from this software 31 * without specific prior written permission. 32 * 33 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 34 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 35 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 36 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 37 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 38 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 39 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 40 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 41 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 42 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 43 * SUCH DAMAGE. 44 * 45 * from: @(#)fd.c 7.4 (Berkeley) 5/25/91 46 * $Id: fd.c,v 1.69 1995/11/04 17:07:17 bde Exp $ 47 * 48 */ 49 50#include "ft.h" 51#if NFT < 1 52#undef NFDC 53#endif 54#include "fd.h" 55 56#if NFDC > 0 57 58#include <sys/param.h> 59#include <sys/systm.h> 60#include <sys/kernel.h> 61#include <sys/conf.h> 62#include <sys/file.h> 63#include <sys/ioctl.h> 64#include <machine/clock.h> 65#include <machine/ioctl_fd.h> 66#include <sys/disklabel.h> 67#include <sys/diskslice.h> 68#include <machine/cpu.h> 69#include <sys/buf.h> 70#include <sys/uio.h> 71#include <sys/malloc.h> 72#include <sys/proc.h> 73#include <sys/syslog.h> 74#include <sys/devconf.h> 75#include <sys/dkstat.h> 76#include <i386/isa/isa.h> 77#include <i386/isa/isa_device.h> 78#include <i386/isa/fdreg.h> 79#include <i386/isa/fdc.h> 80#include <i386/isa/rtc.h> 81#include <machine/stdarg.h> 82#if NFT > 0 83#include <sys/ftape.h> 84#include <i386/isa/ftreg.h> 85#endif 86#ifdef DEVFS 87#include <sys/devfsext.h> 88#endif 89 90static int fd_goaway(struct kern_devconf *, int); 91static int fdc_goaway(struct kern_devconf *, int); 92static int 93fd_externalize(struct proc *, struct kern_devconf *, void *, size_t); 94 95/* 96 * Templates for the kern_devconf structures used when we attach. 97 */ 98static struct kern_devconf kdc_fd[NFD] = { { 99 0, 0, 0, /* filled in by kern_devconf.c */ 100 "fd", 0, { MDDT_DISK, 0 }, 101 fd_externalize, 0, fd_goaway, DISK_EXTERNALLEN, 102 0, /* parent */ 103 0, /* parentdata */ 104 DC_UNCONFIGURED, /* state */ 105 "floppy disk", 106 DC_CLS_DISK /* class */ 107} }; 108 109struct kern_devconf kdc_fdc[NFDC] = { { 110 0, 0, 0, /* filled in by kern_devconf.c */ 111 "fdc", 0, { MDDT_ISA, 0, "bio" }, 112 isa_generic_externalize, 0, fdc_goaway, ISA_EXTERNALLEN, 113 0, /* parent */ 114 0, /* parentdata */ 115 DC_UNCONFIGURED, /* state */ 116 "floppy disk/tape controller", 117 DC_CLS_MISC /* class */ 118} }; 119 120static inline void 121fd_registerdev(int ctlr, int unit) 122{ 123 if(unit != 0) 124 kdc_fd[unit] = kdc_fd[0]; 125 126 kdc_fd[unit].kdc_unit = unit; 127 kdc_fd[unit].kdc_parent = &kdc_fdc[ctlr]; 128 kdc_fd[unit].kdc_parentdata = 0; 129 dev_attach(&kdc_fd[unit]); 130} 131 132static inline void 133fdc_registerdev(struct isa_device *dvp) 134{ 135 int unit = dvp->id_unit; 136 137 if(unit != 0) 138 kdc_fdc[unit] = kdc_fdc[0]; 139 140 kdc_fdc[unit].kdc_unit = unit; 141 kdc_fdc[unit].kdc_parent = &kdc_isa0; 142 kdc_fdc[unit].kdc_parentdata = dvp; 143 dev_attach(&kdc_fdc[unit]); 144} 145 146static int 147fdc_goaway(struct kern_devconf *kdc, int force) 148{ 149 if(force) { 150 dev_detach(kdc); 151 return 0; 152 } else { 153 return EBUSY; /* XXX fix */ 154 } 155} 156 157static int 158fd_goaway(struct kern_devconf *kdc, int force) 159{ 160 dev_detach(kdc); 161 return 0; 162} 163 164#define b_cylin b_resid /* XXX now spelled b_cylinder elsewhere */ 165 166/* misuse a flag to identify format operation */ 167#define B_FORMAT B_XXX 168 169/* 170 * this biotab field doubles as a field for the physical unit number 171 * on the controller 172 */ 173#define id_physid id_scsiid 174 175/* error returns for fd_cmd() */ 176#define FD_FAILED -1 177#define FD_NOT_VALID -2 178#define FDC_ERRMAX 100 /* do not log more */ 179 180#define NUMTYPES 14 181#define NUMDENS (NUMTYPES - 6) 182 183/* These defines (-1) must match index for fd_types */ 184#define F_TAPE_TYPE 0x020 /* bit for fd_types to indicate tape */ 185#define NO_TYPE 0 /* must match NO_TYPE in ft.c */ 186#define FD_1720 1 187#define FD_1480 2 188#define FD_1440 3 189#define FD_1200 4 190#define FD_820 5 191#define FD_800 6 192#define FD_720 7 193#define FD_360 8 194 195#define FD_1480in5_25 9 196#define FD_1440in5_25 10 197#define FD_820in5_25 11 198#define FD_800in5_25 12 199#define FD_720in5_25 13 200#define FD_360in5_25 14 201 202 203struct fd_type fd_types[NUMTYPES] = 204{ 205{ 21,2,0xFF,0x04,82,3444,1,FDC_500KBPS,2,0x0C,2 }, /* 1.72M in HD 3.5in */ 206{ 18,2,0xFF,0x1B,82,2952,1,FDC_500KBPS,2,0x6C,1 }, /* 1.48M in HD 3.5in */ 207{ 18,2,0xFF,0x1B,80,2880,1,FDC_500KBPS,2,0x6C,1 }, /* 1.44M in HD 3.5in */ 208{ 15,2,0xFF,0x1B,80,2400,1,FDC_500KBPS,2,0x54,1 }, /* 1.2M in HD 5.25/3.5 */ 209{ 10,2,0xFF,0x10,82,1640,1,FDC_250KBPS,2,0x2E,1 }, /* 820K in HD 3.5in */ 210{ 10,2,0xFF,0x10,80,1600,1,FDC_250KBPS,2,0x2E,1 }, /* 800K in HD 3.5in */ 211{ 9,2,0xFF,0x20,80,1440,1,FDC_250KBPS,2,0x50,1 }, /* 720K in HD 3.5in */ 212{ 9,2,0xFF,0x2A,40, 720,1,FDC_250KBPS,2,0x50,1 }, /* 360K in DD 5.25in */ 213 214{ 18,2,0xFF,0x02,82,2952,1,FDC_500KBPS,2,0x02,2 }, /* 1.48M in HD 5.25in */ 215{ 18,2,0xFF,0x02,80,2880,1,FDC_500KBPS,2,0x02,2 }, /* 1.44M in HD 5.25in */ 216{ 10,2,0xFF,0x10,82,1640,1,FDC_300KBPS,2,0x2E,1 }, /* 820K in HD 5.25in */ 217{ 10,2,0xFF,0x10,80,1600,1,FDC_300KBPS,2,0x2E,1 }, /* 800K in HD 5.25in */ 218{ 9,2,0xFF,0x20,80,1440,1,FDC_300KBPS,2,0x50,1 }, /* 720K in HD 5.25in */ 219{ 9,2,0xFF,0x23,40, 720,2,FDC_300KBPS,2,0x50,1 }, /* 360K in HD 5.25in */ 220}; 221 222#define DRVS_PER_CTLR 2 /* 2 floppies */ 223 224/***********************************************************************\ 225* Per controller structure. * 226\***********************************************************************/ 227struct fdc_data fdc_data[NFDC]; 228 229/***********************************************************************\ 230* Per drive structure. * 231* N per controller (DRVS_PER_CTLR) * 232\***********************************************************************/ 233struct fd_data { 234 struct fdc_data *fdc; /* pointer to controller structure */ 235 int fdsu; /* this units number on this controller */ 236 int type; /* Drive type (FD_1440...) */ 237 struct fd_type *ft; /* pointer to the type descriptor */ 238 int flags; 239#define FD_OPEN 0x01 /* it's open */ 240#define FD_ACTIVE 0x02 /* it's active */ 241#define FD_MOTOR 0x04 /* motor should be on */ 242#define FD_MOTOR_WAIT 0x08 /* motor coming up */ 243 int skip; 244 int hddrv; 245#define FD_NO_TRACK -2 246 int track; /* where we think the head is */ 247 int options; /* user configurable options, see ioctl_fd.h */ 248 int dkunit; /* disk stats unit number */ 249} fd_data[NFD]; 250 251/***********************************************************************\ 252* Throughout this file the following conventions will be used: * 253* fd is a pointer to the fd_data struct for the drive in question * 254* fdc is a pointer to the fdc_data struct for the controller * 255* fdu is the floppy drive unit number * 256* fdcu is the floppy controller unit number * 257* fdsu is the floppy drive unit number on that controller. (sub-unit) * 258\***********************************************************************/ 259 260#if NFT > 0 261int ftopen(dev_t, int); 262int ftintr(ftu_t ftu); 263int ftclose(dev_t, int); 264void ftstrategy(struct buf *); 265int ftioctl(dev_t, int, caddr_t, int, struct proc *); 266int ftdump(dev_t); 267int ftsize(dev_t); 268int ftattach(struct isa_device *, struct isa_device *, int); 269#endif 270 271/* autoconfig functions */ 272static int fdprobe(struct isa_device *); 273static int fdattach(struct isa_device *); 274 275/* needed for ft driver, thus exported */ 276int in_fdc(fdcu_t); 277int out_fdc(fdcu_t, int); 278 279/* internal functions */ 280static void set_motor(fdcu_t, int, int); 281# define TURNON 1 282# define TURNOFF 0 283static timeout_t fd_turnoff; 284static timeout_t fd_motor_on; 285static void fd_turnon(fdu_t); 286static void fdc_reset(fdc_p); 287static int fd_in(fdcu_t, int *); 288static void fdstart(fdcu_t); 289static timeout_t fd_timeout; 290static timeout_t fd_pseudointr; 291static int fdstate(fdcu_t, fdc_p); 292static int retrier(fdcu_t); 293static int fdformat(dev_t, struct fd_formb *, struct proc *); 294 295 296#define DEVIDLE 0 297#define FINDWORK 1 298#define DOSEEK 2 299#define SEEKCOMPLETE 3 300#define IOCOMPLETE 4 301#define RECALCOMPLETE 5 302#define STARTRECAL 6 303#define RESETCTLR 7 304#define SEEKWAIT 8 305#define RECALWAIT 9 306#define MOTORWAIT 10 307#define IOTIMEDOUT 11 308 309#ifdef DEBUG 310char *fdstates[] = 311{ 312"DEVIDLE", 313"FINDWORK", 314"DOSEEK", 315"SEEKCOMPLETE", 316"IOCOMPLETE", 317"RECALCOMPLETE", 318"STARTRECAL", 319"RESETCTLR", 320"SEEKWAIT", 321"RECALWAIT", 322"MOTORWAIT", 323"IOTIMEDOUT" 324}; 325 326/* CAUTION: fd_debug causes huge amounts of logging output */ 327int fd_debug = 0; 328#define TRACE0(arg) if(fd_debug) printf(arg) 329#define TRACE1(arg1, arg2) if(fd_debug) printf(arg1, arg2) 330#else /* DEBUG */ 331#define TRACE0(arg) 332#define TRACE1(arg1, arg2) 333#endif /* DEBUG */ 334 335/* autoconfig structure */ 336 337struct isa_driver fdcdriver = { 338 fdprobe, fdattach, "fdc", 339}; 340 341struct isa_device *fdcdevs[NFDC]; 342 343/* 344 * Provide hw.devconf information. 345 */ 346static int 347fd_externalize(struct proc *p, struct kern_devconf *kdc, 348 void *userp, size_t len) 349{ 350 return disk_externalize(fd_data[kdc->kdc_unit].fdsu, userp, &len); 351} 352 353static int 354fdc_externalize(struct proc *p, struct kern_devconf *kdc, 355 void *userp, size_t len) 356{ 357 return isa_externalize(fdcdevs[kdc->kdc_unit], userp, &len); 358} 359 360static int 361fdc_err(fdcu_t fdcu, const char *s) 362{ 363 fdc_data[fdcu].fdc_errs++; 364 if(s) { 365 if(fdc_data[fdcu].fdc_errs < FDC_ERRMAX) 366 printf("fdc%d: %s", fdcu, s); 367 else if(fdc_data[fdcu].fdc_errs == FDC_ERRMAX) 368 printf("fdc%d: too many errors, not logging any more\n", 369 fdcu); 370 } 371 372 return FD_FAILED; 373} 374 375/* 376 * fd_cmd: Send a command to the chip. Takes a varargs with this structure: 377 * Unit number, 378 * # of output bytes, output bytes as ints ..., 379 * # of input bytes, input bytes as ints ... 380 */ 381 382int 383fd_cmd(fdcu_t fdcu, int n_out, ...) 384{ 385 u_char cmd; 386 int n_in; 387 int n; 388 va_list ap; 389 390 va_start(ap, n_out); 391 cmd = (u_char)(va_arg(ap, int)); 392 va_end(ap); 393 va_start(ap, n_out); 394 for (n = 0; n < n_out; n++) 395 { 396 if (out_fdc(fdcu, va_arg(ap, int)) < 0) 397 { 398 char msg[50]; 399 sprintf(msg, 400 "cmd %x failed at out byte %d of %d\n", 401 cmd, n + 1, n_out); 402 return fdc_err(fdcu, msg); 403 } 404 } 405 n_in = va_arg(ap, int); 406 for (n = 0; n < n_in; n++) 407 { 408 int *ptr = va_arg(ap, int *); 409 if (fd_in(fdcu, ptr) < 0) 410 { 411 char msg[50]; 412 sprintf(msg, 413 "cmd %02x failed at in byte %d of %d\n", 414 cmd, n + 1, n_in); 415 return fdc_err(fdcu, msg); 416 } 417 } 418 419 return 0; 420} 421 422int 423fd_sense_drive_status(fdc_p fdc, int *st3p) 424{ 425 int st3; 426 427 if (fd_cmd(fdc->fdcu, 2, NE7CMD_SENSED, fdc->fdu, 1, &st3)) 428 { 429 return fdc_err(fdc->fdcu, "Sense Drive Status failed\n"); 430 } 431 if (st3p) 432 *st3p = st3; 433 434 return 0; 435} 436 437int 438fd_sense_int(fdc_p fdc, int *st0p, int *cylp) 439{ 440 int st0, cyl; 441 442 int ret = fd_cmd(fdc->fdcu, 1, NE7CMD_SENSEI, 1, &st0); 443 444 if (ret) 445 { 446 (void)fdc_err(fdc->fdcu, 447 "sense intr err reading stat reg 0\n"); 448 return ret; 449 } 450 451 if (st0p) 452 *st0p = st0; 453 454 if ((st0 & NE7_ST0_IC) == NE7_ST0_IC_IV) 455 { 456 /* 457 * There doesn't seem to have been an interrupt. 458 */ 459 return FD_NOT_VALID; 460 } 461 462 if (fd_in(fdc->fdcu, &cyl) < 0) 463 { 464 return fdc_err(fdc->fdcu, "can't get cyl num\n"); 465 } 466 467 if (cylp) 468 *cylp = cyl; 469 470 return 0; 471} 472 473 474int 475fd_read_status(fdc_p fdc, int fdsu) 476{ 477 int i, ret; 478 479 for (i = 0; i < 7; i++) 480 { 481 /* 482 * XXX types are poorly chosen. Only bytes can by read 483 * from the hardware, but fdc_status wants u_longs and 484 * fd_in() gives ints. 485 */ 486 int status; 487 488 ret = fd_in(fdc->fdcu, &status); 489 fdc->status[i] = status; 490 if (ret != 0) 491 break; 492 } 493 494 if (ret == 0) 495 fdc->flags |= FDC_STAT_VALID; 496 else 497 fdc->flags &= ~FDC_STAT_VALID; 498 499 return ret; 500} 501 502/****************************************************************************/ 503/* autoconfiguration stuff */ 504/****************************************************************************/ 505 506/* 507 * probe for existance of controller 508 */ 509static int 510fdprobe(struct isa_device *dev) 511{ 512 fdcu_t fdcu = dev->id_unit; 513 if(fdc_data[fdcu].flags & FDC_ATTACHED) 514 { 515 printf("fdc%d: unit used multiple times\n", fdcu); 516 return 0; 517 } 518 519 fdcdevs[fdcu] = dev; 520 fdc_data[fdcu].baseport = dev->id_iobase; 521 522#ifndef DEV_LKM 523 fdc_registerdev(dev); 524#endif 525 526 /* First - lets reset the floppy controller */ 527 outb(dev->id_iobase+FDOUT, 0); 528 DELAY(100); 529 outb(dev->id_iobase+FDOUT, FDO_FRST); 530 531 /* see if it can handle a command */ 532 if (fd_cmd(fdcu, 533 3, NE7CMD_SPECIFY, NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0), 534 0)) 535 { 536 return(0); 537 } 538 kdc_fdc[fdcu].kdc_state = DC_IDLE; 539 return (IO_FDCSIZE); 540} 541 542/* 543 * wire controller into system, look for floppy units 544 */ 545static int 546fdattach(struct isa_device *dev) 547{ 548 unsigned fdt; 549 fdu_t fdu; 550 fdcu_t fdcu = dev->id_unit; 551 fdc_p fdc = fdc_data + fdcu; 552 fd_p fd; 553 int fdsu, st0, st3, i, unithasfd; 554 struct isa_device *fdup; 555 int ic_type = 0; 556#ifdef DEVFS 557 char name[64]; 558 void *key; 559#endif /* DEVFS */ 560 561 fdc->fdcu = fdcu; 562 fdc->flags |= FDC_ATTACHED; 563 fdc->dmachan = dev->id_drq; 564 fdc->state = DEVIDLE; 565 /* reset controller, turn motor off, clear fdout mirror reg */ 566 outb(fdc->baseport + FDOUT, ((fdc->fdout = 0))); 567 568 /* check for each floppy drive */ 569 for (fdup = isa_biotab_fdc; fdup->id_driver != 0; fdup++) { 570 if (fdup->id_iobase != dev->id_iobase) 571 continue; 572 fdu = fdup->id_unit; 573 fd = &fd_data[fdu]; 574 if (fdu >= (NFD+NFT)) 575 continue; 576 fdsu = fdup->id_physid; 577 /* look up what bios thinks we have */ 578 switch (fdu) { 579 case 0: fdt = (rtcin(RTC_FDISKETTE) & 0xf0); 580 break; 581 case 1: fdt = ((rtcin(RTC_FDISKETTE) << 4) & 0xf0); 582 break; 583 default: fdt = RTCFDT_NONE; 584 break; 585 } 586 /* is there a unit? */ 587 if ((fdt == RTCFDT_NONE) 588#if NFT > 0 589 || (fdsu >= DRVS_PER_CTLR)) { 590#else 591 ) { 592 fd->type = NO_TYPE; 593#endif 594#if NFT > 0 595 /* If BIOS says no floppy, or > 2nd device */ 596 /* Probe for and attach a floppy tape. */ 597 /* Tell FT if there was already a disk */ 598 /* with this unit number found. */ 599 600 unithasfd = 0; 601 if (fdu < NFD && fd->type != NO_TYPE) 602 unithasfd = 1; 603 if (ftattach(dev, fdup, unithasfd)) 604 continue; 605 if (fdsu < DRVS_PER_CTLR) 606 fd->type = NO_TYPE; 607#endif 608 continue; 609 } 610 611 /* select it */ 612 set_motor(fdcu, fdsu, TURNON); 613 DELAY(1000000); /* 1 sec */ 614 615 if (ic_type == 0 && 616 fd_cmd(fdcu, 1, NE7CMD_VERSION, 1, &ic_type) == 0) 617 { 618 printf("fdc%d: ", fdcu); 619 ic_type = (u_char)ic_type; 620 switch( ic_type ) { 621 case 0x80: 622 printf("NEC 765\n"); 623 fdc->fdct = FDC_NE765; 624 kdc_fdc[fdcu].kdc_description = 625 "NEC 765 floppy disk/tape controller"; 626 break; 627 case 0x81: 628 printf("Intel 82077\n"); 629 fdc->fdct = FDC_I82077; 630 kdc_fdc[fdcu].kdc_description = 631 "Intel 82077 floppy disk/tape controller"; 632 break; 633 case 0x90: 634 printf("NEC 72065B\n"); 635 fdc->fdct = FDC_NE72065; 636 kdc_fdc[fdcu].kdc_description = 637 "NEC 72065B floppy disk/tape controller"; 638 break; 639 default: 640 printf("unknown IC type %02x\n", ic_type); 641 fdc->fdct = FDC_UNKNOWN; 642 break; 643 } 644 } 645 if ((fd_cmd(fdcu, 2, NE7CMD_SENSED, fdsu, 1, &st3) == 0) && 646 (st3 & NE7_ST3_T0)) { 647 /* if at track 0, first seek inwards */ 648 /* seek some steps: */ 649 (void)fd_cmd(fdcu, 3, NE7CMD_SEEK, fdsu, 10, 0); 650 DELAY(300000); /* ...wait a moment... */ 651 (void)fd_sense_int(fdc, 0, 0); /* make ctrlr happy */ 652 } 653 654 /* If we're at track 0 first seek inwards. */ 655 if ((fd_sense_drive_status(fdc, &st3) == 0) && 656 (st3 & NE7_ST3_T0)) { 657 /* Seek some steps... */ 658 if (fd_cmd(fdcu, 3, NE7CMD_SEEK, fdsu, 10, 0) == 0) { 659 /* ...wait a moment... */ 660 DELAY(300000); 661 /* make ctrlr happy: */ 662 (void)fd_sense_int(fdc, 0, 0); 663 } 664 } 665 666 for(i = 0; i < 2; i++) { 667 /* 668 * we must recalibrate twice, just in case the 669 * heads have been beyond cylinder 76, since most 670 * FDCs still barf when attempting to recalibrate 671 * more than 77 steps 672 */ 673 /* go back to 0: */ 674 if (fd_cmd(fdcu, 2, NE7CMD_RECAL, fdsu, 0) == 0) { 675 /* a second being enough for full stroke seek*/ 676 DELAY(i == 0? 1000000: 300000); 677 678 /* anything responding? */ 679 if (fd_sense_int(fdc, &st0, 0) == 0 && 680 (st0 & NE7_ST0_EC) == 0) 681 break; /* already probed succesfully */ 682 } 683 } 684 685 set_motor(fdcu, fdsu, TURNOFF); 686 687 if (st0 & NE7_ST0_EC) /* no track 0 -> no drive present */ 688 continue; 689 690 fd->track = FD_NO_TRACK; 691 fd->fdc = fdc; 692 fd->fdsu = fdsu; 693 fd->options = 0; 694 printf("fd%d: ", fdu); 695 696 fd_registerdev(fdcu, fdu); 697 switch (fdt) { 698 case RTCFDT_12M: 699 printf("1.2MB 5.25in\n"); 700 fd->type = FD_1200; 701 kdc_fd[fdu].kdc_description = 702 "1.2MB (1200K) 5.25in floppy disk drive"; 703#ifdef DEVFS 704 sprintf(name,"fd%d.1200",fdu); 705#endif /* DEVFS */ 706 break; 707 case RTCFDT_144M: 708 printf("1.44MB 3.5in\n"); 709 fd->type = FD_1440; 710 kdc_fd[fdu].kdc_description = 711 "1.44MB (1440K) 3.5in floppy disk drive"; 712#ifdef DEVFS 713 sprintf(name,"fd%d.1440",fdu); 714#endif /* DEVFS */ 715 break; 716 case RTCFDT_288M: 717 case RTCFDT_288M_1: 718 printf("2.88MB 3.5in - 1.44MB mode\n"); 719 fd->type = FD_1440; 720 kdc_fd[fdu].kdc_description = 721 "2.88MB (2880K) 3.5in floppy disk drive in 1.44 mode"; 722#ifdef DEVFS 723 sprintf(name,"fd%d.1440",fdu); 724#endif /* DEVFS */ 725 break; 726 case RTCFDT_360K: 727 printf("360KB 5.25in\n"); 728 fd->type = FD_360; 729 kdc_fd[fdu].kdc_description = 730 "360KB 5.25in floppy disk drive"; 731#ifdef DEVFS 732 sprintf(name,"fd%d.360",fdu); 733#endif /* DEVFS */ 734 break; 735 case RTCFDT_720K: 736 printf("720KB 3.5in\n"); 737 fd->type = FD_720; 738 kdc_fd[fdu].kdc_description = 739 "720KB 3.5in floppy disk drive"; 740#ifdef DEVFS 741 sprintf(name,"fd%d.720",fdu); 742#endif /* DEVFS */ 743 break; 744 default: 745 printf("unknown\n"); 746 fd->type = NO_TYPE; 747#ifdef DEVFS 748 sprintf(name,"fd%d.xxxx",fdu); 749#endif /* DEVFS */ 750 break; 751 } 752 kdc_fd[fdu].kdc_state = DC_IDLE; 753#ifdef DEVFS 754 key = dev_add("/disks/rfloppy",name,(caddr_t)Fdopen,fdu * 8, 755 DV_CHR,0,0,0644); 756 key = dev_add("/disks/floppy",name,(caddr_t)Fdopen,fdu * 8, 757 DV_BLK,0,0,0644); 758#endif /* DEVFS */ 759 if (dk_ndrive < DK_NDRIVE) { 760 sprintf(dk_names[dk_ndrive], "fd%d", fdu); 761 fd->dkunit = dk_ndrive++; 762 /* 763 * XXX assume rate is FDC_500KBPS. 764 */ 765 dk_wpms[dk_ndrive] = 500000 / 8 / 2; 766 } else { 767 fd->dkunit = -1; 768 } 769 } 770 771 return (1); 772} 773 774/****************************************************************************/ 775/* motor control stuff */ 776/* remember to not deselect the drive we're working on */ 777/****************************************************************************/ 778static void 779set_motor(fdcu_t fdcu, int fdsu, int turnon) 780{ 781 int fdout = fdc_data[fdcu].fdout; 782 int needspecify = 0; 783 784 if(turnon) { 785 fdout &= ~FDO_FDSEL; 786 fdout |= (FDO_MOEN0 << fdsu) + fdsu; 787 } else 788 fdout &= ~(FDO_MOEN0 << fdsu); 789 790 if(!turnon 791 && (fdout & (FDO_MOEN0+FDO_MOEN1+FDO_MOEN2+FDO_MOEN3)) == 0) 792 /* gonna turn off the last drive, put FDC to bed */ 793 fdout &= ~ (FDO_FRST|FDO_FDMAEN); 794 else { 795 /* make sure controller is selected and specified */ 796 if((fdout & (FDO_FRST|FDO_FDMAEN)) == 0) 797 needspecify = 1; 798 fdout |= (FDO_FRST|FDO_FDMAEN); 799 } 800 801 outb(fdc_data[fdcu].baseport+FDOUT, fdout); 802 fdc_data[fdcu].fdout = fdout; 803 kdc_fdc[fdcu].kdc_state = (fdout & FDO_FRST)? DC_BUSY: DC_IDLE; 804 TRACE1("[0x%x->FDOUT]", fdout); 805 806 if(needspecify) { 807 /* 808 * XXX 809 * special case: since we have just woken up the FDC 810 * from its sleep, we silently assume the command will 811 * be accepted, and do not test for a timeout 812 */ 813 (void)fd_cmd(fdcu, 3, NE7CMD_SPECIFY, 814 NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0), 815 0); 816 } 817} 818 819static void 820fd_turnoff(void *arg1) 821{ 822 fdu_t fdu = (fdu_t)arg1; 823 int s; 824 fd_p fd = fd_data + fdu; 825 826 TRACE1("[fd%d: turnoff]", fdu); 827 s = splbio(); 828 fd->flags &= ~FD_MOTOR; 829 set_motor(fd->fdc->fdcu, fd->fdsu, TURNOFF); 830 splx(s); 831} 832 833static void 834fd_motor_on(void *arg1) 835{ 836 fdu_t fdu = (fdu_t)arg1; 837 int s; 838 839 fd_p fd = fd_data + fdu; 840 s = splbio(); 841 fd->flags &= ~FD_MOTOR_WAIT; 842 if((fd->fdc->fd == fd) && (fd->fdc->state == MOTORWAIT)) 843 { 844 fdintr(fd->fdc->fdcu); 845 } 846 splx(s); 847} 848 849static void 850fd_turnon(fdu_t fdu) 851{ 852 fd_p fd = fd_data + fdu; 853 if(!(fd->flags & FD_MOTOR)) 854 { 855 fd->flags |= (FD_MOTOR + FD_MOTOR_WAIT); 856 set_motor(fd->fdc->fdcu, fd->fdsu, TURNON); 857 timeout(fd_motor_on, (caddr_t)fdu, hz); /* in 1 sec its ok */ 858 } 859} 860 861static void 862fdc_reset(fdc_p fdc) 863{ 864 fdcu_t fdcu = fdc->fdcu; 865 866 /* Try a reset, keep motor on */ 867 outb(fdc->baseport + FDOUT, fdc->fdout & ~(FDO_FRST|FDO_FDMAEN)); 868 TRACE1("[0x%x->FDOUT]", fdc->fdout & ~(FDO_FRST|FDO_FDMAEN)); 869 DELAY(100); 870 /* enable FDC, but defer interrupts a moment */ 871 outb(fdc->baseport + FDOUT, fdc->fdout & ~FDO_FDMAEN); 872 TRACE1("[0x%x->FDOUT]", fdc->fdout & ~FDO_FDMAEN); 873 DELAY(100); 874 outb(fdc->baseport + FDOUT, fdc->fdout); 875 TRACE1("[0x%x->FDOUT]", fdc->fdout); 876 877 /* XXX after a reset, silently believe the FDC will accept commands */ 878 (void)fd_cmd(fdcu, 3, NE7CMD_SPECIFY, 879 NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0), 880 0); 881} 882 883/****************************************************************************/ 884/* fdc in/out */ 885/****************************************************************************/ 886int 887in_fdc(fdcu_t fdcu) 888{ 889 int baseport = fdc_data[fdcu].baseport; 890 int i, j = 100000; 891 while ((i = inb(baseport+FDSTS) & (NE7_DIO|NE7_RQM)) 892 != (NE7_DIO|NE7_RQM) && j-- > 0) 893 if (i == NE7_RQM) 894 return fdc_err(fdcu, "ready for output in input\n"); 895 if (j <= 0) 896 return fdc_err(fdcu, bootverbose? "input ready timeout\n": 0); 897#ifdef DEBUG 898 i = inb(baseport+FDDATA); 899 TRACE1("[FDDATA->0x%x]", (unsigned char)i); 900 return(i); 901#else 902 return inb(baseport+FDDATA); 903#endif 904} 905 906/* 907 * fd_in: Like in_fdc, but allows you to see if it worked. 908 */ 909static int 910fd_in(fdcu_t fdcu, int *ptr) 911{ 912 int baseport = fdc_data[fdcu].baseport; 913 int i, j = 100000; 914 while ((i = inb(baseport+FDSTS) & (NE7_DIO|NE7_RQM)) 915 != (NE7_DIO|NE7_RQM) && j-- > 0) 916 if (i == NE7_RQM) 917 return fdc_err(fdcu, "ready for output in input\n"); 918 if (j <= 0) 919 return fdc_err(fdcu, bootverbose? "input ready timeout\n": 0); 920#ifdef DEBUG 921 i = inb(baseport+FDDATA); 922 TRACE1("[FDDATA->0x%x]", (unsigned char)i); 923 *ptr = i; 924 return 0; 925#else 926 i = inb(baseport+FDDATA); 927 if (ptr) 928 *ptr = i; 929 return 0; 930#endif 931} 932 933int 934out_fdc(fdcu_t fdcu, int x) 935{ 936 int baseport = fdc_data[fdcu].baseport; 937 int i; 938 939 /* Check that the direction bit is set */ 940 i = 100000; 941 while ((inb(baseport+FDSTS) & NE7_DIO) && i-- > 0); 942 if (i <= 0) return fdc_err(fdcu, "direction bit not set\n"); 943 944 /* Check that the floppy controller is ready for a command */ 945 i = 100000; 946 while ((inb(baseport+FDSTS) & NE7_RQM) == 0 && i-- > 0); 947 if (i <= 0) 948 return fdc_err(fdcu, bootverbose? "output ready timeout\n": 0); 949 950 /* Send the command and return */ 951 outb(baseport+FDDATA, x); 952 TRACE1("[0x%x->FDDATA]", x); 953 return (0); 954} 955 956/****************************************************************************/ 957/* fdopen/fdclose */ 958/****************************************************************************/ 959int 960Fdopen(dev_t dev, int flags, int mode, struct proc *p) 961{ 962 fdu_t fdu = FDUNIT(minor(dev)); 963 int type = FDTYPE(minor(dev)); 964 fdc_p fdc; 965 966#if NFT > 0 967 /* check for a tape open */ 968 if (type & F_TAPE_TYPE) 969 return(ftopen(dev, flags)); 970#endif 971 /* check bounds */ 972 if (fdu >= NFD) 973 return(ENXIO); 974 fdc = fd_data[fdu].fdc; 975 if ((fdc == NULL) || (fd_data[fdu].type == NO_TYPE)) 976 return(ENXIO); 977 if (type > NUMDENS) 978 return(ENXIO); 979 if (type == 0) 980 type = fd_data[fdu].type; 981 else { 982 if (type != fd_data[fdu].type) { 983 switch (fd_data[fdu].type) { 984 case FD_360: 985 return(ENXIO); 986 case FD_720: 987 if ( type != FD_820 988 && type != FD_800 989 ) 990 return(ENXIO); 991 break; 992 case FD_1200: 993 switch (type) { 994 case FD_1480: 995 type = FD_1480in5_25; 996 break; 997 case FD_1440: 998 type = FD_1440in5_25; 999 break; 1000 case FD_820: 1001 type = FD_820in5_25; 1002 break; 1003 case FD_800: 1004 type = FD_800in5_25; 1005 break; 1006 case FD_720: 1007 type = FD_720in5_25; 1008 break; 1009 case FD_360: 1010 type = FD_360in5_25; 1011 break; 1012 default: 1013 return(ENXIO); 1014 } 1015 break; 1016 case FD_1440: 1017 if ( type != FD_1720 1018 && type != FD_1480 1019 && type != FD_1200 1020 && type != FD_820 1021 && type != FD_800 1022 && type != FD_720 1023 ) 1024 return(ENXIO); 1025 break; 1026 } 1027 } 1028 } 1029 fd_data[fdu].ft = fd_types + type - 1; 1030 fd_data[fdu].flags |= FD_OPEN; 1031 kdc_fd[fdu].kdc_state = DC_BUSY; 1032 1033 return 0; 1034} 1035 1036int 1037fdclose(dev_t dev, int flags, int mode, struct proc *p) 1038{ 1039 fdu_t fdu = FDUNIT(minor(dev)); 1040 1041#if NFT > 0 1042 int type = FDTYPE(minor(dev)); 1043 1044 if (type & F_TAPE_TYPE) 1045 return ftclose(dev, flags); 1046#endif 1047 fd_data[fdu].flags &= ~FD_OPEN; 1048 fd_data[fdu].options &= ~FDOPT_NORETRY; 1049 kdc_fd[fdu].kdc_state = DC_IDLE; 1050 1051 return(0); 1052} 1053 1054 1055/****************************************************************************/ 1056/* fdstrategy */ 1057/****************************************************************************/ 1058void 1059fdstrategy(struct buf *bp) 1060{ 1061 register struct buf *dp; 1062 long nblocks, blknum; 1063 int s; 1064 fdcu_t fdcu; 1065 fdu_t fdu; 1066 fdc_p fdc; 1067 fd_p fd; 1068 size_t fdblk; 1069 1070 fdu = FDUNIT(minor(bp->b_dev)); 1071 fd = &fd_data[fdu]; 1072 fdc = fd->fdc; 1073 fdcu = fdc->fdcu; 1074 1075#if NFT > 0 1076 if (FDTYPE(minor(bp->b_dev)) & F_TAPE_TYPE) { 1077 /* ft tapes do not (yet) support strategy i/o */ 1078 bp->b_error = ENODEV; 1079 bp->b_flags |= B_ERROR; 1080 goto bad; 1081 } 1082 /* check for controller already busy with tape */ 1083 if (fdc->flags & FDC_TAPE_BUSY) { 1084 bp->b_error = EBUSY; 1085 bp->b_flags |= B_ERROR; 1086 goto bad; 1087 } 1088#endif 1089 fdblk = 128 << (fd->ft->secsize); 1090 if (!(bp->b_flags & B_FORMAT)) { 1091 if ((fdu >= NFD) || (bp->b_blkno < 0)) { 1092 printf( 1093 "fd%d: fdstrat: bad request blkno = %lu, bcount = %ld\n", 1094 fdu, (u_long)bp->b_blkno, bp->b_bcount); 1095 bp->b_error = EINVAL; 1096 bp->b_flags |= B_ERROR; 1097 goto bad; 1098 } 1099 if ((bp->b_bcount % fdblk) != 0) { 1100 bp->b_error = EINVAL; 1101 bp->b_flags |= B_ERROR; 1102 goto bad; 1103 } 1104 } 1105 1106 /* 1107 * Set up block calculations. 1108 */ 1109 blknum = (unsigned long) bp->b_blkno * DEV_BSIZE/fdblk; 1110 nblocks = fd->ft->size; 1111 if (blknum + (bp->b_bcount / fdblk) > nblocks) { 1112 if (blknum == nblocks) { 1113 bp->b_resid = bp->b_bcount; 1114 } else { 1115 bp->b_error = ENOSPC; 1116 bp->b_flags |= B_ERROR; 1117 } 1118 goto bad; 1119 } 1120 bp->b_cylin = blknum / (fd->ft->sectrac * fd->ft->heads); 1121 bp->b_pblkno = bp->b_blkno; 1122 dp = &(fdc->head); 1123 s = splbio(); 1124 disksort(dp, bp); 1125 untimeout(fd_turnoff, (caddr_t)fdu); /* a good idea */ 1126 fdstart(fdcu); 1127 splx(s); 1128 return; 1129 1130bad: 1131 biodone(bp); 1132} 1133 1134/***************************************************************\ 1135* fdstart * 1136* We have just queued something.. if the controller is not busy * 1137* then simulate the case where it has just finished a command * 1138* So that it (the interrupt routine) looks on the queue for more* 1139* work to do and picks up what we just added. * 1140* If the controller is already busy, we need do nothing, as it * 1141* will pick up our work when the present work completes * 1142\***************************************************************/ 1143static void 1144fdstart(fdcu_t fdcu) 1145{ 1146 int s; 1147 1148 s = splbio(); 1149 if(fdc_data[fdcu].state == DEVIDLE) 1150 { 1151 fdintr(fdcu); 1152 } 1153 splx(s); 1154} 1155 1156static void 1157fd_timeout(void *arg1) 1158{ 1159 fdcu_t fdcu = (fdcu_t)arg1; 1160 fdu_t fdu = fdc_data[fdcu].fdu; 1161 int baseport = fdc_data[fdcu].baseport; 1162 struct buf *dp, *bp; 1163 int s; 1164 1165 dp = &fdc_data[fdcu].head; 1166 bp = dp->b_actf; 1167 1168 /* 1169 * Due to IBM's brain-dead design, the FDC has a faked ready 1170 * signal, hardwired to ready == true. Thus, any command 1171 * issued if there's no diskette in the drive will _never_ 1172 * complete, and must be aborted by resetting the FDC. 1173 * Many thanks, Big Blue! 1174 */ 1175 1176 s = splbio(); 1177 1178 TRACE1("fd%d[fd_timeout()]", fdu); 1179 /* See if the controller is still busy (patiently awaiting data) */ 1180 if(((inb(baseport + FDSTS)) & (NE7_CB|NE7_RQM)) == NE7_CB) 1181 { 1182 TRACE1("[FDSTS->0x%x]", inb(baseport + FDSTS)); 1183 /* yup, it is; kill it now */ 1184 fdc_reset(&fdc_data[fdcu]); 1185 printf("fd%d: Operation timeout\n", fdu); 1186 } 1187 1188 if (bp) 1189 { 1190 retrier(fdcu); 1191 fdc_data[fdcu].status[0] = NE7_ST0_IC_RC; 1192 fdc_data[fdcu].state = IOTIMEDOUT; 1193 if( fdc_data[fdcu].retry < 6) 1194 fdc_data[fdcu].retry = 6; 1195 } 1196 else 1197 { 1198 fdc_data[fdcu].fd = (fd_p) 0; 1199 fdc_data[fdcu].fdu = -1; 1200 fdc_data[fdcu].state = DEVIDLE; 1201 } 1202 fdintr(fdcu); 1203 splx(s); 1204} 1205 1206/* just ensure it has the right spl */ 1207static void 1208fd_pseudointr(void *arg1) 1209{ 1210 fdcu_t fdcu = (fdcu_t)arg1; 1211 int s; 1212 1213 s = splbio(); 1214 fdintr(fdcu); 1215 splx(s); 1216} 1217 1218/***********************************************************************\ 1219* fdintr * 1220* keep calling the state machine until it returns a 0 * 1221* ALWAYS called at SPLBIO * 1222\***********************************************************************/ 1223void 1224fdintr(fdcu_t fdcu) 1225{ 1226 fdc_p fdc = fdc_data + fdcu; 1227#if NFT > 0 1228 fdu_t fdu = fdc->fdu; 1229 1230 if (fdc->flags & FDC_TAPE_BUSY) 1231 (ftintr(fdu)); 1232 else 1233#endif 1234 while(fdstate(fdcu, fdc)) 1235 ; 1236} 1237 1238/***********************************************************************\ 1239* The controller state machine. * 1240* if it returns a non zero value, it should be called again immediatly * 1241\***********************************************************************/ 1242static int 1243fdstate(fdcu_t fdcu, fdc_p fdc) 1244{ 1245 int read, format, head, sec = 0, sectrac, st0, cyl, st3; 1246 unsigned long blknum; 1247 fdu_t fdu = fdc->fdu; 1248 fd_p fd; 1249 register struct buf *dp, *bp; 1250 struct fd_formb *finfo = NULL; 1251 size_t fdblk; 1252 1253 dp = &(fdc->head); 1254 bp = dp->b_actf; 1255 if(!bp) 1256 { 1257 /***********************************************\ 1258 * nothing left for this controller to do * 1259 * Force into the IDLE state, * 1260 \***********************************************/ 1261 fdc->state = DEVIDLE; 1262 if(fdc->fd) 1263 { 1264 printf("fd%d: unexpected valid fd pointer\n", 1265 fdc->fdu); 1266 fdc->fd = (fd_p) 0; 1267 fdc->fdu = -1; 1268 } 1269 TRACE1("[fdc%d IDLE]", fdcu); 1270 return(0); 1271 } 1272 fdu = FDUNIT(minor(bp->b_dev)); 1273 fd = fd_data + fdu; 1274 fdblk = 128 << fd->ft->secsize; 1275 if (fdc->fd && (fd != fdc->fd)) 1276 { 1277 printf("fd%d: confused fd pointers\n", fdu); 1278 } 1279 read = bp->b_flags & B_READ; 1280 format = bp->b_flags & B_FORMAT; 1281 if(format) 1282 finfo = (struct fd_formb *)bp->b_un.b_addr; 1283 TRACE1("fd%d", fdu); 1284 TRACE1("[%s]", fdstates[fdc->state]); 1285 TRACE1("(0x%x)", fd->flags); 1286 untimeout(fd_turnoff, (caddr_t)fdu); 1287 timeout(fd_turnoff, (caddr_t)fdu, 4 * hz); 1288 switch (fdc->state) 1289 { 1290 case DEVIDLE: 1291 case FINDWORK: /* we have found new work */ 1292 fdc->retry = 0; 1293 fd->skip = 0; 1294 fdc->fd = fd; 1295 fdc->fdu = fdu; 1296 outb(fdc->baseport+FDCTL, fd->ft->trans); 1297 TRACE1("[0x%x->FDCTL]", fd->ft->trans); 1298 /*******************************************************\ 1299 * If the next drive has a motor startup pending, then * 1300 * it will start up in it's own good time * 1301 \*******************************************************/ 1302 if(fd->flags & FD_MOTOR_WAIT) 1303 { 1304 fdc->state = MOTORWAIT; 1305 return(0); /* come back later */ 1306 } 1307 /*******************************************************\ 1308 * Maybe if it's not starting, it SHOULD be starting * 1309 \*******************************************************/ 1310 if (!(fd->flags & FD_MOTOR)) 1311 { 1312 fdc->state = MOTORWAIT; 1313 fd_turnon(fdu); 1314 return(0); 1315 } 1316 else /* at least make sure we are selected */ 1317 { 1318 set_motor(fdcu, fd->fdsu, TURNON); 1319 } 1320 fdc->state = DOSEEK; 1321 break; 1322 case DOSEEK: 1323 if (bp->b_cylin == fd->track) 1324 { 1325 fdc->state = SEEKCOMPLETE; 1326 break; 1327 } 1328 if (fd_cmd(fdcu, 3, NE7CMD_SEEK, 1329 fd->fdsu, bp->b_cylin * fd->ft->steptrac, 1330 0)) 1331 { 1332 /* 1333 * seek command not accepted, looks like 1334 * the FDC went off to the Saints... 1335 */ 1336 fdc->retry = 6; /* try a reset */ 1337 return(retrier(fdcu)); 1338 } 1339 fd->track = FD_NO_TRACK; 1340 fdc->state = SEEKWAIT; 1341 return(0); /* will return later */ 1342 case SEEKWAIT: 1343 /* allow heads to settle */ 1344 timeout(fd_pseudointr, (caddr_t)fdcu, hz / 16); 1345 fdc->state = SEEKCOMPLETE; 1346 return(0); /* will return later */ 1347 case SEEKCOMPLETE : /* SEEK DONE, START DMA */ 1348 /* Make sure seek really happened*/ 1349 if(fd->track == FD_NO_TRACK) 1350 { 1351 int descyl = bp->b_cylin * fd->ft->steptrac; 1352 do { 1353 /* 1354 * This might be a "ready changed" interrupt, 1355 * which cannot really happen since the 1356 * RDY pin is hardwired to + 5 volts. This 1357 * generally indicates a "bouncing" intr 1358 * line, so do one of the following: 1359 * 1360 * When running on an enhanced FDC that is 1361 * known to not go stuck after responding 1362 * with INVALID, fetch all interrupt states 1363 * until seeing either an INVALID or a 1364 * real interrupt condition. 1365 * 1366 * When running on a dumb old NE765, give 1367 * up immediately. The controller will 1368 * provide up to four dummy RC interrupt 1369 * conditions right after reset (for the 1370 * corresponding four drives), so this is 1371 * our only chance to get notice that it 1372 * was not the FDC that caused the interrupt. 1373 */ 1374 if (fd_sense_int(fdc, &st0, &cyl) 1375 == FD_NOT_VALID) 1376 return 0; 1377 if(fdc->fdct == FDC_NE765 1378 && (st0 & NE7_ST0_IC) == NE7_ST0_IC_RC) 1379 return 0; /* hope for a real intr */ 1380 } while ((st0 & NE7_ST0_IC) == NE7_ST0_IC_RC); 1381 1382 if (0 == descyl) 1383 { 1384 int failed = 0; 1385 /* 1386 * seek to cyl 0 requested; make sure we are 1387 * really there 1388 */ 1389 if (fd_sense_drive_status(fdc, &st3)) 1390 failed = 1; 1391 if ((st3 & NE7_ST3_T0) == 0) { 1392 printf( 1393 "fd%d: Seek to cyl 0, but not really there (ST3 = %b)\n", 1394 fdu, st3, NE7_ST3BITS); 1395 failed = 1; 1396 } 1397 1398 if (failed) 1399 { 1400 if(fdc->retry < 3) 1401 fdc->retry = 3; 1402 return(retrier(fdcu)); 1403 } 1404 } 1405 1406 if (cyl != descyl) 1407 { 1408 printf( 1409 "fd%d: Seek to cyl %d failed; am at cyl %d (ST0 = 0x%x)\n", 1410 fdu, descyl, cyl, st0); 1411 return(retrier(fdcu)); 1412 } 1413 } 1414 1415 fd->track = bp->b_cylin; 1416 if(format) 1417 fd->skip = (char *)&(finfo->fd_formb_cylno(0)) 1418 - (char *)finfo; 1419 isa_dmastart(bp->b_flags, bp->b_un.b_addr+fd->skip, 1420 format ? bp->b_bcount : fdblk, fdc->dmachan); 1421 blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/fdblk 1422 + fd->skip/fdblk; 1423 sectrac = fd->ft->sectrac; 1424 sec = blknum % (sectrac * fd->ft->heads); 1425 head = sec / sectrac; 1426 sec = sec % sectrac + 1; 1427 fd->hddrv = ((head&1)<<2)+fdu; 1428 1429 if(format || !read) 1430 { 1431 /* make sure the drive is writable */ 1432 if(fd_sense_drive_status(fdc, &st3) != 0) 1433 { 1434 /* stuck controller? */ 1435 fdc->retry = 6; /* reset the beast */ 1436 return(retrier(fdcu)); 1437 } 1438 if(st3 & NE7_ST3_WP) 1439 { 1440 /* 1441 * XXX YES! this is ugly. 1442 * in order to force the current operation 1443 * to fail, we will have to fake an FDC 1444 * error - all error handling is done 1445 * by the retrier() 1446 */ 1447 fdc->status[0] = NE7_ST0_IC_AT; 1448 fdc->status[1] = NE7_ST1_NW; 1449 fdc->status[2] = 0; 1450 fdc->status[3] = fd->track; 1451 fdc->status[4] = head; 1452 fdc->status[5] = sec; 1453 fdc->retry = 8; /* break out immediately */ 1454 fdc->state = IOTIMEDOUT; /* not really... */ 1455 return (1); 1456 } 1457 } 1458 1459 if(format) 1460 { 1461 /* formatting */ 1462 if(fd_cmd(fdcu, 6, 1463 NE7CMD_FORMAT, 1464 head << 2 | fdu, 1465 finfo->fd_formb_secshift, 1466 finfo->fd_formb_nsecs, 1467 finfo->fd_formb_gaplen, 1468 finfo->fd_formb_fillbyte, 1469 0)) 1470 { 1471 /* controller fell over */ 1472 fdc->retry = 6; 1473 return(retrier(fdcu)); 1474 } 1475 } 1476 else 1477 { 1478 if (fd_cmd(fdcu, 9, 1479 (read ? NE7CMD_READ : NE7CMD_WRITE), 1480 head << 2 | fdu, /* head & unit */ 1481 fd->track, /* track */ 1482 head, 1483 sec, /* sector + 1 */ 1484 fd->ft->secsize, /* sector size */ 1485 sectrac, /* sectors/track */ 1486 fd->ft->gap, /* gap size */ 1487 fd->ft->datalen, /* data length */ 1488 0)) 1489 { 1490 /* the beast is sleeping again */ 1491 fdc->retry = 6; 1492 return(retrier(fdcu)); 1493 } 1494 } 1495 fdc->state = IOCOMPLETE; 1496 timeout(fd_timeout, (caddr_t)fdcu, hz); 1497 return(0); /* will return later */ 1498 case IOCOMPLETE: /* IO DONE, post-analyze */ 1499 untimeout(fd_timeout, (caddr_t)fdcu); 1500 1501 if (fd_read_status(fdc, fd->fdsu)) 1502 { 1503 if (fdc->retry < 6) 1504 fdc->retry = 6; /* force a reset */ 1505 return retrier(fdcu); 1506 } 1507 1508 fdc->state = IOTIMEDOUT; 1509 1510 /* FALLTHROUGH */ 1511 1512 case IOTIMEDOUT: 1513 isa_dmadone(bp->b_flags, bp->b_un.b_addr+fd->skip, 1514 format ? bp->b_bcount : fdblk, fdc->dmachan); 1515 if (fdc->status[0] & NE7_ST0_IC) 1516 { 1517 if ((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_AT 1518 && fdc->status[1] & NE7_ST1_OR) { 1519 /* 1520 * DMA overrun. Someone hogged the bus 1521 * and didn't release it in time for the 1522 * next FDC transfer. 1523 * Just restart it, don't increment retry 1524 * count. (vak) 1525 */ 1526 fdc->state = SEEKCOMPLETE; 1527 return (1); 1528 } 1529 else if((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_IV 1530 && fdc->retry < 6) 1531 fdc->retry = 6; /* force a reset */ 1532 else if((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_AT 1533 && fdc->status[2] & NE7_ST2_WC 1534 && fdc->retry < 3) 1535 fdc->retry = 3; /* force recalibrate */ 1536 return(retrier(fdcu)); 1537 } 1538 /* All OK */ 1539 fd->skip += fdblk; 1540 if (!format && fd->skip < bp->b_bcount) 1541 { 1542 /* set up next transfer */ 1543 blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/fdblk 1544 + fd->skip/fdblk; 1545 bp->b_cylin = 1546 (blknum / (fd->ft->sectrac * fd->ft->heads)); 1547 fdc->state = DOSEEK; 1548 } 1549 else 1550 { 1551 /* ALL DONE */ 1552 fd->skip = 0; 1553 bp->b_resid = 0; 1554 dp->b_actf = bp->b_actf; 1555 biodone(bp); 1556 fdc->fd = (fd_p) 0; 1557 fdc->fdu = -1; 1558 fdc->state = FINDWORK; 1559 } 1560 return(1); 1561 case RESETCTLR: 1562 fdc_reset(fdc); 1563 fdc->retry++; 1564 fdc->state = STARTRECAL; 1565 break; 1566 case STARTRECAL: 1567 if(fd_cmd(fdcu, 1568 2, NE7CMD_RECAL, fdu, 1569 0)) /* Recalibrate Function */ 1570 { 1571 /* arrgl */ 1572 fdc->retry = 6; 1573 return(retrier(fdcu)); 1574 } 1575 fdc->state = RECALWAIT; 1576 return(0); /* will return later */ 1577 case RECALWAIT: 1578 /* allow heads to settle */ 1579 timeout(fd_pseudointr, (caddr_t)fdcu, hz / 8); 1580 fdc->state = RECALCOMPLETE; 1581 return(0); /* will return later */ 1582 case RECALCOMPLETE: 1583 do { 1584 /* 1585 * See SEEKCOMPLETE for a comment on this: 1586 */ 1587 if (fd_sense_int(fdc, &st0, &cyl) == FD_NOT_VALID) 1588 return 0; 1589 if(fdc->fdct == FDC_NE765 1590 && (st0 & NE7_ST0_IC) == NE7_ST0_IC_RC) 1591 return 0; /* hope for a real intr */ 1592 } while ((st0 & NE7_ST0_IC) == NE7_ST0_IC_RC); 1593 if ((st0 & NE7_ST0_IC) != NE7_ST0_IC_NT || cyl != 0) 1594 { 1595 if(fdc->retry > 3) 1596 /* 1597 * a recalibrate from beyond cylinder 77 1598 * will "fail" due to the FDC limitations; 1599 * since people used to complain much about 1600 * the failure message, try not logging 1601 * this one if it seems to be the first 1602 * time in a line 1603 */ 1604 printf("fd%d: recal failed ST0 %b cyl %d\n", 1605 fdu, st0, NE7_ST0BITS, cyl); 1606 if(fdc->retry < 3) fdc->retry = 3; 1607 return(retrier(fdcu)); 1608 } 1609 fd->track = 0; 1610 /* Seek (probably) necessary */ 1611 fdc->state = DOSEEK; 1612 return(1); /* will return immediatly */ 1613 case MOTORWAIT: 1614 if(fd->flags & FD_MOTOR_WAIT) 1615 { 1616 return(0); /* time's not up yet */ 1617 } 1618 /* 1619 * since the controller was off, it has lost its 1620 * idea about the current track it were; thus, 1621 * recalibrate the bastard 1622 */ 1623 fdc->state = STARTRECAL; 1624 return(1); /* will return immediatly */ 1625 default: 1626 printf("fdc%d: Unexpected FD int->", fdcu); 1627 if (fd_read_status(fdc, fd->fdsu) == 0) 1628 printf("FDC status :%lx %lx %lx %lx %lx %lx %lx ", 1629 fdc->status[0], 1630 fdc->status[1], 1631 fdc->status[2], 1632 fdc->status[3], 1633 fdc->status[4], 1634 fdc->status[5], 1635 fdc->status[6] ); 1636 else 1637 printf("No status available "); 1638 if (fd_sense_int(fdc, &st0, &cyl) != 0) 1639 { 1640 printf("[controller is dead now]\n"); 1641 return(0); 1642 } 1643 printf("ST0 = %x, PCN = %x\n", st0, cyl); 1644 return(0); 1645 } 1646 /*XXX confusing: some branches return immediately, others end up here*/ 1647 return(1); /* Come back immediatly to new state */ 1648} 1649 1650static int 1651retrier(fdcu) 1652 fdcu_t fdcu; 1653{ 1654 fdc_p fdc = fdc_data + fdcu; 1655 register struct buf *dp, *bp; 1656 1657 dp = &(fdc->head); 1658 bp = dp->b_actf; 1659 1660 if(fd_data[FDUNIT(minor(bp->b_dev))].options & FDOPT_NORETRY) 1661 goto fail; 1662 switch(fdc->retry) 1663 { 1664 case 0: case 1: case 2: 1665 fdc->state = SEEKCOMPLETE; 1666 break; 1667 case 3: case 4: case 5: 1668 fdc->state = STARTRECAL; 1669 break; 1670 case 6: 1671 fdc->state = RESETCTLR; 1672 break; 1673 case 7: 1674 break; 1675 default: 1676 fail: 1677 { 1678 dev_t sav_b_dev = bp->b_dev; 1679 /* Trick diskerr */ 1680 bp->b_dev = makedev(major(bp->b_dev), 1681 (FDUNIT(minor(bp->b_dev))<<3)|RAW_PART); 1682 diskerr(bp, "fd", "hard error", LOG_PRINTF, 1683 fdc->fd->skip / DEV_BSIZE, 1684 (struct disklabel *)NULL); 1685 bp->b_dev = sav_b_dev; 1686 if (fdc->flags & FDC_STAT_VALID) 1687 { 1688 printf( 1689 " (ST0 %b ST1 %b ST2 %b cyl %ld hd %ld sec %ld)\n", 1690 fdc->status[0], NE7_ST0BITS, 1691 fdc->status[1], NE7_ST1BITS, 1692 fdc->status[2], NE7_ST2BITS, 1693 fdc->status[3], fdc->status[4], 1694 fdc->status[5]); 1695 } 1696 else 1697 printf(" (No status)\n"); 1698 } 1699 bp->b_flags |= B_ERROR; 1700 bp->b_error = EIO; 1701 bp->b_resid = bp->b_bcount - fdc->fd->skip; 1702 dp->b_actf = bp->b_actf; 1703 fdc->fd->skip = 0; 1704 biodone(bp); 1705 fdc->state = FINDWORK; 1706 fdc->fd = (fd_p) 0; 1707 fdc->fdu = -1; 1708 /* XXX abort current command, if any. */ 1709 return(1); 1710 } 1711 fdc->retry++; 1712 return(1); 1713} 1714 1715static int 1716fdformat(dev, finfo, p) 1717 dev_t dev; 1718 struct fd_formb *finfo; 1719 struct proc *p; 1720{ 1721 fdu_t fdu; 1722 fd_p fd; 1723 1724 struct buf *bp; 1725 int rv = 0, s; 1726 size_t fdblk; 1727 1728 fdu = FDUNIT(minor(dev)); 1729 fd = &fd_data[fdu]; 1730 fdblk = 128 << fd->ft->secsize; 1731 1732 /* set up a buffer header for fdstrategy() */ 1733 bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT); 1734 if(bp == 0) 1735 return ENOBUFS; 1736 /* 1737 * keep the process from being swapped 1738 */ 1739 p->p_flag |= P_PHYSIO; 1740 bzero((void *)bp, sizeof(struct buf)); 1741 bp->b_flags = B_BUSY | B_PHYS | B_FORMAT; 1742 bp->b_proc = p; 1743 bp->b_dev = dev; 1744 1745 /* 1746 * calculate a fake blkno, so fdstrategy() would initiate a 1747 * seek to the requested cylinder 1748 */ 1749 bp->b_blkno = (finfo->cyl * (fd->ft->sectrac * fd->ft->heads) 1750 + finfo->head * fd->ft->sectrac) * fdblk / DEV_BSIZE; 1751 1752 bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs; 1753 bp->b_un.b_addr = (caddr_t)finfo; 1754 1755 /* now do the format */ 1756 fdstrategy(bp); 1757 1758 /* ...and wait for it to complete */ 1759 s = splbio(); 1760 while(!(bp->b_flags & B_DONE)) 1761 { 1762 rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 20 * hz); 1763 if(rv == EWOULDBLOCK) 1764 break; 1765 } 1766 splx(s); 1767 1768 if(rv == EWOULDBLOCK) { 1769 /* timed out */ 1770 rv = EIO; 1771 biodone(bp); 1772 } 1773 if(bp->b_flags & B_ERROR) 1774 rv = bp->b_error; 1775 /* 1776 * allow the process to be swapped 1777 */ 1778 p->p_flag &= ~P_PHYSIO; 1779 free(bp, M_TEMP); 1780 return rv; 1781} 1782 1783/* 1784 * TODO: don't allocate buffer on stack. 1785 */ 1786 1787int 1788fdioctl(dev, cmd, addr, flag, p) 1789 dev_t dev; 1790 int cmd; 1791 caddr_t addr; 1792 int flag; 1793 struct proc *p; 1794{ 1795 fdu_t fdu = FDUNIT(minor(dev)); 1796 fd_p fd = &fd_data[fdu]; 1797 size_t fdblk; 1798 1799 struct fd_type *fdt; 1800 struct disklabel *dl; 1801 char buffer[DEV_BSIZE]; 1802 int error = 0; 1803 1804#if NFT > 0 1805 int type = FDTYPE(minor(dev)); 1806 1807 /* check for a tape ioctl */ 1808 if (type & F_TAPE_TYPE) 1809 return ftioctl(dev, cmd, addr, flag, p); 1810#endif 1811 1812 fdblk = 128 << fd->ft->secsize; 1813 1814 switch (cmd) 1815 { 1816 case DIOCGDINFO: 1817 bzero(buffer, sizeof (buffer)); 1818 dl = (struct disklabel *)buffer; 1819 dl->d_secsize = fdblk; 1820 fdt = fd_data[FDUNIT(minor(dev))].ft; 1821 dl->d_secpercyl = fdt->size / fdt->tracks; 1822 dl->d_type = DTYPE_FLOPPY; 1823 1824 if (readdisklabel(dkmodpart(dev, RAW_PART), fdstrategy, dl) 1825 == NULL) 1826 error = 0; 1827 else 1828 error = EINVAL; 1829 1830 *(struct disklabel *)addr = *dl; 1831 break; 1832 1833 case DIOCSDINFO: 1834 if ((flag & FWRITE) == 0) 1835 error = EBADF; 1836 break; 1837 1838 case DIOCWLABEL: 1839 if ((flag & FWRITE) == 0) 1840 error = EBADF; 1841 break; 1842 1843 case DIOCWDINFO: 1844 if ((flag & FWRITE) == 0) 1845 { 1846 error = EBADF; 1847 break; 1848 } 1849 1850 dl = (struct disklabel *)addr; 1851 1852 if ((error = setdisklabel((struct disklabel *)buffer, dl, 1853 (u_long)0)) != 0) 1854 break; 1855 1856 error = writedisklabel(dev, fdstrategy, 1857 (struct disklabel *)buffer); 1858 break; 1859 1860 case FD_FORM: 1861 if((flag & FWRITE) == 0) 1862 error = EBADF; /* must be opened for writing */ 1863 else if(((struct fd_formb *)addr)->format_version != 1864 FD_FORMAT_VERSION) 1865 error = EINVAL; /* wrong version of formatting prog */ 1866 else 1867 error = fdformat(dev, (struct fd_formb *)addr, p); 1868 break; 1869 1870 case FD_GTYPE: /* get drive type */ 1871 *(struct fd_type *)addr = *fd_data[FDUNIT(minor(dev))].ft; 1872 break; 1873 1874 case FD_STYPE: /* set drive type */ 1875 /* this is considered harmful; only allow for superuser */ 1876 if(suser(p->p_ucred, &p->p_acflag) != 0) 1877 return EPERM; 1878 *fd_data[FDUNIT(minor(dev))].ft = *(struct fd_type *)addr; 1879 break; 1880 1881 case FD_GOPTS: /* get drive options */ 1882 *(int *)addr = fd_data[FDUNIT(minor(dev))].options; 1883 break; 1884 1885 case FD_SOPTS: /* set drive options */ 1886 fd_data[FDUNIT(minor(dev))].options = *(int *)addr; 1887 break; 1888 1889 default: 1890 error = ENOTTY; 1891 break; 1892 } 1893 return (error); 1894} 1895 1896#endif 1897/* 1898 * Hello emacs, these are the 1899 * Local Variables: 1900 * c-indent-level: 8 1901 * c-continued-statement-offset: 8 1902 * c-continued-brace-offset: 0 1903 * c-brace-offset: -8 1904 * c-brace-imaginary-offset: 0 1905 * c-argdecl-indent: 8 1906 * c-label-offset: -8 1907 * c++-hanging-braces: 1 1908 * c++-access-specifier-offset: -8 1909 * c++-empty-arglist-indent: 8 1910 * c++-friend-offset: 0 1911 * End: 1912 */ 1913