|
|
1.1 ! root 1: /*----------------------------------------------------------------*/ ! 2: /* ! 3: Qlogic linux driver - work in progress. No Warranty express or implied. ! 4: Use at your own risk. Support Tort Reform so you won't have to read all ! 5: these silly disclaimers. ! 6: ! 7: Copyright 1994, Tom Zerucha. ! 8: [email protected] ! 9: ! 10: Additional Code, and much appreciated help by ! 11: Michael A. Griffith ! 12: [email protected] ! 13: ! 14: Thanks to Eric Youngdale and Dave Hinds for loadable module and PCMCIA ! 15: help respectively, and for suffering through my foolishness during the ! 16: debugging process. ! 17: ! 18: Reference Qlogic FAS408 Technical Manual, 53408-510-00A, May 10, 1994 ! 19: (you can reference it, but it is incomplete and inaccurate in places) ! 20: ! 21: Version 0.45 6/9/96 - kernel 1.2.0+ ! 22: ! 23: Functions as standalone, loadable, and PCMCIA driver, the latter from ! 24: Dave Hind's PCMCIA package. ! 25: ! 26: Redistributable under terms of the GNU Public License ! 27: ! 28: */ ! 29: /*----------------------------------------------------------------*/ ! 30: /* Configuration */ ! 31: ! 32: /* Set the following to 2 to use normal interrupt (active high/totempole- ! 33: tristate), otherwise use 0 (REQUIRED FOR PCMCIA) for active low, open ! 34: drain */ ! 35: #define QL_INT_ACTIVE_HIGH 2 ! 36: ! 37: /* Set the following to 1 to enable the use of interrupts. Note that 0 tends ! 38: to be more stable, but slower (or ties up the system more) */ ! 39: #define QL_USE_IRQ 1 ! 40: ! 41: /* Set the following to max out the speed of the PIO PseudoDMA transfers, ! 42: again, 0 tends to be slower, but more stable. */ ! 43: #define QL_TURBO_PDMA 1 ! 44: ! 45: /* This should be 1 to enable parity detection */ ! 46: #define QL_ENABLE_PARITY 1 ! 47: ! 48: /* This will reset all devices when the driver is initialized (during bootup). ! 49: The other linux drivers don't do this, but the DOS drivers do, and after ! 50: using DOS or some kind of crash or lockup this will bring things back ! 51: without requiring a cold boot. It does take some time to recover from a ! 52: reset, so it is slower, and I have seen timeouts so that devices weren't ! 53: recognized when this was set. */ ! 54: #define QL_RESET_AT_START 0 ! 55: ! 56: /* crystal frequency in megahertz (for offset 5 and 9) ! 57: Please set this for your card. Most Qlogic cards are 40 Mhz. The ! 58: Control Concepts ISA (not VLB) is 24 Mhz */ ! 59: #define XTALFREQ 40 ! 60: ! 61: /**********/ ! 62: /* DANGER! modify these at your own risk */ ! 63: /* SLOWCABLE can usually be reset to zero if you have a clean setup and ! 64: proper termination. The rest are for synchronous transfers and other ! 65: advanced features if your device can transfer faster than 5Mb/sec. ! 66: If you are really curious, email me for a quick howto until I have ! 67: something official */ ! 68: /**********/ ! 69: ! 70: /*****/ ! 71: /* config register 1 (offset 8) options */ ! 72: /* This needs to be set to 1 if your cabling is long or noisy */ ! 73: #define SLOWCABLE 1 ! 74: ! 75: /*****/ ! 76: /* offset 0xc */ ! 77: /* This will set fast (10Mhz) synchronous timing when set to 1 ! 78: For this to have an effect, FASTCLK must also be 1 */ ! 79: #define FASTSCSI 0 ! 80: ! 81: /* This when set to 1 will set a faster sync transfer rate */ ! 82: #define FASTCLK 0 ! 83: /*(XTALFREQ>25?1:0)*/ ! 84: ! 85: /*****/ ! 86: /* offset 6 */ ! 87: /* This is the sync transfer divisor, XTALFREQ/X will be the maximum ! 88: achievable data rate (assuming the rest of the system is capable ! 89: and set properly) */ ! 90: #define SYNCXFRPD 5 ! 91: /*(XTALFREQ/5)*/ ! 92: ! 93: /*****/ ! 94: /* offset 7 */ ! 95: /* This is the count of how many synchronous transfers can take place ! 96: i.e. how many reqs can occur before an ack is given. ! 97: The maximum value for this is 15, the upper bits can modify ! 98: REQ/ACK assertion and deassertion during synchronous transfers ! 99: If this is 0, the bus will only transfer asynchronously */ ! 100: #define SYNCOFFST 0 ! 101: /* for the curious, bits 7&6 control the deassertion delay in 1/2 cycles ! 102: of the 40Mhz clock. If FASTCLK is 1, specifying 01 (1/2) will ! 103: cause the deassertion to be early by 1/2 clock. Bits 5&4 control ! 104: the assertion delay, also in 1/2 clocks (FASTCLK is ignored here). */ ! 105: ! 106: /*----------------------------------------------------------------*/ ! 107: #ifdef PCMCIA ! 108: #undef QL_INT_ACTIVE_HIGH ! 109: #define QL_INT_ACTIVE_HIGH 0 ! 110: #define MODULE ! 111: #endif ! 112: ! 113: #include <linux/module.h> ! 114: ! 115: #ifdef PCMCIA ! 116: #undef MODULE ! 117: #endif ! 118: ! 119: #include <linux/blk.h> /* to get disk capacity */ ! 120: #include <linux/kernel.h> ! 121: #include <linux/string.h> ! 122: #include <linux/ioport.h> ! 123: #include <linux/sched.h> ! 124: #include <linux/proc_fs.h> ! 125: #include <linux/unistd.h> ! 126: #include <asm/io.h> ! 127: #include <asm/irq.h> ! 128: #include "sd.h" ! 129: #include "hosts.h" ! 130: #include "qlogicfas.h" ! 131: #include<linux/stat.h> ! 132: ! 133: struct proc_dir_entry proc_scsi_qlogicfas = { ! 134: PROC_SCSI_QLOGICFAS, 6, "qlogicfas", ! 135: S_IFDIR | S_IRUGO | S_IXUGO, 2 ! 136: }; ! 137: ! 138: /*----------------------------------------------------------------*/ ! 139: /* driver state info, local to driver */ ! 140: static int qbase = 0; /* Port */ ! 141: static int qinitid; /* initiator ID */ ! 142: static int qabort; /* Flag to cause an abort */ ! 143: static int qlirq = -1; /* IRQ being used */ ! 144: static char qinfo[80]; /* description */ ! 145: static Scsi_Cmnd *qlcmd; /* current command being processed */ ! 146: ! 147: static int qlcfg5 = ( XTALFREQ << 5 ); /* 15625/512 */ ! 148: static int qlcfg6 = SYNCXFRPD; ! 149: static int qlcfg7 = SYNCOFFST; ! 150: static int qlcfg8 = ( SLOWCABLE << 7 ) | ( QL_ENABLE_PARITY << 4 ); ! 151: static int qlcfg9 = ( ( XTALFREQ + 4 ) / 5 ); ! 152: static int qlcfgc = ( FASTCLK << 3 ) | ( FASTSCSI << 4 ); ! 153: ! 154: /*----------------------------------------------------------------*/ ! 155: /* The qlogic card uses two register maps - These macros select which one */ ! 156: #define REG0 ( outb( inb( qbase + 0xd ) & 0x7f , qbase + 0xd ), outb( 4 , qbase + 0xd )) ! 157: #define REG1 ( outb( inb( qbase + 0xd ) | 0x80 , qbase + 0xd ), outb( 0xb4 | QL_INT_ACTIVE_HIGH , qbase + 0xd )) ! 158: ! 159: /* following is watchdog timeout in microseconds */ ! 160: #define WATCHDOG 5000000 ! 161: ! 162: /*----------------------------------------------------------------*/ ! 163: /* the following will set the monitor border color (useful to find ! 164: where something crashed or gets stuck at and as a simple profiler) */ ! 165: ! 166: #if 0 ! 167: #define rtrc(i) {inb(0x3da);outb(0x31,0x3c0);outb((i),0x3c0);} ! 168: #else ! 169: #define rtrc(i) {} ! 170: #endif ! 171: ! 172: /*----------------------------------------------------------------*/ ! 173: /* local functions */ ! 174: /*----------------------------------------------------------------*/ ! 175: static void ql_zap(void); ! 176: /* error recovery - reset everything */ ! 177: void ql_zap() ! 178: { ! 179: int x; ! 180: unsigned long flags; ! 181: save_flags( flags ); ! 182: cli(); ! 183: x = inb(qbase + 0xd); ! 184: REG0; ! 185: outb(3, qbase + 3); /* reset SCSI */ ! 186: outb(2, qbase + 3); /* reset chip */ ! 187: if (x & 0x80) ! 188: REG1; ! 189: restore_flags( flags ); ! 190: } ! 191: ! 192: /*----------------------------------------------------------------*/ ! 193: /* do pseudo-dma */ ! 194: static int ql_pdma(int phase, char *request, int reqlen) ! 195: { ! 196: int j; ! 197: j = 0; ! 198: if (phase & 1) { /* in */ ! 199: #if QL_TURBO_PDMA ! 200: rtrc(4) ! 201: /* empty fifo in large chunks */ ! 202: if( reqlen >= 128 && (inb( qbase + 8 ) & 2) ) { /* full */ ! 203: insl( qbase + 4, request, 32 ); ! 204: reqlen -= 128; ! 205: request += 128; ! 206: } ! 207: while( reqlen >= 84 && !( j & 0xc0 ) ) /* 2/3 */ ! 208: if( (j=inb( qbase + 8 )) & 4 ) { ! 209: insl( qbase + 4, request, 21 ); ! 210: reqlen -= 84; ! 211: request += 84; ! 212: } ! 213: if( reqlen >= 44 && (inb( qbase + 8 ) & 8) ) { /* 1/3 */ ! 214: insl( qbase + 4, request, 11 ); ! 215: reqlen -= 44; ! 216: request += 44; ! 217: } ! 218: #endif ! 219: /* until both empty and int (or until reclen is 0) */ ! 220: rtrc(7) ! 221: j = 0; ! 222: while( reqlen && !( (j & 0x10) && (j & 0xc0) ) ) { ! 223: /* while bytes to receive and not empty */ ! 224: j &= 0xc0; ! 225: while ( reqlen && !( (j=inb(qbase + 8)) & 0x10 ) ) { ! 226: *request++ = inb(qbase + 4); ! 227: reqlen--; ! 228: } ! 229: if( j & 0x10 ) ! 230: j = inb(qbase+8); ! 231: ! 232: } ! 233: } ! 234: else { /* out */ ! 235: #if QL_TURBO_PDMA ! 236: rtrc(4) ! 237: if( reqlen >= 128 && inb( qbase + 8 ) & 0x10 ) { /* empty */ ! 238: outsl(qbase + 4, request, 32 ); ! 239: reqlen -= 128; ! 240: request += 128; ! 241: } ! 242: while( reqlen >= 84 && !( j & 0xc0 ) ) /* 1/3 */ ! 243: if( !((j=inb( qbase + 8 )) & 8) ) { ! 244: outsl( qbase + 4, request, 21 ); ! 245: reqlen -= 84; ! 246: request += 84; ! 247: } ! 248: if( reqlen >= 40 && !(inb( qbase + 8 ) & 4 ) ) { /* 2/3 */ ! 249: outsl( qbase + 4, request, 10 ); ! 250: reqlen -= 40; ! 251: request += 40; ! 252: } ! 253: #endif ! 254: /* until full and int (or until reclen is 0) */ ! 255: rtrc(7) ! 256: j = 0; ! 257: while( reqlen && !( (j & 2) && (j & 0xc0) ) ) { ! 258: /* while bytes to send and not full */ ! 259: while ( reqlen && !( (j=inb(qbase + 8)) & 2 ) ) { ! 260: outb(*request++, qbase + 4); ! 261: reqlen--; ! 262: } ! 263: if( j & 2 ) ! 264: j = inb(qbase+8); ! 265: } ! 266: } ! 267: /* maybe return reqlen */ ! 268: return inb( qbase + 8 ) & 0xc0; ! 269: } ! 270: ! 271: /*----------------------------------------------------------------*/ ! 272: /* wait for interrupt flag (polled - not real hardware interrupt) */ ! 273: static int ql_wai(void) ! 274: { ! 275: int i,k; ! 276: k = 0; ! 277: i = jiffies + WATCHDOG; ! 278: while ( i > jiffies && !qabort && !((k = inb(qbase + 4)) & 0xe0)) ! 279: barrier(); ! 280: if (i <= jiffies) ! 281: return (DID_TIME_OUT); ! 282: if (qabort) ! 283: return (qabort == 1 ? DID_ABORT : DID_RESET); ! 284: if (k & 0x60) ! 285: ql_zap(); ! 286: if (k & 0x20) ! 287: return (DID_PARITY); ! 288: if (k & 0x40) ! 289: return (DID_ERROR); ! 290: return 0; ! 291: } ! 292: ! 293: /*----------------------------------------------------------------*/ ! 294: /* initiate scsi command - queueing handler */ ! 295: static void ql_icmd(Scsi_Cmnd * cmd) ! 296: { ! 297: unsigned int i; ! 298: unsigned long flags; ! 299: ! 300: qabort = 0; ! 301: ! 302: save_flags( flags ); ! 303: cli(); ! 304: REG0; ! 305: /* clearing of interrupts and the fifo is needed */ ! 306: inb(qbase + 5); /* clear interrupts */ ! 307: if (inb(qbase + 5)) /* if still interrupting */ ! 308: outb(2, qbase + 3); /* reset chip */ ! 309: else if (inb(qbase + 7) & 0x1f) ! 310: outb(1, qbase + 3); /* clear fifo */ ! 311: while (inb(qbase + 5)); /* clear ints */ ! 312: REG1; ! 313: outb(1, qbase + 8); /* set for PIO pseudo DMA */ ! 314: outb(0, qbase + 0xb); /* disable ints */ ! 315: inb(qbase + 8); /* clear int bits */ ! 316: REG0; ! 317: outb(0x40, qbase + 0xb); /* enable features */ ! 318: ! 319: /* configurables */ ! 320: outb( qlcfgc , qbase + 0xc); ! 321: /* config: no reset interrupt, (initiator) bus id */ ! 322: outb( 0x40 | qlcfg8 | qinitid, qbase + 8); ! 323: outb( qlcfg7 , qbase + 7 ); ! 324: outb( qlcfg6 , qbase + 6 ); ! 325: /**/ ! 326: outb(qlcfg5, qbase + 5); /* select timer */ ! 327: outb(qlcfg9 & 7, qbase + 9); /* prescaler */ ! 328: /* outb(0x99, qbase + 5); */ ! 329: outb(cmd->target, qbase + 4); ! 330: ! 331: for (i = 0; i < cmd->cmd_len; i++) ! 332: outb(cmd->cmnd[i], qbase + 2); ! 333: qlcmd = cmd; ! 334: outb(0x41, qbase + 3); /* select and send command */ ! 335: restore_flags( flags ); ! 336: } ! 337: /*----------------------------------------------------------------*/ ! 338: /* process scsi command - usually after interrupt */ ! 339: static unsigned int ql_pcmd(Scsi_Cmnd * cmd) ! 340: { ! 341: unsigned int i, j, k; ! 342: unsigned int result; /* ultimate return result */ ! 343: unsigned int status; /* scsi returned status */ ! 344: unsigned int message; /* scsi returned message */ ! 345: unsigned int phase; /* recorded scsi phase */ ! 346: unsigned int reqlen; /* total length of transfer */ ! 347: struct scatterlist *sglist; /* scatter-gather list pointer */ ! 348: unsigned int sgcount; /* sg counter */ ! 349: ! 350: rtrc(1) ! 351: j = inb(qbase + 6); ! 352: i = inb(qbase + 5); ! 353: if (i == 0x20) { ! 354: return (DID_NO_CONNECT << 16); ! 355: } ! 356: i |= inb(qbase + 5); /* the 0x10 bit can be set after the 0x08 */ ! 357: if (i != 0x18) { ! 358: printk("Ql:Bad Interrupt status:%02x\n", i); ! 359: ql_zap(); ! 360: return (DID_BAD_INTR << 16); ! 361: } ! 362: j &= 7; /* j = inb( qbase + 7 ) >> 5; */ ! 363: /* correct status is supposed to be step 4 */ ! 364: /* it sometimes returns step 3 but with 0 bytes left to send */ ! 365: /* We can try stuffing the FIFO with the max each time, but we will get a ! 366: sequence of 3 if any bytes are left (but we do flush the FIFO anyway */ ! 367: if(j != 3 && j != 4) { ! 368: printk("Ql:Bad sequence for command %d, int %02X, cmdleft = %d\n", j, i, inb( qbase+7 ) & 0x1f ); ! 369: ql_zap(); ! 370: return (DID_ERROR << 16); ! 371: } ! 372: result = DID_OK; ! 373: if (inb(qbase + 7) & 0x1f) /* if some bytes in fifo */ ! 374: outb(1, qbase + 3); /* clear fifo */ ! 375: /* note that request_bufflen is the total xfer size when sg is used */ ! 376: reqlen = cmd->request_bufflen; ! 377: /* note that it won't work if transfers > 16M are requested */ ! 378: if (reqlen && !((phase = inb(qbase + 4)) & 6)) { /* data phase */ ! 379: rtrc(2) ! 380: outb(reqlen, qbase); /* low-mid xfer cnt */ ! 381: outb(reqlen >> 8, qbase+1); /* low-mid xfer cnt */ ! 382: outb(reqlen >> 16, qbase + 0xe); /* high xfer cnt */ ! 383: outb(0x90, qbase + 3); /* command do xfer */ ! 384: /* PIO pseudo DMA to buffer or sglist */ ! 385: REG1; ! 386: if (!cmd->use_sg) ! 387: ql_pdma(phase, cmd->request_buffer, cmd->request_bufflen); ! 388: else { ! 389: sgcount = cmd->use_sg; ! 390: sglist = cmd->request_buffer; ! 391: while (sgcount--) { ! 392: if (qabort) { ! 393: REG0; ! 394: return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16); ! 395: } ! 396: if (ql_pdma(phase, sglist->address, sglist->length)) ! 397: break; ! 398: sglist++; ! 399: } ! 400: } ! 401: REG0; ! 402: rtrc(2) ! 403: /* wait for irq (split into second state of irq handler if this can take time) */ ! 404: if ((k = ql_wai())) ! 405: return (k << 16); ! 406: k = inb(qbase + 5); /* should be 0x10, bus service */ ! 407: } ! 408: /*** Enter Status (and Message In) Phase ***/ ! 409: k = jiffies + WATCHDOG; ! 410: while ( k > jiffies && !qabort && !(inb(qbase + 4) & 6)); /* wait for status phase */ ! 411: if ( k <= jiffies ) { ! 412: ql_zap(); ! 413: return (DID_TIME_OUT << 16); ! 414: } ! 415: while (inb(qbase + 5)); /* clear pending ints */ ! 416: if (qabort) ! 417: return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16); ! 418: outb(0x11, qbase + 3); /* get status and message */ ! 419: if ((k = ql_wai())) ! 420: return (k << 16); ! 421: i = inb(qbase + 5); /* get chip irq stat */ ! 422: j = inb(qbase + 7) & 0x1f; /* and bytes rec'd */ ! 423: status = inb(qbase + 2); ! 424: message = inb(qbase + 2); ! 425: /* should get function complete int if Status and message, else bus serv if only status */ ! 426: if (!((i == 8 && j == 2) || (i == 0x10 && j == 1))) { ! 427: printk("Ql:Error during status phase, int=%02X, %d bytes recd\n", i, j); ! 428: result = DID_ERROR; ! 429: } ! 430: outb(0x12, qbase + 3); /* done, disconnect */ ! 431: rtrc(1) ! 432: if ((k = ql_wai())) ! 433: return (k << 16); ! 434: /* should get bus service interrupt and disconnect interrupt */ ! 435: i = inb(qbase + 5); /* should be bus service */ ! 436: while (!qabort && ((i & 0x20) != 0x20)) { ! 437: barrier(); ! 438: i |= inb(qbase + 5); ! 439: } ! 440: rtrc(0) ! 441: if (qabort) ! 442: return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16); ! 443: return (result << 16) | (message << 8) | (status & STATUS_MASK); ! 444: } ! 445: ! 446: #if QL_USE_IRQ ! 447: /*----------------------------------------------------------------*/ ! 448: /* interrupt handler */ ! 449: static void ql_ihandl(int irq, void *dev_id, struct pt_regs * regs) ! 450: { ! 451: Scsi_Cmnd *icmd; ! 452: REG0; ! 453: if (!(inb(qbase + 4) & 0x80)) /* false alarm? */ ! 454: return; ! 455: if (qlcmd == NULL) { /* no command to process? */ ! 456: int i; ! 457: i = 16; ! 458: while (i-- && inb(qbase + 5)); /* maybe also ql_zap() */ ! 459: return; ! 460: } ! 461: icmd = qlcmd; ! 462: icmd->result = ql_pcmd(icmd); ! 463: qlcmd = NULL; ! 464: /* if result is CHECK CONDITION done calls qcommand to request sense */ ! 465: (icmd->scsi_done) (icmd); ! 466: } ! 467: #endif ! 468: ! 469: /*----------------------------------------------------------------*/ ! 470: /* global functions */ ! 471: /*----------------------------------------------------------------*/ ! 472: /* non queued command */ ! 473: #if QL_USE_IRQ ! 474: static void qlidone(Scsi_Cmnd * cmd) {}; /* null function */ ! 475: #endif ! 476: ! 477: /* command process */ ! 478: int qlogicfas_command(Scsi_Cmnd * cmd) ! 479: { ! 480: int k; ! 481: #if QL_USE_IRQ ! 482: if (qlirq >= 0) { ! 483: qlogicfas_queuecommand(cmd, qlidone); ! 484: while (qlcmd != NULL); ! 485: return cmd->result; ! 486: } ! 487: #endif ! 488: /* non-irq version */ ! 489: if (cmd->target == qinitid) ! 490: return (DID_BAD_TARGET << 16); ! 491: ql_icmd(cmd); ! 492: if ((k = ql_wai())) ! 493: return (k << 16); ! 494: return ql_pcmd(cmd); ! 495: ! 496: } ! 497: ! 498: #if QL_USE_IRQ ! 499: /*----------------------------------------------------------------*/ ! 500: /* queued command */ ! 501: int qlogicfas_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) ! 502: { ! 503: if(cmd->target == qinitid) { ! 504: cmd->result = DID_BAD_TARGET << 16; ! 505: done(cmd); ! 506: return 0; ! 507: } ! 508: ! 509: cmd->scsi_done = done; ! 510: /* wait for the last command's interrupt to finish */ ! 511: while (qlcmd != NULL) ! 512: barrier(); ! 513: ql_icmd(cmd); ! 514: return 0; ! 515: } ! 516: #else ! 517: int qlogicfas_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) ! 518: { ! 519: return 1; ! 520: } ! 521: #endif ! 522: ! 523: #ifdef PCMCIA ! 524: /*----------------------------------------------------------------*/ ! 525: /* allow PCMCIA code to preset the port */ ! 526: /* port should be 0 and irq to -1 respectively for autoprobing */ ! 527: void qlogicfas_preset(int port, int irq) ! 528: { ! 529: qbase=port; ! 530: qlirq=irq; ! 531: } ! 532: #endif ! 533: ! 534: /*----------------------------------------------------------------*/ ! 535: /* look for qlogic card and init if found */ ! 536: int qlogicfas_detect(Scsi_Host_Template * host) ! 537: { ! 538: int i, j; /* these are only used by IRQ detect */ ! 539: int qltyp; /* type of chip */ ! 540: struct Scsi_Host *hreg; /* registered host structure */ ! 541: unsigned long flags; ! 542: ! 543: host->proc_dir = &proc_scsi_qlogicfas; ! 544: ! 545: /* Qlogic Cards only exist at 0x230 or 0x330 (the chip itself decodes the ! 546: address - I check 230 first since MIDI cards are typically at 330 ! 547: ! 548: Theoretically, two Qlogic cards can coexist in the same system. This ! 549: should work by simply using this as a loadable module for the second ! 550: card, but I haven't tested this. ! 551: */ ! 552: ! 553: if( !qbase ) { ! 554: for (qbase = 0x230; qbase < 0x430; qbase += 0x100) { ! 555: if( check_region( qbase , 0x10 ) ) ! 556: continue; ! 557: REG1; ! 558: if ( ( (inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7 ) ! 559: && ( (inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7 ) ) ! 560: break; ! 561: } ! 562: if (qbase == 0x430) ! 563: return 0; ! 564: } ! 565: else ! 566: printk( "Ql: Using preset base address of %03x\n", qbase ); ! 567: ! 568: qltyp = inb(qbase + 0xe) & 0xf8; ! 569: qinitid = host->this_id; ! 570: if (qinitid < 0) ! 571: qinitid = 7; /* if no ID, use 7 */ ! 572: outb(1, qbase + 8); /* set for PIO pseudo DMA */ ! 573: REG0; ! 574: outb(0x40 | qlcfg8 | qinitid, qbase + 8); /* (ini) bus id, disable scsi rst */ ! 575: outb(qlcfg5, qbase + 5); /* select timer */ ! 576: outb(qlcfg9, qbase + 9); /* prescaler */ ! 577: #if QL_RESET_AT_START ! 578: outb( 3 , qbase + 3 ); ! 579: REG1; ! 580: while( inb( qbase + 0xf ) & 4 ); ! 581: REG0; ! 582: #endif ! 583: #if QL_USE_IRQ ! 584: /* IRQ probe - toggle pin and check request pending */ ! 585: ! 586: if( qlirq == -1 ) { ! 587: save_flags( flags ); ! 588: cli(); ! 589: i = 0xffff; ! 590: j = 3; ! 591: outb(0x90, qbase + 3); /* illegal command - cause interrupt */ ! 592: REG1; ! 593: outb(10, 0x20); /* access pending interrupt map */ ! 594: outb(10, 0xa0); ! 595: while (j--) { ! 596: outb(0xb0 | QL_INT_ACTIVE_HIGH , qbase + 0xd); /* int pin off */ ! 597: i &= ~(inb(0x20) | (inb(0xa0) << 8)); /* find IRQ off */ ! 598: outb(0xb4 | QL_INT_ACTIVE_HIGH , qbase + 0xd); /* int pin on */ ! 599: i &= inb(0x20) | (inb(0xa0) << 8); /* find IRQ on */ ! 600: } ! 601: REG0; ! 602: while (inb(qbase + 5)); /* purge int */ ! 603: j = -1; ! 604: while (i) /* find on bit */ ! 605: i >>= 1, j++; /* should check for exactly 1 on */ ! 606: qlirq = j; ! 607: restore_flags( flags ); ! 608: } ! 609: else ! 610: printk( "Ql: Using preset IRQ %d\n", qlirq ); ! 611: ! 612: if (qlirq >= 0 && !request_irq(qlirq, ql_ihandl, 0, "qlogicfas", NULL)) ! 613: host->can_queue = 1; ! 614: #endif ! 615: request_region( qbase , 0x10 ,"qlogicfas"); ! 616: hreg = scsi_register( host , 0 ); /* no host data */ ! 617: hreg->io_port = qbase; ! 618: hreg->n_io_port = 16; ! 619: hreg->dma_channel = -1; ! 620: if( qlirq != -1 ) ! 621: hreg->irq = qlirq; ! 622: ! 623: sprintf(qinfo, "Qlogicfas Driver version 0.45, chip %02X at %03X, IRQ %d, TPdma:%d", ! 624: qltyp, qbase, qlirq, QL_TURBO_PDMA ); ! 625: host->name = qinfo; ! 626: ! 627: return 1; ! 628: } ! 629: ! 630: /*----------------------------------------------------------------*/ ! 631: /* return bios parameters */ ! 632: int qlogicfas_biosparam(Disk * disk, kdev_t dev, int ip[]) ! 633: { ! 634: /* This should mimic the DOS Qlogic driver's behavior exactly */ ! 635: ip[0] = 0x40; ! 636: ip[1] = 0x20; ! 637: ip[2] = disk->capacity / (ip[0] * ip[1]); ! 638: if (ip[2] > 1024) { ! 639: ip[0] = 0xff; ! 640: ip[1] = 0x3f; ! 641: ip[2] = disk->capacity / (ip[0] * ip[1]); ! 642: if (ip[2] > 1023) ! 643: ip[2] = 1023; ! 644: } ! 645: return 0; ! 646: } ! 647: ! 648: /*----------------------------------------------------------------*/ ! 649: /* abort command in progress */ ! 650: int qlogicfas_abort(Scsi_Cmnd * cmd) ! 651: { ! 652: qabort = 1; ! 653: ql_zap(); ! 654: return 0; ! 655: } ! 656: ! 657: /*----------------------------------------------------------------*/ ! 658: /* reset SCSI bus */ ! 659: int qlogicfas_reset(Scsi_Cmnd * cmd, unsigned int flags) ! 660: { ! 661: qabort = 2; ! 662: ql_zap(); ! 663: return 1; ! 664: } ! 665: ! 666: /*----------------------------------------------------------------*/ ! 667: /* return info string */ ! 668: const char *qlogicfas_info(struct Scsi_Host * host) ! 669: { ! 670: return qinfo; ! 671: } ! 672: ! 673: #ifdef MODULE ! 674: /* Eventually this will go into an include file, but this will be later */ ! 675: Scsi_Host_Template driver_template = QLOGICFAS; ! 676: ! 677: #include "scsi_module.c" ! 678: #endif ! 679:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.