|
|
1.1.1.5 ! root 1: /*#define DEBUG 1*/ 1.1 root 2: /*- 3: * Copyright (c) 1990 The Regents of the University of California. 4: * All rights reserved. 5: * 6: * This code is derived from software contributed to Berkeley by 7: * Don Ahn. 8: * 9: * Redistribution and use in source and binary forms, with or without 10: * modification, are permitted provided that the following conditions 11: * are met: 12: * 1. Redistributions of source code must retain the above copyright 13: * notice, this list of conditions and the following disclaimer. 14: * 2. Redistributions in binary form must reproduce the above copyright 15: * notice, this list of conditions and the following disclaimer in the 16: * documentation and/or other materials provided with the distribution. 17: * 3. All advertising materials mentioning features or use of this software 18: * must display the following acknowledgement: 19: * This product includes software developed by the University of 20: * California, Berkeley and its contributors. 21: * 4. Neither the name of the University nor the names of its contributors 22: * may be used to endorse or promote products derived from this software 23: * without specific prior written permission. 24: * 25: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35: * SUCH DAMAGE. 36: * 1.1.1.5 ! root 37: * from: @(#)fd.c 7.4 (Berkeley) 5/25/91 ! 38: * fd.c,v 1.19.2.1 1993/07/28 00:11:21 deraadt Exp ! 39: * ! 40: * Largely rewritten to handle multiple controllers and drives ! 41: * By Julian Elischer, Sun Apr 4 16:34:33 WST 1993 ! 42: */ ! 43: /* ! 44: * fd.c,v ! 45: * Revision 1.19.2.1 1993/07/28 00:11:21 deraadt ! 46: * wd.c: fixes 1 drive systems ! 47: * fd.c: improves reliability ! 48: * changes from wolfgang ! 49: * ! 50: * Revision 1.19 1993/07/16 15:44:22 mycroft ! 51: * #include cpufunc,h so inb() and outb() are inlined. ! 52: * ! 53: * Revision 1.18 1993/07/06 06:06:29 deraadt ! 54: * clean up code for timeout/untimeout/wakeup prototypes. ! 55: * ! 56: * Revision 1.17 1993/06/29 19:12:44 deraadt ! 57: * uninitialized variable reported by <[email protected]> ! 58: * ! 59: * Revision 1.16 1993/06/21 09:39:52 deraadt ! 60: * I don't know what I did that was so critical, but now the floppy driver ! 61: * works on my machine (it did not before). Big voodoo. ! 62: * ! 63: * Revision 1.15 1993/06/20 08:42:05 deraadt ! 64: * if the floppy does not exist, say nothing. ! 65: * ! 66: * Revision 1.14 1993/06/18 06:19:16 cgd ! 67: * new floppy driver, merged from patchkit patch #153 ! 68: * ! 69: * Revision 1.1.1.1 1993/06/12 14:58:02 rgrimes ! 70: * Initial import, 0.1 + pk 0.2.4-B1 ! 71: * ! 72: * Revision 1.10 93/04/13 16:53:29 root ! 73: * make sure turning off a drive motor doesn't deselect another ! 74: * drive active at the time. ! 75: * Also added a pointer from the fd_data to it's fd_type. ! 76: * ! 77: * Revision 1.9 93/04/13 15:31:02 root ! 78: * make all seeks go through DOSEEK state so are sure of being done right. ! 79: * ! 80: * Revision 1.8 93/04/12 21:20:13 root ! 81: * only check if old fd is the one we are working on if there IS ! 82: * an old fd pointer. (in fdstate()) ! 83: * ! 84: * Revision 1.7 93/04/11 17:05:35 root ! 85: * cleanup timeouts etc. ! 86: * also fix bug to select teh correct drive when running > 1 drive ! 87: * at a time. ! 88: * ! 89: * Revision 1.6 93/04/05 00:48:45 root ! 90: * change a timeout and add version to banner message ! 91: * ! 92: * Revision 1.5 93/04/04 16:39:08 root ! 93: * first working version.. some floppy controllers don't seem to ! 94: * like 2 int. status inquiries in a row. ! 95: * 1.1 root 96: */ 97: 98: #include "fd.h" 1.1.1.4 root 99: #if NFDC > 0 1.1 root 100: 101: #include "param.h" 102: #include "dkbad.h" 103: #include "systm.h" 104: #include "conf.h" 105: #include "file.h" 106: #include "ioctl.h" 107: #include "buf.h" 108: #include "uio.h" 1.1.1.5 ! root 109: #include "machine/cpufunc.h" ! 110: #include "i386/isa/isa.h" 1.1 root 111: #include "i386/isa/isa_device.h" 112: #include "i386/isa/fdreg.h" 113: #include "i386/isa/icu.h" 1.1.1.3 root 114: #include "i386/isa/rtc.h" 1.1 root 115: 1.1.1.2 root 116: #define FDUNIT(s) ((s>>3)&1) 117: #define FDTYPE(s) ((s)&7) 1.1 root 118: 119: #define b_cylin b_resid 120: #define FDBLK 512 121: 122: struct fd_type { 123: int sectrac; /* sectors per track */ 124: int secsize; /* size code for sectors */ 125: int datalen; /* data len when secsize = 0 */ 126: int gap; /* gap len between sectors */ 127: int tracks; /* total num of tracks */ 128: int size; /* size of disk in sectors */ 129: int steptrac; /* steps per cylinder */ 130: int trans; /* transfer speed code */ 1.1.1.5 ! root 131: int heads; /* number of heads */ 1.1 root 132: }; 133: 1.1.1.5 ! root 134: struct fd_type fd_types[] = ! 135: { ! 136: { 18,2,0xFF,0x1B,80,2880,1,0,2 }, /* 1.44 meg HD 3.5in floppy */ ! 137: { 15,2,0xFF,0x1B,80,2400,1,0,2 }, /* 1.2 meg HD floppy */ ! 138: { 9,2,0xFF,0x23,40,720,2,1,2 }, /* 360k floppy in 1.2meg drive */ ! 139: { 9,2,0xFF,0x2A,40,720,1,1,2 }, /* 360k floppy in DD drive */ ! 140: { 9,2,0xFF,0x2A,80,1440,1,0 }, /* 720K drive. PROBABLY WRONG */ 1.1 root 141: }; 142: 1.1.1.5 ! root 143: #define DRVS_PER_CTLR 2 ! 144: /***********************************************************************\ ! 145: * Per controller structure. * ! 146: \***********************************************************************/ ! 147: struct fdc_data ! 148: { ! 149: int fdcu; /* our unit number */ ! 150: int baseport; ! 151: int dmachan; ! 152: int flags; ! 153: #define FDC_ATTACHED 0x01 ! 154: struct fd_data *fd; ! 155: int fdu; /* the active drive */ 1.1 root 156: struct buf head; /* Head of buf chain */ 157: struct buf rhead; /* Raw head of buf chain */ 1.1.1.5 ! root 158: int state; ! 159: int retry; ! 160: int status[7]; /* copy of the registers */ ! 161: }fdc_data[NFDC]; ! 162: ! 163: /***********************************************************************\ ! 164: * Per drive structure. * ! 165: * N per controller (presently 2) (DRVS_PER_CTLR) * ! 166: \***********************************************************************/ ! 167: struct fd_data { ! 168: struct fdc_data *fdc; ! 169: int fdu; /* this unit number */ ! 170: int fdsu; /* this units number on this controller */ ! 171: int type; /* Drive type (HD, DD */ ! 172: struct fd_type *ft; /* pointer to the type descriptor */ ! 173: int flags; ! 174: #define FD_OPEN 0x01 /* it's open */ ! 175: #define FD_ACTIVE 0x02 /* it's active */ ! 176: #define FD_MOTOR 0x04 /* motor should be on */ ! 177: #define FD_MOTOR_WAIT 0x08 /* motor coming up */ ! 178: int skip; ! 179: int hddrv; ! 180: int track; /* where we think the head is */ ! 181: } fd_data[NFD]; ! 182: ! 183: /***********************************************************************\ ! 184: * Throughout this file the following conventions will be used: * ! 185: * fd is a pointer to the fd_data struct for the drive in question * ! 186: * fdc is a pointer to the fdc_data struct for the controller * ! 187: * fdu is the floppy drive unit number * ! 188: * fdcu is the floppy controller unit number * ! 189: * fdsu is the floppy drive unit number on that controller. (sub-unit) * ! 190: \***********************************************************************/ ! 191: typedef int fdu_t; ! 192: typedef int fdcu_t; ! 193: typedef int fdsu_t; ! 194: typedef struct fd_data *fd_p; ! 195: typedef struct fdc_data *fdc_p; ! 196: ! 197: #define DEVIDLE 0 ! 198: #define FINDWORK 1 ! 199: #define DOSEEK 2 ! 200: #define SEEKCOMPLETE 3 ! 201: #define IOCOMPLETE 4 ! 202: #define RECALCOMPLETE 5 ! 203: #define STARTRECAL 6 ! 204: #define RESETCTLR 7 ! 205: #define SEEKWAIT 8 ! 206: #define RECALWAIT 9 ! 207: #define MOTORWAIT 10 ! 208: #define IOTIMEDOUT 11 ! 209: ! 210: #ifdef DEBUG ! 211: char *fdstates[] = ! 212: { ! 213: "DEVIDLE", ! 214: "FINDWORK", ! 215: "DOSEEK", ! 216: "SEEKCOMPLETE", ! 217: "IOCOMPLETE", ! 218: "RECALCOMPLETE", ! 219: "STARTRECAL", ! 220: "RESETCTLR", ! 221: "SEEKWAIT", ! 222: "RECALWAIT", ! 223: "MOTORWAIT", ! 224: "IOTIMEDOUT" ! 225: }; 1.1 root 226: 227: 1.1.1.5 ! root 228: int fd_debug = 1; ! 229: #define TRACE0(arg) if(fd_debug) printf(arg) ! 230: #define TRACE1(arg1,arg2) if(fd_debug) printf(arg1,arg2) ! 231: #else DEBUG ! 232: #define TRACE0(arg) ! 233: #define TRACE1(arg1,arg2) ! 234: #endif DEBUG 1.1 root 235: 1.1.1.5 ! root 236: extern int hz; 1.1 root 237: /* state needed for current transfer */ 238: 239: /****************************************************************************/ 240: /* autoconfiguration stuff */ 241: /****************************************************************************/ 1.1.1.5 ! root 242: int fdprobe(), fdattach(), fd_turnoff(); 1.1 root 243: 1.1.1.4 root 244: struct isa_driver fdcdriver = { 245: fdprobe, fdattach, "fdc", 1.1 root 246: }; 247: 1.1.1.3 root 248: /* 249: * probe for existance of controller 250: */ 1.1.1.5 ! root 251: fdprobe(dev) ! 252: struct isa_device *dev; 1.1 root 253: { 1.1.1.5 ! root 254: fdc_p fdc = &fdc_data[dev->id_unit]; ! 255: int fdcu = dev->id_unit; 1.1.1.3 root 256: 1.1.1.5 ! root 257: fdc->baseport = dev->id_iobase; ! 258: ! 259: /* Try a reset, don't change motor on */ ! 260: set_motor(fdcu,0,1); ! 261: DELAY(100); ! 262: set_motor(fdcu,0,0); 1.1.1.3 root 263: /* see if it can handle a command */ 1.1.1.5 ! root 264: if (out_fdc(fdcu,NE7CMD_SPECIFY) < 0) ! 265: { 1.1.1.3 root 266: return(0); 267: } 1.1.1.5 ! root 268: out_fdc(fdcu,0xDF); ! 269: out_fdc(fdcu,2); ! 270: ! 271: fdc->dmachan = dev->id_drq; ! 272: fdc->fdcu = dev->id_unit; ! 273: fdc->flags |= FDC_ATTACHED; ! 274: fdc->state = DEVIDLE; ! 275: ! 276: /* ! 277: * tdr: I've put this here, because with the new way for ! 278: * attach() being called it cannot go there. ! 279: */ ! 280: /* Set transfer to 500kbps */ ! 281: outb(fdc->baseport+fdctl,0); /*XXX*/ ! 282: ! 283: return (IO_FDCSIZE); 1.1 root 284: } 285: 1.1.1.3 root 286: /* 287: * wire controller into system, look for floppy units 288: */ 1.1.1.5 ! root 289: fdattach(dev) ! 290: struct isa_device *dev; 1.1.1.3 root 291: { 1.1.1.5 ! root 292: unsigned fdt=0,st0, cyl; ! 293: fdu_t fdu = dev->id_unit; ! 294: fdcu_t fdcu = dev->id_masunit; ! 295: fdc_p fdc = &fdc_data[dev->id_masunit]; ! 296: fd_p fd = &fd_data[dev->id_unit]; ! 297: int fdsu = dev->id_physid; ! 298: ! 299: if(dev->id_physid < 0 || dev->id_physid > 1) { ! 300: printf("fdc%d: cannot support physical unit %d\n", ! 301: dev->id_masunit, dev->id_physid); ! 302: return 0; ! 303: } ! 304: if(dev->id_masunit==0) ! 305: fdt = rtcin(RTC_FDISKETTE); ! 306: else ! 307: fdt = 0xff; /* cmos only knows two floppies */ ! 308: ! 309: if(dev->id_physid == 1) ! 310: fdt <<= 4; ! 311: ! 312: #ifdef notyet ! 313: /* select it */ ! 314: fd_turnon1(fdu); ! 315: spinwait(1000); /* 1 sec */ ! 316: out_fdc(fdcu,NE7CMD_RECAL); /* Recalibrate Function */ ! 317: out_fdc(fdcu,fdsu); ! 318: spinwait(1000); /* 1 sec */ ! 319: ! 320: /* anything responding */ ! 321: out_fdc(fdcu,NE7CMD_SENSEI); ! 322: st0 = in_fdc(fdcu); ! 323: cyl = in_fdc(fdcu); ! 324: if (st0 & 0xd0) ! 325: continue; ! 326: #endif ! 327: fd->track = -2; ! 328: fd->fdc = fdc; ! 329: fd->fdsu = fdsu; ! 330: ! 331: switch(fdt & 0xf0) { ! 332: case RTCFDT_NONE: ! 333: /*printf("fd%d at fdc%d targ %d: nonexistant device\n", ! 334: dev->id_unit, dev->id_masunit, dev->id_physid);*/ ! 335: return 0; ! 336: break; ! 337: case RTCFDT_12M: ! 338: printf("fd%d at fdc%d targ %d: 1.2MB 80 cyl, 2 head, 15 sec\n", ! 339: dev->id_unit, dev->id_masunit, dev->id_physid); ! 340: fd->type = 1; ! 341: break; ! 342: case RTCFDT_144M: ! 343: printf("fd%d at fdc%d targ %d: 1.44MB 80 cyl, 2 head, 18 sec\n", ! 344: dev->id_unit, dev->id_masunit, dev->id_physid); ! 345: fd->type = 0; ! 346: break; ! 347: case RTCFDT_360K: ! 348: printf("fd%d at fdc%d targ %d: 360KB 40 cyl, 2 head, 9 sec\n", ! 349: dev->id_unit, dev->id_masunit, dev->id_physid); ! 350: fd->type = 3; ! 351: break; ! 352: case RTCFDT_720K: ! 353: printf("fd%d at fdc%d targ %d: 720KB 80 cyl, 2 head, 9 sec\n", ! 354: dev->id_unit, dev->id_masunit, dev->id_physid); ! 355: fd->type = 4; ! 356: break; ! 357: default: ! 358: printf("fd%d at fdc%d targ %d: unknown device type 0x%x\n", ! 359: dev->id_unit, dev->id_masunit, dev->id_physid, ! 360: fdt & 0xf0); ! 361: return 0; ! 362: break; 1.1.1.4 root 363: } 1.1.1.5 ! root 364: ! 365: fd->ft = &fd_types[fd->type]; ! 366: fd_turnoff(fdu); ! 367: return 1; 1.1 root 368: } 369: 370: int 371: fdsize(dev) 372: dev_t dev; 373: { 1.1.1.3 root 374: return(0); 1.1 root 375: } 376: 377: /****************************************************************************/ 378: /* fdstrategy */ 379: /****************************************************************************/ 380: fdstrategy(bp) 381: register struct buf *bp; /* IO operation to perform */ 382: { 383: register struct buf *dp,*dp0,*dp1; 384: long nblocks,blknum; 1.1.1.5 ! root 385: int s; ! 386: fdcu_t fdcu; ! 387: fdu_t fdu; ! 388: fdc_p fdc; ! 389: fd_p fd; ! 390: ! 391: fdu = FDUNIT(minor(bp->b_dev)); ! 392: fd = &fd_data[fdu]; ! 393: fdc = fd->fdc; ! 394: fdcu = fdc->fdcu; 1.1.1.3 root 395: /*type = FDTYPE(minor(bp->b_dev));*/ 1.1 root 396: 1.1.1.5 ! root 397: if ((fdu >= NFD) || (bp->b_blkno < 0)) { ! 398: printf("fdstrat: fdu = %d, blkno = %d, bcount = %d\n", ! 399: fdu, bp->b_blkno, bp->b_bcount); 1.1 root 400: pg("fd:error in fdstrategy"); 401: bp->b_error = EINVAL; 402: bp->b_flags |= B_ERROR; 403: goto bad; 404: } 405: /* 406: * Set up block calculations. 407: */ 408: blknum = (unsigned long) bp->b_blkno * DEV_BSIZE/FDBLK; 1.1.1.5 ! root 409: nblocks = fd->ft->size; 1.1 root 410: if (blknum + (bp->b_bcount / FDBLK) > nblocks) { 411: if (blknum == nblocks) { 412: bp->b_resid = bp->b_bcount; 413: } else { 414: bp->b_error = ENOSPC; 415: bp->b_flags |= B_ERROR; 416: } 417: goto bad; 418: } 1.1.1.5 ! root 419: bp->b_cylin = blknum / (fd->ft->sectrac * fd->ft->heads); ! 420: dp = &(fdc->head); 1.1 root 421: s = splbio(); 422: disksort(dp, bp); 1.1.1.5 ! root 423: untimeout((timeout_t)fd_turnoff, (caddr_t)fdu); /* a good idea */ ! 424: fdstart(fdcu); 1.1 root 425: splx(s); 426: return; 427: 428: bad: 429: biodone(bp); 430: } 431: 432: /****************************************************************************/ 433: /* motor control stuff */ 1.1.1.5 ! root 434: /* remember to not deselect the drive we're working on */ 1.1 root 435: /****************************************************************************/ 1.1.1.5 ! root 436: set_motor(fdcu_t fdcu, fdu_t fdu, int reset) 1.1 root 437: { 438: int m0,m1; 1.1.1.5 ! root 439: int selunit; ! 440: fd_p fd; ! 441: if(fd = fdc_data[fdcu].fd)/* yes an assign! */ ! 442: { ! 443: selunit = fd->fdsu; ! 444: } ! 445: else ! 446: { ! 447: selunit = 0; ! 448: } ! 449: m0 = fd_data[fdcu * DRVS_PER_CTLR + 0].flags & FD_MOTOR; ! 450: m1 = fd_data[fdcu * DRVS_PER_CTLR + 1].flags & FD_MOTOR; ! 451: outb(fdc_data[fdcu].baseport+fdout, ! 452: selunit 1.1.1.3 root 453: | (reset ? 0 : (FDO_FRST|FDO_FDMAEN)) 454: | (m0 ? FDO_MOEN0 : 0) 455: | (m1 ? FDO_MOEN1 : 0)); 1.1.1.5 ! root 456: TRACE1("[0x%x->fdout]",( ! 457: selunit ! 458: | (reset ? 0 : (FDO_FRST|FDO_FDMAEN)) ! 459: | (m0 ? FDO_MOEN0 : 0) ! 460: | (m1 ? FDO_MOEN1 : 0))); ! 461: } ! 462: ! 463: fd_turnoff(fdu_t fdu) ! 464: { ! 465: fd_p fd = fd_data + fdu; ! 466: fd->flags &= ~FD_MOTOR; ! 467: set_motor(fd->fdc->fdcu,fd->fdsu,0); ! 468: } ! 469: ! 470: fd_motor_on(fdu_t fdu) ! 471: { ! 472: fd_p fd = fd_data + fdu; ! 473: fd->flags &= ~FD_MOTOR_WAIT; ! 474: if((fd->fdc->fd == fd) && (fd->fdc->state == MOTORWAIT)) ! 475: { ! 476: fd_pseudointr(fd->fdc->fdcu); ! 477: } 1.1 root 478: } 479: 1.1.1.5 ! root 480: fd_turnon(fdu_t fdu) 1.1 root 481: { 1.1.1.5 ! root 482: fd_p fd = fd_data + fdu; ! 483: if(!(fd->flags & FD_MOTOR)) ! 484: { ! 485: fd_turnon1(fdu); ! 486: fd->flags |= FD_MOTOR_WAIT; ! 487: timeout((timeout_t)fd_motor_on, (caddr_t)fdu, hz); /* in 1 sec its ok */ ! 488: } 1.1 root 489: } 490: 1.1.1.5 ! root 491: fd_turnon1(fdu_t fdu) 1.1 root 492: { 1.1.1.5 ! root 493: fd_p fd = fd_data + fdu; ! 494: fd->flags |= FD_MOTOR; ! 495: set_motor(fd->fdc->fdcu,fd->fdsu,0); 1.1 root 496: } 497: 498: /****************************************************************************/ 499: /* fdc in/out */ 500: /****************************************************************************/ 501: int 1.1.1.5 ! root 502: in_fdc(fdcu_t fdcu) 1.1 root 503: { 1.1.1.5 ! root 504: int baseport = fdc_data[fdcu].baseport; 1.1.1.3 root 505: int i, j = 100000; 1.1.1.5 ! root 506: while ((i = inb(baseport+fdsts) & (NE7_DIO|NE7_RQM)) ! 507: != (NE7_DIO|NE7_RQM) && j-- > 0) 1.1 root 508: if (i == NE7_RQM) return -1; 1.1.1.3 root 509: if (j <= 0) 510: return(-1); 1.1.1.5 ! root 511: #ifdef DEBUG ! 512: i = inb(baseport+fddata); ! 513: TRACE1("[fddata->0x%x]",(unsigned char)i); ! 514: return(i); ! 515: #else ! 516: return inb(baseport+fddata); ! 517: #endif 1.1 root 518: } 519: 1.1.1.5 ! root 520: out_fdc(fdcu_t fdcu,int x) 1.1 root 521: { 1.1.1.5 ! root 522: int baseport = fdc_data[fdcu].baseport; 1.1.1.3 root 523: int i = 100000; 1.1 root 524: 1.1.1.5 ! root 525: while ((inb(baseport+fdsts) & NE7_DIO) && i-- > 0); ! 526: while ((inb(baseport+fdsts) & NE7_RQM) == 0 && i-- > 0); 1.1.1.3 root 527: if (i <= 0) return (-1); 1.1.1.5 ! root 528: outb(baseport+fddata,x); ! 529: TRACE1("[0x%x->fddata]",x); 1.1.1.3 root 530: return (0); 1.1 root 531: } 532: 1.1.1.3 root 533: static fdopenf; 1.1 root 534: /****************************************************************************/ 535: /* fdopen/fdclose */ 536: /****************************************************************************/ 537: Fdopen(dev, flags) 538: dev_t dev; 539: int flags; 540: { 1.1.1.5 ! root 541: fdu_t fdu = FDUNIT(minor(dev)); ! 542: /*int type = FDTYPE(minor(dev));*/ 1.1 root 543: int s; 544: 545: /* check bounds */ 1.1.1.5 ! root 546: if (fdu >= NFD) return(ENXIO); ! 547: /*if (type >= sizeof(fd_types)/sizeof(fd_types[0]) ) return(ENXIO);*/ ! 548: fd_data[fdu].flags |= FD_OPEN; 1.1 root 549: 550: return 0; 551: } 552: 553: fdclose(dev, flags) 554: dev_t dev; 555: { 1.1.1.5 ! root 556: fdu_t fdu = FDUNIT(minor(dev)); ! 557: fd_data[fdu].flags &= ~FD_OPEN; 1.1.1.2 root 558: return(0); 1.1 root 559: } 560: 561: 1.1.1.5 ! root 562: /***************************************************************\ ! 563: * fdstart * ! 564: * We have just queued something.. if the controller is not busy * ! 565: * then simulate the case where it has just finished a command * ! 566: * So that it (the interrupt routine) looks on the queue for more* ! 567: * work to do and picks up what we just added. * ! 568: * If the controller is already busy, we need do nothing, as it * ! 569: * will pick up our work when the present work completes * ! 570: \***************************************************************/ ! 571: fdstart(fdcu_t fdcu) 1.1 root 572: { 573: register struct buf *dp,*bp; 574: int s; 1.1.1.5 ! root 575: fdu_t fdu; 1.1 root 576: 577: s = splbio(); 1.1.1.5 ! root 578: if(fdc_data[fdcu].state == DEVIDLE) ! 579: { ! 580: fdintr(fdcu); 1.1 root 581: } 582: splx(s); 583: } 584: 1.1.1.5 ! root 585: fd_timeout(fdcu_t fdcu) 1.1 root 586: { 1.1.1.5 ! root 587: fdu_t fdu = fdc_data[fdcu].fdu; 1.1.1.3 root 588: int st0, st3, cyl; 1.1 root 589: struct buf *dp,*bp; 590: 1.1.1.5 ! root 591: dp = &fdc_data[fdcu].head; 1.1 root 592: bp = dp->b_actf; 593: 1.1.1.5 ! root 594: out_fdc(fdcu,NE7CMD_SENSED); ! 595: out_fdc(fdcu,fd_data[fdu].hddrv); ! 596: st3 = in_fdc(fdcu); ! 597: ! 598: out_fdc(fdcu,NE7CMD_SENSEI); ! 599: st0 = in_fdc(fdcu); ! 600: cyl = in_fdc(fdcu); ! 601: printf("fd%d: Operation timeout ST0 %b cyl %d ST3 %b\n", ! 602: fdu, ! 603: st0, ! 604: NE7_ST0BITS, ! 605: cyl, ! 606: st3, ! 607: NE7_ST3BITS); ! 608: ! 609: if (bp) ! 610: { ! 611: retrier(fdcu); ! 612: fdc_data[fdcu].status[0] = 0xc0; ! 613: fdc_data[fdcu].state = IOTIMEDOUT; ! 614: if( fdc_data[fdcu].retry < 6) ! 615: fdc_data[fdcu].retry = 6; ! 616: } ! 617: else ! 618: { ! 619: fdc_data[fdcu].fd = (fd_p) 0; ! 620: fdc_data[fdcu].fdu = -1; ! 621: fdc_data[fdcu].state = DEVIDLE; 1.1.1.3 root 622: } 1.1.1.5 ! root 623: fd_pseudointr(fdcu); 1.1 root 624: } 625: 1.1.1.5 ! root 626: /* just ensure it has the right spl */ ! 627: fd_pseudointr(fdcu_t fdcu) ! 628: { ! 629: int s; ! 630: s = splbio(); ! 631: fdintr(fdcu); ! 632: splx(s); ! 633: } ! 634: ! 635: /***********************************************************************\ ! 636: * fdintr * ! 637: * keep calling the state machine until it returns a 0 * ! 638: * ALWAYS called at SPLBIO * ! 639: \***********************************************************************/ ! 640: fdintr(fdcu_t fdcu) ! 641: { ! 642: fdc_p fdc = fdc_data + fdcu; ! 643: while(fdstate(fdcu, fdc)); ! 644: } ! 645: ! 646: /***********************************************************************\ ! 647: * The controller state machine. * ! 648: * if it returns a non zero value, it should be called again immediatly * ! 649: \***********************************************************************/ ! 650: int fdstate(fdcu_t fdcu, fdc_p fdc) 1.1 root 651: { 1.1.1.3 root 652: int read,head,trac,sec,i,s,sectrac,cyl,st0; 1.1 root 653: unsigned long blknum; 1.1.1.5 ! root 654: fdu_t fdu = fdc->fdu; ! 655: fd_p fd; ! 656: register struct buf *dp,*bp; 1.1 root 657: 1.1.1.5 ! root 658: dp = &(fdc->head); 1.1 root 659: bp = dp->b_actf; 1.1.1.5 ! root 660: if(!bp) ! 661: { ! 662: /***********************************************\ ! 663: * nothing left for this controller to do * ! 664: * Force into the IDLE state, * ! 665: \***********************************************/ ! 666: fdc->state = DEVIDLE; ! 667: if(fdc->fd) ! 668: { ! 669: printf("unexpected valid fd pointer (fdu = %d)\n" ! 670: ,fdc->fdu); ! 671: fdc->fd = (fd_p) 0; ! 672: fdc->fdu = -1; ! 673: } ! 674: TRACE1("[fdc%d IDLE]",fdcu); ! 675: return(0); ! 676: } ! 677: fdu = FDUNIT(minor(bp->b_dev)); ! 678: fd = fd_data + fdu; ! 679: if (fdc->fd && (fd != fdc->fd)) ! 680: { ! 681: printf("confused fd pointers\n"); ! 682: } 1.1 root 683: read = bp->b_flags & B_READ; 1.1.1.5 ! root 684: TRACE1("fd%d",fdu); ! 685: TRACE1("[%s]",fdstates[fdc->state]); ! 686: TRACE1("(0x%x)",fd->flags); ! 687: untimeout((timeout_t)fd_turnoff, (caddr_t)fdu); ! 688: timeout((timeout_t)fd_turnoff, (caddr_t)fdu, 4 * hz); ! 689: switch (fdc->state) ! 690: { ! 691: case DEVIDLE: ! 692: case FINDWORK: /* we have found new work */ ! 693: fdc->retry = 0; ! 694: fd->skip = 0; ! 695: fdc->fd = fd; ! 696: fdc->fdu = fdu; ! 697: /*******************************************************\ ! 698: * If the next drive has a motor startup pending, then * ! 699: * it will start up in it's own good time * ! 700: \*******************************************************/ ! 701: if(fd->flags & FD_MOTOR_WAIT) ! 702: { ! 703: fdc->state = MOTORWAIT; ! 704: return(0); /* come back later */ ! 705: } ! 706: /*******************************************************\ ! 707: * Maybe if it's not starting, it SHOULD be starting * ! 708: \*******************************************************/ ! 709: if (!(fd->flags & FD_MOTOR)) ! 710: { ! 711: fdc->state = MOTORWAIT; ! 712: fd_turnon(fdu); ! 713: return(0); ! 714: } ! 715: else /* at least make sure we are selected */ ! 716: { ! 717: set_motor(fdcu,fd->fdsu,0); ! 718: } ! 719: fdc->state = DOSEEK; ! 720: break; ! 721: case DOSEEK: ! 722: if (bp->b_cylin == fd->track) ! 723: { ! 724: fdc->state = SEEKCOMPLETE; ! 725: break; ! 726: } ! 727: out_fdc(fdcu,NE7CMD_SEEK); /* Seek function */ ! 728: out_fdc(fdcu,fd->fdsu); /* Drive number */ ! 729: out_fdc(fdcu,bp->b_cylin * fd->ft->steptrac); ! 730: fd->track = -2; ! 731: fdc->state = SEEKWAIT; ! 732: return(0); /* will return later */ ! 733: case SEEKWAIT: ! 734: /* allow heads to settle */ ! 735: timeout((timeout_t)fd_pseudointr, (caddr_t)fdcu, hz/50); ! 736: fdc->state = SEEKCOMPLETE; ! 737: return(0); /* will return later */ ! 738: break; ! 739: ! 740: case SEEKCOMPLETE : /* SEEK DONE, START DMA */ 1.1 root 741: /* Make sure seek really happened*/ 1.1.1.5 ! root 742: if(fd->track == -2) ! 743: { ! 744: int descyl = bp->b_cylin * fd->ft->steptrac; ! 745: out_fdc(fdcu,NE7CMD_SENSEI); ! 746: i = in_fdc(fdcu); ! 747: cyl = in_fdc(fdcu); ! 748: if (cyl != descyl) ! 749: { ! 750: printf("fd%d: Seek to cyl %d failed; am at cyl %d (ST0 = 0x%x)\n", fdu, ! 751: descyl, cyl, i, NE7_ST0BITS); ! 752: return(retrier(fdcu)); 1.1 root 753: } 754: } 755: 1.1.1.5 ! root 756: fd->track = bp->b_cylin; ! 757: isa_dmastart(bp->b_flags, bp->b_un.b_addr+fd->skip, ! 758: FDBLK, fdc->dmachan); 1.1 root 759: blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK 1.1.1.5 ! root 760: + fd->skip/FDBLK; ! 761: sectrac = fd->ft->sectrac; ! 762: sec = blknum % (sectrac * fd->ft->heads); 1.1 root 763: head = sec / sectrac; 764: sec = sec % sectrac + 1; 1.1.1.5 ! root 765: /*XXX*/ fd->hddrv = ((head&1)<<2)+fdu; 1.1 root 766: 1.1.1.5 ! root 767: if (read) ! 768: { ! 769: out_fdc(fdcu,NE7CMD_READ); /* READ */ ! 770: } ! 771: else ! 772: { ! 773: out_fdc(fdcu,NE7CMD_WRITE); /* WRITE */ ! 774: } ! 775: out_fdc(fdcu,head << 2 | fdu); /* head & unit */ ! 776: out_fdc(fdcu,fd->track); /* track */ ! 777: out_fdc(fdcu,head); ! 778: out_fdc(fdcu,sec); /* sector XXX +1? */ ! 779: out_fdc(fdcu,fd->ft->secsize); /* sector size */ ! 780: out_fdc(fdcu,sectrac); /* sectors/track */ ! 781: out_fdc(fdcu,fd->ft->gap); /* gap size */ ! 782: out_fdc(fdcu,fd->ft->datalen); /* data length */ ! 783: fdc->state = IOCOMPLETE; ! 784: timeout((timeout_t)fd_timeout, (caddr_t)fdcu, 2 * hz); ! 785: return(0); /* will return later */ ! 786: case IOCOMPLETE: /* IO DONE, post-analyze */ ! 787: untimeout((timeout_t)fd_timeout, (caddr_t)fdcu); ! 788: for(i=0;i<7;i++) ! 789: { ! 790: fdc->status[i] = in_fdc(fdcu); ! 791: } ! 792: case IOTIMEDOUT: /*XXX*/ ! 793: isa_dmadone(bp->b_flags, bp->b_un.b_addr+fd->skip, ! 794: FDBLK, fdc->dmachan); ! 795: if (fdc->status[0]&0xF8) ! 796: { ! 797: return(retrier(fdcu)); 1.1 root 798: } 799: /* All OK */ 1.1.1.5 ! root 800: fd->skip += FDBLK; ! 801: if (fd->skip < bp->b_bcount) ! 802: { ! 803: /* set up next transfer */ ! 804: blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK ! 805: + fd->skip/FDBLK; ! 806: bp->b_cylin = (blknum / (fd->ft->sectrac * fd->ft->heads)); ! 807: fdc->state = DOSEEK; ! 808: } ! 809: else ! 810: { 1.1 root 811: /* ALL DONE */ 1.1.1.5 ! root 812: fd->skip = 0; 1.1 root 813: bp->b_resid = 0; 814: dp->b_actf = bp->av_forw; 815: biodone(bp); 1.1.1.5 ! root 816: fdc->fd = (fd_p) 0; ! 817: fdc->fdu = -1; ! 818: fdc->state = FINDWORK; 1.1 root 819: } 1.1.1.5 ! root 820: return(1); ! 821: case RESETCTLR: 1.1 root 822: /* Try a reset, keep motor on */ 1.1.1.5 ! root 823: set_motor(fdcu,fd->fdsu,1); 1.1.1.3 root 824: DELAY(100); 1.1.1.5 ! root 825: set_motor(fdcu,fd->fdsu,0); ! 826: outb(fdc->baseport+fdctl,fd->ft->trans); ! 827: TRACE1("[0x%x->fdctl]",fd->ft->trans); ! 828: fdc->retry++; ! 829: fdc->state = STARTRECAL; 1.1 root 830: break; 1.1.1.5 ! root 831: case STARTRECAL: ! 832: out_fdc(fdcu,NE7CMD_SPECIFY); /* specify command */ ! 833: out_fdc(fdcu,0xDF); ! 834: out_fdc(fdcu,2); ! 835: out_fdc(fdcu,NE7CMD_RECAL); /* Recalibrate Function */ ! 836: out_fdc(fdcu,fdu); ! 837: fdc->state = RECALWAIT; ! 838: return(0); /* will return later */ ! 839: case RECALWAIT: 1.1.1.3 root 840: /* allow heads to settle */ 1.1.1.5 ! root 841: timeout((timeout_t)fd_pseudointr, (caddr_t)fdcu, hz/30); ! 842: fdc->state = RECALCOMPLETE; ! 843: return(0); /* will return later */ ! 844: case RECALCOMPLETE: ! 845: out_fdc(fdcu,NE7CMD_SENSEI); ! 846: st0 = in_fdc(fdcu); ! 847: cyl = in_fdc(fdcu); ! 848: if (cyl != 0) ! 849: { ! 850: printf("fd%d: recal failed ST0 %b cyl %d\n", fdu, ! 851: st0, NE7_ST0BITS, cyl); ! 852: return(retrier(fdcu)); ! 853: } ! 854: fd->track = 0; ! 855: /* Seek (probably) necessary */ ! 856: fdc->state = DOSEEK; ! 857: return(1); /* will return immediatly */ ! 858: case MOTORWAIT: ! 859: if(fd->flags & FD_MOTOR_WAIT) ! 860: { ! 861: return(0); /* time's not up yet */ ! 862: } ! 863: fdc->state = DOSEEK; ! 864: return(1); /* will return immediatly */ 1.1 root 865: default: 866: printf("Unexpected FD int->"); 1.1.1.5 ! root 867: out_fdc(fdcu,NE7CMD_SENSEI); ! 868: st0 = in_fdc(fdcu); ! 869: cyl = in_fdc(fdcu); 1.1 root 870: printf("ST0 = %lx, PCN = %lx\n",i,sec); 1.1.1.5 ! root 871: out_fdc(fdcu,0x4A); ! 872: out_fdc(fdcu,fd->fdsu); 1.1 root 873: for(i=0;i<7;i++) { 1.1.1.5 ! root 874: fdc->status[i] = in_fdc(fdcu); 1.1 root 875: } 876: printf("intr status :%lx %lx %lx %lx %lx %lx %lx ", 1.1.1.5 ! root 877: fdc->status[0], ! 878: fdc->status[1], ! 879: fdc->status[2], ! 880: fdc->status[3], ! 881: fdc->status[4], ! 882: fdc->status[5], ! 883: fdc->status[6] ); ! 884: return(0); 1.1 root 885: } 1.1.1.5 ! root 886: return(1); /* Come back immediatly to new state */ ! 887: } ! 888: ! 889: retrier(fdcu_t fdcu) ! 890: { ! 891: fdc_p fdc = fdc_data + fdcu; ! 892: register struct buf *dp,*bp; ! 893: ! 894: dp = &(fdc->head); ! 895: bp = dp->b_actf; ! 896: ! 897: switch(fdc->retry) ! 898: { ! 899: case 0: case 1: case 2: ! 900: fdc->state = SEEKCOMPLETE; ! 901: break; ! 902: case 3: case 4: case 5: ! 903: fdc->state = STARTRECAL; ! 904: break; 1.1.1.3 root 905: case 6: 1.1.1.5 ! root 906: fdc->state = RESETCTLR; ! 907: break; 1.1.1.3 root 908: case 7: 1.1 root 909: break; 910: default: 1.1.1.5 ! root 911: { ! 912: printf("fd%d: hard error (ST0 %b ", ! 913: fdc->fdu, fdc->status[0], NE7_ST0BITS); ! 914: printf(" ST1 %b ", fdc->status[1], NE7_ST1BITS); ! 915: printf(" ST2 %b ", fdc->status[2], NE7_ST2BITS); ! 916: printf(" ST3 %b ", fdc->status[3], NE7_ST3BITS); ! 917: printf("cyl %d hd %d sec %d)\n", ! 918: fdc->status[4], fdc->status[5], fdc->status[6]); ! 919: } ! 920: bp->b_flags |= B_ERROR; ! 921: bp->b_error = EIO; ! 922: bp->b_resid = bp->b_bcount - fdc->fd->skip; ! 923: dp->b_actf = bp->av_forw; ! 924: fdc->fd->skip = 0; ! 925: biodone(bp); ! 926: fdc->state = FINDWORK; ! 927: fdc->fd = (fd_p) 0; ! 928: fdc->fdu = -1; ! 929: return(1); 1.1 root 930: } 1.1.1.5 ! root 931: fdc->retry++; ! 932: return(1); 1.1 root 933: } 1.1.1.5 ! root 934: 1.1 root 935: #endif 1.1.1.5 ! root 936:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.