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