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: aha1740.c,v 1.1 1992/07/24 06:27:38 root Exp root $
   2  *  linux/kernel/aha1740.c
   3  *
   4  *  Based loosely on aha1542.c which is
   5  *  Copyright (C) 1992  Tommy Thorn
   6  *  and
   7  *  Modified by Eric Youngdale
   8  *
   9  *  This file is aha1740.c, written and
  10  *  Copyright (C) 1992  Brad McLean
  11  *  
  12  * aha1740_makecode needs more work
  13  */
  14 
  15 #include <linux/kernel.h>
  16 #include <linux/head.h>
  17 #include <linux/types.h>
  18 #include <linux/string.h>
  19 
  20 #include <linux/sched.h>
  21 #include <asm/dma.h>
  22 
  23 #include <asm/system.h>
  24 #include <asm/io.h>
  25 #include "../blk.h"
  26 #include "scsi.h"
  27 #include "hosts.h"
  28 
  29 #include "aha1740.h"
  30 /* #define DEBUG */
  31 #ifdef DEBUG
  32 #define DEB(x) x
  33 #else
  34 #define DEB(x)
  35 #endif
  36 /*
  37 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 $";
  38 */
  39 
  40 static unsigned int slot, base;
  41 static unsigned char irq_level;
  42 
  43 static struct ecb ecb[AHA1740_ECBS];    /* One for each queued operation */
  44 
  45 static int aha1740_last_ecb_used  = 0;  /* optimization */
  46 
  47 int aha1740_makecode(unchar *sense, unchar *status)
     /* [previous][next][first][last][top][bottom][index][help] */
  48 {
  49     struct statusword {
  50         ushort  don:1,  /* Command Done - No Error */
  51                 du:1,   /* Data underrun */
  52         :1,     qf:1,   /* Queue full */
  53                 sc:1,   /* Specification Check */
  54                 dor:1,  /* Data overrun */
  55                 ch:1,   /* Chaining Halted */
  56                 intr:1, /* Interrupt issued */
  57                 asa:1,  /* Additional Status Available */
  58                 sns:1,  /* Sense information Stored */
  59         :1,     ini:1,  /* Initialization Required */
  60                 me:1,   /* Major error or exception */
  61         :1,     eca:1, :1;  /* Extended Contingent alliance */
  62         } status_word;
  63     int retval = DID_OK;
  64 
  65     status_word = * (struct statusword *) status;
  66 #ifdef DEBUG
  67 printk("makecode from %x,%x,%x,%x %x,%x,%x,%x",status[0],status[1],status[2],status[3],
  68 sense[0],sense[1],sense[2],sense[3]);
  69 #endif
  70     if ( status_word.don )
  71         return 0;
  72 /*
  73     if ( status_word.du && status[2] != 0x11 )
  74         return 0;
  75 */
  76     if ( status[2] == 0x11 )
  77                 retval = DID_TIME_OUT;
  78     else
  79                 retval = DID_ERROR;    
  80     return status[3] | retval << 16; /* OKAY, SO I'M LAZY! I'll fix it later... */
  81 }
  82 
  83 int aha1740_test_port()
     /* [previous][next][first][last][top][bottom][index][help] */
  84 {
  85     char    name[4],tmp;
  86 
  87     /* Okay, look for the EISA ID's */
  88     name[0]= 'A' -1 + ((tmp = inb(HID0)) >> 2); /* First character */
  89     name[1]= 'A' -1 + ((tmp & 3) << 3);
  90     name[1]+= ((tmp = inb(HID1)) >> 5)&0x7;     /* Second Character */
  91     name[2]= 'A' -1 + (tmp & 0x1f);             /* Third Character */
  92     name[3]=0;
  93     tmp = inb(HID2);
  94     if ( strcmp ( name, HID_MFG ) || inb(HID2) != HID_PRD )
  95         return 0;   /* Not an Adaptec 174x */
  96 
  97 /*    if ( inb(HID3) < HID_REV ) */
  98     if ( inb(HID3) != HID_REV )
  99         printk("aha1740: Warning; board revision of %d; expected %d\n",
 100             inb(HID3),HID_REV);
 101 
 102     if ( inb(EBCNTRL) != EBCNTRL_VALUE )
 103     {
 104         printk("aha1740: Board detected, but EBCNTRL = %x, so disabled it.\n",
 105             inb(EBCNTRL));
 106         return 0;
 107     }
 108 
 109     if ( inb(PORTADR) & PORTADDR_ENH )
 110         return 1;   /* Okay, we're all set */
 111     printk("aha1740: Board detected, but not in enhanced mode, so disabled it.\n");
 112     return 0;
 113 }
 114 
 115 /* What's this little function for? */
 116 const char *aha1740_info(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 117 {
 118     static char buffer[] = "";                  /* looks nicer without anything here */
 119     return buffer;
 120 }
 121 
 122 /* A "high" level interrupt handler */
 123 void aha1740_intr_handle(int foo)
     /* [previous][next][first][last][top][bottom][index][help] */
 124 {
 125     void (*my_done)(Scsi_Cmnd *);
 126     int errstatus, adapstat;
 127     int number_serviced;
 128     struct ecb *ecbptr;
 129     Scsi_Cmnd *SCtmp;
 130 
 131     number_serviced = 0;
 132 
 133     while(inb(G2STAT) & G2STAT_INTPEND){
 134         DEB(printk("aha1740_intr top of loop.\n"));
 135         adapstat = inb(G2INTST);
 136         outb(G2CNTRL_IRST,G2CNTRL); /* interrupt reset */
 137       
 138         switch ( adapstat & G2INTST_MASK )
 139         {
 140         case    G2INTST_CCBRETRY:
 141             printk("aha1740 complete with retry!\n");
 142         case    G2INTST_CCBERROR:
 143         case    G2INTST_CCBGOOD:
 144             ecbptr = (void *) ( ((ulong) inb(MBOXIN0)) +
 145                                 ((ulong) inb(MBOXIN1) <<8) +
 146                                 ((ulong) inb(MBOXIN2) <<16) +
 147                                 ((ulong) inb(MBOXIN3) <<24) );
 148             outb(G2CNTRL_HRDY,G2CNTRL); /* Host Ready -> Mailbox in complete */
 149             SCtmp = ecbptr->SCpnt;
 150             if (SCtmp->host_scribble)
 151                 scsi_free(SCtmp->host_scribble, 512);
 152           /* Fetch the sense data, and tuck it away, in the required slot.  The
 153              Adaptec automatically fetches it, and there is no guarantee that
 154              we will still have it in the cdb when we come back */
 155             if ( (adapstat & G2INTST_MASK) == G2INTST_CCBERROR )
 156               {
 157                 memcpy(SCtmp->sense_buffer, ecbptr->sense, 
 158                        sizeof(SCtmp->sense_buffer));
 159                 errstatus = aha1740_makecode(ecbptr->sense,ecbptr->status);
 160               }
 161             else
 162                 errstatus = 0;
 163             DEB(if (errstatus) printk("aha1740_intr_handle: returning %6x\n", errstatus));
 164             SCtmp->result = errstatus;
 165             my_done = ecbptr->done;
 166             memset(ecbptr,0,sizeof(struct ecb)); 
 167             if ( my_done )
 168                 my_done(SCtmp);
 169             break;
 170         case    G2INTST_HARDFAIL:
 171             printk("aha1740 hardware failure!\n");
 172             panic("aha1740.c"); /* Goodbye */
 173         case    G2INTST_ASNEVENT:
 174             printk("aha1740 asynchronous event: %02x %02x %02x %02x %02x\n",adapstat,
 175                 inb(MBOXIN0),inb(MBOXIN1),inb(MBOXIN2),inb(MBOXIN3)); /* Say What? */
 176             outb(G2CNTRL_HRDY,G2CNTRL); /* Host Ready -> Mailbox in complete */
 177             break;
 178         case    G2INTST_CMDGOOD:
 179             /* set immediate command success flag here: */
 180             break;
 181         case    G2INTST_CMDERROR:
 182             /* Set immediate command failure flag here: */
 183             break;
 184         }
 185       number_serviced++;
 186     };
 187 }
 188 
 189 int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
     /* [previous][next][first][last][top][bottom][index][help] */
 190 {
 191     unchar direction;
 192     unchar *cmd = (unchar *) SCpnt->cmnd;
 193     unchar target = SCpnt->target;
 194     void *buff = SCpnt->request_buffer;
 195     int bufflen = SCpnt->request_bufflen;
 196     int ecbno;
 197     DEB(int i);
 198 
 199     DEB(if (target > 0 || SCpnt->lun > 0) {
 200       SCpnt->result = DID_TIME_OUT << 16;
 201       done(SCpnt); return 0;});
 202     
 203     if(*cmd == REQUEST_SENSE){
 204 #ifndef DEBUG
 205       if (bufflen != 16) {
 206         printk("Wrong buffer length supplied for request sense (%d)\n",bufflen);
 207         panic("aha1740.c");
 208       };
 209 #endif
 210       SCpnt->result = 0;
 211       done(SCpnt); 
 212       return 0;
 213     };
 214 
 215 #ifdef DEBUG
 216     if (*cmd == READ_10 || *cmd == WRITE_10)
 217       i = xscsi2int(cmd+2);
 218     else if (*cmd == READ_6 || *cmd == WRITE_6)
 219       i = scsi2int(cmd+2);
 220     else
 221       i = -1;
 222     if (done)
 223       printk("aha1740_queuecommand: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen);
 224     else
 225       printk("aha1740_command: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen);
 226     printk("scsi cmd:");
 227     for (i = 0; i < (*cmd<=0x1f?6:10); i++) printk("%02x ", cmd[i]);
 228     printk("\n");
 229 #ifdef 0
 230     if (*cmd == WRITE_10 || *cmd == WRITE_6)
 231       return 0; /* we are still testing, so *don't* write */
 232 #endif
 233 #endif
 234 
 235 /* locate an available ecb */
 236 
 237     cli();
 238     ecbno = aha1740_last_ecb_used + 1;
 239     if (ecbno >= AHA1740_ECBS) ecbno = 0;
 240 
 241     do{
 242       if( ! ecb[ecbno].cmdw )
 243         break;
 244       ecbno++;
 245       if (ecbno >= AHA1740_ECBS ) ecbno = 0;
 246     } while (ecbno != aha1740_last_ecb_used);
 247 
 248     if( ecb[ecbno].cmdw )
 249       panic("Unable to find empty ecb for aha1740.\n");
 250 
 251     ecb[ecbno].cmdw = AHA1740CMD_INIT;  /* SCSI Initiator Command to reserve*/
 252 
 253     aha1740_last_ecb_used = ecbno;    
 254     sti();
 255 
 256 #ifdef DEBUG
 257     printk("Sending command (%d %x)...",ecbno, done);
 258 #endif
 259 
 260     ecb[ecbno].cdblen = (*cmd<=0x1f)?6:10;      /* SCSI Command Descriptor Block Length */
 261 
 262     direction = 0;
 263     if (*cmd == READ_10 || *cmd == READ_6)
 264         direction = 1;
 265     else if (*cmd == WRITE_10 || *cmd == WRITE_6)
 266         direction = 0;
 267 
 268     memcpy(ecb[ecbno].cdb, cmd, ecb[ecbno].cdblen);
 269 
 270     if (SCpnt->use_sg) {
 271       struct scatterlist * sgpnt;
 272       struct aha1740_chain * cptr;
 273 #ifdef DEBUG
 274       unsigned char * ptr;
 275 #endif
 276       int i;
 277       ecb[ecbno].sg = 1;          /* SCSI Initiator Command  w/scatter-gather*/
 278       SCpnt->host_scribble = scsi_malloc(512);
 279       sgpnt = (struct scatterlist *) SCpnt->request_buffer;
 280       cptr = (struct aha1740_chain *) SCpnt->host_scribble; 
 281       if (cptr == NULL) panic("aha1740.c: unable to allocate DMA memory\n");
 282       for(i=0; i<SCpnt->use_sg; i++) {
 283         cptr[i].dataptr = (long) sgpnt[i].address;
 284         cptr[i].datalen = sgpnt[i].length;
 285       };
 286       ecb[ecbno].datalen = SCpnt->use_sg * sizeof(struct aha1740_chain);
 287       ecb[ecbno].dataptr = (long) cptr;
 288 #ifdef DEBUG
 289       printk("cptr %x: ",cptr);
 290       ptr = (unsigned char *) cptr;
 291       for(i=0;i<24;i++) printk("%02x ", ptr[i]);
 292 #endif
 293     } else {
 294       SCpnt->host_scribble = NULL;
 295       ecb[ecbno].datalen = bufflen;
 296       ecb[ecbno].dataptr = (long) buff;
 297     };
 298     ecb[ecbno].lun = SCpnt->lun;
 299     ecb[ecbno].ses = 1; /* Suppress underrun errors */
 300 /*    ecb[ecbno].dat=1; */ /* Yes, check the data direction */
 301     ecb[ecbno].dir= direction;
 302     ecb[ecbno].ars=1;  /* Yes, get the sense on an error */
 303     ecb[ecbno].senselen = 12;   /* Why 12? Eric? MAXSENSE? */
 304     ecb[ecbno].senseptr = (long) ecb[ecbno].sense;
 305     ecb[ecbno].statusptr = (long) ecb[ecbno].status;
 306     ecb[ecbno].done = done;
 307     ecb[ecbno].SCpnt = SCpnt;
 308 #ifdef DEBUG
 309     { int i;
 310     printk("aha1740_command: sending.. ");
 311     for (i = 0; i < sizeof(ecb[ecbno])-10; i++)
 312       printk("%02x ", ((unchar *)&ecb[ecbno])[i]);
 313     };
 314     printk("\n");
 315 #endif
 316     if (done) { ulong adrs;
 317 
 318         if ( ! (inb(G2STAT) & G2STAT_MBXOUT) )  /* Spec claim's it's so fast */
 319           printk("aha1740_mbxout wait!\n");     /* that this is okay? It seems */
 320         while ( ! (inb(G2STAT) & G2STAT_MBXOUT) ); /* to work, so I'll leave it */
 321         adrs = (ulong) &(ecb[ecbno]);
 322         outb((char) (adrs&0xff), MBOXOUT0);
 323         outb((char) ((adrs>>8)&0xff), MBOXOUT1);
 324         outb((char) ((adrs>>16)&0xff), MBOXOUT2);
 325         outb((char) ((adrs>>24)&0xff), MBOXOUT3);
 326         if ( inb(G2STAT) & G2STAT_BUSY )        /* Again, allegedly fast */
 327           printk("aha1740_attn wait!\n");
 328         while ( inb(G2STAT) & G2STAT_BUSY );
 329         outb(ATTN_START | (target & 7), ATTN);  /* Start it up */
 330     }
 331     else
 332       printk("aha1740_queuecommand: done can't be NULL\n");
 333     
 334     return 0;
 335 }
 336 
 337 static volatile int internal_done_flag = 0;
 338 static volatile int internal_done_errcode = 0;
 339 static void internal_done(Scsi_Cmnd * SCpnt)
     /* [previous][next][first][last][top][bottom][index][help] */
 340 {
 341     internal_done_errcode = SCpnt->result;
 342     ++internal_done_flag;
 343 }
 344 
 345 int aha1740_command(Scsi_Cmnd * SCpnt)
     /* [previous][next][first][last][top][bottom][index][help] */
 346 {
 347     aha1740_queuecommand(SCpnt, internal_done);
 348 
 349     while (!internal_done_flag);
 350     internal_done_flag = 0;
 351     return internal_done_errcode;
 352 }
 353 
 354 /* Query the board for it's port addresses, etc.  Actually, the irq_level is
 355     all we care about for this board, since it's EISA */
 356 
 357 static int aha1740_getconfig()
     /* [previous][next][first][last][top][bottom][index][help] */
 358 {
 359   int iop, bios, scsi, dma;
 360   static int iotab[] = { 0, 0, 0x130, 0x134, 0x230, 0x234, 0x330, 0x334 };
 361   static int intab[] = { 9,10,11,12,0,14,15,0 };
 362   static int dmatab[] = { 0,5,6,7 };
 363 
 364   iop = iotab [ inb(PORTADR)&0x7 ];
 365   bios = inb(BIOSADR);
 366   irq_level = intab [ inb(INTDEF)&0x7 ];
 367   scsi = inb(SCSIDEF);
 368   dma = dmatab[ (inb(BUSDEF)>>2) & 0x3 ];
 369   return 0;
 370 }
 371 
 372 int aha1740_detect(int hostnum)
     /* [previous][next][first][last][top][bottom][index][help] */
 373 {
 374     memset(ecb,0,sizeof(ecb));
 375     DEB(printk("aha1740_detect: \n"));
 376     
 377     for ( slot=MINEISA; slot <= MAXEISA; slot++ )
 378     {
 379         base = SLOTBASE(slot);
 380         if ( aha1740_test_port(base))  break;
 381     }
 382     if ( slot > MAXEISA )
 383         return 0;
 384 
 385     if (aha1740_getconfig() == -1)
 386         return 0;
 387 
 388     if ( (inb(G2STAT) & (G2STAT_MBXOUT | G2STAT_BUSY) ) != G2STAT_MBXOUT )
 389     {
 390         outb(G2CNTRL_HRST,G2CNTRL);
 391         /* 10 Msec Delay Here */
 392         outb(0,G2CNTRL);    
 393     }
 394 
 395     printk("Configuring Adaptec at IO:%x, IRQ %d\n",base,
 396            irq_level);
 397 
 398     DEB(printk("aha1740_detect: enable interrupt channel %d\n", irq_level));
 399 
 400     if (request_irq(irq_level,aha1740_intr_handle)) {
 401       printk("Unable to allocate IRQ for adaptec controller.\n");
 402       return 0;
 403     };
 404     return 1;
 405 }
 406 
 407 int aha1740_abort(Scsi_Cmnd * SCpnt, int i)
     /* [previous][next][first][last][top][bottom][index][help] */
 408 {
 409     DEB(printk("aha1740_abort\n"));
 410     return 0;
 411 }
 412 
 413 int aha1740_reset(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 414 {
 415     DEB(printk("aha1740_reset called\n"));
 416     return 0;
 417 }
 418 
 419 int aha1740_biosparam(int size, int dev, int* info){
     /* [previous][next][first][last][top][bottom][index][help] */
 420 DEB(printk("aha1740_biosparam\n"));
 421   info[0] = 64;
 422   info[1] = 32;
 423   info[2] = size >> 11;
 424   if (info[2] >= 1024) info[2] = 1024;
 425   return 0;
 426 }
 427 
 428 

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