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