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