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_detect
  12. qlogic_biosparam
  13. qlogic_abort
  14. qlogic_reset
  15. 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    Reference Qlogic FAS408 Technical Manual, 53408-510-00A, May 10, 1994
  15    (you can reference it, but it is incomplete and inaccurate in places)
  16 
  17    Version 0.38a
  18 
  19    This also works with loadable SCSI as a module.  Check configuration
  20    options QL_INT_ACTIVE_HIGH and QL_TURBO_PDMA for PCMCIA usage (which
  21    also requires an enabler).
  22 
  23    Redistributable under terms of the GNU Public License
  24 
  25 */
  26 /*----------------------------------------------------------------*/
  27 /* Configuration */
  28 
  29 /* Set the following to 2 to use normal interrupt (active high/totempole-
  30    tristate), otherwise use 0 (REQUIRED FOR PCMCIA) for active low, open
  31    drain */
  32 #define QL_INT_ACTIVE_HIGH 2
  33 
  34 /* Set the following to 1 to enable the use of interrupts.  Note that 0 tends
  35    to be more stable, but slower (or ties up the system more) */
  36 #define QL_USE_IRQ 1
  37 
  38 /* Set the following to max out the speed of the PIO PseudoDMA transfers,
  39    again, 0 tends to be slower, but more stable.  THIS SHOULD BE ZERO FOR
  40    PCMCIA */
  41 #define QL_TURBO_PDMA 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 #define QL_RESET_AT_START 1
  47 
  48 /* This will set fast (10Mhz) synchronous timing, FASTCLK must also be 1*/
  49 #define FASTSCSI  0
  50 
  51 /* This will set a faster sync transfer rate */
  52 #define FASTCLK   0
  53 
  54 /* This bit needs to be set to 1 if your cabling is long or noisy */
  55 #define SLOWCABLE 0
  56 
  57 /* This is the sync transfer divisor, 40Mhz/X will be the data rate
  58         The power on default is 5, the maximum normal value is 5 */
  59 #define SYNCXFRPD 4
  60 
  61 /* This is the count of how many synchronous transfers can take place
  62         i.e. how many reqs can occur before an ack is given.
  63         The maximum value for this is 15, the upper bits can modify
  64         REQ/ACK assertion and deassertion during synchronous transfers
  65         If this is 0, the bus will only transfer asynchronously */
  66 #define SYNCOFFST 0
  67 /* for the curious, bits 7&6 control the deassertion delay in 1/2 cycles
  68         of the 40Mhz clock. If FASTCLK is 1, specifying 01 (1/2) will
  69         cause the deassertion to be early by 1/2 clock.  Bits 5&4 control
  70         the assertion delay, also in 1/2 clocks (FASTCLK is ignored here). */
  71 
  72 /*----------------------------------------------------------------*/
  73 
  74 #include "../block/blk.h"       /* to get disk capacity */
  75 #include <linux/kernel.h>
  76 #include <linux/string.h>
  77 #include <linux/ioport.h>
  78 #include <linux/sched.h>
  79 #include <unistd.h>
  80 #include <asm/io.h>
  81 #include <asm/irq.h>
  82 #include "sd.h"
  83 #include "hosts.h"
  84 #include "qlogic.h"
  85 
  86 /*----------------------------------------------------------------*/
  87 /* driver state info, local to driver */
  88 static int          qbase;      /* Port */
  89 static int          qinitid;    /* initiator ID */
  90 static int          qabort;     /* Flag to cause an abort */
  91 static int          qlirq;      /* IRQ being used */
  92 static char         qinfo[80];  /* description */
  93 static Scsi_Cmnd   *qlcmd;      /* current command being processed */
  94 
  95 /*----------------------------------------------------------------*/
  96 
  97 #define REG0 ( outb( inb( qbase + 0xd ) & 0x7f , qbase + 0xd ), outb( 4 , qbase + 0xd ))
  98 #define REG1 ( outb( inb( qbase + 0xd ) | 0x80 , qbase + 0xd ), outb( 0xb4 | QL_INT_ACTIVE_HIGH , qbase + 0xd ))
  99 
 100 /* following is watchdog timeout */
 101 #define WATCHDOG 5000000
 102 
 103 /*----------------------------------------------------------------*/
 104 /* the following will set the monitor border color (useful to find
 105    where something crashed or gets stuck at and as a simple profiler) */
 106 
 107 #if 0
 108 #define rtrc(i) {inb(0x3da);outb(0x31,0x3c0);outb((i),0x3c0);}
 109 #else
 110 #define rtrc(i) {}
 111 #endif
 112 
 113 /*----------------------------------------------------------------*/
 114 /* local functions */
 115 /*----------------------------------------------------------------*/
 116 static void     ql_zap(void);
 117 /* error recovery - reset everything */
 118 void    ql_zap()
     /* [previous][next][first][last][top][bottom][index][help] */
 119 {
 120 int     x;
 121         cli();
 122         x = inb(qbase + 0xd);
 123         REG0;
 124         outb(3, qbase + 3);                             /* reset SCSI */
 125         outb(2, qbase + 3);                             /* reset chip */
 126         if (x & 0x80)
 127                 REG1;
 128         sti();
 129 }
 130 
 131 /*----------------------------------------------------------------*/
 132 /* do pseudo-dma */
 133 static int      ql_pdma(int phase, char *request, int reqlen)
     /* [previous][next][first][last][top][bottom][index][help] */
 134 {
 135 int     j;
 136         j = 0;
 137         if (phase & 1) {        /* in */
 138 #if QL_TURBO_PDMA
 139                 /* empty fifo in large chunks */
 140                 if( reqlen >= 128 && (inb( qbase + 8 ) & 2) ) { /* full */
 141                         insl( qbase + 4, request, 32 );
 142                         reqlen -= 128;
 143                         request += 128;
 144                 }
 145                 while( reqlen >= 84 && !( j & 0xc0 ) ) /* 2/3 */
 146                         if( (j=inb( qbase + 8 )) & 4 ) {
 147                                 insl( qbase + 4, request, 21 );
 148                                 reqlen -= 84;
 149                                 request += 84;
 150                         }
 151                 if( reqlen >= 44 && (inb( qbase + 8 ) & 8) ) {  /* 1/3 */
 152                         insl( qbase + 4, request, 11 );
 153                         reqlen -= 44;
 154                         request += 44;
 155                 }
 156 #endif
 157                 /* until both empty and int (or until reclen is 0) */
 158                 j = 0;
 159                 while( reqlen && !( (j & 0x10) && (j & 0xc0) ) ) {
 160                         /* while bytes to receive and not empty */
 161                         j &= 0xc0;
 162                         while ( reqlen && !( (j=inb(qbase + 8)) & 0x10 ) ) {
 163                                 *request++ = inb(qbase + 4);
 164                                 reqlen--;
 165                         }
 166                         if( j & 0x10 )
 167                                 j = inb(qbase+8);
 168 
 169                 }
 170         }
 171         else {  /* out */
 172 #if QL_TURBO_PDMA
 173                 if( reqlen >= 128 && inb( qbase + 8 ) & 0x10 ) { /* empty */
 174                         outsl(qbase + 4, request, 32 );
 175                         reqlen -= 128;
 176                         request += 128;
 177                 }
 178                 while( reqlen >= 84 && !( j & 0xc0 ) ) /* 1/3 */
 179                         if( !((j=inb( qbase + 8 )) & 8) ) {
 180                                 outsl( qbase + 4, request, 21 );
 181                                 reqlen -= 84;
 182                                 request += 84;
 183                         }
 184                 if( reqlen >= 40 && !(inb( qbase + 8 ) & 4 ) ) { /* 2/3 */
 185                         outsl( qbase + 4, request, 10 );
 186                         reqlen -= 40;
 187                         request += 40;
 188                 }
 189 #endif
 190                 /* until full and int (or until reclen is 0) */
 191                 j = 0;
 192                 while( reqlen && !( (j & 2) && (j & 0xc0) ) ) {
 193                         /* while bytes to send and not full */
 194                         while ( reqlen && !( (j=inb(qbase + 8)) & 2 ) ) {
 195                                 outb(*request++, qbase + 4);
 196                                 reqlen--;
 197                         }
 198                         if( j & 2 )
 199                                 j = inb(qbase+8);
 200                 }
 201         }
 202 /* maybe return reqlen */
 203         return inb( qbase + 8 ) & 0xc0;
 204 }
 205 
 206 /*----------------------------------------------------------------*/
 207 /* wait for interrupt flag (polled - not real hardware interrupt) */
 208 static int      ql_wai(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 209 {
 210 int     i,k;
 211         i = jiffies + WATCHDOG;
 212         while ( i > jiffies && !qabort && !((k = inb(qbase + 4)) & 0xe0));
 213         if (i <= jiffies)
 214                 return (DID_TIME_OUT);
 215         if (qabort)
 216                 return (qabort == 1 ? DID_ABORT : DID_RESET);
 217         if (k & 0x60)
 218                 ql_zap();
 219         if (k & 0x20)
 220                 return (DID_PARITY);
 221         if (k & 0x40)
 222                 return (DID_ERROR);
 223         return 0;
 224 }
 225 
 226 /*----------------------------------------------------------------*/
 227 /* initiate scsi command - queueing handler */
 228 static void     ql_icmd(Scsi_Cmnd * cmd)
     /* [previous][next][first][last][top][bottom][index][help] */
 229 {
 230 unsigned int        i;
 231         qabort = 0;
 232 
 233         cli();
 234         REG0;
 235 /* clearing of interrupts and the fifo is needed */
 236         inb(qbase + 5);                         /* clear interrupts */
 237         if (inb(qbase + 5))                     /* if still interrupting */
 238                 outb(2, qbase + 3);             /* reset chip */
 239         else if (inb(qbase + 7) & 0x1f)
 240                 outb(1, qbase + 3);             /* clear fifo */
 241         while (inb(qbase + 5));                 /* clear ints */
 242         REG1;
 243         outb(1, qbase + 8);                     /* set for PIO pseudo DMA */
 244         outb(0, qbase + 0xb);                   /* disable ints */
 245         inb(qbase + 8);                         /* clear int bits */
 246         REG0;
 247         outb(0x40, qbase + 0xb);                /* enable features */
 248 
 249 /* configurables */
 250 #if FASTSCSI
 251 #if FASTCLK
 252         outb(0x18, qbase + 0xc);
 253 #else
 254         outb(0x10, qbase + 0xc);
 255 #endif
 256 #else
 257 #if FASTCLK
 258         outb(8, qbase + 0xc);
 259 #endif
 260 #endif
 261 
 262 #if SLOWCABLE
 263         outb(0xd0 | qinitid, qbase + 8);        /* (initiator) bus id */
 264 #else
 265         outb(0x50 | qinitid, qbase + 8);        /* (initiator) bus id */
 266 #endif
 267         outb( SYNCOFFST , qbase + 7 );
 268         outb( SYNCXFRPD , qbase + 6 );
 269 /**/
 270         outb(0x99, qbase + 5);  /* timer */
 271         outb(cmd->target, qbase + 4);
 272 
 273         for (i = 0; i < cmd->cmd_len; i++)
 274                 outb(cmd->cmnd[i], qbase + 2);
 275         qlcmd = cmd;
 276         outb(0x41, qbase + 3);  /* select and send command */
 277         sti();
 278 }
 279 /*----------------------------------------------------------------*/
 280 /* process scsi command - usually after interrupt */
 281 static unsigned int     ql_pcmd(Scsi_Cmnd * cmd)
     /* [previous][next][first][last][top][bottom][index][help] */
 282 {
 283 unsigned int    i, j, k;
 284 unsigned int    result;                 /* ultimate return result */
 285 unsigned int    status;                 /* scsi returned status */
 286 unsigned int    message;                /* scsi returned message */
 287 unsigned int    phase;                  /* recorded scsi phase */
 288 unsigned int    reqlen;                 /* total length of transfer */
 289 struct scatterlist      *sglist;        /* scatter-gather list pointer */
 290 unsigned int    sgcount;                /* sg counter */
 291 
 292         j = inb(qbase + 6);
 293         i = inb(qbase + 5);
 294         if (i == 0x20) {
 295                 return (DID_NO_CONNECT << 16);
 296         }
 297         i |= inb(qbase + 5);    /* the 0x10 bit can be set after the 0x08 */
 298         if (i != 0x18) {
 299                 printk("Ql:Bad Interrupt status:%02x\n", i);
 300                 ql_zap();
 301                 return (DID_BAD_INTR << 16);
 302         }
 303         j &= 7; /* j = inb( qbase + 7 ) >> 5; */
 304 /* correct status is supposed to be step 4 */
 305 /* it sometimes returns step 3 but with 0 bytes left to send */
 306 /* We can try stuffing the FIFO with the max each time, but we will get a
 307    sequence of 3 if any bytes are left (but we do flush the FIFO anyway */
 308         if(j != 3 && j != 4) {
 309                 printk("Ql:Bad sequence for command %d, int %02X, cmdleft = %d\n", j, i, inb( qbase+7 ) & 0x1f );
 310                 ql_zap();
 311                 return (DID_ERROR << 16);
 312         }
 313         result = DID_OK;
 314         if (inb(qbase + 7) & 0x1f)      /* if some bytes in fifo */
 315                 outb(1, qbase + 3);             /* clear fifo */
 316 /* note that request_bufflen is the total xfer size when sg is used */
 317         reqlen = cmd->request_bufflen;
 318 /* note that it won't work if transfers > 16M are requested */
 319         if (reqlen && !((phase = inb(qbase + 4)) & 6)) {        /* data phase */
 320 rtrc(1)
 321                 outb(reqlen, qbase);                    /* low-mid xfer cnt */
 322                 outb(reqlen >> 8, qbase+1);                     /* low-mid xfer cnt */
 323                 outb(reqlen >> 16, qbase + 0xe);        /* high xfer cnt */
 324                 outb(0x90, qbase + 3);                  /* command do xfer */
 325 /* PIO pseudo DMA to buffer or sglist */
 326                 REG1;
 327                 if (!cmd->use_sg)
 328                         ql_pdma(phase, cmd->request_buffer, cmd->request_bufflen);
 329                 else {
 330                         sgcount = cmd->use_sg;
 331                         sglist = cmd->request_buffer;
 332                         while (sgcount--) {
 333                                 if (qabort) {
 334                                         REG0;
 335                                         return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16);
 336                                 }
 337                                 if (ql_pdma(phase, sglist->address, sglist->length))
 338                                         break;
 339                                 sglist++;
 340                         }
 341                 }
 342                 REG0;
 343 rtrc(2)
 344 /* wait for irq (split into second state of irq handler if this can take time) */
 345                 if ((k = ql_wai()))
 346                         return (k << 16);
 347                 k = inb(qbase + 5);     /* should be 0x10, bus service */
 348         }
 349 /*** Enter Status (and Message In) Phase ***/
 350         k = jiffies + WATCHDOG;
 351 rtrc(4)
 352         while ( k > jiffies && !qabort && !(inb(qbase + 4) & 6));       /* wait for status phase */
 353         if ( k <= jiffies ) {
 354                 ql_zap();
 355                 return (DID_TIME_OUT << 16);
 356         }
 357         while (inb(qbase + 5));                                 /* clear pending ints */
 358         if (qabort)
 359                 return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16);
 360         outb(0x11, qbase + 3);                                  /* get status and message */
 361         if ((k = ql_wai()))
 362                 return (k << 16);
 363         i = inb(qbase + 5);                                     /* get chip irq stat */
 364         j = inb(qbase + 7) & 0x1f;                              /* and bytes rec'd */
 365         status = inb(qbase + 2);
 366         message = inb(qbase + 2);
 367 /* should get function complete int if Status and message, else bus serv if only status */
 368         if (!((i == 8 && j == 2) || (i == 0x10 && j == 1))) {
 369                 printk("Ql:Error during status phase, int=%02X, %d bytes recd\n", i, j);
 370                 result = DID_ERROR;
 371         }
 372         outb(0x12, qbase + 3);  /* done, disconnect */
 373 rtrc(3)
 374         if ((k = ql_wai()))
 375                 return (k << 16);
 376 /* should get bus service interrupt and disconnect interrupt */
 377         i = inb(qbase + 5);     /* should be bus service */
 378         while (!qabort && ((i & 0x20) != 0x20))
 379                 i |= inb(qbase + 5);
 380 rtrc(0)
 381         if (qabort)
 382                 return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16);
 383         return (result << 16) | (message << 8) | (status & STATUS_MASK);
 384 }
 385 
 386 #if QL_USE_IRQ
 387 /*----------------------------------------------------------------*/
 388 /* interrupt handler */
 389 static void                 ql_ihandl(int irq)
     /* [previous][next][first][last][top][bottom][index][help] */
 390 {
 391 Scsi_Cmnd          *icmd;
 392         REG0;
 393         if (!(inb(qbase + 4) & 0x80))   /* false alarm? */
 394                 return;
 395         if (qlcmd == NULL) {            /* no command to process? */
 396                 while (inb(qbase + 5)); /* maybe also ql_zap() */
 397                 return;
 398         }
 399         icmd = qlcmd;
 400         icmd->result = ql_pcmd(icmd);
 401         qlcmd = NULL;
 402 /* if result is CHECK CONDITION done calls qcommand to request sense */
 403         (icmd->scsi_done) (icmd);
 404 }
 405 #endif
 406 
 407 /*----------------------------------------------------------------*/
 408 /* global functions */
 409 /*----------------------------------------------------------------*/
 410 /* non queued command */
 411 #if QL_USE_IRQ
 412 static void     qlidone(Scsi_Cmnd * cmd) {};            /* null function */
     /* [previous][next][first][last][top][bottom][index][help] */
 413 #endif
 414 
 415 /* command process */
 416 int     qlogic_command(Scsi_Cmnd * cmd)
     /* [previous][next][first][last][top][bottom][index][help] */
 417 {
 418 int     k;
 419 #if QL_USE_IRQ
 420         if (qlirq >= 0) {
 421                 qlogic_queuecommand(cmd, qlidone);
 422                 while (qlcmd != NULL);
 423                 return cmd->result;
 424         }
 425 #endif
 426 /* non-irq version */
 427         if (cmd->target == qinitid)
 428                 return (DID_BAD_TARGET << 16);
 429         ql_icmd(cmd);
 430         if ((k = ql_wai()))
 431                 return (k << 16);
 432         return ql_pcmd(cmd);
 433 
 434 }
 435 
 436 #if QL_USE_IRQ
 437 /*----------------------------------------------------------------*/
 438 /* queued command */
 439 int     qlogic_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
     /* [previous][next][first][last][top][bottom][index][help] */
 440 {
 441         if(cmd->target == qinitid) {
 442                 cmd->result = DID_BAD_TARGET << 16;
 443                 done(cmd);
 444                 return 0;
 445         }
 446 
 447         cmd->scsi_done = done;
 448 /* wait for the last command's interrupt to finish */
 449         while (qlcmd != NULL);
 450         ql_icmd(cmd);
 451         return 0;
 452 }
 453 #else
 454 int     qlogic_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
     /* [previous][next][first][last][top][bottom][index][help] */
 455 {
 456         return 1;
 457 }
 458 #endif
 459 
 460 /*----------------------------------------------------------------*/
 461 /* look for qlogic card and init if found */
 462 int     qlogic_detect(Scsi_Host_Template * host)
     /* [previous][next][first][last][top][bottom][index][help] */
 463 {
 464 int     i, j;                   /* these are only used by IRQ detect */
 465 int     qltyp;                  /* type of chip */
 466 struct  Scsi_Host       *hreg;  /* registered host structure */
 467 
 468 /* Qlogic Cards only exist at 0x230 or 0x330 (the chip itself decodes the
 469    address - I check 230 first since MIDI cards are typically at 330
 470    Note that this will not work for 2 Qlogic cards in 1 system.  The
 471    easiest way to do that is to create 2 versions of this file, one for
 472    230 and one for 330.
 473 
 474    Alternately, the Scsi_Host structure now stores the i/o port and can
 475    be used to set the port (go through and replace qbase with
 476    (struct Scsi_Cmnd *) cmd->host->io_port, or for efficiency, set a local
 477    copy of qbase.  There will also need to be something similar within the
 478    IRQ handlers to sort out which board it came from and thus which port.
 479 */
 480 
 481         for (qbase = 0x230; qbase < 0x430; qbase += 0x100) {
 482                 if( check_region( qbase , 0x10 ) )
 483                         continue;
 484                 REG1;
 485                 if ( ( (inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7 )
 486                   && ( (inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7 ) )
 487                         break;
 488         }
 489         if (qbase == 0x430)
 490                 return 0;
 491 
 492         qltyp = inb(qbase + 0xe) & 0xf8;
 493         qinitid = host->this_id;
 494         if (qinitid < 0)
 495                 qinitid = 7;                    /* if no ID, use 7 */
 496         outb(1, qbase + 8);                     /* set for PIO pseudo DMA */
 497         REG0;
 498         outb(0xd0 | qinitid, qbase + 8);        /* (ini) bus id, disable scsi rst */
 499         outb(0x99, qbase + 5);                  /* select timer */
 500         qlirq = -1;
 501 #if QL_RESET_AT_START
 502         outb( 3 , qbase + 3 );
 503         REG1;
 504         while( inb( qbase + 0xf ) & 4 );
 505         REG0;
 506 #endif
 507 #if QL_USE_IRQ
 508 /* IRQ probe - toggle pin and check request pending */
 509         cli();
 510         i = 0xffff;
 511         j = 3;
 512         outb(0x90, qbase + 3);  /* illegal command - cause interrupt */
 513         REG1;
 514         outb(10, 0x20); /* access pending interrupt map */
 515         outb(10, 0xa0);
 516         while (j--) {
 517                 outb(0xb0 | QL_INT_ACTIVE_HIGH , qbase + 0xd);          /* int pin off */
 518                 i &= ~(inb(0x20) | (inb(0xa0) << 8));   /* find IRQ off */
 519                 outb(0xb4 | QL_INT_ACTIVE_HIGH , qbase + 0xd);          /* int pin on */
 520                 i &= inb(0x20) | (inb(0xa0) << 8);      /* find IRQ on */
 521         }
 522         REG0;
 523         while (inb(qbase + 5));                         /* purge int */
 524         while (i)                                       /* find on bit */
 525                 i >>= 1, qlirq++;       /* should check for exactly 1 on */
 526         if (qlirq >= 0 && !request_irq(qlirq, ql_ihandl, SA_INTERRUPT, "qlogic"))
 527                 host->can_queue = 1;
 528         sti();
 529 #endif
 530         request_region( qbase , 0x10 ,"qlogic");
 531 
 532         hreg = scsi_register( host , 0 );       /* no host data */
 533         hreg->io_port = qbase;
 534         hreg->n_io_port = 16;
 535         if( qlirq != -1 )
 536                 hreg->irq = qlirq;
 537 
 538         sprintf(qinfo, "Qlogic Driver version 0.38a, chip %02X at %03X, IRQ %d", qltyp, qbase, qlirq);
 539         host->name = qinfo;
 540 
 541         return 1;
 542 }
 543 
 544 /*----------------------------------------------------------------*/
 545 /* return bios parameters */
 546 int     qlogic_biosparam(Disk * disk, int dev, int ip[])
     /* [previous][next][first][last][top][bottom][index][help] */
 547 {
 548 /* This should mimic the DOS Qlogic driver's behavior exactly */
 549         ip[0] = 0x40;
 550         ip[1] = 0x20;
 551         ip[2] = disk->capacity / (ip[0] * ip[1]);
 552         if (ip[2] > 1024) {
 553                 ip[0] = 0xff;
 554                 ip[1] = 0x3f;
 555                 ip[2] = disk->capacity / (ip[0] * ip[1]);
 556                 if (ip[2] > 1023)
 557                         ip[2] = 1023;
 558         }
 559         return 0;
 560 }
 561 
 562 /*----------------------------------------------------------------*/
 563 /* abort command in progress */
 564 int     qlogic_abort(Scsi_Cmnd * cmd)
     /* [previous][next][first][last][top][bottom][index][help] */
 565 {
 566         qabort = 1;
 567         ql_zap();
 568         return 0;
 569 }
 570 
 571 /*----------------------------------------------------------------*/
 572 /* reset SCSI bus */
 573 int     qlogic_reset(Scsi_Cmnd * cmd)
     /* [previous][next][first][last][top][bottom][index][help] */
 574 {
 575         qabort = 2;
 576         ql_zap();
 577         return 1;
 578 }
 579 
 580 /*----------------------------------------------------------------*/
 581 /* return info string */
 582 const char      *qlogic_info(struct Scsi_Host * host)
     /* [previous][next][first][last][top][bottom][index][help] */
 583 {
 584         return qinfo;
 585 }
 586 
 587 #ifdef MODULE
 588 /* Eventually this will go into an include file, but this will be later */
 589 Scsi_Host_Template driver_template = QLOGIC;
 590 
 591 #include "scsi_module.c"
 592 #endif

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