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

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