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