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. makecode
  4. aha1542_test_port
  5. aha1542_info
  6. aha1542_intr_handle
  7. aha1542_queuecommand
  8. internal_done
  9. aha1542_command
  10. setup_mailboxes
  11. call_buh
  12. aha1542_detect
  13. aha1542_abort
  14. aha1542_reset

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

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