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