root/kernel/blk_drv/scsi/aha1542.c

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

DEFINITIONS

This source file includes following definitions.
  1. aha1542_stat
  2. aha1542_out
  3. aha1542_in
  4. makecode
  5. aha1542_test_port
  6. aha1542_info
  7. aha1542_intr_handle
  8. aha1542_queuecommand
  9. internal_done
  10. aha1542_command
  11. setup_mailboxes
  12. call_buh
  13. aha1542_query
  14. aha1542_detect
  15. aha1542_abort
  16. aha1542_reset

   1 /* $Id: aha1542.c,v 1.1 1992/07/24 06:27:38 root Exp root $
   2  *  linux/kernel/aha1542.c
   3  *
   4  *  Copyright (C) 1992  Tommy Thorn
   5  */
   6 
   7 #include <linux/config.h>
   8 #include <linux/kernel.h>
   9 #include <linux/head.h>
  10 #include <linux/types.h>
  11 #include <linux/string.h>
  12 
  13 #include <asm/system.h>
  14 #include <asm/io.h>
  15 #include "scsi.h"
  16 #include "hosts.h"
  17 
  18 #include "aha1542.h"
  19 #ifdef DEBUG
  20 #define DEB(x) x
  21 #else
  22 #define DEB(x)
  23 #endif
  24 
  25 /*
  26 static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/aha1542.c,v 1.1 1992/07/24 06:27:38 root Exp root $";
  27 */
  28 
  29 #define base 0x330
  30 #define intr_chan 11
  31 
  32 static struct mailbox mb[2];
  33 static struct ccb ccb;
  34 
  35 long WAITtimeout, WAITnexttimeout = 3000000;
  36 
  37 void (*do_done)(int, int) = NULL;
  38 int aha1542_host = 0;
  39 extern void aha1542_interrupt();
  40 
  41 #define aha1542_intr_reset()  outb(IRST, CONTROL)
  42 #define aha1542_enable_intr() outb(inb_p(0xA1) & ~8, 0xA1)
  43 #define aha1542_disable_intr() outb(inb_p(0xA1) | 8, 0xA1)
  44 
  45 #define WAIT(port, mask, allof, noneof)                                 \
  46  { register WAITbits;                                                   \
  47    register WAITtimeout = WAITnexttimeout;                              \
  48    while (1) {                                                          \
  49      WAITbits = inb(port) & (mask);                                     \
  50      if ((WAITbits & (allof)) == (allof) && ((WAITbits & (noneof)) == 0)) \
  51        break;                                                           \
  52      if (--WAITtimeout == 0) goto fail;                                 \
  53    }                                                                    \
  54  }
  55 
  56 static void aha1542_stat(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  57 {
  58 /*    int s = inb(STATUS), i = inb(INTRFLAGS);
  59   printk("status=%x intrflags=%x\n", s, i, WAITnexttimeout-WAITtimeout); */
  60 }
  61 
  62 static int aha1542_out(unchar *cmdp, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
  63 {
  64     while (len--)
  65       {
  66           WAIT(STATUS, CDF, 0, CDF);
  67           outb(*cmdp++, DATA);
  68       }
  69     return 0;
  70   fail:
  71     printk("aha1542_out failed(%d): ", len+1); aha1542_stat();
  72     return 1;
  73 }
  74 
  75 static int aha1542_in(unchar *cmdp, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
  76 {
  77     while (len--)
  78       {
  79           WAIT(STATUS, DF, DF, 0);
  80           *cmdp++ = inb(DATA);
  81       }
  82     return 0;
  83   fail:
  84     printk("aha1542_in failed(%d): ", len+1); aha1542_stat();
  85     return 1;
  86 }
  87 int makecode(unsigned hosterr, unsigned scsierr)
     /* [previous][next][first][last][top][bottom][index][help] */
  88 {
  89     switch (hosterr) {
  90       case 0x0:
  91       case 0xa: /* Linked command complete without error and linked normally */
  92       case 0xb: /* Linked command complete without error, interrupt generated */
  93         hosterr = 0;
  94         break;
  95 
  96       case 0x11: /* Selection time out-The initiator selection or target
  97                     reselection was not complete within the SCSI Time out period */
  98         hosterr = DID_TIME_OUT;
  99         break;
 100 
 101       case 0x12: /* Data overrun/underrun-The target attempted to transfer more data
 102                     thean was allocated by the Data Length field or the sum of the
 103                     Scatter / Gather Data Length fields. */
 104 
 105       case 0x13: /* Unexpected bus free-The target dropped the SCSI BSY at an unexpected time. */
 106 
 107       case 0x15: /* MBO command was not 00, 01 or 02-The first byte of the CB was
 108                     invalid. This usually indicates a software failure. */
 109 
 110       case 0x16: /* Invalid CCB Operation Code-The first byte of the CCB was invalid.
 111                     This usually indicates a software failure. */
 112 
 113       case 0x17: /* Linked CCB does not have the same LUN-A subsequent CCB of a set
 114                     of linked CCB's does not specify the same logical unit number as
 115                     the first. */
 116       case 0x18: /* Invalid Target Direction received from Host-The direction of a
 117                     Target Mode CCB was invalid. */
 118 
 119       case 0x19: /* Duplicate CCB Received in Target Mode-More than once CCB was
 120                     received to service data transfer between the same target LUN
 121                     and initiator SCSI ID in the same direction. */
 122 
 123       case 0x1a: /* Invalid CCB or Segment List Parameter-A segment list with a zero
 124                     length segment or invalid segment list boundaries was received.
 125                     A CCB parameter was invalid. */
 126         hosterr = DID_ERROR; /* Couldn't find any better */
 127         break;
 128 
 129       case 0x14: /* Target bus phase sequence failure-An invalid bus phase or bus
 130                     phase sequence was requested by the target. The host adapter
 131                     will generate a SCSI Reset Condition, notifying the host with
 132                     a SCRD interrupt */
 133         hosterr = DID_RESET;
 134         break;
 135       default:
 136         printk("makecode: unknown hoststatus %x\n", hosterr);
 137         break;
 138     }
 139     return scsierr|(hosterr << 16);
 140 }
 141 
 142 int aha1542_test_port(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 143 {
 144     volatile int debug = 0;
 145     
 146     /* Reset the adapter. I ought to make a hard reset, but it's not really nessesary */
 147     
 148     /*  DEB(printk("aha1542_test_port called \n")); */
 149     
 150     outb(SRST|IRST/*|SCRST*/, CONTROL);
 151     
 152     debug = 1;
 153     /* Expect INIT and IDLE, any of the others are bad */
 154     WAIT(STATUS, STATMASK, INIT|IDLE, STST|DIAGF|INVDCMD|DF|CDF);
 155     
 156     debug = 2;
 157     /* Shouldn't have generated any interrupts during reset */
 158     if (inb(INTRFLAGS)&INTRMASK) goto fail;
 159     
 160     debug = 3;
 161     /* Test the basic ECHO command */
 162     outb(CMD_ECHO, DATA);
 163     
 164     debug = 4;
 165     /* Wait for CDF=0. If any of the others are set, it's bad */
 166     WAIT(STATUS, STATMASK, 0, STST|DIAGF|INVDCMD|DF|CDF);
 167     
 168     debug = 5;
 169     /* The meaning of life */
 170     outb(42, DATA);
 171     
 172     debug = 6;
 173     /* Expect only DF, that is, data ready */
 174     WAIT(STATUS, STATMASK, DF, STST|DIAGF|CDF|INVDCMD);
 175     
 176     debug = 7;
 177     /* Is the answer correct? */
 178     if (inb(DATA) != 42) goto fail;
 179     
 180     debug = 8;
 181     /* Reading port should reset DF */
 182     if (inb(STATUS) & DF) goto fail;
 183     
 184     debug = 9;
 185     /* When HACC, command is completed, and we're though testing */
 186     WAIT(INTRFLAGS, HACC, HACC, 0);
 187     /* now initialize adapter */
 188     
 189     debug = 10;
 190     /* Clear interrupts */
 191     outb(IRST, CONTROL);
 192     
 193     debug = 11;
 194     
 195     return debug;                               /* 1 = ok */
 196   fail:
 197     return 0;                                   /* 0 = not ok */
 198 }
 199 
 200 /* What's this little function for? */
 201 char *aha1542_info(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 202 {
 203     static char buffer[] = "";                  /* looks nicer without anything here */
 204     return buffer;
 205 }
 206 
 207 /* A "high" level interrupt handler */
 208 void aha1542_intr_handle(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 209 {
 210     void (*my_done)(int, int) = do_done;
 211     int errstatus;
 212 
 213     do_done = NULL;
 214 #ifdef DEBUG
 215     {
 216     int flag = inb(INTRFLAGS);
 217     printk("aha1542_intr_handle: ");
 218     if (!(flag&ANYINTR)) printk("no interrupt?");
 219     if (flag&MBIF) printk("MBIF ");
 220     if (flag&MBOA) printk("MBOF ");
 221     if (flag&HACC) printk("HACC ");
 222     if (flag&SCRD) printk("SCRD ");
 223     printk("status %02x\n", inb(STATUS));
 224     if (ccb.tarstat|ccb.hastat)
 225       printk("aha1542_command: returning %x (status %d)\n", ccb.tarstat + ((int) ccb.hastat << 16), mb[1].status);
 226   };
 227 #endif
 228     aha1542_intr_reset();
 229     if (!my_done) {
 230         printk("aha1542_intr_handle: Unexpected interrupt\n");
 231         return;
 232     }
 233 
 234     /* is there mail :-) */
 235         
 236     if (!mb[1].status) {
 237         DEB(printk("aha1542_intr_handle: strange: mbif but no mail!\n"));
 238         my_done(aha1542_host, DID_TIME_OUT << 16);
 239         return;
 240     }
 241 
 242     /* more error checking left out here */
 243     if (mb[1].status != 1)
 244       /* This is surely wrong, but I don't know what's right */
 245       errstatus = makecode(ccb.hastat, ccb.tarstat);
 246     else
 247       errstatus = 0;
 248 
 249     mb[1].status = 0;
 250 
 251     if (ccb.tarstat == 2) {
 252         int i;
 253         DEB(printk("aha1542_intr_handle: sense:"));
 254 #ifdef DEBUG
 255         for (i = 0; i < 12; i++)
 256           printk("%02x ", ccb.cdb[ccb.cdblen+i]);
 257         printk("\n");
 258 #endif
 259 /*
 260         DEB(printk("aha1542_intr_handle: buf:"));
 261         for (i = 0; i < bufflen; i++)
 262           printk("%02x ", ((unchar *)buff)[i]);
 263         printk("\n");
 264 */
 265     }
 266     DEB(if (errstatus) printk("aha1542_intr_handle: returning %6x\n", errstatus));
 267     my_done(aha1542_host, errstatus);
 268     return;
 269 }
 270 
 271 int aha1542_queuecommand(unchar target, const void *cmnd, void *buff, int bufflen, void (*done)(int, int))
     /* [previous][next][first][last][top][bottom][index][help] */
 272 {
 273     unchar ahacmd = CMD_START_SCSI;
 274     unchar direction;
 275     unchar *cmd = (unchar *) cmnd;
 276     DEB(int i);
 277 
 278     DEB(if (target > 1) {done(aha1542_host, DID_TIME_OUT << 16); return 0;});
 279     
 280     if(*cmd == REQUEST_SENSE){
 281       memcpy(buff, &ccb.cdb[ccb.cdblen], bufflen);
 282       done(aha1542_host, 0); 
 283       return 0;
 284     };
 285 
 286 #ifdef DEBUG
 287     if (*cmd == READ_10 || *cmd == WRITE_10)
 288       i = xscsi2int(cmd+2);
 289     else if (*cmd == READ_6 || *cmd == WRITE_6)
 290       i = scsi2int(cmd+2);
 291     else
 292       i = -1;
 293     if (done)
 294       printk("aha1542_queuecommand: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen);
 295     else
 296       printk("aha1542_command: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen);
 297     aha1542_stat();
 298     printk("aha1542_queuecommand: dumping scsi cmd:");
 299     for (i = 0; i < (*cmd<=0x1f?6:10); i++) printk("%02x ", cmd[i]);
 300     printk("\n");
 301     if (*cmd == WRITE_10 || *cmd == WRITE_6)
 302       return 0; /* we are still testing, so *don't* write */
 303 #endif
 304     memset(&ccb, 0, sizeof ccb);
 305 
 306     ccb.cdblen = (*cmd<=0x1f)?6:10;     /* SCSI Command Descriptor Block Length */
 307 
 308     direction = 0;
 309     if (*cmd == READ_10 || *cmd == READ_6)
 310         direction = 8;
 311     else if (*cmd == WRITE_10 || *cmd == WRITE_6)
 312         direction = 16;
 313 
 314     memcpy(ccb.cdb, cmd, ccb.cdblen);
 315     ccb.op = 0;                         /* SCSI Initiator Command */
 316     ccb.idlun = (target&7)<<5 | direction;  /* SCSI Target Id */
 317     ccb.rsalen = 12;
 318     any2scsi(ccb.datalen, bufflen);
 319     any2scsi(ccb.dataptr, buff);
 320     ccb.linkptr[0] = ccb.linkptr[1] = ccb.linkptr[2] = 0;
 321     ccb.commlinkid = 0;
 322     
 323     mb[0].status = 1;
 324     mb[1].status = 0;
 325     
 326 #ifdef DEBUGd
 327     printk("aha1542_command: sending.. ");
 328     for (i = 0; i < sizeof(ccb)-10; i++)
 329       printk("%02x ", ((unchar *)&ccb)[i]);
 330 #endif
 331     
 332     if (done) {
 333         DEB(printk("aha1542_queuecommand: now waiting for interrupt "); aha1542_stat());
 334         if (do_done)
 335           printk("aha1542_queuecommand: Two concurrent queuecommand?\n");
 336         else
 337           do_done = done;
 338         aha1542_out(&ahacmd, 1);                /* start scsi command */
 339         DEB(aha1542_stat());
 340         aha1542_enable_intr();
 341     }
 342     else
 343       printk("aha1542_queuecommand: done can't be NULL\n");
 344     
 345     return 0;
 346 }
 347 
 348 volatile static int internal_done_flag = 0;
 349 volatile static int internal_done_errcode = 0;
 350 static void internal_done(int host, int errcode)
     /* [previous][next][first][last][top][bottom][index][help] */
 351 {
 352     internal_done_errcode = errcode;
 353     ++internal_done_flag;
 354 }
 355 
 356 int aha1542_command(unchar target, const void *cmnd, void *buff, int bufflen)
     /* [previous][next][first][last][top][bottom][index][help] */
 357 {
 358     DEB(printk("aha1542_command: ..calling aha1542_queuecommand\n"));
 359     aha1542_queuecommand(target, cmnd, buff, bufflen, internal_done);
 360 
 361     while (!internal_done_flag);
 362     internal_done_flag = 0;
 363     return internal_done_errcode;
 364 }
 365 
 366 /* Initialize mailboxes */
 367 static void setup_mailboxes()
     /* [previous][next][first][last][top][bottom][index][help] */
 368 {
 369     static unchar cmd[5] = {CMD_MBINIT, 1};
 370     
 371     mb[0].status = mb[1].status = 0;
 372     aha1542_intr_reset();               /* reset interrupts, so they don't block */     
 373     any2scsi((cmd+2), mb);
 374     any2scsi(mb[0].ccbptr, &ccb);
 375     aha1542_out(cmd, 5);
 376     WAIT(INTRFLAGS, INTRMASK, HACC, 0);
 377     while (0) {
 378       fail:
 379         printk("aha1542_detect: failed setting up mailboxes\n");
 380     }
 381     aha1542_intr_reset();
 382 }
 383 
 384 /* a hack to avoid a strange compilation error */
 385 
 386 void call_buh()
     /* [previous][next][first][last][top][bottom][index][help] */
 387 {
 388     set_intr_gate(0x2b,&aha1542_interrupt);
 389 }
 390 
 391 /* Query the board to find out if it is a 1542 or a 1740, or whatever. */
 392 static void aha1542_query()
     /* [previous][next][first][last][top][bottom][index][help] */
 393 {
 394   static unchar inquiry_cmd[] = {CMD_INQUIRY };
 395   static unchar inquiry_result[4];
 396   int i;
 397   i = inb(STATUS);
 398   if (i & DF) {
 399     i = inb(DATA);
 400     printk("Stale data:%x ");
 401   };
 402   aha1542_out(inquiry_cmd, 1);
 403   aha1542_in(inquiry_result, 4);
 404   WAIT(INTRFLAGS, INTRMASK, HACC, 0);
 405   while (0) {
 406   fail:
 407     printk("aha1542_detect: query card type\n");
 408   }
 409       aha1542_intr_reset();
 410   printk("Inquiry:");
 411   for(i=0;i<4;i++) printk("%x ",inquiry_result[i]);
 412 }
 413 /* return non-zero on detection */
 414 int aha1542_detect(int hostnum)
     /* [previous][next][first][last][top][bottom][index][help] */
 415 {
 416     int i;
 417 
 418     DEB(printk("aha1542_detect: \n"));
 419     
 420     if (!(i = aha1542_test_port())) {
 421         return 0;
 422     }
 423  
 424     /* Set the Bus on/off-times as not to ruin floppy performens */
 425     {
 426         static unchar oncmd[] = {CMD_BUSON_TIME, 5};
 427         static unchar offcmd[] = {CMD_BUSOFF_TIME, 9};
 428         
 429         aha1542_intr_reset();
 430         aha1542_out(oncmd, 2);
 431         WAIT(INTRFLAGS, INTRMASK, HACC, 0);
 432         aha1542_intr_reset();
 433         aha1542_out(offcmd, 2);
 434         WAIT(INTRFLAGS, INTRMASK, HACC, 0);
 435         while (0) {
 436           fail:
 437             printk("aha1542_detect: setting bus on/off-time failed\n");
 438         }
 439         aha1542_intr_reset();
 440     }
 441     aha1542_query();
 442 
 443     DEB(aha1542_stat());
 444     setup_mailboxes();
 445 
 446     DEB(aha1542_stat());
 447 
 448     DEB(printk("aha1542_detect: enable interrupt channel %d\n", intr_chan));
 449     call_buh();
 450 
 451     if (intr_chan >= 8)
 452       outb(inb_p(0x21)&0xfb,0x21);              /* open for slave ?? */
 453 
 454     DEB(printk("aha1542_detect: enabling interrupts\n"));
 455     aha1542_enable_intr();
 456 
 457 #ifdef DEBUG
 458     DEB(printk(" *** READ CAPACITY ***\n"));
 459 
 460     {
 461         unchar buf[8];
 462         static unchar cmd[] = { READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 463         int i;
 464         
 465         for (i = 0; i < sizeof(buf); ++i) buf[i] = 0x87;
 466         for (i = 0; i < 2; ++i)
 467           if (!aha1542_command(i, cmd, buf, sizeof(buf))) {
 468               printk("aha_detect: LU %d sector_size %d device_size %d\n",
 469                      i, xscsi2int(buf+4), xscsi2int(buf));
 470           }
 471     }
 472 
 473     DEB(printk(" *** NOW RUNNING MY OWN TEST *** \n"));
 474 
 475     for (i = 0; i < 4; ++i)
 476       {
 477           unsigned char cmd[10];
 478           static buffer[512];
 479           
 480           cmd[0] = READ_10;
 481           cmd[1] = 0;
 482           xany2scsi(cmd+2, i);
 483           cmd[6] = 0;
 484           cmd[7] = 0;
 485           cmd[8] = 1;
 486           cmd[9] = 0;
 487           aha1542_command(0, cmd, buffer, 512);
 488       }
 489 #endif
 490     aha1542_host = hostnum;
 491     return 1;
 492 }
 493 
 494 int aha1542_abort(int i)
     /* [previous][next][first][last][top][bottom][index][help] */
 495 {
 496     DEB(printk("aha1542_abort\n"));
 497     return 0;
 498 }
 499 
 500 int aha1542_reset(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 501 {
 502     DEB(printk("aha1542_reset called\n"));
 503     return 0;
 504 }
 505 
 506 __asm__("
 507 _aha1542_interrupt:
 508         cld
 509         pushl %eax
 510         pushl %ecx
 511         pushl %edx
 512         push %ds
 513         push %es
 514         push %fs
 515         movl $0x10,%eax
 516         mov %ax,%ds
 517         mov %ax,%es
 518         movl $0x17,%eax
 519         mov %ax,%fs
 520         movb $0x20,%al
 521         outb %al,$0xA0          # EOI to interrupt controller #1
 522         jmp 1f                  # give port chance to breathe
 523 1:      jmp 1f
 524 1:      outb %al,$0x20
 525 # Please, someone, change this to use the timer
 526 #       andl $0xfffeffff,_timer_active
 527         movl $_aha1542_intr_handle,%edx
 528         call *%edx              # ``interesting'' way of handling intr.
 529         pop %fs
 530         pop %es
 531         pop %ds
 532         popl %edx
 533         popl %ecx
 534         popl %eax
 535         iret
 536 ");

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