root/drivers/scsi/aha1740.c

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

DEFINITIONS

This source file includes following definitions.
  1. aha1740_makecode
  2. aha1740_test_port
  3. aha1740_info
  4. aha1740_intr_handle
  5. aha1740_queuecommand
  6. internal_done
  7. aha1740_command
  8. aha1740_getconfig
  9. aha1740_detect
  10. aha1740_abort
  11. aha1740_reset
  12. aha1740_biosparam

   1 /*  $Id$
   2  *  1993/03/31
   3  *  linux/kernel/aha1740.c
   4  *
   5  *  Based loosely on aha1542.c which is
   6  *  Copyright (C) 1992  Tommy Thorn and
   7  *  Modified by Eric Youngdale
   8  *
   9  *  This file is aha1740.c, written and
  10  *  Copyright (C) 1992,1993  Brad McLean
  11  *  
  12  *  Modifications to makecode and queuecommand
  13  *  for proper handling of multiple devices courteously
  14  *  provided by Michael Weller, March, 1993
  15  *
  16  * aha1740_makecode may still need even more work
  17  * if it doesn't work for your devices, take a look.
  18  */
  19 
  20 #include <linux/kernel.h>
  21 #include <linux/head.h>
  22 #include <linux/types.h>
  23 #include <linux/string.h>
  24 #include <linux/ioport.h>
  25 
  26 #include <linux/sched.h>
  27 #include <asm/dma.h>
  28 
  29 #include <asm/system.h>
  30 #include <asm/io.h>
  31 #include "../block/blk.h"
  32 #include "scsi.h"
  33 #include "hosts.h"
  34 #include "sd.h"
  35 
  36 #include "aha1740.h"
  37 
  38 /* IF YOU ARE HAVING PROBLEMS WITH THIS DRIVER, AND WANT TO WATCH
  39    IT WORK, THEN:
  40 #define DEBUG
  41 */
  42 #ifdef DEBUG
  43 #define DEB(x) x
  44 #else
  45 #define DEB(x)
  46 #endif
  47 
  48 /*
  49 static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/aha1740.c,v 1.1 1992/07/24 06:27:38 root Exp root $";
  50 */
  51 
  52 static unsigned int slot, base;
  53 static unsigned char irq_level;
  54 
  55 static struct ecb ecb[AHA1740_ECBS];    /* One for each queued operation */
  56 
  57 static int aha1740_last_ecb_used  = 0;  /* optimization */
  58 
  59 int aha1740_makecode(unchar *sense, unchar *status)
     /* [previous][next][first][last][top][bottom][index][help] */
  60 {
  61     struct statusword
  62     {
  63         ushort  don:1,  /* Command Done - No Error */
  64                 du:1,   /* Data underrun */
  65         :1,     qf:1,   /* Queue full */
  66                 sc:1,   /* Specification Check */
  67                 dor:1,  /* Data overrun */
  68                 ch:1,   /* Chaining Halted */
  69                 intr:1, /* Interrupt issued */
  70                 asa:1,  /* Additional Status Available */
  71                 sns:1,  /* Sense information Stored */
  72         :1,     ini:1,  /* Initialization Required */
  73                 me:1,   /* Major error or exception */
  74         :1,     eca:1,  /* Extended Contingent alliance */
  75         :1;
  76     } status_word;
  77     int retval = DID_OK;
  78 
  79     status_word = * (struct statusword *) status;
  80 #ifdef DEBUG
  81 printk("makecode from %x,%x,%x,%x %x,%x,%x,%x",status[0],status[1],status[2],status[3],
  82 sense[0],sense[1],sense[2],sense[3]);
  83 #endif
  84     if (!status_word.don) /* Anything abnormal was detected */
  85     {
  86         if ( (status[1]&0x18) || status_word.sc ) /*Additional info available*/
  87         {
  88             /* Use the supplied info for futher diagnostics */
  89             switch ( status[2] )
  90             {
  91             case 0x12:
  92                 if ( status_word.dor )
  93                     retval=DID_ERROR;   /* It's an Overrun */
  94                 /* If not overrun, assume underrun and ignore it! */
  95             case 0x00: /* No info, assume no error, should not occur */
  96                 break;
  97             case 0x11:
  98             case 0x21:
  99                 retval=DID_TIME_OUT;
 100                 break;
 101             case 0x0a:
 102                 retval=DID_BAD_TARGET;
 103                 break;
 104             case 0x04:
 105             case 0x05:
 106                 retval=DID_ABORT; /* Either by this driver or the AHA1740
 107                                          itself */
 108                 break;
 109             default:
 110                 retval=DID_ERROR; /* No further diagnostics possible */
 111             } 
 112         }
 113         else
 114         { /* Michael suggests, and Brad concurs: */
 115             if ( status_word.qf )
 116             {
 117                 retval = DID_TIME_OUT; /* forces a redo */
 118                 /* I think this specific one should not happen -Brad */
 119                 printk("aha1740.c: WARNING: AHA1740 queue overflow!\n");
 120             }
 121             else if ( status[0]&0x60 )
 122             {
 123                 retval = DID_ERROR; /* Didn't found a better error */
 124             }
 125             /* In any other case return DID_OK so for example
 126                CONDITION_CHECKS make it through to the appropriate
 127                device driver */
 128         }
 129     }
 130     /* Under all circumstances supply the target status -Michael */
 131     return status[3] | retval << 16;
 132 }
 133 
 134 int aha1740_test_port(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 135 {
 136     char    name[4],tmp;
 137 
 138     /* Okay, look for the EISA ID's */
 139     name[0]= 'A' -1 + ((tmp = inb(HID0)) >> 2); /* First character */
 140     name[1]= 'A' -1 + ((tmp & 3) << 3);
 141     name[1]+= ((tmp = inb(HID1)) >> 5)&0x7;     /* Second Character */
 142     name[2]= 'A' -1 + (tmp & 0x1f);             /* Third Character */
 143     name[3]=0;
 144     tmp = inb(HID2);
 145     if ( strcmp ( name, HID_MFG ) || inb(HID2) != HID_PRD )
 146         return 0;   /* Not an Adaptec 174x */
 147 
 148 /*  if ( inb(HID3) != HID_REV )
 149         printk("aha1740: Warning; board revision of %d; expected %d\n",
 150             inb(HID3),HID_REV); */
 151 
 152     if ( inb(EBCNTRL) != EBCNTRL_VALUE )
 153     {
 154         printk("aha1740: Board detected, but EBCNTRL = %x, so disabled it.\n",
 155             inb(EBCNTRL));
 156         return 0;
 157     }
 158 
 159     if ( inb(PORTADR) & PORTADDR_ENH )
 160         return 1;   /* Okay, we're all set */
 161         
 162     printk("aha1740: Board detected, but not in enhanced mode, so disabled it.\n");
 163     return 0;
 164 }
 165 
 166 const char *aha1740_info(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 167 {
 168     static char buffer[] = "Adaptec 174x (EISA)";
 169     return buffer;
 170 }
 171 
 172 /* A "high" level interrupt handler */
 173 void aha1740_intr_handle(int foo)
     /* [previous][next][first][last][top][bottom][index][help] */
 174 {
 175     void (*my_done)(Scsi_Cmnd *);
 176     int errstatus, adapstat;
 177     int number_serviced;
 178     struct ecb *ecbptr;
 179     Scsi_Cmnd *SCtmp;
 180 
 181     number_serviced = 0;
 182 
 183     while(inb(G2STAT) & G2STAT_INTPEND)
 184     {
 185         DEB(printk("aha1740_intr top of loop.\n"));
 186         adapstat = inb(G2INTST);
 187         outb(G2CNTRL_IRST,G2CNTRL); /* interrupt reset */
 188       
 189         switch ( adapstat & G2INTST_MASK )
 190         {
 191         case    G2INTST_CCBRETRY:
 192         case    G2INTST_CCBERROR:
 193         case    G2INTST_CCBGOOD:
 194             ecbptr = (struct ecb *) (   ((ulong) inb(MBOXIN0)) +
 195                                         ((ulong) inb(MBOXIN1) <<8) +
 196                                         ((ulong) inb(MBOXIN2) <<16) +
 197                                         ((ulong) inb(MBOXIN3) <<24) );
 198             outb(G2CNTRL_HRDY,G2CNTRL); /* Host Ready -> Mailbox in complete */
 199             SCtmp = ecbptr->SCpnt;
 200             if (SCtmp->host_scribble)
 201                 scsi_free(SCtmp->host_scribble, 512);
 202           /* Fetch the sense data, and tuck it away, in the required slot.  The
 203              Adaptec automatically fetches it, and there is no guarantee that
 204              we will still have it in the cdb when we come back */
 205             if ( (adapstat & G2INTST_MASK) == G2INTST_CCBERROR )
 206               {
 207                 memcpy(SCtmp->sense_buffer, ecbptr->sense, 
 208                        sizeof(SCtmp->sense_buffer));
 209                 errstatus = aha1740_makecode(ecbptr->sense,ecbptr->status);
 210               }
 211             else
 212                 errstatus = 0;
 213             DEB(if (errstatus) printk("aha1740_intr_handle: returning %6x\n", errstatus));
 214             SCtmp->result = errstatus;
 215             my_done = ecbptr->done;
 216             memset(ecbptr,0,sizeof(struct ecb)); 
 217             if ( my_done )
 218                 my_done(SCtmp);
 219             break;
 220         case    G2INTST_HARDFAIL:
 221             printk("aha1740 hardware failure!\n");
 222             panic("aha1740.c"); /* Goodbye */
 223         case    G2INTST_ASNEVENT:
 224             printk("aha1740 asynchronous event: %02x %02x %02x %02x %02x\n",adapstat,
 225                 inb(MBOXIN0),inb(MBOXIN1),inb(MBOXIN2),inb(MBOXIN3)); /* Say What? */
 226             outb(G2CNTRL_HRDY,G2CNTRL); /* Host Ready -> Mailbox in complete */
 227             break;
 228         case    G2INTST_CMDGOOD:
 229             /* set immediate command success flag here: */
 230             break;
 231         case    G2INTST_CMDERROR:
 232             /* Set immediate command failure flag here: */
 233             break;
 234         }
 235       number_serviced++;
 236     };
 237 }
 238 
 239 int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
     /* [previous][next][first][last][top][bottom][index][help] */
 240 {
 241     unchar direction;
 242     unchar *cmd = (unchar *) SCpnt->cmnd;
 243     unchar target = SCpnt->target;
 244     void *buff = SCpnt->request_buffer;
 245     int bufflen = SCpnt->request_bufflen;
 246     int ecbno;
 247     DEB(int i);
 248 
 249     
 250     if(*cmd == REQUEST_SENSE)
 251     {
 252         if (bufflen != sizeof(SCpnt->sense_buffer))
 253         {
 254             printk("Wrong buffer length supplied for request sense (%d)\n",bufflen);
 255         }
 256         SCpnt->result = 0;
 257         done(SCpnt); 
 258         return 0;
 259     }
 260 
 261 #ifdef DEBUG
 262     if (*cmd == READ_10 || *cmd == WRITE_10)
 263         i = xscsi2int(cmd+2);
 264     else if (*cmd == READ_6 || *cmd == WRITE_6)
 265         i = scsi2int(cmd+2);
 266     else
 267         i = -1;
 268     printk("aha1740_queuecommand: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen);
 269     printk("scsi cmd:");
 270     for (i = 0; i < (COMMAND_SIZE(*cmd)); i++) printk("%02x ", cmd[i]);
 271     printk("\n");
 272 #endif
 273 
 274     /* locate an available ecb */
 275 
 276     cli();
 277     ecbno = aha1740_last_ecb_used + 1;          /* An optimization */
 278     if (ecbno >= AHA1740_ECBS) ecbno = 0;
 279 
 280     do{
 281       if( ! ecb[ecbno].cmdw )
 282         break;
 283       ecbno++;
 284       if (ecbno >= AHA1740_ECBS ) ecbno = 0;
 285     } while (ecbno != aha1740_last_ecb_used);
 286 
 287     if( ecb[ecbno].cmdw )
 288       panic("Unable to find empty ecb for aha1740.\n");
 289 
 290     ecb[ecbno].cmdw = AHA1740CMD_INIT;  /* SCSI Initiator Command doubles as reserved flag */
 291 
 292     aha1740_last_ecb_used = ecbno;    
 293     sti();
 294 
 295 #ifdef DEBUG
 296     printk("Sending command (%d %x)...",ecbno, done);
 297 #endif
 298 
 299     ecb[ecbno].cdblen = COMMAND_SIZE(*cmd);     /* SCSI Command Descriptor Block Length */
 300 
 301     direction = 0;
 302     if (*cmd == READ_10 || *cmd == READ_6)
 303         direction = 1;
 304     else if (*cmd == WRITE_10 || *cmd == WRITE_6)
 305         direction = 0;
 306 
 307     memcpy(ecb[ecbno].cdb, cmd, ecb[ecbno].cdblen);
 308 
 309     if (SCpnt->use_sg)
 310     {
 311         struct scatterlist * sgpnt;
 312         struct aha1740_chain * cptr;
 313         int i;
 314 #ifdef DEBUG
 315         unsigned char * ptr;
 316 #endif
 317         ecb[ecbno].sg = 1;        /* SCSI Initiator Command  w/scatter-gather*/
 318         SCpnt->host_scribble = (unsigned char *) scsi_malloc(512);
 319         sgpnt = (struct scatterlist *) SCpnt->request_buffer;
 320         cptr = (struct aha1740_chain *) SCpnt->host_scribble; 
 321         if (cptr == NULL) panic("aha1740.c: unable to allocate DMA memory\n");
 322         for(i=0; i<SCpnt->use_sg; i++)
 323         {
 324             cptr[i].dataptr = (long) sgpnt[i].address;
 325             cptr[i].datalen = sgpnt[i].length;
 326         }
 327         ecb[ecbno].datalen = SCpnt->use_sg * sizeof(struct aha1740_chain);
 328         ecb[ecbno].dataptr = (long) cptr;
 329 #ifdef DEBUG
 330         printk("cptr %x: ",cptr);
 331         ptr = (unsigned char *) cptr;
 332         for(i=0;i<24;i++) printk("%02x ", ptr[i]);
 333 #endif
 334     }
 335     else
 336     {
 337         SCpnt->host_scribble = NULL;
 338         ecb[ecbno].datalen = bufflen;
 339         ecb[ecbno].dataptr = (long) buff;
 340     }
 341     ecb[ecbno].lun = SCpnt->lun;
 342     ecb[ecbno].ses = 1; /* Suppress underrun errors */
 343     ecb[ecbno].dir= direction;
 344     ecb[ecbno].ars=1;  /* Yes, get the sense on an error */
 345     ecb[ecbno].senselen = 12;
 346     ecb[ecbno].senseptr = (long) ecb[ecbno].sense;
 347     ecb[ecbno].statusptr = (long) ecb[ecbno].status;
 348     ecb[ecbno].done = done;
 349     ecb[ecbno].SCpnt = SCpnt;
 350 #ifdef DEBUG
 351     {
 352         int i;
 353         printk("aha1740_command: sending.. ");
 354         for (i = 0; i < sizeof(ecb[ecbno])-10; i++)
 355             printk("%02x ", ((unchar *)&ecb[ecbno])[i]);
 356     }
 357     printk("\n");
 358 #endif
 359     if (done)
 360     { /*  You may question the code below, which contains potentially
 361           non-terminating while loops with interrupts disabled.  So did
 362           I when I wrote it, but the Adaptec Spec says the card is so fast,
 363           that this problem virtually never occurs so I've kept it.  We
 364           do printk a warning first, so that you'll know if it happens.
 365           In practive the only time we've seen this message is when some-
 366           thing else is in the driver was broken, like _makecode(), or
 367           when a scsi device hung the scsi bus.  Even under these conditions,
 368           The loop actually only cycled < 3 times (we instrumented it). */
 369         ulong adrs;
 370 
 371         DEB(printk("aha1740[%d] critical section\n",ecbno));
 372         cli();
 373         if ( ! (inb(G2STAT) & G2STAT_MBXOUT) )
 374         {
 375             printk("aha1740[%d]_mbxout wait!\n",ecbno);
 376             cli(); /* printk may have done a sti()! */
 377         }
 378         while ( ! (inb(G2STAT) & G2STAT_MBXOUT) );      /* Oh Well. */
 379         adrs = (ulong) &(ecb[ecbno]);                   /* Spit the command */
 380         outb((char) (adrs&0xff), MBOXOUT0);             /* out, note this set */
 381         outb((char) ((adrs>>8)&0xff), MBOXOUT1);        /* of outb's must be */
 382         outb((char) ((adrs>>16)&0xff), MBOXOUT2);       /* atomic */
 383         outb((char) ((adrs>>24)&0xff), MBOXOUT3);
 384         if ( inb(G2STAT) & G2STAT_BUSY )
 385         {
 386             printk("aha1740[%d]_attn wait!\n",ecbno);
 387             cli();
 388         }
 389         while ( inb(G2STAT) & G2STAT_BUSY );            /* And Again! */
 390         outb(ATTN_START | (target & 7), ATTN);  /* Start it up */
 391         sti();
 392         DEB(printk("aha1740[%d] request queued.\n",ecbno));
 393     }
 394     else
 395       printk("aha1740_queuecommand: done can't be NULL\n");
 396     
 397     return 0;
 398 }
 399 
 400 static volatile int internal_done_flag = 0;
 401 static volatile int internal_done_errcode = 0;
 402 
 403 static void internal_done(Scsi_Cmnd * SCpnt)
     /* [previous][next][first][last][top][bottom][index][help] */
 404 {
 405     internal_done_errcode = SCpnt->result;
 406     ++internal_done_flag;
 407 }
 408 
 409 int aha1740_command(Scsi_Cmnd * SCpnt)
     /* [previous][next][first][last][top][bottom][index][help] */
 410 {
 411     aha1740_queuecommand(SCpnt, internal_done);
 412 
 413     while (!internal_done_flag);
 414     internal_done_flag = 0;
 415     return internal_done_errcode;
 416 }
 417 
 418 /* Query the board for its irq_level.  Nothing else matters
 419    in enhanced mode on an EISA bus. */
 420 
 421 void aha1740_getconfig(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 422 {
 423   static int intab[] = { 9,10,11,12,0,14,15,0 };
 424 
 425   irq_level = intab [ inb(INTDEF)&0x7 ];
 426 }
 427 
 428 int aha1740_detect(Scsi_Host_Template * tpnt)
     /* [previous][next][first][last][top][bottom][index][help] */
 429 {
 430     memset(&ecb, 0, sizeof(struct ecb));
 431     DEB(printk("aha1740_detect: \n"));
 432     
 433     for ( slot=MINEISA; slot <= MAXEISA; slot++ )
 434     {
 435         base = SLOTBASE(slot);
 436 
 437         /* The ioports for eisa boards are generally beyond that used in the
 438            check,snarf_region code, but this may change at some point, so we
 439            go through the motions. */
 440 
 441         if(check_region(base, 0x5c)) continue;  /* See if in use */
 442         if ( aha1740_test_port())  break;
 443     }
 444     if ( slot > MAXEISA )
 445         return 0;
 446 
 447     aha1740_getconfig();
 448 
 449     if ( (inb(G2STAT) & (G2STAT_MBXOUT | G2STAT_BUSY) ) != G2STAT_MBXOUT )
 450     {   /* If the card isn't ready, hard reset it */
 451         outb(G2CNTRL_HRST,G2CNTRL);
 452         outb(0,G2CNTRL);    
 453     }
 454 
 455     printk("Configuring Adaptec at IO:%x, IRQ %d\n",base,
 456            irq_level);
 457 
 458     DEB(printk("aha1740_detect: enable interrupt channel %d\n", irq_level));
 459 
 460     if (request_irq(irq_level,aha1740_intr_handle))
 461     {
 462         printk("Unable to allocate IRQ for adaptec controller.\n");
 463         return 0;
 464     }
 465     snarf_region(base, 0x5c);  /* Reserve the space that we need to use */
 466     return 1;
 467 }
 468 
 469 /* Note:  They following two functions do not apply very well to the Adaptec,
 470 which basically manages its own affairs quite well without our interference,
 471 so I haven't put anything into them.  I can faintly imagine someone with a
 472 *very* badly behaved SCSI target (perhaps an old tape?) wanting the abort(),
 473 but it hasn't happened yet, and doing aborts brings the Adaptec to its
 474 knees.  I cannot (at this moment in time) think of any reason to reset the
 475 card once it's running.  So there. */
 476 
 477 int aha1740_abort(Scsi_Cmnd * SCpnt)
     /* [previous][next][first][last][top][bottom][index][help] */
 478 {
 479     DEB(printk("aha1740_abort called\n"));
 480     return SCSI_ABORT_SNOOZE;
 481 }
 482 
 483 /* We do not implement a reset function here, but the upper level code assumes
 484    that it will get some kind of response for the command in SCpnt.  We must
 485    oblige, or the command will hang the scsi system */
 486 
 487 int aha1740_reset(Scsi_Cmnd * SCpnt)
     /* [previous][next][first][last][top][bottom][index][help] */
 488 {
 489     DEB(printk("aha1740_reset called\n"));
 490     return SCSI_RESET_PUNT;
 491 }
 492 
 493 int aha1740_biosparam(Disk * disk, int dev, int* ip)
     /* [previous][next][first][last][top][bottom][index][help] */
 494 {
 495   int size = disk->capacity;
 496 DEB(printk("aha1740_biosparam\n"));
 497   ip[0] = 64;
 498   ip[1] = 32;
 499   ip[2] = size >> 11;
 500 /*  if (ip[2] >= 1024) ip[2] = 1024; */
 501   return 0;
 502 }
 503 
 504 /* Okay, you made it all the way through.  As of this writing, 3/31/93, I'm
 505 brad@saturn.gaylord.com or brad@bradpc.gaylord.com.  I'll try to help as time
 506 permits if you have any trouble with this driver.  Happy Linuxing! */

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