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

1.1     ! root        1: /* $Id: 7000fasst.c,v 1.1 1992/07/24 06:27:38 root Exp root $
        !             2:  *  linux/kernel/7000fasst.c
        !             3:  *
        !             4:  *  Copyright (C) 1992  Thomas Wuensche
        !             5:  *     closely related to the aha1542 driver from Tommy Thorn
        !             6:  *     ( as close as different hardware allows on a lowlevel-driver :-) )
        !             7:  */
        !             8: 
        !             9: #include <linux/config.h>
        !            10: #include <linux/kernel.h>
        !            11: #include <linux/head.h>
        !            12: #include <linux/types.h>
        !            13: #include <linux/string.h>
        !            14: #include <asm/system.h>
        !            15: #include <asm/io.h>
        !            16: #include "scsi.h"
        !            17: #include "hosts.h"
        !            18: 
        !            19: struct mailbox{
        !            20:        unchar status;
        !            21:        unchar scbptr[3];
        !            22: };
        !            23: 
        !            24: /* #define DEBUG */
        !            25: 
        !            26: #include "7000fasst.h"
        !            27: #ifdef DEBUG
        !            28: #define DEB(x) x
        !            29: #else
        !            30: #define DEB(x)
        !            31: #endif
        !            32: 
        !            33: /*static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/7000fasst.c,v 1.1 1992/07/24 06:27:38 root Exp root $";*/
        !            34: 
        !            35: static struct scb scbs[OGMB_CNT];
        !            36: 
        !            37: long wd7000fasst_WAITnexttimeout = 3000000;
        !            38: 
        !            39: void (*wd7000fasst_do_done)() = NULL;
        !            40: extern void wd7000fasst_interrupt();
        !            41: void wd7000fasst_call_buh();
        !            42: 
        !            43: static unchar controlstat = 0;
        !            44: static unchar wd7000fasst_hostno;
        !            45: 
        !            46: #define wd7000fasst_intr_reset()  outb(0,INTR_ACK)
        !            47: #define PC_IMR 0x21
        !            48: #define AT_IMR 0xa1
        !            49: 
        !            50: #define wd7000fasst_enable_intr(){\
        !            51:        controlstat |= INT_EN;\
        !            52:        outb(controlstat,CONTROL);\
        !            53:        outb((inb((intr_chan<=7)?PC_IMR:AT_IMR))& ~0xff,(intr_chan<=7)?PC_IMR:AT_IMR);}
        !            54: 
        !            55: #define wd7000fasst_disable_intr() outb(controlstat |= INT_EN, CONTROL)
        !            56: #define wd7000fasst_enable_dma() {\
        !            57:        controlstat |= DMA_EN;\
        !            58:        outb(controlstat,CONTROL);\
        !            59:        outb((DMA_CH|CASCADE),DMA_MODE_REG);\
        !            60:        outb(DMA_CH,DMA_MASK_REG);}
        !            61: 
        !            62: #define wd7000fasst_disable_dma() {\
        !            63:        outb(DMA_CH|S_DMA_MASK,DMA_MASK_REG);\
        !            64:        controlstat &= ~DMA_EN;\
        !            65:        outb(controlstat,CONTROL);}
        !            66: 
        !            67: #define WAIT(port, mask, allof, noneof)                                        \
        !            68:  { register WAITbits;                                                  \
        !            69:    register WAITtimeout = wd7000fasst_WAITnexttimeout;                         \
        !            70:    while (1) {                                                         \
        !            71:      WAITbits = inb(port) & (mask);                                    \
        !            72:      if ((WAITbits & (allof)) == (allof) && ((WAITbits & (noneof)) == 0)) \
        !            73:        break;                                                          \
        !            74:      if (--WAITtimeout == 0) goto fail;                                        \
        !            75:    }                                                                   \
        !            76:  }
        !            77: 
        !            78: static void wd7000fasst_stat(void)
        !            79: {
        !            80: /*    int s = inb(ASC_STAT), i = inb(INTR_STAT);*/
        !            81: /*    printk("status = %x, intrflags = %x served %d last %x\n", s, i, intr_flag, intr_last); 
        !            82:     printk("status=%x intrflags=%x\n", s, i);
        !            83: */}
        !            84: 
        !            85: static int wd7000fasst_out(unchar *cmdp, int len)
        !            86: {
        !            87:     while (len--)
        !            88:       {
        !            89:          WAIT(ASC_STAT, STATMASK, CMD_RDY, 0);
        !            90:          outb(*cmdp++, COMMAND);
        !            91:       }
        !            92:     return 0;
        !            93:   fail:
        !            94:     printk("wd7000fasst_out failed(%d): ", len+1); wd7000fasst_stat();
        !            95:     return 1;
        !            96: }
        !            97: 
        !            98: int wd7000fasst_make_error_code(unsigned hosterr, unsigned scsierr)
        !            99: {   
        !           100: #ifdef DEBUG
        !           101:     int in_error=hosterr;
        !           102: #endif
        !           103:     switch ((hosterr&0xff00)>>8){
        !           104:        case 0: /* It is reserved, should never happen */
        !           105:                hosterr=DID_ERROR;
        !           106:                break;
        !           107:        case 1: hosterr=DID_OK;
        !           108:                break;
        !           109:        case 2: /* Command complete with logged error */
        !           110:                /* My actual copies of the manual pages are unreadable
        !           111:                 * For now we simply tell there is an error */
        !           112:                DEB(printk("Hosterror: VUE = %x\n",hosterr&0xff);)
        !           113:                switch (hosterr&0xff) {
        !           114:                    default:    DEB(printk("wd7000fasst_make_error_code: unknown hoststatus %x\n", hosterr);)
        !           115:                                hosterr=DID_ERROR;
        !           116:                                break;
        !           117:                }
        !           118:                break;
        !           119:        case 4: hosterr=DID_BAD_TARGET; /* Command failed to complete without SCSI status */
        !           120:                break;
        !           121:        case 5: hosterr=DID_RESET;      /* Cmd terminated; Bus reset by external device */
        !           122:                break;
        !           123:        case 6: hosterr=DID_ERROR;/* Hardware Failure, requires host reset */
        !           124:                break;
        !           125:        case 7: hosterr=DID_RESET;
        !           126:                break;
        !           127:        case 8: hosterr=DID_OK;
        !           128:                printk("wd7000fasst: Linked command not implemented\n");
        !           129:                break;
        !           130:        }
        !           131: #ifdef DEBUG
        !           132:     if (scsierr||hosterr) printk("SCSI-Command error: SCSI %x HOST %x RETURN %x\n",scsierr,in_error,hosterr);
        !           133: #endif
        !           134:     return scsierr|(hosterr << 16);
        !           135: }
        !           136: 
        !           137: /* The following is space for the Mailboxes */
        !           138: struct{ struct mailbox ombox[OGMB_CNT]; 
        !           139:        struct mailbox imbox[ICMB_CNT]; } mbstruct;
        !           140: 
        !           141: int wd7000fasst_init(void)
        !           142: {   int i;
        !           143:     volatile int debug = 0;
        !           144:     /* Page 47 */
        !           145:     unchar init_block[]={ 1, 7, 0x18, 0x18, 0, 0, 0, 0, OGMB_CNT, ICMB_CNT };
        !           146:     /* Reset the adapter. I ought to make a hard reset, but it's not really nessesary */
        !           147:     
        !           148:     DEB(printk("wd7000fasst_init called \n")); 
        !           149:     
        !           150:     outb(SCSI_RES|ASC_RES, CONTROL);
        !           151:     /* Wait at least 25 us */
        !           152:     for (i=0; i< 1000; i++) inb(ASC_STAT);
        !           153:     /* Now reset the reset */
        !           154:     outb(0,CONTROL);
        !           155:     debug = 1;
        !           156:     /* Expect Command Port Ready */
        !           157:     WAIT(ASC_STAT, STATMASK, CMD_RDY, 0);
        !           158:     DEB(printk("wd7000fasst_init: Power on Diagnostics finished\n"));
        !           159:     if ((i=inb(INTR_STAT))!=1) 
        !           160:        printk("Power on Diagnostics error %x\n",i); 
        !           161:     
        !           162:     debug = 2;
        !           163:     /* Clear mbstruct */
        !           164:     memset(&mbstruct,0,sizeof (mbstruct));
        !           165:     /* Set up init block */
        !           166:     any2scsi(init_block+5,&mbstruct);
        !           167:     /* Execute init command */
        !           168:     wd7000fasst_out(init_block,sizeof(init_block));
        !           169:     DEB(printk("Init-Block :");
        !           170:     for (i=0;i<sizeof(init_block);i++) printk(" %x",init_block[i]);
        !           171:     printk("\n");)
        !           172:     /* Wait until init finished */
        !           173:     WAIT(ASC_STAT, STATMASK, CMD_RDY | ASC_INI, 0);
        !           174:     outb(2,COMMAND);
        !           175:     WAIT(ASC_STAT, STATMASK, CMD_RDY | ASC_INI, 0);
        !           176:     /* Enable Interrupt and DMA */
        !           177:     wd7000fasst_enable_dma();
        !           178:     wd7000fasst_call_buh();
        !           179:     DEB(printk("wd7000fasst_detect: enable interrupt channel %d\n", intr_chan));
        !           180:     wd7000fasst_enable_intr(); 
        !           181:     printk("wd7000fasst_init: Controller initialized\n");
        !           182:     return 1;
        !           183:   fail:
        !           184:     return 0;                                  /* 0 = not ok */
        !           185: }
        !           186: 
        !           187: /* What's this little function for? */
        !           188: char *wd7000fasst_info(void)
        !           189: {
        !           190:     static char buffer[] = "Western Digital 7000-FASST";
        !           191:     return buffer;
        !           192: }
        !           193: 
        !           194: /* A "high" level interrupt handler */
        !           195: void wd7000fasst_intr_handle(void)
        !           196: {   struct scb * scbptr;
        !           197:     DEB(int len=sizeof (struct scb);)
        !           198:     DEB(int k;)
        !           199:     unsigned host_error,scsi_error;
        !           200:     int flag = inb(INTR_STAT);
        !           201:     void (*my_done)() = wd7000fasst_do_done;
        !           202:     int errstatus;
        !           203:     DEB(printk("WD Interrupt aufgetreten\n"));
        !           204:     if (!(inb(ASC_STAT)&0x80)){ 
        !           205:        printk("Interrupt without Interrupt\n"); 
        !           206:        wd7000fasst_intr_reset();
        !           207:        return; 
        !           208:     }
        !           209:     wd7000fasst_do_done = NULL;
        !           210:     if (!my_done) {
        !           211:        printk("wd7000fasst_intr_handle: Unexpected interrupt\n");
        !           212:        wd7000fasst_intr_reset();
        !           213:        return;
        !           214:     }
        !           215: 
        !           216:     /* is there mail for me :-) */
        !           217:     if ((flag&0xc0)==0xc0){
        !           218:        /* Ok, the interrupt is for an incoming mailbox */
        !           219:        /* We make the content available for the starter  of the command */
        !           220:        DEB(if ((flag&0xc0)==0xc0) printk("INTR_STAT: %x mbstat: %x\n",flag,mbstruct.imbox[flag&0x3f].status));
        !           221:        if (mbstruct.imbox[flag&0x3f].status==0){
        !           222:            /* Something strange happened */
        !           223:            wd7000fasst_intr_reset();
        !           224:            return;
        !           225:            ;
        !           226:        }
        !           227:        scbptr=(struct scb *)scsi2int(mbstruct.imbox[flag&0x3f].scbptr);
        !           228:        DEB(printk("Datenbereiche aus %x ein %x \n",scbptr,&(scbs[flag&0x3f]));
        !           229:        printk("SCB after return:\n");
        !           230:        k=0;
        !           231:        while (len-- >0){
        !           232:            printk("%x ",*((unchar *)scbptr));
        !           233:            ((unchar *)scbptr)++;
        !           234:            if (++k==16){ printk("\n"); k=0; }
        !           235:        });
        !           236:     }
        !           237:     else { printk("Error in interrupt\n"); return; }
        !           238:     /* more error checking left out here */
        !           239: 
        !           240:     scbptr=(struct scb *)scsi2int(mbstruct.imbox[flag&0x3f].scbptr);
        !           241:     host_error=scbptr->vue |  mbstruct.imbox[flag&0x3f].status<<8;
        !           242:     scsi_error=scbptr->sretstat;
        !           243:     errstatus=wd7000fasst_make_error_code(host_error,scsi_error);    
        !           244:     DEB(if (errstatus) printk("Target was %x\n",scbptr->idlun>>5);)
        !           245:     DEB(if (errstatus) printk("wd7000fasst_intr_handle: returning %6x\n", errstatus));
        !           246:     DEB(printk("wd7000fasst_intr_handle: Status of the finished command: %x\n",mbstruct.imbox[flag&0x3f].status));
        !           247:     /* I make a SCSI reset */
        !           248:     /* Left out */
        !           249:     my_done(wd7000fasst_hostno,errstatus);
        !           250:     wd7000fasst_intr_reset();
        !           251:     return;
        !           252: }
        !           253: 
        !           254: volatile static int internal_done_flag = 0;
        !           255: volatile static int internal_done_errcode = 0;
        !           256: 
        !           257: /* The following code queues a SCSI command */
        !           258: int wd7000fasst_queuecommand(unchar target, const void *cmnd, void *buff, int bufflen, 
        !           259:                void (*done)(int, int))
        !           260: {
        !           261:     int i;
        !           262: #ifdef DEBUG
        !           263:     int j;
        !           264: #endif
        !           265:     unchar *cmd = (unchar *) cmnd;
        !           266: /* We first look for a free outgoing mailbox */
        !           267:     for (i=0;i<OGMB_CNT;i++){
        !           268:        if (mbstruct.ombox[i].status==0){
        !           269:            /* We found one, now set up the scb */
        !           270:            DEB(printk("Found outgoing mbox %x\n",i));
        !           271:            memset(&scbs[i], 0, sizeof(struct scb));
        !           272:            /* scbs[i].cdblen = (*cmd<=0x1f)?6:10; */   /* SCSI Command Descriptor Block Length */
        !           273:            memcpy(scbs[i].scbdata, cmd, (*cmd<=0x1f)?6:10);
        !           274:            scbs[i].op = 0;                             /* SCSI Initiator Command */
        !           275:            scbs[i].idlun = (target<<5)&0xe0;           /* SCSI Target Id Bit 7-5 Target Id*/
        !           276:            any2scsi(scbs[i].dataptr,buff);
        !           277:            any2scsi(scbs[i].maxdata,bufflen);
        !           278:            scbs[i].direc=0x40;         /* Disable direction check */
        !           279:            DEB(printk("Kommando fuer target %x ist: ",target);
        !           280:                for (j=0;j<12;j++) printk(" %x",scbs[i].scbdata[j]);
        !           281:                printk("\n"));
        !           282:            /* Now we set up the pointer to scb, then the status of the mbox */
        !           283:            any2scsi((mbstruct.ombox[i].scbptr),&(scbs[i]));
        !           284:            mbstruct.ombox[i].status=1;
        !           285:            /* Everything set up, start the command */
        !           286:            break;
        !           287:        }
        !           288:     }
        !           289:     if (i==OGMB_CNT){
        !           290:        /* No free mbox, send command "Interrupt on free OGMB" */
        !           291:        DEB(printk("No free Mailbox\n"));
        !           292:        return 0;
        !           293:     }
        !           294:     {  int len,k;
        !           295:        struct scb * scbptr;
        !           296:            DEB(printk("Found outgoing mbox %x\n",i));
        !           297:        scbptr=&(scbs[i]);
        !           298:        len=sizeof(struct scb);
        !           299:        k=0;
        !           300:        DEB(printk("SCB before execute:\n");
        !           301:            while (len-- >0){
        !           302:                printk("%x ",*((unchar *)scbptr));
        !           303:                ((unchar *)scbptr)++;
        !           304:                if (++k==16){ printk("\n"); k=0; }
        !           305:            };)
        !           306:     }
        !           307:     /* Set up the "done" response function */
        !           308:     if (done) {
        !           309:        DEB(printk("wd7000fasst_queuecommand: now waiting for interrupt "); 
        !           310:            wd7000fasst_stat());
        !           311:        if (wd7000fasst_do_done)
        !           312:            printk("wd7000fasst_queuecommand: Two concurrent queuecommand?\n");
        !           313:        else
        !           314:            wd7000fasst_do_done = done;
        !           315:        DEB(wd7000fasst_stat());
        !           316:        wd7000fasst_enable_intr(); 
        !           317:     }
        !           318:     else{
        !           319:        printk("wd7000fasst_queuecommand: done can't be NULL\n");
        !           320:        return 0;
        !           321:     }
        !           322:     /* Now we initialize execution */
        !           323: retry: WAIT(ASC_STAT,STATMASK,CMD_RDY,0);
        !           324:        outb(0x80+i,COMMAND);
        !           325:        WAIT(ASC_STAT,STATMASK,CMD_RDY,0);
        !           326:        if (inb(ASC_STAT)&CMD_REJ) goto retry;
        !           327:        return 1;
        !           328:     /* Wait until done */
        !           329: 
        !           330: fail:
        !           331:     return 0;
        !           332: }
        !           333: 
        !           334: /* We use this function for queueing a command from wd7000fasst_command */ 
        !           335: static void internal_done(int host, int errcode)
        !           336: {
        !           337:     internal_done_errcode = errcode;
        !           338:     ++internal_done_flag;
        !           339: }
        !           340: 
        !           341: int wd7000fasst_command(unchar target, const void *cmnd, void *buff, int bufflen)
        !           342: {
        !           343: #ifdef DEBUG
        !           344:     int k;
        !           345: #endif
        !           346:     wd7000fasst_queuecommand(target, cmnd, buff, bufflen, internal_done);
        !           347: 
        !           348:     while (!internal_done_flag);
        !           349:     internal_done_flag = 0;
        !           350:     DEB(printk("wd7000fasst_command finished: ..leaving with errcode %x\n",
        !           351:        internal_done_errcode));
        !           352:     DEB(for (k=0;k<5000000;k++) inb(INTR_STAT));
        !           353:     return internal_done_errcode;
        !           354: }
        !           355: 
        !           356: /* a hack to avoid a strange compilation error */
        !           357: 
        !           358: void wd7000fasst_call_buh()
        !           359: {
        !           360:     set_intr_gate((intr_chan<=7)?intr_chan+8:intr_chan+0x20,&wd7000fasst_interrupt);
        !           361: }
        !           362: 
        !           363: /* return non-zero on detection */
        !           364: static const char *wd_bases[] = {(char *)0xce000};
        !           365: typedef struct {char * signature;
        !           366:                unsigned offset;
        !           367:                unsigned length;
        !           368:               }Signature;
        !           369: 
        !           370: static const Signature signatures[] =
        !           371:              {{"SSTBIOS",0xd,0x7}};
        !           372: 
        !           373: #define NUM_SIGNATURES (sizeof(signatures)/sizeof(Signature))
        !           374: 
        !           375: int wd7000fasst_detect(int hostnum) /* hostnum ignored for now */
        !           376: {
        !           377:     int i,j;
        !           378:     char const * base_address = 0;
        !           379:     /* Store our host number */
        !           380:     wd7000fasst_hostno=hostnum;
        !           381:     DEB(printk("wd7000fasst_detect: \n"));
        !           382: 
        !           383:     for(i=0;i<(sizeof(wd_bases)/sizeof(char *));i++){
        !           384:        for(j=0;j<NUM_SIGNATURES;j++){
        !           385:            if(!memcmp((void *)(wd_bases[i] + signatures[j].offset),
        !           386:                (void *) signatures[j].signature,signatures[j].length)){
        !           387:                    base_address=wd_bases[i];
        !           388:                    printk("WD 7000-FASST detected\n");
        !           389:            }   
        !           390:        }
        !           391:     }
        !           392:     if (!base_address) return 0;
        !           393:     wd7000fasst_init();    
        !           394: 
        !           395:     /* Set the Bus on/off-times as not to ruin floppy performens */
        !           396: 
        !           397:     wd7000fasst_stat();
        !           398: 
        !           399:     printk(" *** READ CAPACITY ***\n");
        !           400: 
        !           401:     {   unchar rstat;
        !           402:        unchar buf[8];
        !           403:        static unchar cmd[] = { READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0};
        !           404:        int i;
        !           405:        
        !           406:        for (i = 0; i < sizeof(buf); ++i) buf[i] = 0x87;
        !           407:        for (i = 0; i < 3; ++i){
        !           408:          rstat=0;
        !           409:          while (rstat<2){
        !           410:            if (wd7000fasst_command(i, cmd, buf, sizeof(buf))) rstat++;
        !           411:            else break;
        !           412:          }
        !           413:          if (rstat<2)
        !           414:              printk("wd7000fasst_detect: LU %d sector_size 0x%x device_size 0x%x capacity %d\n",
        !           415:                i, xscsi2int(buf+4), xscsi2int(buf), xscsi2int(buf+4)*xscsi2int(buf));
        !           416:        }
        !           417:     }
        !           418: 
        !           419:     return 1;
        !           420: }
        !           421: 
        !           422: int wd7000fasst_abort(int i)
        !           423: {
        !           424:     printk("wd7000fasst_abort\n");
        !           425:     return 0;
        !           426: }
        !           427: 
        !           428: int wd7000fasst_reset(void)
        !           429: {
        !           430:     printk("wd7000fasst_reset called\n");
        !           431:     return 0;
        !           432: }
        !           433: 
        !           434: __asm__("
        !           435: _wd7000fasst_interrupt:
        !           436:        cld
        !           437:        pushl %eax
        !           438:        pushl %ecx
        !           439:        pushl %edx
        !           440:        push %ds
        !           441:        push %es
        !           442:        push %fs
        !           443:        movl $0x10,%eax
        !           444:        mov %ax,%ds
        !           445:        mov %ax,%es
        !           446:        movl $0x17,%eax
        !           447:        mov %ax,%fs
        !           448: # Please, someone, change this to use the timer
        !           449: #      andl $0xfffeffff,_timer_active
        !           450:        movl $_wd7000fasst_intr_handle,%edx
        !           451:        call *%edx              # ``interesting'' way of handling intr.
        !           452: # Free the interrupt only after resetting the host interrupt
        !           453:        movb $0x20,%al
        !           454:        outb %al,$0xA0          # EOI to interrupt controller #1
        !           455:        jmp 1f                  # give port chance to breathe
        !           456: 1:     jmp 1f
        !           457: 1:     outb %al,$0x20
        !           458:        pop %fs
        !           459:        pop %es
        !           460:        pop %ds
        !           461:        popl %edx
        !           462:        popl %ecx
        !           463:        popl %eax
        !           464:        iret
        !           465: ");

unix.superglobalmegacorp.com

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