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