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