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

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