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