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