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

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