|
|
1.1 ! root 1: /* ! 2: * This file is in2000.c, written and ! 3: * Copyright (C) 1993 Brad McLean ! 4: * Last edit 1/19/95 TZ ! 5: * Disclaimer: ! 6: * Note: This is ugly. I know it, I wrote it, but my whole ! 7: * focus was on getting the damn thing up and out quickly. ! 8: * Future stuff that would be nice: Command chaining, and ! 9: * a local queue of commands would speed stuff up considerably. ! 10: * Disconnection needs some supporting code. All of this ! 11: * is beyond the scope of what I wanted to address, but if you ! 12: * have time and patience, more power to you. ! 13: * Also, there are some constants scattered throughout that ! 14: * should have defines, and I should have built functions to ! 15: * address the registers on the WD chip. ! 16: * Oh well, I'm out of time for this project. ! 17: * The one good thing to be said is that you can use the card. ! 18: */ ! 19: ! 20: /* ! 21: * This module was updated by Shaun Savage first on 5-13-93 ! 22: * At that time the write was fixed, irq detection, and some ! 23: * timing stuff. since that time other problems were fixed. ! 24: * On 7-20-93 this file was updated for patch level 11 ! 25: * There are still problems with it but it work on 95% of ! 26: * the machines. There are still problems with it working with ! 27: * IDE drives, as swap drive and HD that support reselection. ! 28: * But for most people it will work. ! 29: */ ! 30: /* More changes by Bill Earnest, [email protected] ! 31: * through 4/07/94. Includes rewrites of FIFO routines, ! 32: * length-limited commands to make swap partitions work. ! 33: * Merged the changes released by Larry Doolittle, based on input ! 34: * from Jon Luckey, Roger Sunshine, John Shifflett. The FAST_FIFO ! 35: * doesn't work for me. Scatter-gather code from Eric. The change to ! 36: * an IF stmt. in the interrupt routine finally made it stable. ! 37: * Limiting swap request size patch to ll_rw_blk.c not needed now. ! 38: * Please ignore the clutter of debug stmts., pretty can come later. ! 39: */ ! 40: /* Merged code from Matt Postiff improving the auto-sense validation ! 41: * for all I/O addresses. Some reports of problems still come in, but ! 42: * have been unable to reproduce or localize the cause. Some are from ! 43: * LUN > 0 problems, but that is not host specific. Now 6/6/94. ! 44: */ ! 45: /* Changes for 1.1.28 kernel made 7/19/94, code not affected. (WDE) ! 46: */ ! 47: /* Changes for 1.1.43+ kernels made 8/25/94, code added to check for ! 48: * new BIOS version, derived by [email protected]. (WDE) ! 49: * ! 50: * 1/7/95 Fix from Peter Lu ([email protected]) for datalen vs. dataptr ! 51: * logic, much more stable under load. ! 52: * ! 53: * 1/19/95 ([email protected]) Added module and biosparam support for ! 54: * larger SCSI hard drives (untested). ! 55: */ ! 56: ! 57: #ifdef MODULE ! 58: #include <linux/module.h> ! 59: #endif ! 60: ! 61: #include <linux/kernel.h> ! 62: #include <linux/head.h> ! 63: #include <linux/types.h> ! 64: #include <linux/string.h> ! 65: #include <linux/sched.h> ! 66: #include <linux/proc_fs.h> ! 67: #include <asm/dma.h> ! 68: #include <asm/system.h> ! 69: #include <asm/io.h> ! 70: #include <linux/blk.h> ! 71: #include "scsi.h" ! 72: #include "hosts.h" ! 73: #include "sd.h" ! 74: ! 75: #include "in2000.h" ! 76: #include<linux/stat.h> ! 77: ! 78: struct proc_dir_entry proc_scsi_in2000 = { ! 79: PROC_SCSI_IN2000, 6, "in2000", ! 80: S_IFDIR | S_IRUGO | S_IXUGO, 2 ! 81: }; ! 82: ! 83: /*#define FAST_FIFO_IO*/ ! 84: ! 85: /*#define DEBUG*/ ! 86: #ifdef DEBUG ! 87: #define DEB(x) x ! 88: #else ! 89: #define DEB(x) ! 90: #endif ! 91: ! 92: /* These functions are based on include/asm/io.h */ ! 93: #ifndef inw ! 94: inline static unsigned short inw( unsigned short port ) ! 95: { ! 96: unsigned short _v; ! 97: ! 98: __asm__ volatile ("inw %1,%0" ! 99: :"=a" (_v):"d" ((unsigned short) port)); ! 100: return _v; ! 101: } ! 102: #endif ! 103: ! 104: #ifndef outw ! 105: inline static void outw( unsigned short value, unsigned short port ) ! 106: { ! 107: __asm__ volatile ("outw %0,%1" ! 108: : /* no outputs */ ! 109: :"a" ((unsigned short) value), ! 110: "d" ((unsigned short) port)); ! 111: } ! 112: #endif ! 113: ! 114: /* These functions are lifted from drivers/block/hd.c */ ! 115: ! 116: #define port_read(port,buf,nr) \ ! 117: __asm__("cld;rep;insw": :"d" (port),"D" (buf),"c" (nr):"cx","di") ! 118: ! 119: #define port_write(port,buf,nr) \ ! 120: __asm__("cld;rep;outsw": :"d" (port),"S" (buf),"c" (nr):"cx","si") ! 121: ! 122: static unsigned int base; ! 123: static unsigned int ficmsk; ! 124: static unsigned char irq_level; ! 125: static int in2000_datalen; ! 126: static unsigned int in2000_nsegment; ! 127: static unsigned int in2000_current_segment; ! 128: static unsigned short *in2000_dataptr; ! 129: static char in2000_datawrite; ! 130: static struct scatterlist * in2000_scatter; ! 131: static Scsi_Cmnd *in2000_SCptr = 0; ! 132: ! 133: static void (*in2000_done)(Scsi_Cmnd *); ! 134: ! 135: static int in2000_test_port(int index) ! 136: { ! 137: static const int *bios_tab[] = { ! 138: (int *) 0xc8000, (int *) 0xd0000, (int *) 0xd8000 }; ! 139: int i; ! 140: char tmp; ! 141: ! 142: tmp = inb(INFLED); ! 143: /* First, see if the DIP switch values are valid */ ! 144: /* The test of B7 may fail on some early boards, mine works. */ ! 145: if ( ((~tmp & 0x3) != index ) || (tmp & 0x80) || !(tmp & 0x4) ) ! 146: return 0; ! 147: printk("IN-2000 probe got dip setting of %02X\n", tmp); ! 148: tmp = inb(INVERS); ! 149: /* Add some extra sanity checks here */ ! 150: for(i=0; i < 3; i++) ! 151: if(*(bios_tab[i]+0x04) == 0x41564f4e || ! 152: *(bios_tab[i]+0xc) == 0x61776c41) { ! 153: printk("IN-2000 probe found hdw. vers. %02x, BIOS at %06x\n", ! 154: tmp, (unsigned int)bios_tab[i]); ! 155: return 1; ! 156: } ! 157: printk("in2000 BIOS not found.\n"); ! 158: return 0; ! 159: } ! 160: ! 161: ! 162: /* ! 163: * retrieve the current transaction counter from the WD ! 164: */ ! 165: ! 166: static unsigned in2000_txcnt(void) ! 167: { ! 168: unsigned total=0; ! 169: ! 170: if(inb(INSTAT) & 0x20) return 0xffffff; /* not readable now */ ! 171: outb(TXCNTH,INSTAT); /* then autoincrement */ ! 172: total = (inb(INDATA) & 0xff) << 16; ! 173: outb(TXCNTM,INSTAT); ! 174: total += (inb(INDATA) & 0xff) << 8; ! 175: outb(TXCNTL,INSTAT); ! 176: total += (inb(INDATA) & 0xff); ! 177: return total; ! 178: } ! 179: ! 180: /* ! 181: * Note: the FIFO is screwy, and has a counter granularity of 16 bytes, so ! 182: * we have to reconcile the FIFO counter, the transaction byte count from the ! 183: * WD chip, and of course, our desired transaction size. It may look strange, ! 184: * and could probably use improvement, but it works, for now. ! 185: */ ! 186: ! 187: static void in2000_fifo_out(void) /* uses FIFOCNTR */ ! 188: { ! 189: unsigned count, infcnt, txcnt; ! 190: ! 191: infcnt = inb(INFCNT)& 0xfe; /* FIFO counter */ ! 192: do { ! 193: txcnt = in2000_txcnt(); ! 194: /*DEB(printk("FIw:%d %02x %d\n", in2000_datalen, infcnt, txcnt));*/ ! 195: count = (infcnt << 3) - 32; /* don't fill completely */ ! 196: if ( count > in2000_datalen ) ! 197: count = in2000_datalen; /* limit to actual data on hand */ ! 198: count >>= 1; /* Words, not bytes */ ! 199: #ifdef FAST_FIFO_IO ! 200: if ( count ) { ! 201: port_write(INFIFO, in2000_dataptr, count); ! 202: in2000_datalen -= (count<<1); ! 203: } ! 204: #else ! 205: while ( count-- ) ! 206: { ! 207: outw(*in2000_dataptr++, INFIFO); ! 208: in2000_datalen -= 2; ! 209: } ! 210: #endif ! 211: } while((in2000_datalen > 0) && ((infcnt = (inb(INFCNT)) & 0xfe) >= 0x20) ); ! 212: /* If scatter-gather, go on to next segment */ ! 213: if( !in2000_datalen && ++in2000_current_segment < in2000_nsegment) ! 214: { ! 215: in2000_scatter++; ! 216: in2000_datalen = in2000_scatter->length; ! 217: in2000_dataptr = (unsigned short*)in2000_scatter->address; ! 218: } ! 219: if ( in2000_datalen <= 0 ) ! 220: { ! 221: ficmsk = 0; ! 222: count = 32; /* Always says to use this much flush */ ! 223: while ( count-- ) ! 224: outw(0, INFIFO); ! 225: outb(2, ININTR); /* Mask FIFO Interrupts when done */ ! 226: } ! 227: } ! 228: ! 229: static void in2000_fifo_in(void) /* uses FIFOCNTR */ ! 230: { ! 231: unsigned fic, count, count2; ! 232: ! 233: count = inb(INFCNT) & 0xe1; ! 234: do{ ! 235: count2 = count; ! 236: count = (fic = inb(INFCNT)) & 0xe1; ! 237: } while ( count != count2 ); ! 238: DEB(printk("FIir:%d %02x %08x\n", in2000_datalen,fic,(unsigned int )in2000_dataptr)); ! 239: do { ! 240: count2 = in2000_txcnt(); /* bytes yet to come over SCSI bus */ ! 241: DEB(printk("FIr:%d %02x %08x %08x\n", in2000_datalen,fic,count2,(unsigned int)in2000_dataptr)); ! 242: if(count2 > 65536) count2 = 0; ! 243: if(fic > 128) count = 1024; ! 244: else if(fic > 64) count = 512; ! 245: else if (fic > 32) count = 256; ! 246: else if ( count2 < in2000_datalen ) /* if drive has < what we want */ ! 247: count = in2000_datalen - count2; /* FIFO has the rest */ ! 248: if ( count > in2000_datalen ) /* count2 is lesser of FIFO & rqst */ ! 249: count2 = in2000_datalen >> 1; /* converted to word count */ ! 250: else ! 251: count2 = count >> 1; ! 252: count >>= 1; /* also to words */ ! 253: count -= count2; /* extra left over in FIFO */ ! 254: #ifdef FAST_FIFO_IO ! 255: if ( count2 ) { ! 256: port_read(INFIFO, in2000_dataptr, count2); ! 257: in2000_datalen -= (count2<<1); ! 258: } ! 259: #else ! 260: while ( count2-- ) ! 261: { ! 262: *in2000_dataptr++ = inw(INFIFO); ! 263: in2000_datalen -=2; ! 264: } ! 265: #endif ! 266: } while((in2000_datalen > 0) && (fic = inb(INFCNT)) ); ! 267: DEB(printk("FIer:%d %02x %08x\n", in2000_datalen,fic,(unsigned int )in2000_dataptr)); ! 268: /* while ( count-- ) ! 269: inw(INFIFO);*/ /* Throw away some extra stuff */ ! 270: if( !in2000_datalen && ++in2000_current_segment < in2000_nsegment) ! 271: { ! 272: in2000_scatter++; ! 273: in2000_datalen = in2000_scatter->length; ! 274: in2000_dataptr = (unsigned short*)in2000_scatter->address; ! 275: } ! 276: if ( ! in2000_datalen ){ ! 277: outb(2, ININTR); /* Mask FIFO Interrupts when done */ ! 278: ficmsk = 0;} ! 279: } ! 280: ! 281: static void in2000_intr_handle(int irq, struct pt_regs *regs) ! 282: { ! 283: int result=0; ! 284: unsigned int count,auxstatus,scsistatus,cmdphase,scsibyte; ! 285: int action=0; ! 286: Scsi_Cmnd *SCptr; ! 287: ! 288: DEB(printk("INT:%d %02x %08x\n", in2000_datalen, inb(INFCNT),(unsigned int)in2000_dataptr)); ! 289: ! 290: if (( (ficmsk & (count = inb(INFCNT))) == 0xfe ) || ! 291: ( (inb(INSTAT) & 0x8c) == 0x80)) ! 292: { /* FIFO interrupt or WD interrupt */ ! 293: auxstatus = inb(INSTAT); /* need to save now */ ! 294: outb(SCSIST,INSTAT); ! 295: scsistatus = inb(INDATA); /* This clears the WD intrpt bit */ ! 296: outb(TARGETU,INSTAT); /* then autoincrement */ ! 297: scsibyte = inb(INDATA); /* Get the scsi status byte */ ! 298: outb(CMDPHAS,INSTAT); ! 299: cmdphase = inb(INDATA); ! 300: DEB(printk("(int2000:%02x %02x %02x %02x %02x)\n",count,auxstatus, ! 301: scsistatus,cmdphase,scsibyte)); ! 302: ! 303: /* Why do we assume that we need to send more data here??? ERY */ ! 304: if ( in2000_datalen ) /* data xfer pending */ ! 305: { ! 306: if ( in2000_dataptr == NULL ) ! 307: printk("int2000: dataptr=NULL datalen=%d\n", ! 308: in2000_datalen); ! 309: else if ( in2000_datawrite ) ! 310: in2000_fifo_out(); ! 311: else ! 312: in2000_fifo_in(); ! 313: } ! 314: if ( (auxstatus & 0x8c) == 0x80 ) ! 315: { /* There is a WD Chip interrupt & register read good */ ! 316: outb(2,ININTR); /* Disable fifo interrupts */ ! 317: ficmsk = 0; ! 318: result = DID_OK << 16; ! 319: /* 16=Select & transfer complete, 85=got disconnect */ ! 320: if ((scsistatus != 0x16) && (scsistatus != 0x85) ! 321: && (scsistatus != 0x42)){ ! 322: /* printk("(WDi2000:%02x %02x %02x %02x %02x)\n",count,auxstatus, ! 323: scsistatus,cmdphase,scsibyte);*/ ! 324: /* printk("QDAT:%d %08x %02x\n", ! 325: in2000_datalen,(unsigned int)in2000_dataptr,ficmsk);*/ ! 326: ; ! 327: } ! 328: switch ( scsistatus & 0xf0 ) ! 329: { ! 330: case 0x00: /* Card Reset Completed */ ! 331: action = 3; ! 332: break; ! 333: case 0x10: /* Successful Command Completion */ ! 334: if ( scsistatus & 0x8 ) ! 335: action = 1; ! 336: break; ! 337: case 0x20: /* Command Paused or Aborted */ ! 338: if ( (scsistatus & 0x8) ) ! 339: action = 1; ! 340: else if ( (scsistatus & 7) < 2 ) ! 341: action = 2; ! 342: else ! 343: result = DID_ABORT << 16; ! 344: break; ! 345: case 0x40: /* Terminated early */ ! 346: if ( scsistatus & 0x8 ) ! 347: action = 1; ! 348: else if ( (scsistatus & 7) > 2 ) ! 349: action = 2; ! 350: else ! 351: result = DID_TIME_OUT << 16; ! 352: break; ! 353: case 0x80: /* Service Required from SCSI bus */ ! 354: if ( scsistatus & 0x8 ) ! 355: action = 1; ! 356: else ! 357: action = 2; ! 358: break; ! 359: } /* end switch(scsistatus) */ ! 360: outb(0,INFLED); ! 361: switch ( action ) ! 362: { ! 363: case 0x02: /* Issue an abort */ ! 364: outb(COMMAND,INSTAT); ! 365: outb(1,INDATA); /* ABORT COMMAND */ ! 366: result = DID_ABORT << 16; ! 367: case 0x00: /* Basically all done */ ! 368: if ( ! in2000_SCptr ) ! 369: return; ! 370: in2000_SCptr->result = result | scsibyte; ! 371: SCptr = in2000_SCptr; ! 372: in2000_SCptr = 0; ! 373: if ( in2000_done ) ! 374: (*in2000_done)(SCptr); ! 375: break; ! 376: case 0x01: /* We need to reissue a command */ ! 377: outb(CMDPHAS,INSTAT); ! 378: switch ( scsistatus & 7 ) ! 379: { ! 380: case 0: /* Data out phase */ ! 381: case 1: /* Data in phase */ ! 382: case 4: /* Unspec info out phase */ ! 383: case 5: /* Unspec info in phase */ ! 384: case 6: /* Message in phase */ ! 385: case 7: /* Message in phase */ ! 386: outb(0x41,INDATA); /* rdy to disconn */ ! 387: break; ! 388: case 2: /* command phase */ ! 389: outb(0x30,INDATA); /* rdy to send cmd bytes */ ! 390: break; ! 391: case 3: /* status phase */ ! 392: outb(0x45,INDATA); /* To go to status phase,*/ ! 393: outb(TXCNTH,INSTAT); /* elim. data, autoinc */ ! 394: outb(0,INDATA); ! 395: outb(0,INDATA); ! 396: outb(0,INDATA); ! 397: in2000_datalen = 0; ! 398: in2000_dataptr = 0; ! 399: break; ! 400: } /* end switch(scsistatus) */ ! 401: outb(COMMAND,INSTAT); ! 402: outb(8,INDATA); /* RESTART THE COMMAND */ ! 403: break; ! 404: case 0x03: /* Finish up a Card Reset */ ! 405: outb(TIMEOUT,INSTAT); /* I got these values */ ! 406: /* by reverse Engineering */ ! 407: outb(IN2000_TMOUT,INDATA); /* the Always' bios. */ ! 408: outb(CONTROL,INSTAT); ! 409: outb(0,INDATA); ! 410: outb(SYNCTXR,INSTAT); ! 411: outb(0x40,INDATA); /* async, 4 cyc xfer per. */ ! 412: break; ! 413: } /* end switch(action) */ ! 414: } /* end if auxstatus for WD int */ ! 415: } /* end while intrpt active */ ! 416: } ! 417: ! 418: int in2000_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *)) ! 419: { ! 420: unchar direction; ! 421: unchar *cmd = (unchar *) SCpnt->cmnd; ! 422: unchar target = SCpnt->target; ! 423: void *buff = SCpnt->request_buffer; ! 424: unsigned long flags; ! 425: int bufflen = SCpnt->request_bufflen; ! 426: int timeout, size, loop; ! 427: int i; ! 428: ! 429: /* ! 430: * This SCSI command has no data phase, but unfortunately the mid-level ! 431: * SCSI drivers ask for 256 bytes of data xfer. Our card hangs if you ! 432: * do this, so we protect against it here. It would be nice if the mid- ! 433: * level could be changed, but who knows if that would break other host ! 434: * adapter drivers. ! 435: */ ! 436: if ( *cmd == TEST_UNIT_READY ) ! 437: bufflen = 0; ! 438: ! 439: /* ! 440: * What it looks like. Boy did I get tired of reading its output. ! 441: */ ! 442: if (*cmd == READ_10 || *cmd == WRITE_10) { ! 443: i = xscsi2int((cmd+1)); ! 444: } else if (*cmd == READ_6 || *cmd == WRITE_6) { ! 445: i = scsi2int((cmd+1)); ! 446: } else { ! 447: i = -1; ! 448: } ! 449: #ifdef DEBUG ! 450: printk("in2000qcmd: pos %d len %d ", i, bufflen); ! 451: printk("scsi cmd:"); ! 452: for (i = 0; i < SCpnt->cmd_len; i++) printk("%02x ", cmd[i]); ! 453: printk("\n"); ! 454: #endif ! 455: direction = 1; /* assume for most commands */ ! 456: if (*cmd == WRITE_10 || *cmd == WRITE_6) ! 457: direction = 0; ! 458: size = SCpnt->cmd_len; /* CDB length */ ! 459: /* ! 460: * Setup our current pointers ! 461: * This is where you would allocate a control structure in a queue, ! 462: * If you were going to upgrade this to do multiple issue. ! 463: * Note that datalen and dataptr exist because we can change the ! 464: * values during the course of the operation, while managing the ! 465: * FIFO. ! 466: * Note the nasty little first clause. In theory, the mid-level ! 467: * drivers should never hand us more than one command at a time, ! 468: * but just in case someone gets cute in configuring the driver, ! 469: * we'll protect them, although not very politely. ! 470: */ ! 471: if ( in2000_SCptr ) ! 472: { ! 473: printk("in2000_queue_command waiting for free command block!\n"); ! 474: while ( in2000_SCptr ) ! 475: barrier(); ! 476: } ! 477: for ( timeout = jiffies + 5; timeout > jiffies; ) ! 478: { ! 479: if ( ! ( inb(INSTAT) & 0xb0 ) ) ! 480: { ! 481: timeout = 0; ! 482: break; ! 483: } ! 484: else ! 485: { ! 486: inb(INSTAT); ! 487: outb(SCSIST,INSTAT); ! 488: inb(INDATA); ! 489: outb(TARGETU,INSTAT); /* then autoinc */ ! 490: inb(INDATA); ! 491: inb(INDATA); ! 492: } ! 493: } ! 494: if ( timeout ) ! 495: { ! 496: printk("in2000_queue_command timeout!\n"); ! 497: SCpnt->result = DID_TIME_OUT << 16; ! 498: (*done)(SCpnt); ! 499: return 1; ! 500: } ! 501: /* Added for scatter-gather support */ ! 502: in2000_nsegment = SCpnt->use_sg; ! 503: in2000_current_segment = 0; ! 504: if(SCpnt->use_sg){ ! 505: in2000_scatter = (struct scatterlist *) buff; ! 506: in2000_datalen = in2000_scatter->length; ! 507: in2000_dataptr = (unsigned short*)in2000_scatter->address; ! 508: } else { ! 509: in2000_scatter = NULL; ! 510: in2000_datalen = bufflen; ! 511: in2000_dataptr = (unsigned short*) buff; ! 512: }; ! 513: in2000_done = done; ! 514: in2000_SCptr = SCpnt; ! 515: /* ! 516: * Write the CDB to the card, then the LUN, the length, and the target. ! 517: */ ! 518: outb(TOTSECT, INSTAT); /* start here then autoincrement */ ! 519: for ( loop=0; loop < size; loop++ ) ! 520: outb(cmd[loop],INDATA); ! 521: outb(TARGETU,INSTAT); ! 522: outb(SCpnt->lun & 7,INDATA); ! 523: SCpnt->host_scribble = NULL; ! 524: outb(TXCNTH,INSTAT); /* then autoincrement */ ! 525: outb(bufflen>>16,INDATA); ! 526: outb(bufflen>>8,INDATA); ! 527: outb(bufflen,INDATA); ! 528: outb(target&7,INDATA); ! 529: /* ! 530: * Set up the FIFO ! 531: */ ! 532: save_flags(flags); ! 533: cli(); /* so FIFO init waits till WD set */ ! 534: outb(0,INFRST); ! 535: if ( direction == 1 ) ! 536: { ! 537: in2000_datawrite = 0; ! 538: outb(0,INFWRT); ! 539: } ! 540: else ! 541: { ! 542: in2000_datawrite = 1; ! 543: for ( loop=16; --loop; ) /* preload the outgoing fifo */ ! 544: { ! 545: outw(*in2000_dataptr++,INFIFO); ! 546: if(in2000_datalen > 0) in2000_datalen-=2; ! 547: } ! 548: } ! 549: ficmsk = 0xff; ! 550: /* ! 551: * Start it up ! 552: */ ! 553: outb(CONTROL,INSTAT); /* WD BUS Mode */ ! 554: outb(0x4C,INDATA); ! 555: if ( in2000_datalen ) /* if data xfer cmd */ ! 556: outb(0,ININTR); /* Enable FIFO intrpt some boards? */ ! 557: outb(COMMAND,INSTAT); ! 558: outb(0,INNLED); ! 559: outb(8,INDATA); /* Select w/ATN & Transfer */ ! 560: restore_flags(flags); /* let the intrpt rip */ ! 561: return 0; ! 562: } ! 563: ! 564: static volatile int internal_done_flag = 0; ! 565: static volatile int internal_done_errcode = 0; ! 566: ! 567: static void internal_done(Scsi_Cmnd * SCpnt) ! 568: { ! 569: internal_done_errcode = SCpnt->result; ! 570: ++internal_done_flag; ! 571: } ! 572: ! 573: int in2000_command(Scsi_Cmnd * SCpnt) ! 574: { ! 575: in2000_queuecommand(SCpnt, internal_done); ! 576: ! 577: while (!internal_done_flag); ! 578: internal_done_flag = 0; ! 579: return internal_done_errcode; ! 580: } ! 581: ! 582: int in2000_detect(Scsi_Host_Template * tpnt) ! 583: { ! 584: /* Order chosen to reduce conflicts with some multi-port serial boards */ ! 585: int base_tab[] = { 0x220,0x200,0x110,0x100 }; ! 586: int int_tab[] = { 15,14,11,10 }; ! 587: struct Scsi_Host * shpnt; ! 588: int loop, tmp; ! 589: ! 590: DEB(printk("in2000_detect: \n")); ! 591: ! 592: tpnt->proc_dir = &proc_scsi_in2000; ! 593: ! 594: for ( loop=0; loop < 4; loop++ ) ! 595: { ! 596: base = base_tab[loop]; ! 597: if ( in2000_test_port(loop)) break; ! 598: } ! 599: if ( loop == 4 ) ! 600: return 0; ! 601: ! 602: /* Read the dip switch values again for miscellaneous checking and ! 603: informative messages */ ! 604: tmp = inb(INFLED); ! 605: ! 606: /* Bit 2 tells us if interrupts are disabled */ ! 607: if ( (tmp & 0x4) == 0 ) { ! 608: printk("The IN-2000 is not configured for interrupt operation\n"); ! 609: printk("Change the DIP switch settings to enable interrupt operation\n"); ! 610: } ! 611: ! 612: /* Bit 6 tells us about floppy controller */ ! 613: printk("IN-2000 probe found floppy controller on IN-2000 "); ! 614: if ( (tmp & 0x40) == 0) ! 615: printk("enabled\n"); ! 616: else ! 617: printk("disabled\n"); ! 618: ! 619: /* Bit 5 tells us about synch/asynch mode */ ! 620: printk("IN-2000 probe found IN-2000 in "); ! 621: if ( (tmp & 0x20) == 0) ! 622: printk("synchronous mode\n"); ! 623: else ! 624: printk("asynchronous mode\n"); ! 625: ! 626: irq_level = int_tab [ ((~inb(INFLED)>>3)&0x3) ]; ! 627: ! 628: printk("Configuring IN2000 at IO:%x, IRQ %d" ! 629: #ifdef FAST_FIFO_IO ! 630: " (using fast FIFO I/O code)" ! 631: #endif ! 632: "\n",base, irq_level); ! 633: ! 634: outb(2,ININTR); /* Shut off the FIFO first, so it won't ask for data.*/ ! 635: if (request_irq(irq_level,in2000_intr_handle, 0, "in2000")) ! 636: { ! 637: printk("in2000_detect: Unable to allocate IRQ.\n"); ! 638: return 0; ! 639: } ! 640: outb(0,INFWRT); /* read mode so WD can intrpt */ ! 641: outb(SCSIST,INSTAT); ! 642: inb(INDATA); /* free status reg, clear WD intrpt */ ! 643: outb(OWNID,INSTAT); ! 644: outb(0x7,INDATA); /* we use addr 7 */ ! 645: outb(COMMAND,INSTAT); ! 646: outb(0,INDATA); /* do chip reset */ ! 647: shpnt = scsi_register(tpnt, 0); ! 648: /* Set these up so that we can unload the driver properly. */ ! 649: shpnt->io_port = base; ! 650: shpnt->n_io_port = 12; ! 651: shpnt->irq = irq_level; ! 652: request_region(base, 12,"in2000"); /* Prevent other drivers from using this space */ ! 653: return 1; ! 654: } ! 655: ! 656: int in2000_abort(Scsi_Cmnd * SCpnt) ! 657: { ! 658: DEB(printk("in2000_abort\n")); ! 659: /* ! 660: * Ask no stupid questions, just order the abort. ! 661: */ ! 662: outb(COMMAND,INSTAT); ! 663: outb(1,INDATA); /* Abort Command */ ! 664: return 0; ! 665: } ! 666: ! 667: static inline void delay( unsigned how_long ) ! 668: { ! 669: unsigned long time = jiffies + how_long; ! 670: while (jiffies < time) ; ! 671: } ! 672: ! 673: int in2000_reset(Scsi_Cmnd * SCpnt) ! 674: { ! 675: DEB(printk("in2000_reset called\n")); ! 676: /* ! 677: * Note: this is finished off by an incoming interrupt ! 678: */ ! 679: outb(0,INFWRT); /* read mode so WD can intrpt */ ! 680: outb(SCSIST,INSTAT); ! 681: inb(INDATA); ! 682: outb(OWNID,INSTAT); ! 683: outb(0x7,INDATA); /* ID=7,noadv, no parity, clk div=2 (8-10Mhz clk) */ ! 684: outb(COMMAND,INSTAT); ! 685: outb(0,INDATA); /* reset WD chip */ ! 686: delay(2); ! 687: #ifdef SCSI_RESET_PENDING ! 688: return SCSI_RESET_PENDING; ! 689: #else ! 690: if(SCpnt) SCpnt->flags |= NEEDS_JUMPSTART; ! 691: return 0; ! 692: #endif ! 693: } ! 694: ! 695: int in2000_biosparam(Disk * disk, kdev_t dev, int* iinfo) ! 696: { ! 697: int size = disk->capacity; ! 698: DEB(printk("in2000_biosparam\n")); ! 699: iinfo[0] = 64; ! 700: iinfo[1] = 32; ! 701: iinfo[2] = size >> 11; ! 702: /* This should approximate the large drive handling that the DOS ASPI manager ! 703: uses. Drives very near the boundaries may not be handled correctly (i.e. ! 704: near 2.0 Gb and 4.0 Gb) */ ! 705: if (iinfo[2] > 1024) { ! 706: iinfo[0] = 64; ! 707: iinfo[1] = 63; ! 708: iinfo[2] = disk->capacity / (iinfo[0] * iinfo[1]); ! 709: } ! 710: if (iinfo[2] > 1024) { ! 711: iinfo[0] = 128; ! 712: iinfo[1] = 63; ! 713: iinfo[2] = disk->capacity / (iinfo[0] * iinfo[1]); ! 714: } ! 715: if (iinfo[2] > 1024) { ! 716: iinfo[0] = 255; ! 717: iinfo[1] = 63; ! 718: iinfo[2] = disk->capacity / (iinfo[0] * iinfo[1]); ! 719: if (iinfo[2] > 1023) ! 720: iinfo[2] = 1023; ! 721: } ! 722: return 0; ! 723: } ! 724: ! 725: #ifdef MODULE ! 726: /* Eventually this will go into an include file, but this will be later */ ! 727: Scsi_Host_Template driver_template = IN2000; ! 728: ! 729: #include "scsi_module.c" ! 730: #endif ! 731:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.