Annotation of linux/kernel/blk_drv/scsi/aha1542.c, revision 1.1

1.1     ! root        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)
        !            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)
        !            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)
        !            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)
        !           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)
        !           188: {
        !           189:     static char buffer[] = "Adaptec 1542";
        !           190:     return buffer;
        !           191: }
        !           192: 
        !           193: /* A "high" level interrupt handler */
        !           194: void aha1542_intr_handle(void)
        !           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))
        !           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)
        !           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)
        !           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()
        !           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()
        !           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 */
        !           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)
        !           440: {
        !           441:     DEB(printk("aha1542_abort\n"));
        !           442:     return 0;
        !           443: }
        !           444: 
        !           445: int aha1542_reset(void)
        !           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: ");

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.