fdc.c revision 3085
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 * Portions 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 * joerg_wunsch@uriah.sax.de (Joerg Wunsch) 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions 16 * are met: 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution. 22 * 3. All advertising materials mentioning features or use of this software 23 * must display the following acknowledgement: 24 * This product includes software developed by the University of 25 * California, Berkeley and its contributors. 26 * 4. Neither the name of the University nor the names of its contributors 27 * may be used to endorse or promote products derived from this software 28 * without specific prior written permission. 29 * 30 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 31 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 33 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 34 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 35 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 36 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 37 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 38 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 39 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 40 * SUCH DAMAGE. 41 * 42 * from: @(#)fd.c 7.4 (Berkeley) 5/25/91 43 * $Id: fd.c,v 1.31 1994/09/17 18:08:36 joerg Exp $ 44 * 45 */ 46 47#include "ft.h" 48#if NFT < 1 49#undef NFDC 50#endif 51#include "fd.h" 52 53#if NFDC > 0 54 55#include <sys/param.h> 56#include <sys/dkbad.h> 57#include <sys/systm.h> 58#include <sys/kernel.h> 59#include <sys/conf.h> 60#include <sys/file.h> 61#include <sys/ioctl.h> 62#include <machine/ioctl_fd.h> 63#include <sys/disklabel.h> 64#include <sys/buf.h> 65#include <sys/uio.h> 66#include <sys/malloc.h> 67#include <sys/proc.h> 68#include <sys/syslog.h> 69#include <i386/isa/isa.h> 70#include <i386/isa/isa_device.h> 71#include <i386/isa/fdreg.h> 72#include <i386/isa/fdc.h> 73#include <i386/isa/rtc.h> 74#if NFT > 0 75#include <sys/ftape.h> 76#include <i386/isa/ftreg.h> 77#endif 78 79#define RAW_PART 2 80#define b_cylin b_resid 81 82/* misuse a flag to identify format operation */ 83#define B_FORMAT B_XXX 84 85/* 86 * this biotab field doubles as a field for the physical unit number 87 * on the controller 88 */ 89#define id_physid id_scsiid 90 91#define NUMTYPES 14 92#define NUMDENS (NUMTYPES - 6) 93 94/* These defines (-1) must match index for fd_types */ 95#define F_TAPE_TYPE 0x020 /* bit for fd_types to indicate tape */ 96#define NO_TYPE 0 /* must match NO_TYPE in ft.c */ 97#define FD_1720 1 98#define FD_1480 2 99#define FD_1440 3 100#define FD_1200 4 101#define FD_820 5 102#define FD_800 6 103#define FD_720 7 104#define FD_360 8 105 106#define FD_1480in5_25 9 107#define FD_1440in5_25 10 108#define FD_820in5_25 11 109#define FD_800in5_25 12 110#define FD_720in5_25 13 111#define FD_360in5_25 14 112 113 114struct fd_type fd_types[NUMTYPES] = 115{ 116{ 21,2,0xFF,0x04,82,3444,1,FDC_500KBPS,2,0x0C,2 }, /* 1.72M in HD 3.5in */ 117{ 18,2,0xFF,0x1B,82,2952,1,FDC_500KBPS,2,0x6C,1 }, /* 1.48M in HD 3.5in */ 118{ 18,2,0xFF,0x1B,80,2880,1,FDC_500KBPS,2,0x6C,1 }, /* 1.44M in HD 3.5in */ 119{ 15,2,0xFF,0x1B,80,2400,1,FDC_500KBPS,2,0x54,1 }, /* 1.2M in HD 5.25/3.5 */ 120{ 10,2,0xFF,0x10,82,1640,1,FDC_250KBPS,2,0x2E,1 }, /* 820K in HD 3.5in */ 121{ 10,2,0xFF,0x10,80,1600,1,FDC_250KBPS,2,0x2E,1 }, /* 800K in HD 3.5in */ 122{ 9,2,0xFF,0x20,80,1440,1,FDC_250KBPS,2,0x50,1 }, /* 720K in HD 3.5in */ 123{ 9,2,0xFF,0x2A,40, 720,1,FDC_250KBPS,2,0x50,1 }, /* 360K in DD 5.25in */ 124 125{ 18,2,0xFF,0x02,82,2952,1,FDC_500KBPS,2,0x02,2 }, /* 1.48M in HD 5.25in */ 126{ 18,2,0xFF,0x02,80,2880,1,FDC_500KBPS,2,0x02,2 }, /* 1.44M in HD 5.25in */ 127{ 10,2,0xFF,0x10,82,1640,1,FDC_300KBPS,2,0x2E,1 }, /* 820K in HD 5.25in */ 128{ 10,2,0xFF,0x10,80,1600,1,FDC_300KBPS,2,0x2E,1 }, /* 800K in HD 5.25in */ 129{ 9,2,0xFF,0x20,80,1440,1,FDC_300KBPS,2,0x50,1 }, /* 720K in HD 5.25in */ 130{ 9,2,0xFF,0x23,40, 720,2,FDC_300KBPS,2,0x50,1 }, /* 360K in HD 5.25in */ 131}; 132 133#define DRVS_PER_CTLR 2 /* 2 floppies */ 134/***********************************************************************\ 135* Per controller structure. * 136\***********************************************************************/ 137struct fdc_data fdc_data[NFDC]; 138 139/***********************************************************************\ 140* Per drive structure. * 141* N per controller (DRVS_PER_CTLR) * 142\***********************************************************************/ 143struct fd_data { 144 struct fdc_data *fdc; /* pointer to controller structure */ 145 int fdsu; /* this units number on this controller */ 146 int type; /* Drive type (FD_1440...) */ 147 struct fd_type *ft; /* pointer to the type descriptor */ 148 int flags; 149#define FD_OPEN 0x01 /* it's open */ 150#define FD_ACTIVE 0x02 /* it's active */ 151#define FD_MOTOR 0x04 /* motor should be on */ 152#define FD_MOTOR_WAIT 0x08 /* motor coming up */ 153 int skip; 154 int hddrv; 155 int track; /* where we think the head is */ 156 int options; /* user configurable options, see ioctl_fd.h */ 157} fd_data[NFD]; 158 159/***********************************************************************\ 160* Throughout this file the following conventions will be used: * 161* fd is a pointer to the fd_data struct for the drive in question * 162* fdc is a pointer to the fdc_data struct for the controller * 163* fdu is the floppy drive unit number * 164* fdcu is the floppy controller unit number * 165* fdsu is the floppy drive unit number on that controller. (sub-unit) * 166\***********************************************************************/ 167 168#if NFT > 0 169int ftopen(dev_t, int); 170int ftintr(ftu_t ftu); 171int ftclose(dev_t, int); 172void ftstrategy(struct buf *); 173int ftioctl(dev_t, int, caddr_t, int, struct proc *); 174int ftdump(dev_t); 175int ftsize(dev_t); 176int ftattach(struct isa_device *, struct isa_device *); 177#endif 178 179/* autoconfig functions */ 180static int fdprobe(struct isa_device *); 181static int fdattach(struct isa_device *); 182 183/* exported functions */ 184int fdsize (dev_t); 185void fdintr(fdcu_t); 186int Fdopen(dev_t, int); 187int fdclose(dev_t, int); 188void fdstrategy(struct buf *); 189int fdioctl(dev_t, int, caddr_t, int, struct proc *); 190 191/* needed for ft driver, thus exported */ 192int in_fdc(fdcu_t); 193int out_fdc(fdcu_t, int); 194 195/* internal functions */ 196static void set_motor(fdcu_t, int, int); 197# define TURNON 1 198# define TURNOFF 0 199static timeout_t fd_turnoff; 200static timeout_t fd_motor_on; 201static void fd_turnon(fdu_t); 202static void fdc_reset(fdc_p); 203static void fdstart(fdcu_t); 204static timeout_t fd_timeout; 205static timeout_t fd_pseudointr; 206static int fdstate(fdcu_t, fdc_p); 207static int retrier(fdcu_t); 208static int fdformat(dev_t, struct fd_formb *, struct proc *); 209 210 211#define DEVIDLE 0 212#define FINDWORK 1 213#define DOSEEK 2 214#define SEEKCOMPLETE 3 215#define IOCOMPLETE 4 216#define RECALCOMPLETE 5 217#define STARTRECAL 6 218#define RESETCTLR 7 219#define SEEKWAIT 8 220#define RECALWAIT 9 221#define MOTORWAIT 10 222#define IOTIMEDOUT 11 223 224#ifdef DEBUG 225char *fdstates[] = 226{ 227"DEVIDLE", 228"FINDWORK", 229"DOSEEK", 230"SEEKCOMPLETE", 231"IOCOMPLETE", 232"RECALCOMPLETE", 233"STARTRECAL", 234"RESETCTLR", 235"SEEKWAIT", 236"RECALWAIT", 237"MOTORWAIT", 238"IOTIMEDOUT" 239}; 240 241/* CAUTION: fd_debug causes huge amounts of logging output */ 242int fd_debug = 0; 243#define TRACE0(arg) if(fd_debug) printf(arg) 244#define TRACE1(arg1, arg2) if(fd_debug) printf(arg1, arg2) 245#else /* DEBUG */ 246#define TRACE0(arg) 247#define TRACE1(arg1, arg2) 248#endif /* DEBUG */ 249 250/****************************************************************************/ 251/* autoconfiguration stuff */ 252/****************************************************************************/ 253struct isa_driver fdcdriver = { 254 fdprobe, fdattach, "fdc", 255}; 256 257/* 258 * probe for existance of controller 259 */ 260static int 261fdprobe(dev) 262 struct isa_device *dev; 263{ 264 fdcu_t fdcu = dev->id_unit; 265 if(fdc_data[fdcu].flags & FDC_ATTACHED) 266 { 267 printf("fdc: same unit (%d) used multiple times\n", fdcu); 268 return 0; 269 } 270 271 fdc_data[fdcu].baseport = dev->id_iobase; 272 273 /* First - lets reset the floppy controller */ 274 outb(dev->id_iobase+FDOUT, 0); 275 DELAY(100); 276 outb(dev->id_iobase+FDOUT, FDO_FRST); 277 278 /* see if it can handle a command */ 279 if (out_fdc(fdcu, NE7CMD_SPECIFY) < 0) 280 { 281 return(0); 282 } 283 out_fdc(fdcu, NE7_SPEC_1(3, 240)); 284 out_fdc(fdcu, NE7_SPEC_2(2, 0)); 285 return (IO_FDCSIZE); 286} 287 288/* 289 * wire controller into system, look for floppy units 290 */ 291static int 292fdattach(dev) 293 struct isa_device *dev; 294{ 295 unsigned fdt; 296 fdu_t fdu; 297 fdcu_t fdcu = dev->id_unit; 298 fdc_p fdc = fdc_data + fdcu; 299 fd_p fd; 300 int fdsu, st0, i; 301 struct isa_device *fdup; 302 303 fdc->fdcu = fdcu; 304 fdc->flags |= FDC_ATTACHED; 305 fdc->dmachan = dev->id_drq; 306 fdc->state = DEVIDLE; 307 /* reset controller, turn motor off, clear fdout mirror reg */ 308 outb(fdc->baseport + FDOUT, ((fdc->fdout = 0))); 309 printf("fdc%d:", fdcu); 310 311 /* check for each floppy drive */ 312 for (fdup = isa_biotab_fdc; fdup->id_driver != 0; fdup++) { 313 if (fdup->id_iobase != dev->id_iobase) 314 continue; 315 fdu = fdup->id_unit; 316 fd = &fd_data[fdu]; 317 if (fdu >= (NFD+NFT)) 318 continue; 319 fdsu = fdup->id_physid; 320 /* look up what bios thinks we have */ 321 switch (fdu) { 322 case 0: fdt = (rtcin(RTC_FDISKETTE) & 0xf0); 323 break; 324 case 1: fdt = ((rtcin(RTC_FDISKETTE) << 4) & 0xf0); 325 break; 326 default: fdt = RTCFDT_NONE; 327 break; 328 } 329 /* is there a unit? */ 330 if ((fdt == RTCFDT_NONE) 331#if NFT > 0 332 || (fdsu >= DRVS_PER_CTLR)) { 333#else 334 ) { 335 fd->type = NO_TYPE; 336#endif 337#if NFT > 0 338 /* If BIOS says no floppy, or > 2nd device */ 339 /* Probe for and attach a floppy tape. */ 340 if (ftattach(dev, fdup)) 341 continue; 342 if (fdsu < DRVS_PER_CTLR) 343 fd->type = NO_TYPE; 344#endif 345 continue; 346 } 347 348 /* select it */ 349 set_motor(fdcu, fdsu, TURNON); 350 DELAY(1000000); /* 1 sec */ 351 out_fdc(fdcu, NE7CMD_SENSED); 352 out_fdc(fdcu, fdsu); 353 if(in_fdc(fdcu) & NE7_ST3_T0) { 354 /* if at track 0, first seek inwards */ 355 out_fdc(fdcu, NE7CMD_SEEK); /* seek some steps... */ 356 out_fdc(fdcu, fdsu); 357 out_fdc(fdcu, 10); 358 DELAY(300000); /* ...wait a moment... */ 359 out_fdc(fdcu, NE7CMD_SENSEI); /* make ctrlr happy */ 360 (void)in_fdc(fdcu); 361 (void)in_fdc(fdcu); 362 } 363 for(i = 0; i < 2; i++) { 364 /* 365 * we must recalibrate twice, just in case the 366 * heads have been beyond cylinder 76, since most 367 * FDCs still barf when attempting to recalibrate 368 * more than 77 steps 369 */ 370 out_fdc(fdcu, NE7CMD_RECAL); /* go back to 0 */ 371 out_fdc(fdcu, fdsu); 372 /* a second being enough for full stroke seek */ 373 DELAY(i == 0? 1000000: 300000); 374 375 /* anything responding? */ 376 out_fdc(fdcu, NE7CMD_SENSEI); 377 st0 = in_fdc(fdcu); 378 (void)in_fdc(fdcu); 379 380 if ((st0 & NE7_ST0_EC) == 0) 381 break; /* already probed succesfully */ 382 } 383 384 set_motor(fdcu, fdsu, TURNOFF); 385 386 if (st0 & NE7_ST0_EC) /* no track 0 -> no drive present */ 387 continue; 388 389 fd->track = -2; 390 fd->fdc = fdc; 391 fd->fdsu = fdsu; 392 fd->options = 0; 393 printf(" [%d: fd%d: ", fdsu, fdu); 394 395 switch (fdt) { 396 case RTCFDT_12M: 397 printf("1.2MB 5.25in]"); 398 fd->type = FD_1200; 399 break; 400 case RTCFDT_144M: 401 printf("1.44MB 3.5in]"); 402 fd->type = FD_1440; 403 break; 404 case RTCFDT_360K: 405 printf("360KB 5.25in]"); 406 fd->type = FD_360; 407 break; 408 case RTCFDT_720K: 409 printf("720KB 3.5in]"); 410 fd->type = FD_720; 411 break; 412 default: 413 printf("unknown]"); 414 fd->type = NO_TYPE; 415 break; 416 } 417 } 418 printf("\n"); 419 420 return (1); 421} 422 423int 424fdsize(dev) 425 dev_t dev; 426{ 427 return(0); 428} 429 430/****************************************************************************/ 431/* motor control stuff */ 432/* remember to not deselect the drive we're working on */ 433/****************************************************************************/ 434static void 435set_motor(fdcu, fdsu, turnon) 436 fdcu_t fdcu; 437 int fdsu; 438 int turnon; 439{ 440 int fdout = fdc_data[fdcu].fdout; 441 int needspecify = 0; 442 443 if(turnon) { 444 fdout &= ~FDO_FDSEL; 445 fdout |= (FDO_MOEN0 << fdsu) + fdsu; 446 } else 447 fdout &= ~(FDO_MOEN0 << fdsu); 448 449 if(!turnon 450 && (fdout & (FDO_MOEN0+FDO_MOEN1+FDO_MOEN2+FDO_MOEN3)) == 0) 451 /* gonna turn off the last drive, put FDC to bed */ 452 fdout &= ~ (FDO_FRST|FDO_FDMAEN); 453 else { 454 /* make sure controller is selected and specified */ 455 if((fdout & (FDO_FRST|FDO_FDMAEN)) == 0) 456 needspecify = 1; 457 fdout |= (FDO_FRST|FDO_FDMAEN); 458 } 459 460 outb(fdc_data[fdcu].baseport+FDOUT, fdout); 461 fdc_data[fdcu].fdout = fdout; 462 TRACE1("[0x%x->FDOUT]", fdout); 463 464 if(needspecify) { 465 out_fdc(fdcu, NE7CMD_SPECIFY); 466 out_fdc(fdcu, NE7_SPEC_1(3, 240)); 467 out_fdc(fdcu, NE7_SPEC_2(2, 0)); 468 } 469} 470 471/* ARGSUSED */ 472static void 473fd_turnoff(void *arg1) 474{ 475 fdu_t fdu = (fdu_t)arg1; 476 int s; 477 478 fd_p fd = fd_data + fdu; 479 s = splbio(); 480 fd->flags &= ~FD_MOTOR; 481 set_motor(fd->fdc->fdcu, fd->fdsu, TURNOFF); 482 splx(s); 483} 484 485/* ARGSUSED */ 486static void 487fd_motor_on(void *arg1) 488{ 489 fdu_t fdu = (fdu_t)arg1; 490 int s; 491 492 fd_p fd = fd_data + fdu; 493 s = splbio(); 494 fd->flags &= ~FD_MOTOR_WAIT; 495 if((fd->fdc->fd == fd) && (fd->fdc->state == MOTORWAIT)) 496 { 497 fdintr(fd->fdc->fdcu); 498 } 499 splx(s); 500} 501 502static void 503fd_turnon(fdu) 504 fdu_t fdu; 505{ 506 fd_p fd = fd_data + fdu; 507 if(!(fd->flags & FD_MOTOR)) 508 { 509 fd->flags |= (FD_MOTOR + FD_MOTOR_WAIT); 510 set_motor(fd->fdc->fdcu, fd->fdsu, TURNON); 511 timeout(fd_motor_on, (caddr_t)fdu, hz); /* in 1 sec its ok */ 512 } 513} 514 515static void 516fdc_reset(fdc) 517 fdc_p fdc; 518{ 519 fdcu_t fdcu = fdc->fdcu; 520 521 /* Try a reset, keep motor on */ 522 outb(fdc->baseport + FDOUT, fdc->fdout & ~(FDO_FRST|FDO_FDMAEN)); 523 TRACE1("[0x%x->FDOUT]", fdc->fdout & ~(FDO_FRST|FDO_FDMAEN)); 524 DELAY(100); 525 /* enable FDC, but defer interrupts a moment */ 526 outb(fdc->baseport + FDOUT, fdc->fdout & ~FDO_FDMAEN); 527 TRACE1("[0x%x->FDOUT]", fdc->fdout & ~FDO_FDMAEN); 528 DELAY(100); 529 outb(fdc->baseport + FDOUT, fdc->fdout); 530 TRACE1("[0x%x->FDOUT]", fdc->fdout); 531 532 out_fdc(fdcu, NE7CMD_SPECIFY); 533 out_fdc(fdcu, NE7_SPEC_1(3, 240)); 534 out_fdc(fdcu, NE7_SPEC_2(2, 0)); 535} 536 537/****************************************************************************/ 538/* fdc in/out */ 539/****************************************************************************/ 540int 541in_fdc(fdcu) 542 fdcu_t fdcu; 543{ 544 int baseport = fdc_data[fdcu].baseport; 545 int i, j = 100000; 546 while ((i = inb(baseport+FDSTS) & (NE7_DIO|NE7_RQM)) 547 != (NE7_DIO|NE7_RQM) && j-- > 0) 548 if (i == NE7_RQM) return -1; 549 if (j <= 0) 550 return(-1); 551#ifdef DEBUG 552 i = inb(baseport+FDDATA); 553 TRACE1("[FDDATA->0x%x]", (unsigned char)i); 554 return(i); 555#else 556 return inb(baseport+FDDATA); 557#endif 558} 559 560int 561out_fdc(fdcu, x) 562 fdcu_t fdcu; 563 int x; 564{ 565 int baseport = fdc_data[fdcu].baseport; 566 int i; 567 568 /* Check that the direction bit is set */ 569 i = 100000; 570 while ((inb(baseport+FDSTS) & NE7_DIO) && i-- > 0); 571 if (i <= 0) return (-1); /* Floppy timed out */ 572 573 /* Check that the floppy controller is ready for a command */ 574 i = 100000; 575 while ((inb(baseport+FDSTS) & NE7_RQM) == 0 && i-- > 0); 576 if (i <= 0) return (-1); /* Floppy timed out */ 577 578 /* Send the command and return */ 579 outb(baseport+FDDATA, x); 580 TRACE1("[0x%x->FDDATA]", x); 581 return (0); 582} 583 584/****************************************************************************/ 585/* fdopen/fdclose */ 586/****************************************************************************/ 587int 588Fdopen(dev, flags) 589 dev_t dev; 590 int flags; 591{ 592 fdu_t fdu = FDUNIT(minor(dev)); 593 int type = FDTYPE(minor(dev)); 594 fdc_p fdc; 595 596#if NFT > 0 597 /* check for a tape open */ 598 if (type & F_TAPE_TYPE) 599 return(ftopen(dev, flags)); 600#endif 601 /* check bounds */ 602 if (fdu >= NFD) 603 return(ENXIO); 604 fdc = fd_data[fdu].fdc; 605 if ((fdc == NULL) || (fd_data[fdu].type == NO_TYPE)) 606 return(ENXIO); 607 if (type > NUMDENS) 608 return(ENXIO); 609 if (type == 0) 610 type = fd_data[fdu].type; 611 else { 612 if (type != fd_data[fdu].type) { 613 switch (fd_data[fdu].type) { 614 case FD_360: 615 return(ENXIO); 616 case FD_720: 617 if ( type != FD_820 618 && type != FD_800 619 ) 620 return(ENXIO); 621 break; 622 case FD_1200: 623 switch (type) { 624 case FD_1480: 625 type = FD_1480in5_25; 626 break; 627 case FD_1440: 628 type = FD_1440in5_25; 629 break; 630 case FD_820: 631 type = FD_820in5_25; 632 break; 633 case FD_800: 634 type = FD_800in5_25; 635 break; 636 case FD_720: 637 type = FD_720in5_25; 638 break; 639 case FD_360: 640 type = FD_360in5_25; 641 break; 642 default: 643 return(ENXIO); 644 } 645 break; 646 case FD_1440: 647 if ( type != FD_1720 648 && type != FD_1480 649 && type != FD_1200 650 && type != FD_820 651 && type != FD_800 652 && type != FD_720 653 ) 654 return(ENXIO); 655 break; 656 } 657 } 658 } 659 fd_data[fdu].ft = fd_types + type - 1; 660 fd_data[fdu].flags |= FD_OPEN; 661 662 return 0; 663} 664 665int 666fdclose(dev, flags) 667 dev_t dev; 668 int flags; 669{ 670 fdu_t fdu = FDUNIT(minor(dev)); 671 672#if NFT > 0 673 int type = FDTYPE(minor(dev)); 674 675 if (type & F_TAPE_TYPE) 676 return ftclose(dev, flags); 677#endif 678 fd_data[fdu].flags &= ~FD_OPEN; 679 fd_data[fdu].options &= ~FDOPT_NORETRY; 680 return(0); 681} 682 683 684/****************************************************************************/ 685/* fdstrategy */ 686/****************************************************************************/ 687void 688fdstrategy(struct buf *bp) 689{ 690 register struct buf *dp; 691 long nblocks, blknum; 692 int s; 693 fdcu_t fdcu; 694 fdu_t fdu; 695 fdc_p fdc; 696 fd_p fd; 697 size_t fdblk; 698 699 fdu = FDUNIT(minor(bp->b_dev)); 700 fd = &fd_data[fdu]; 701 fdc = fd->fdc; 702 fdcu = fdc->fdcu; 703 fdblk = 128 << (fd->ft->secsize); 704 705#if NFT > 0 706 if (FDTYPE(minor(bp->b_dev)) & F_TAPE_TYPE) { 707 /* ft tapes do not (yet) support strategy i/o */ 708 bp->b_error = ENXIO; 709 bp->b_flags |= B_ERROR; 710 goto bad; 711 } 712 /* check for controller already busy with tape */ 713 if (fdc->flags & FDC_TAPE_BUSY) { 714 bp->b_error = EBUSY; 715 bp->b_flags |= B_ERROR; 716 goto bad; 717 } 718#endif 719 if (!(bp->b_flags & B_FORMAT)) { 720 if ((fdu >= NFD) || (bp->b_blkno < 0)) { 721 printf("fdstrat: fdu = %d, blkno = %d, bcount = %d\n", 722 fdu, bp->b_blkno, bp->b_bcount); 723 bp->b_error = EINVAL; 724 bp->b_flags |= B_ERROR; 725 goto bad; 726 } 727 if ((bp->b_bcount % fdblk) != 0) { 728 bp->b_error = EINVAL; 729 bp->b_flags |= B_ERROR; 730 goto bad; 731 } 732 } 733 734 /* 735 * Set up block calculations. 736 */ 737 blknum = (unsigned long) bp->b_blkno * DEV_BSIZE/fdblk; 738 nblocks = fd->ft->size; 739 if (blknum + (bp->b_bcount / fdblk) > nblocks) { 740 if (blknum == nblocks) { 741 bp->b_resid = bp->b_bcount; 742 } else { 743 bp->b_error = ENOSPC; 744 bp->b_flags |= B_ERROR; 745 } 746 goto bad; 747 } 748 bp->b_cylin = blknum / (fd->ft->sectrac * fd->ft->heads); 749 dp = &(fdc->head); 750 s = splbio(); 751 disksort(dp, bp); 752 untimeout(fd_turnoff, (caddr_t)fdu); /* a good idea */ 753 fdstart(fdcu); 754 splx(s); 755 return; 756 757bad: 758 biodone(bp); 759} 760 761/***************************************************************\ 762* fdstart * 763* We have just queued something.. if the controller is not busy * 764* then simulate the case where it has just finished a command * 765* So that it (the interrupt routine) looks on the queue for more* 766* work to do and picks up what we just added. * 767* If the controller is already busy, we need do nothing, as it * 768* will pick up our work when the present work completes * 769\***************************************************************/ 770static void 771fdstart(fdcu) 772 fdcu_t fdcu; 773{ 774 int s; 775 776 s = splbio(); 777 if(fdc_data[fdcu].state == DEVIDLE) 778 { 779 fdintr(fdcu); 780 } 781 splx(s); 782} 783 784/* ARGSUSED */ 785static void 786fd_timeout(void *arg1) 787{ 788 fdcu_t fdcu = (fdcu_t)arg1; 789 fdu_t fdu = fdc_data[fdcu].fdu; 790 int baseport = fdc_data[fdcu].baseport; 791 struct buf *dp, *bp; 792 int s; 793 794 dp = &fdc_data[fdcu].head; 795 bp = dp->b_actf; 796 797 /* 798 * Due to IBM's brain-dead design, the FDC has a faked ready 799 * signal, hardwired to ready == true. Thus, any command 800 * issued if there's no diskette in the drive will _never_ 801 * complete, and must be aborted by resetting the FDC. 802 * Many thanks, Big Blue! 803 */ 804 805 s = splbio(); 806 807 TRACE1("fd%d[fd_timeout()]", fdu); 808 /* See if the controller is still busy (patiently awaiting data) */ 809 if(((inb(baseport + FDSTS)) & (NE7_CB|NE7_RQM)) == NE7_CB) 810 { 811 TRACE1("[FDSTS->0x%x]", inb(baseport + FDSTS)); 812 /* yup, it is; kill it now */ 813 fdc_reset(&fdc_data[fdcu]); 814 printf("fd%d: Operation timeout\n", fdu); 815 } 816 817 if (bp) 818 { 819 retrier(fdcu); 820 fdc_data[fdcu].status[0] = NE7_ST0_IC_RC; 821 fdc_data[fdcu].state = IOTIMEDOUT; 822 if( fdc_data[fdcu].retry < 6) 823 fdc_data[fdcu].retry = 6; 824 } 825 else 826 { 827 fdc_data[fdcu].fd = (fd_p) 0; 828 fdc_data[fdcu].fdu = -1; 829 fdc_data[fdcu].state = DEVIDLE; 830 } 831 fdintr(fdcu); 832 splx(s); 833} 834 835/* just ensure it has the right spl */ 836/* ARGSUSED */ 837static void 838fd_pseudointr(void *arg1) 839{ 840 fdcu_t fdcu = (fdcu_t)arg1; 841 int s; 842 843 s = splbio(); 844 fdintr(fdcu); 845 splx(s); 846} 847 848/***********************************************************************\ 849* fdintr * 850* keep calling the state machine until it returns a 0 * 851* ALWAYS called at SPLBIO * 852\***********************************************************************/ 853void 854fdintr(fdcu_t fdcu) 855{ 856 fdc_p fdc = fdc_data + fdcu; 857#if NFT > 0 858 fdu_t fdu = fdc->fdu; 859 860 if (fdc->flags & FDC_TAPE_BUSY) 861 (ftintr(fdu)); 862 else 863#endif 864 while(fdstate(fdcu, fdc)) 865 ; 866} 867 868/***********************************************************************\ 869* The controller state machine. * 870* if it returns a non zero value, it should be called again immediatly * 871\***********************************************************************/ 872static int 873fdstate(fdcu, fdc) 874 fdcu_t fdcu; 875 fdc_p fdc; 876{ 877 int read, format, head, sec = 0, i = 0, sectrac, st0, cyl, st3; 878 unsigned long blknum; 879 fdu_t fdu = fdc->fdu; 880 fd_p fd; 881 register struct buf *dp, *bp; 882 struct fd_formb *finfo = NULL; 883 size_t fdblk; 884 885 dp = &(fdc->head); 886 bp = dp->b_actf; 887 if(!bp) 888 { 889 /***********************************************\ 890 * nothing left for this controller to do * 891 * Force into the IDLE state, * 892 \***********************************************/ 893 fdc->state = DEVIDLE; 894 if(fdc->fd) 895 { 896 printf("unexpected valid fd pointer (fdu = %d)\n", 897 fdc->fdu); 898 fdc->fd = (fd_p) 0; 899 fdc->fdu = -1; 900 } 901 TRACE1("[fdc%d IDLE]", fdcu); 902 return(0); 903 } 904 fdu = FDUNIT(minor(bp->b_dev)); 905 fd = fd_data + fdu; 906 fdblk = 128 << fd->ft->secsize; 907 if (fdc->fd && (fd != fdc->fd)) 908 { 909 printf("confused fd pointers\n"); 910 } 911 read = bp->b_flags & B_READ; 912 format = bp->b_flags & B_FORMAT; 913 if(format) 914 finfo = (struct fd_formb *)bp->b_un.b_addr; 915 TRACE1("fd%d", fdu); 916 TRACE1("[%s]", fdstates[fdc->state]); 917 TRACE1("(0x%x)", fd->flags); 918 untimeout(fd_turnoff, (caddr_t)fdu); 919 timeout(fd_turnoff, (caddr_t)fdu, 4 * hz); 920 switch (fdc->state) 921 { 922 case DEVIDLE: 923 case FINDWORK: /* we have found new work */ 924 fdc->retry = 0; 925 fd->skip = 0; 926 fdc->fd = fd; 927 fdc->fdu = fdu; 928 outb(fdc->baseport+FDCTL, fd->ft->trans); 929 TRACE1("[0x%x->FDCTL]", fd->ft->trans); 930 /*******************************************************\ 931 * If the next drive has a motor startup pending, then * 932 * it will start up in it's own good time * 933 \*******************************************************/ 934 if(fd->flags & FD_MOTOR_WAIT) 935 { 936 fdc->state = MOTORWAIT; 937 return(0); /* come back later */ 938 } 939 /*******************************************************\ 940 * Maybe if it's not starting, it SHOULD be starting * 941 \*******************************************************/ 942 if (!(fd->flags & FD_MOTOR)) 943 { 944 fdc->state = MOTORWAIT; 945 fd_turnon(fdu); 946 return(0); 947 } 948 else /* at least make sure we are selected */ 949 { 950 set_motor(fdcu, fd->fdsu, TURNON); 951 } 952 fdc->state = DOSEEK; 953 break; 954 case DOSEEK: 955 if (bp->b_cylin == fd->track) 956 { 957 fdc->state = SEEKCOMPLETE; 958 break; 959 } 960 out_fdc(fdcu, NE7CMD_SEEK); /* Seek function */ 961 out_fdc(fdcu, fd->fdsu); /* Drive number */ 962 out_fdc(fdcu, bp->b_cylin * fd->ft->steptrac); 963 fd->track = -2; 964 fdc->state = SEEKWAIT; 965 return(0); /* will return later */ 966 case SEEKWAIT: 967 /* allow heads to settle */ 968 timeout(fd_pseudointr, (caddr_t)fdcu, hz / 32); 969 fdc->state = SEEKCOMPLETE; 970 return(0); /* will return later */ 971 case SEEKCOMPLETE : /* SEEK DONE, START DMA */ 972 /* Make sure seek really happened*/ 973 if(fd->track == -2) 974 { 975 int descyl = bp->b_cylin * fd->ft->steptrac; 976 do { 977 out_fdc(fdcu, NE7CMD_SENSEI); 978 st0 = in_fdc(fdcu); 979 cyl = in_fdc(fdcu); 980 /* 981 * if this was a "ready changed" interrupt, 982 * fetch status again (can happen after 983 * enabling controller from reset state) 984 */ 985 } while ((st0 & NE7_ST0_IC) == NE7_ST0_IC_RC); 986 if (0 == descyl) 987 { 988 /* 989 * seek to cyl 0 requested; make sure we are 990 * really there 991 */ 992 out_fdc(fdcu, NE7CMD_SENSED); 993 out_fdc(fdcu, fdu); 994 st3 = in_fdc(fdcu); 995 if ((st3 & NE7_ST3_T0) == 0) { 996 printf( 997 "fd%d: Seek to cyl 0, but not really there (ST3 = %b)\n", 998 fdu, st3, NE7_ST3BITS); 999 if(fdc->retry < 3) 1000 fdc->retry = 3; 1001 return(retrier(fdcu)); 1002 } 1003 } 1004 if (cyl != descyl) 1005 { 1006 printf( 1007 "fd%d: Seek to cyl %d failed; am at cyl %d (ST0 = 0x%x)\n", 1008 fdu, descyl, cyl, st0, NE7_ST0BITS); 1009 return(retrier(fdcu)); 1010 } 1011 } 1012 1013 fd->track = bp->b_cylin; 1014 if(format) 1015 fd->skip = (char *)&(finfo->fd_formb_cylno(0)) 1016 - (char *)finfo; 1017 isa_dmastart(bp->b_flags, bp->b_un.b_addr+fd->skip, 1018 format ? bp->b_bcount : fdblk, fdc->dmachan); 1019 blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/fdblk 1020 + fd->skip/fdblk; 1021 sectrac = fd->ft->sectrac; 1022 sec = blknum % (sectrac * fd->ft->heads); 1023 head = sec / sectrac; 1024 sec = sec % sectrac + 1; 1025 fd->hddrv = ((head&1)<<2)+fdu; 1026 1027 if(format || !read) 1028 { 1029 /* make sure the drive is writable */ 1030 out_fdc(fdcu, NE7CMD_SENSED); 1031 out_fdc(fdcu, fdu); 1032 st3 = in_fdc(fdcu); 1033 if(st3 & NE7_ST3_WP) 1034 { 1035 /* 1036 * XXX YES! this is ugly. 1037 * in order to force the current operation 1038 * to fail, we will have to fake an FDC 1039 * error - all error handling is done 1040 * by the retrier() 1041 */ 1042 fdc->status[0] = NE7_ST0_IC_AT; 1043 fdc->status[1] = NE7_ST1_NW; 1044 fdc->status[2] = 0; 1045 fdc->status[3] = fd->track; 1046 fdc->status[4] = head; 1047 fdc->status[5] = sec; 1048 fdc->retry = 8; /* break out immediately */ 1049 fdc->state = IOTIMEDOUT; /* not really... */ 1050 return (1); 1051 } 1052 } 1053 1054 if(format) 1055 { 1056 /* formatting */ 1057 out_fdc(fdcu, NE7CMD_FORMAT); 1058 out_fdc(fdcu, head << 2 | fdu); 1059 out_fdc(fdcu, finfo->fd_formb_secshift); 1060 out_fdc(fdcu, finfo->fd_formb_nsecs); 1061 out_fdc(fdcu, finfo->fd_formb_gaplen); 1062 out_fdc(fdcu, finfo->fd_formb_fillbyte); 1063 } 1064 else 1065 { 1066 if (read) 1067 { 1068 out_fdc(fdcu, NE7CMD_READ); /* READ */ 1069 } 1070 else 1071 { 1072 out_fdc(fdcu, NE7CMD_WRITE); /* WRITE */ 1073 } 1074 out_fdc(fdcu, head << 2 | fdu); /* head & unit */ 1075 out_fdc(fdcu, fd->track); /* track */ 1076 out_fdc(fdcu, head); 1077 out_fdc(fdcu, sec); /* sector XXX +1? */ 1078 out_fdc(fdcu, fd->ft->secsize); /* sector size */ 1079 out_fdc(fdcu, sectrac); /* sectors/track */ 1080 out_fdc(fdcu, fd->ft->gap); /* gap size */ 1081 out_fdc(fdcu, fd->ft->datalen); /* data length */ 1082 } 1083 fdc->state = IOCOMPLETE; 1084 timeout(fd_timeout, (caddr_t)fdcu, hz); 1085 return(0); /* will return later */ 1086 case IOCOMPLETE: /* IO DONE, post-analyze */ 1087 untimeout(fd_timeout, (caddr_t)fdcu); 1088 for(i=0;i<7;i++) 1089 { 1090 fdc->status[i] = in_fdc(fdcu); 1091 } 1092 fdc->state = IOTIMEDOUT; 1093 /* FALLTHROUGH */ 1094 case IOTIMEDOUT: 1095 isa_dmadone(bp->b_flags, bp->b_un.b_addr+fd->skip, 1096 format ? bp->b_bcount : fdblk, fdc->dmachan); 1097 if (fdc->status[0] & NE7_ST0_IC) 1098 { 1099 if ((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_AT 1100 && fdc->status[1] & NE7_ST1_OR) { 1101 /* 1102 * DMA overrun. Someone hogged the bus 1103 * and didn't release it in time for the 1104 * next FDC transfer. 1105 * Just restart it, don't increment retry 1106 * count. (vak) 1107 */ 1108 fdc->state = SEEKCOMPLETE; 1109 return (1); 1110 } 1111 else if((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_IV 1112 && fdc->retry < 6) 1113 fdc->retry = 6; /* force a reset */ 1114 else if((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_AT 1115 && fdc->status[2] & NE7_ST2_WC 1116 && fdc->retry < 3) 1117 fdc->retry = 3; /* force recalibrate */ 1118 return(retrier(fdcu)); 1119 } 1120 /* All OK */ 1121 fd->skip += fdblk; 1122 if (!format && fd->skip < bp->b_bcount) 1123 { 1124 /* set up next transfer */ 1125 blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/fdblk 1126 + fd->skip/fdblk; 1127 bp->b_cylin = 1128 (blknum / (fd->ft->sectrac * fd->ft->heads)); 1129 fdc->state = DOSEEK; 1130 } 1131 else 1132 { 1133 /* ALL DONE */ 1134 fd->skip = 0; 1135 bp->b_resid = 0; 1136 dp->b_actf = bp->b_actf; 1137 biodone(bp); 1138 fdc->fd = (fd_p) 0; 1139 fdc->fdu = -1; 1140 fdc->state = FINDWORK; 1141 } 1142 return(1); 1143 case RESETCTLR: 1144 fdc_reset(fdc); 1145 fdc->retry++; 1146 fdc->state = STARTRECAL; 1147 break; 1148 case STARTRECAL: 1149 out_fdc(fdcu, NE7CMD_RECAL); /* Recalibrate Function */ 1150 out_fdc(fdcu, fdu); 1151 fdc->state = RECALWAIT; 1152 return(0); /* will return later */ 1153 case RECALWAIT: 1154 /* allow heads to settle */ 1155 timeout(fd_pseudointr, (caddr_t)fdcu, hz / 32); 1156 fdc->state = RECALCOMPLETE; 1157 return(0); /* will return later */ 1158 case RECALCOMPLETE: 1159 do { 1160 out_fdc(fdcu, NE7CMD_SENSEI); 1161 st0 = in_fdc(fdcu); 1162 cyl = in_fdc(fdcu); 1163 /* 1164 * if this was a "ready changed" interrupt, 1165 * fetch status again (can happen after 1166 * enabling controller from reset state) 1167 */ 1168 } while ((st0 & NE7_ST0_IC) == NE7_ST0_IC_RC); 1169 if ((st0 & NE7_ST0_IC) != NE7_ST0_IC_NT || cyl != 0) 1170 { 1171 printf("fd%d: recal failed ST0 %b cyl %d\n", fdu, 1172 st0, NE7_ST0BITS, cyl); 1173 if(fdc->retry < 3) fdc->retry = 3; 1174 return(retrier(fdcu)); 1175 } 1176 fd->track = 0; 1177 /* Seek (probably) necessary */ 1178 fdc->state = DOSEEK; 1179 return(1); /* will return immediatly */ 1180 case MOTORWAIT: 1181 if(fd->flags & FD_MOTOR_WAIT) 1182 { 1183 return(0); /* time's not up yet */ 1184 } 1185 /* 1186 * since the controller was off, it has lost its 1187 * idea about the current track it were; thus, 1188 * recalibrate the bastard 1189 */ 1190 fdc->state = STARTRECAL; 1191 return(1); /* will return immediatly */ 1192 default: 1193 printf("Unexpected FD int->"); 1194 out_fdc(fdcu, NE7CMD_SENSEI); 1195 st0 = in_fdc(fdcu); 1196 cyl = in_fdc(fdcu); 1197 printf("ST0 = %x, PCN = %x\n", st0, cyl); 1198 out_fdc(fdcu, NE7CMD_READID); 1199 out_fdc(fdcu, fd->fdsu); 1200 for(i=0;i<7;i++) { 1201 fdc->status[i] = in_fdc(fdcu); 1202 } 1203 if(fdc->status[0] != -1) 1204 printf("intr status :%lx %lx %lx %lx %lx %lx %lx\n", 1205 fdc->status[0], 1206 fdc->status[1], 1207 fdc->status[2], 1208 fdc->status[3], 1209 fdc->status[4], 1210 fdc->status[5], 1211 fdc->status[6] ); 1212 else 1213 printf("FDC timed out\n"); 1214 return(0); 1215 } 1216 return(1); /* Come back immediatly to new state */ 1217} 1218 1219static int 1220retrier(fdcu) 1221 fdcu_t fdcu; 1222{ 1223 fdc_p fdc = fdc_data + fdcu; 1224 register struct buf *dp, *bp; 1225 1226 dp = &(fdc->head); 1227 bp = dp->b_actf; 1228 1229 if(fd_data[FDUNIT(minor(bp->b_dev))].options & FDOPT_NORETRY) 1230 goto fail; 1231 switch(fdc->retry) 1232 { 1233 case 0: case 1: case 2: 1234 fdc->state = SEEKCOMPLETE; 1235 break; 1236 case 3: case 4: case 5: 1237 fdc->state = STARTRECAL; 1238 break; 1239 case 6: 1240 fdc->state = RESETCTLR; 1241 break; 1242 case 7: 1243 break; 1244 default: 1245 fail: 1246 { 1247 dev_t sav_b_dev = bp->b_dev; 1248 /* Trick diskerr */ 1249 bp->b_dev = makedev(major(bp->b_dev), 1250 (FDUNIT(minor(bp->b_dev))<<3)|RAW_PART); 1251 diskerr(bp, "fd", "hard error", LOG_PRINTF, 1252 fdc->fd->skip / DEV_BSIZE, 1253 (struct disklabel *)NULL); 1254 bp->b_dev = sav_b_dev; 1255 printf(" (ST0 %b ", fdc->status[0], NE7_ST0BITS); 1256 printf(" ST1 %b ", fdc->status[1], NE7_ST1BITS); 1257 printf(" ST2 %b ", fdc->status[2], NE7_ST2BITS); 1258 printf("cyl %d hd %d sec %d)\n", 1259 fdc->status[3], fdc->status[4], fdc->status[5]); 1260 } 1261 bp->b_flags |= B_ERROR; 1262 bp->b_error = EIO; 1263 bp->b_resid = bp->b_bcount - fdc->fd->skip; 1264 dp->b_actf = bp->b_actf; 1265 fdc->fd->skip = 0; 1266 biodone(bp); 1267 fdc->state = FINDWORK; 1268 fdc->fd = (fd_p) 0; 1269 fdc->fdu = -1; 1270 /* XXX abort current command, if any. */ 1271 return(1); 1272 } 1273 fdc->retry++; 1274 return(1); 1275} 1276 1277static int 1278fdformat(dev, finfo, p) 1279 dev_t dev; 1280 struct fd_formb *finfo; 1281 struct proc *p; 1282{ 1283 fdu_t fdu; 1284 fd_p fd; 1285 1286 struct buf *bp; 1287 int rv = 0, s; 1288 size_t fdblk; 1289 1290 fdu = FDUNIT(minor(dev)); 1291 fd = &fd_data[fdu]; 1292 fdblk = 128 << fd->ft->secsize; 1293 1294 /* set up a buffer header for fdstrategy() */ 1295 bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT); 1296 if(bp == 0) 1297 return ENOBUFS; 1298 bzero((void *)bp, sizeof(struct buf)); 1299 bp->b_flags = B_BUSY | B_PHYS | B_FORMAT; 1300 bp->b_proc = p; 1301 bp->b_dev = dev; 1302 1303 /* 1304 * calculate a fake blkno, so fdstrategy() would initiate a 1305 * seek to the requested cylinder 1306 */ 1307 bp->b_blkno = (finfo->cyl * (fd->ft->sectrac * fd->ft->heads) 1308 + finfo->head * fd->ft->sectrac) * fdblk / DEV_BSIZE; 1309 1310 bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs; 1311 bp->b_un.b_addr = (caddr_t)finfo; 1312 1313 /* now do the format */ 1314 fdstrategy(bp); 1315 1316 /* ...and wait for it to complete */ 1317 s = splbio(); 1318 while(!(bp->b_flags & B_DONE)) 1319 { 1320 rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 20 * hz); 1321 if(rv == EWOULDBLOCK) 1322 break; 1323 } 1324 splx(s); 1325 1326 if(rv == EWOULDBLOCK) 1327 /* timed out */ 1328 rv = EIO; 1329 if(bp->b_flags & B_ERROR) 1330 rv = bp->b_error; 1331 biodone(bp); 1332 free(bp, M_TEMP); 1333 return rv; 1334} 1335 1336/* 1337 * 1338 * TODO: Think about allocating buffer off stack. 1339 * Don't pass uncast 0's and NULL's to read/write/setdisklabel(). 1340 * Watch out for NetBSD's different *disklabel() interface. 1341 * 1342 */ 1343 1344int 1345fdioctl(dev, cmd, addr, flag, p) 1346 dev_t dev; 1347 int cmd; 1348 caddr_t addr; 1349 int flag; 1350 struct proc *p; 1351{ 1352 fdu_t fdu = FDUNIT(minor(dev)); 1353 fd_p fd = &fd_data[fdu]; 1354 size_t fdblk; 1355 1356 struct fd_type *fdt; 1357 struct disklabel *dl; 1358 char buffer[DEV_BSIZE]; 1359 int error = 0; 1360 1361#if NFT > 0 1362 int type = FDTYPE(minor(dev)); 1363 1364 /* check for a tape ioctl */ 1365 if (type & F_TAPE_TYPE) 1366 return ftioctl(dev, cmd, addr, flag, p); 1367#endif 1368 1369 fdblk = 128 << fd->ft->secsize; 1370 1371 switch (cmd) 1372 { 1373 case DIOCGDINFO: 1374 bzero(buffer, sizeof (buffer)); 1375 dl = (struct disklabel *)buffer; 1376 dl->d_secsize = fdblk; 1377 fdt = fd_data[FDUNIT(minor(dev))].ft; 1378 dl->d_secpercyl = fdt->size / fdt->tracks; 1379 dl->d_type = DTYPE_FLOPPY; 1380 1381 if (readdisklabel(dev, fdstrategy, dl, NULL, 0, 0) == NULL) 1382 error = 0; 1383 else 1384 error = EINVAL; 1385 1386 *(struct disklabel *)addr = *dl; 1387 break; 1388 1389 case DIOCSDINFO: 1390 if ((flag & FWRITE) == 0) 1391 error = EBADF; 1392 break; 1393 1394 case DIOCWLABEL: 1395 if ((flag & FWRITE) == 0) 1396 error = EBADF; 1397 break; 1398 1399 case DIOCWDINFO: 1400 if ((flag & FWRITE) == 0) 1401 { 1402 error = EBADF; 1403 break; 1404 } 1405 1406 dl = (struct disklabel *)addr; 1407 1408 if ((error = 1409 setdisklabel ((struct disklabel *)buffer, dl, 0, NULL))) 1410 break; 1411 1412 error = writedisklabel(dev, fdstrategy, 1413 (struct disklabel *)buffer, NULL); 1414 break; 1415 1416 case FD_FORM: 1417 if((flag & FWRITE) == 0) 1418 error = EBADF; /* must be opened for writing */ 1419 else if(((struct fd_formb *)addr)->format_version != 1420 FD_FORMAT_VERSION) 1421 error = EINVAL; /* wrong version of formatting prog */ 1422 else 1423 error = fdformat(dev, (struct fd_formb *)addr, p); 1424 break; 1425 1426 case FD_GTYPE: /* get drive type */ 1427 *(struct fd_type *)addr = *fd_data[FDUNIT(minor(dev))].ft; 1428 break; 1429 1430 case FD_STYPE: /* set drive type */ 1431 /* this is considered harmful; only allow for superuser */ 1432 if(suser(p->p_ucred, &p->p_acflag) != 0) 1433 return EPERM; 1434 *fd_data[FDUNIT(minor(dev))].ft = *(struct fd_type *)addr; 1435 break; 1436 1437 case FD_GOPTS: /* get drive options */ 1438 *(int *)addr = fd_data[FDUNIT(minor(dev))].options; 1439 break; 1440 1441 case FD_SOPTS: /* set drive options */ 1442 fd_data[FDUNIT(minor(dev))].options = *(int *)addr; 1443 break; 1444 1445 default: 1446 error = ENOTTY; 1447 break; 1448 } 1449 return (error); 1450} 1451 1452#endif 1453/* 1454 * Hello emacs, these are the 1455 * Local Variables: 1456 * c-indent-level: 8 1457 * c-continued-statement-offset: 8 1458 * c-continued-brace-offset: 0 1459 * c-brace-offset: -8 1460 * c-brace-imaginary-offset: 0 1461 * c-argdecl-indent: 8 1462 * c-label-offset: -8 1463 * c++-hanging-braces: 1 1464 * c++-access-specifier-offset: -8 1465 * c++-empty-arglist-indent: 8 1466 * c++-friend-offset: 0 1467 * End: 1468 */ 1469