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