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_intr_handle
  4. aha1740_queuecommand
  5. internal_done
  6. aha1740_command
  7. aha1740_getconfig
  8. aha1740_detect
  9. aha1740_abort
  10. aha1740_reset
  11. 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 further 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 /* A "high" level interrupt handler */
 167 void aha1740_intr_handle(int irq, struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 168 {
 169     void (*my_done)(Scsi_Cmnd *);
 170     int errstatus, adapstat;
 171     int number_serviced;
 172     struct ecb *ecbptr;
 173     Scsi_Cmnd *SCtmp;
 174 
 175     number_serviced = 0;
 176 
 177     while(inb(G2STAT) & G2STAT_INTPEND)
 178     {
 179         DEB(printk("aha1740_intr top of loop.\n"));
 180         adapstat = inb(G2INTST);
 181         outb(G2CNTRL_IRST,G2CNTRL); /* interrupt reset */
 182       
 183         switch ( adapstat & G2INTST_MASK )
 184         {
 185         case    G2INTST_CCBRETRY:
 186         case    G2INTST_CCBERROR:
 187         case    G2INTST_CCBGOOD:
 188             ecbptr = (struct ecb *) (   ((ulong) inb(MBOXIN0)) +
 189                                         ((ulong) inb(MBOXIN1) <<8) +
 190                                         ((ulong) inb(MBOXIN2) <<16) +
 191                                         ((ulong) inb(MBOXIN3) <<24) );
 192             outb(G2CNTRL_HRDY,G2CNTRL); /* Host Ready -> Mailbox in complete */
 193             if (!ecbptr)
 194             {
 195                 printk("Aha1740 null ecbptr in interrupt (%x,%x,%x,%d)\n",
 196                         inb(G2STAT),adapstat,inb(G2INTST),number_serviced++);
 197                 continue;
 198             }
 199             SCtmp = ecbptr->SCpnt;
 200             if (!SCtmp)
 201             {
 202                 printk("Aha1740 null SCtmp in interrupt (%x,%x,%x,%d)\n",
 203                         inb(G2STAT),adapstat,inb(G2INTST),number_serviced++);
 204                 continue;
 205             }
 206             if (SCtmp->host_scribble)
 207                 scsi_free(SCtmp->host_scribble, 512);
 208           /* Fetch the sense data, and tuck it away, in the required slot.  The
 209              Adaptec automatically fetches it, and there is no guarantee that
 210              we will still have it in the cdb when we come back */
 211             if ( (adapstat & G2INTST_MASK) == G2INTST_CCBERROR )
 212               {
 213                 memcpy(SCtmp->sense_buffer, ecbptr->sense, 
 214                        sizeof(SCtmp->sense_buffer));
 215                 errstatus = aha1740_makecode(ecbptr->sense,ecbptr->status);
 216               }
 217             else
 218                 errstatus = 0;
 219             DEB(if (errstatus) printk("aha1740_intr_handle: returning %6x\n", errstatus));
 220             SCtmp->result = errstatus;
 221             my_done = ecbptr->done;
 222             memset(ecbptr,0,sizeof(struct ecb)); 
 223             if ( my_done )
 224                 my_done(SCtmp);
 225             break;
 226         case    G2INTST_HARDFAIL:
 227             printk("aha1740 hardware failure!\n");
 228             panic("aha1740.c"); /* Goodbye */
 229         case    G2INTST_ASNEVENT:
 230             printk("aha1740 asynchronous event: %02x %02x %02x %02x %02x\n",adapstat,
 231                 inb(MBOXIN0),inb(MBOXIN1),inb(MBOXIN2),inb(MBOXIN3)); /* Say What? */
 232             outb(G2CNTRL_HRDY,G2CNTRL); /* Host Ready -> Mailbox in complete */
 233             break;
 234         case    G2INTST_CMDGOOD:
 235             /* set immediate command success flag here: */
 236             break;
 237         case    G2INTST_CMDERROR:
 238             /* Set immediate command failure flag here: */
 239             break;
 240         }
 241       number_serviced++;
 242     };
 243 }
 244 
 245 int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
     /* [previous][next][first][last][top][bottom][index][help] */
 246 {
 247     unchar direction;
 248     unchar *cmd = (unchar *) SCpnt->cmnd;
 249     unchar target = SCpnt->target;
 250     unsigned long flags;
 251     void *buff = SCpnt->request_buffer;
 252     int bufflen = SCpnt->request_bufflen;
 253     int ecbno;
 254     DEB(int i);
 255 
 256     
 257     if(*cmd == REQUEST_SENSE)
 258     {
 259         if (bufflen != sizeof(SCpnt->sense_buffer))
 260         {
 261             printk("Wrong buffer length supplied for request sense (%d)\n",bufflen);
 262         }
 263         SCpnt->result = 0;
 264         done(SCpnt); 
 265         return 0;
 266     }
 267 
 268 #ifdef DEBUG
 269     if (*cmd == READ_10 || *cmd == WRITE_10)
 270         i = xscsi2int(cmd+2);
 271     else if (*cmd == READ_6 || *cmd == WRITE_6)
 272         i = scsi2int(cmd+2);
 273     else
 274         i = -1;
 275     printk("aha1740_queuecommand: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen);
 276     printk("scsi cmd:");
 277     for (i = 0; i < SCpnt->cmd_len; i++) printk("%02x ", cmd[i]);
 278     printk("\n");
 279 #endif
 280 
 281     /* locate an available ecb */
 282 
 283     save_flags(flags);
 284     cli();
 285     ecbno = aha1740_last_ecb_used + 1;          /* An optimization */
 286     if (ecbno >= AHA1740_ECBS) ecbno = 0;
 287 
 288     do{
 289       if( ! ecb[ecbno].cmdw )
 290         break;
 291       ecbno++;
 292       if (ecbno >= AHA1740_ECBS ) ecbno = 0;
 293     } while (ecbno != aha1740_last_ecb_used);
 294 
 295     if( ecb[ecbno].cmdw )
 296       panic("Unable to find empty ecb for aha1740.\n");
 297 
 298     ecb[ecbno].cmdw = AHA1740CMD_INIT;  /* SCSI Initiator Command doubles as reserved flag */
 299 
 300     aha1740_last_ecb_used = ecbno;    
 301     restore_flags(flags);
 302 
 303 #ifdef DEBUG
 304     printk("Sending command (%d %x)...",ecbno, done);
 305 #endif
 306 
 307     ecb[ecbno].cdblen = SCpnt->cmd_len; /* SCSI Command Descriptor Block Length */
 308 
 309     direction = 0;
 310     if (*cmd == READ_10 || *cmd == READ_6)
 311         direction = 1;
 312     else if (*cmd == WRITE_10 || *cmd == WRITE_6)
 313         direction = 0;
 314 
 315     memcpy(ecb[ecbno].cdb, cmd, ecb[ecbno].cdblen);
 316 
 317     if (SCpnt->use_sg)
 318     {
 319         struct scatterlist * sgpnt;
 320         struct aha1740_chain * cptr;
 321         int i;
 322 #ifdef DEBUG
 323         unsigned char * ptr;
 324 #endif
 325         ecb[ecbno].sg = 1;        /* SCSI Initiator Command  w/scatter-gather*/
 326         SCpnt->host_scribble = (unsigned char *) scsi_malloc(512);
 327         sgpnt = (struct scatterlist *) SCpnt->request_buffer;
 328         cptr = (struct aha1740_chain *) SCpnt->host_scribble; 
 329         if (cptr == NULL) panic("aha1740.c: unable to allocate DMA memory\n");
 330         for(i=0; i<SCpnt->use_sg; i++)
 331         {
 332             cptr[i].dataptr = (long) sgpnt[i].address;
 333             cptr[i].datalen = sgpnt[i].length;
 334         }
 335         ecb[ecbno].datalen = SCpnt->use_sg * sizeof(struct aha1740_chain);
 336         ecb[ecbno].dataptr = (long) cptr;
 337 #ifdef DEBUG
 338         printk("cptr %x: ",cptr);
 339         ptr = (unsigned char *) cptr;
 340         for(i=0;i<24;i++) printk("%02x ", ptr[i]);
 341 #endif
 342     }
 343     else
 344     {
 345         SCpnt->host_scribble = NULL;
 346         ecb[ecbno].datalen = bufflen;
 347         ecb[ecbno].dataptr = (long) buff;
 348     }
 349     ecb[ecbno].lun = SCpnt->lun;
 350     ecb[ecbno].ses = 1; /* Suppress underrun errors */
 351     ecb[ecbno].dir= direction;
 352     ecb[ecbno].ars=1;  /* Yes, get the sense on an error */
 353     ecb[ecbno].senselen = 12;
 354     ecb[ecbno].senseptr = (long) ecb[ecbno].sense;
 355     ecb[ecbno].statusptr = (long) ecb[ecbno].status;
 356     ecb[ecbno].done = done;
 357     ecb[ecbno].SCpnt = SCpnt;
 358 #ifdef DEBUG
 359     {
 360         int i;
 361         printk("aha1740_command: sending.. ");
 362         for (i = 0; i < sizeof(ecb[ecbno])-10; i++)
 363             printk("%02x ", ((unchar *)&ecb[ecbno])[i]);
 364     }
 365     printk("\n");
 366 #endif
 367     if (done)
 368     { /*  You may question the code below, which contains potentially
 369           non-terminating while loops with interrupts disabled.  So did
 370           I when I wrote it, but the Adaptec Spec says the card is so fast,
 371           that this problem virtually never occurs so I've kept it.  We
 372           do printk a warning first, so that you'll know if it happens.
 373           In practice the only time we've seen this message is when some-
 374           thing else is in the driver was broken, like _makecode(), or
 375           when a scsi device hung the scsi bus.  Even under these conditions,
 376           The loop actually only cycled < 3 times (we instrumented it). */
 377         ulong adrs;
 378 
 379         DEB(printk("aha1740[%d] critical section\n",ecbno));
 380         save_flags(flags);
 381         cli();
 382         if ( ! (inb(G2STAT) & G2STAT_MBXOUT) )
 383         {
 384             printk("aha1740[%d]_mbxout wait!\n",ecbno);
 385             cli(); /* printk may have done a sti()! */
 386         }
 387         while ( ! (inb(G2STAT) & G2STAT_MBXOUT) );      /* Oh Well. */
 388         adrs = (ulong) &(ecb[ecbno]);                   /* Spit the command */
 389         outb((char) (adrs&0xff), MBOXOUT0);             /* out, note this set */
 390         outb((char) ((adrs>>8)&0xff), MBOXOUT1);        /* of outb's must be */
 391         outb((char) ((adrs>>16)&0xff), MBOXOUT2);       /* atomic */
 392         outb((char) ((adrs>>24)&0xff), MBOXOUT3);
 393         if ( inb(G2STAT) & G2STAT_BUSY )
 394         {
 395             printk("aha1740[%d]_attn wait!\n",ecbno);
 396             cli();
 397         }
 398         while ( inb(G2STAT) & G2STAT_BUSY );            /* And Again! */
 399         outb(ATTN_START | (target & 7), ATTN);  /* Start it up */
 400         restore_flags(flags);
 401         DEB(printk("aha1740[%d] request queued.\n",ecbno));
 402     }
 403     else
 404       printk("aha1740_queuecommand: done can't be NULL\n");
 405     
 406     return 0;
 407 }
 408 
 409 static volatile int internal_done_flag = 0;
 410 static volatile int internal_done_errcode = 0;
 411 
 412 static void internal_done(Scsi_Cmnd * SCpnt)
     /* [previous][next][first][last][top][bottom][index][help] */
 413 {
 414     internal_done_errcode = SCpnt->result;
 415     ++internal_done_flag;
 416 }
 417 
 418 int aha1740_command(Scsi_Cmnd * SCpnt)
     /* [previous][next][first][last][top][bottom][index][help] */
 419 {
 420     aha1740_queuecommand(SCpnt, internal_done);
 421 
 422     while (!internal_done_flag);
 423     internal_done_flag = 0;
 424     return internal_done_errcode;
 425 }
 426 
 427 /* Query the board for its irq_level.  Nothing else matters
 428    in enhanced mode on an EISA bus. */
 429 
 430 void aha1740_getconfig(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 431 {
 432   static int intab[] = { 9,10,11,12,0,14,15,0 };
 433 
 434   irq_level = intab [ inb(INTDEF)&0x7 ];
 435 }
 436 
 437 int aha1740_detect(Scsi_Host_Template * tpnt)
     /* [previous][next][first][last][top][bottom][index][help] */
 438 {
 439     memset(&ecb, 0, sizeof(struct ecb));
 440     DEB(printk("aha1740_detect: \n"));
 441     
 442     for ( slot=MINEISA; slot <= MAXEISA; slot++ )
 443     {
 444         base = SLOTBASE(slot);
 445 
 446         /* The ioports for eisa boards are generally beyond that used in the
 447            check,snarf_region code, but this may change at some point, so we
 448            go through the motions. */
 449 
 450         if(check_region(base, 0x5c)) continue;  /* See if in use */
 451         if ( aha1740_test_port())  break;
 452     }
 453     if ( slot > MAXEISA )
 454         return 0;
 455 
 456     aha1740_getconfig();
 457 
 458     if ( (inb(G2STAT) & (G2STAT_MBXOUT | G2STAT_BUSY) ) != G2STAT_MBXOUT )
 459     {   /* If the card isn't ready, hard reset it */
 460         outb(G2CNTRL_HRST,G2CNTRL);
 461         outb(0,G2CNTRL);    
 462     }
 463 
 464     printk("Configuring Adaptec at IO:%x, IRQ %d\n",base,
 465            irq_level);
 466 
 467     DEB(printk("aha1740_detect: enable interrupt channel %d\n", irq_level));
 468 
 469     if (request_irq(irq_level,aha1740_intr_handle, 0, "aha1740"))
 470     {
 471         printk("Unable to allocate IRQ for adaptec controller.\n");
 472         return 0;
 473     }
 474     request_region(base, 0x5c,"aha1740");  /* Reserve the space that we need to use */
 475     return 1;
 476 }
 477 
 478 /* Note:  They following two functions do not apply very well to the Adaptec,
 479 which basically manages its own affairs quite well without our interference,
 480 so I haven't put anything into them.  I can faintly imagine someone with a
 481 *very* badly behaved SCSI target (perhaps an old tape?) wanting the abort(),
 482 but it hasn't happened yet, and doing aborts brings the Adaptec to its
 483 knees.  I cannot (at this moment in time) think of any reason to reset the
 484 card once it's running.  So there. */
 485 
 486 int aha1740_abort(Scsi_Cmnd * SCpnt)
     /* [previous][next][first][last][top][bottom][index][help] */
 487 {
 488     DEB(printk("aha1740_abort called\n"));
 489     return SCSI_ABORT_SNOOZE;
 490 }
 491 
 492 /* We do not implement a reset function here, but the upper level code assumes
 493    that it will get some kind of response for the command in SCpnt.  We must
 494    oblige, or the command will hang the scsi system */
 495 
 496 int aha1740_reset(Scsi_Cmnd * SCpnt)
     /* [previous][next][first][last][top][bottom][index][help] */
 497 {
 498     DEB(printk("aha1740_reset called\n"));
 499     return SCSI_RESET_PUNT;
 500 }
 501 
 502 int aha1740_biosparam(Disk * disk, int dev, int* ip)
     /* [previous][next][first][last][top][bottom][index][help] */
 503 {
 504   int size = disk->capacity;
 505 DEB(printk("aha1740_biosparam\n"));
 506   ip[0] = 64;
 507   ip[1] = 32;
 508   ip[2] = size >> 11;
 509 /*  if (ip[2] >= 1024) ip[2] = 1024; */
 510   return 0;
 511 }
 512 
 513 /* Okay, you made it all the way through.  As of this writing, 3/31/93, I'm
 514 brad@saturn.gaylord.com or brad@bradpc.gaylord.com.  I'll try to help as time
 515 permits if you have any trouble with this driver.  Happy Linuxing! */

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