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

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