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