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

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