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

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