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