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