root/drivers/scsi/qlogic.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ql_zap
  2. ql_pdma
  3. ql_wai
  4. ql_icmd
  5. ql_pcmd
  6. ql_ihandl
  7. qlidone
  8. qlogic_command
  9. qlogic_queuecommand
  10. qlogic_queuecommand
  11. qlogic_preset
  12. qlogic_detect
  13. qlogic_biosparam
  14. qlogic_abort
  15. qlogic_reset
  16. qlogic_info

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

/* [previous][next][first][last][top][bottom][index][help] */