Annotation of linux/kernel/blk_drv/scsi/7000fasst.c, revision 1.1.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.