This source file includes following definitions.
- wd7000_enable_intr
 
- wd7000_enable_dma
 
- delay
 
- command_out
 
- alloc_scb
 
- free_scb
 
- init_scbs
 
- mail_out
 
- make_code
 
- wd7000_scsi_done
 
- wd7000_intr_handle
 
- wd7000_queuecommand
 
- wd7000_command
 
- wd7000_init
 
- wd7000_revision
 
- wd7000_detect
 
- wd7000_append_info
 
- wd7000_info
 
- wd7000_set_sync
 
- wd7000_abort
 
- wd7000_reset
 
- wd7000_biosparam
 
   1 
   2 
   3 
   4 
   5 
   6 
   7 
   8 
   9 
  10 
  11 
  12 
  13 
  14 #include <stdarg.h>
  15 #include <linux/kernel.h>
  16 #include <linux/head.h>
  17 #include <linux/types.h>
  18 #include <linux/string.h>
  19 #include <linux/sched.h>
  20 #include <asm/system.h>
  21 #include <asm/dma.h>
  22 #include <asm/io.h>
  23 #include "../blk.h"
  24 #include "scsi.h"
  25 #include "hosts.h"
  26 
  27 
  28 
  29 #include "wd7000.h"
  30 
  31 
  32 #ifdef DEBUG
  33 #define DEB(x) x
  34 #else
  35 #define DEB(x)
  36 #endif
  37 
  38 
  39 
  40 
  41 
  42 
  43 
  44 
  45 
  46 
  47 
  48 
  49 
  50 
  51 
  52 
  53 
  54 
  55 
  56 
  57 
  58 
  59 
  60 
  61 
  62 
  63 
  64 static void wd7000_set_sync(int id);
  65 
  66 static struct {
  67        struct wd_mailbox ogmb[OGMB_CNT]; 
  68        struct wd_mailbox icmb[ICMB_CNT];
  69 } mb;
  70 static int next_ogmb = 0;   
  71 
  72 static Scb scbs[MAX_SCBS];
  73 static Scb *scbfree = NULL;
  74 
  75 static int wd7000_host = 0;
  76 static unchar controlstat = 0;
  77 
  78 static unchar rev_1 = 0, rev_2 = 0;  
  79 
  80 #define wd7000_intr_ack()  outb(0,INTR_ACK)
  81 
  82 #define WAITnexttimeout 3000000
  83 
  84 
  85 static inline void wd7000_enable_intr()
     
  86 {
  87     controlstat |= INT_EN;
  88     outb(controlstat,CONTROL);
  89 }
  90 
  91 
  92 static inline void wd7000_enable_dma()
     
  93 {
  94     controlstat |= DMA_EN;
  95     outb(controlstat,CONTROL);
  96     set_dma_mode(DMA_CH, DMA_MODE_CASCADE);
  97     enable_dma(DMA_CH);
  98 }
  99 
 100 
 101 #define WAIT(port, mask, allof, noneof)                                 \
 102  { register WAITbits;                                                   \
 103    register WAITtimeout = WAITnexttimeout;                              \
 104    while (1) {                                                          \
 105      WAITbits = inb(port) & (mask);                                     \
 106      if ((WAITbits & (allof)) == (allof) && ((WAITbits & (noneof)) == 0)) \
 107        break;                                                           \
 108      if (--WAITtimeout == 0) goto fail;                                 \
 109    }                                                                    \
 110  }
 111 
 112 
 113 static inline void delay( unsigned how_long )
     
 114 {
 115      unsigned long time = jiffies + how_long;
 116 
 117      while (jiffies < time);
 118 }
 119 
 120 
 121 static inline int command_out(unchar *cmdp, int len)
     
 122 {
 123     while (len--)  {
 124         WAIT(ASC_STAT, STATMASK, CMD_RDY, 0);
 125         outb(*cmdp++, COMMAND);
 126     }
 127     return 1;
 128 
 129 fail:
 130     printk("wd7000_out WAIT failed(%d): ", len+1);
 131     return 0;
 132 }
 133 
 134 static inline Scb *alloc_scb(void)
     
 135 {
 136     Scb *scb;
 137     unsigned long flags;
 138 
 139     save_flags(flags);
 140     cli();
 141 
 142     if (scbfree == NULL)  {
 143         panic("wd7000: can't allocate free SCB.\n");
 144         restore_flags(flags);
 145         return NULL;
 146     }
 147     scb = scbfree;  scbfree = scb->next;
 148     memset(scb, 0, sizeof(Scb));  scb->next = NULL;
 149 
 150     restore_flags(flags);
 151 
 152     return scb;
 153 }
 154 
 155 
 156 static inline void free_scb( Scb *scb )
     
 157 {
 158     unsigned long flags;
 159 
 160     save_flags(flags);
 161     cli();
 162 
 163     memset(scb, 0, sizeof(Scb));
 164     scb->next = scbfree;  scbfree = scb;
 165 
 166     restore_flags(flags);
 167 }
 168 
 169 
 170 static inline void init_scbs(void)
     
 171 {
 172     int i;
 173     unsigned long flags;
 174 
 175     save_flags(flags);
 176     cli();
 177 
 178     scbfree = &(scbs[0]);
 179     for (i = 0;  i < MAX_SCBS-1;  i++)  scbs[i].next = &(scbs[i+1]);
 180     scbs[MAX_SCBS-1].next = NULL;
 181 
 182     restore_flags(flags);
 183 }    
 184     
 185 
 186 static int mail_out( Scb *scbptr )
     
 187 
 188 
 189 
 190 {
 191     int i, ogmb;
 192     unsigned long flags;
 193 
 194     DEB(printk("wd7000_scb_out: %06x");)
 195 
 196     
 197     save_flags(flags);
 198     cli();
 199     ogmb = next_ogmb;
 200     for (i = 0; i < OGMB_CNT; i++) {
 201         if (mb.ogmb[ogmb].status == 0)  {
 202             DEB(printk(" using OGMB %x",ogmb));
 203             mb.ogmb[ogmb].status = 1;
 204             any2scsi(mb.ogmb[ogmb].scbptr, scbptr);
 205 
 206             next_ogmb = (ogmb+1) % OGMB_CNT;
 207             break;
 208         }  else
 209             ogmb = (++ogmb) % OGMB_CNT;
 210     }
 211     restore_flags(flags);
 212     DEB(printk(", scb is %x",scbptr);)
 213 
 214     if (i >= OGMB_CNT) {
 215         DEB(printk(", no free OGMBs.\n");)
 216         
 217         return 0;
 218     }
 219 
 220     wd7000_enable_intr(); 
 221     do  {
 222         WAIT(ASC_STAT,STATMASK,CMD_RDY,0);
 223         outb(START_OGMB|ogmb, COMMAND);
 224         WAIT(ASC_STAT,STATMASK,CMD_RDY,0);
 225     }  while (inb(ASC_STAT) & CMD_REJ);
 226 
 227     DEB(printk(", awaiting interrupt.\n");)
 228     return 1;
 229 
 230 fail:
 231     DEB(printk(", WAIT timed out.\n");)
 232     return 0;
 233 }
 234 
 235 
 236 int make_code(unsigned hosterr, unsigned scsierr)
     
 237 {   
 238 #ifdef DEBUG
 239     int in_error = hosterr;
 240 #endif
 241 
 242     switch ((hosterr>>8)&0xff){
 243         case 0: 
 244                 hosterr = DID_ERROR;
 245                 break;
 246         case 1: 
 247                 hosterr = DID_OK;
 248                 break;
 249         case 2:  
 250                 hosterr = DID_OK;
 251                 break;
 252         case 4: 
 253                 hosterr = DID_TIME_OUT;
 254                 break;
 255         case 5: 
 256                 hosterr = DID_RESET;
 257                 break;
 258         case 6: 
 259                 hosterr = DID_BAD_TARGET;
 260                 break;
 261         case 80: 
 262         case 81: 
 263                 hosterr = DID_BAD_INTR;
 264                 break;
 265         case 82: 
 266                 hosterr = DID_ABORT;
 267                 break;
 268         case 83: 
 269         case 84: 
 270                 hosterr = DID_RESET;
 271                 break;
 272         default: 
 273                 hosterr = DID_ERROR;
 274                 break;
 275         }
 276 #ifdef DEBUG
 277     if (scsierr||hosterr)
 278         printk("\nSCSI command error: SCSI %02x host %04x return %d",
 279                scsierr,in_error,hosterr);
 280 #endif
 281     return scsierr | (hosterr << 16);
 282 }
 283 
 284 
 285 static void wd7000_scsi_done(Scsi_Cmnd * SCpnt)
     
 286 {
 287     DEB(printk("wd7000_scsi_done: %06x\n",SCpnt);)
 288     SCpnt->SCp.phase = 0;
 289 }
 290 
 291 
 292 void wd7000_intr_handle(int irq)
     
 293 {
 294     int flag, icmb, errstatus, icmb_status;
 295     int host_error, scsi_error;
 296     Scb *scb;             
 297     unchar *icb;          
 298     Scsi_Cmnd *SCpnt;
 299 
 300     flag = inb(INTR_STAT);
 301     DEB(printk("wd7000_intr_handle: intr stat = %02x",flag);)
 302 
 303     if (!(inb(ASC_STAT)&0x80)){ 
 304         DEB(printk("\nwd7000_intr_handle: phantom interrupt...\n");)
 305         wd7000_intr_ack();
 306         return; 
 307     }
 308 
 309     
 310     if ((flag & 0x40) == 0) {
 311         
 312         DEB(printk("wd7000_intr_handle: free outgoing mailbox\n");)
 313         wd7000_intr_ack();
 314         return;
 315     }
 316     
 317     icmb = flag & 0x3f;
 318     scb = (struct scb *) scsi2int(mb.icmb[icmb].scbptr);
 319     icmb_status = mb.icmb[icmb].status;
 320     mb.icmb[icmb].status = 0;
 321 
 322 #ifdef DEBUG
 323     printk(" ICMB %d posted for SCB/ICB %06x, status %02x, vue %02x",
 324            icmb, scb, icmb_status, scb->vue );
 325 #endif
 326 
 327     if (!(scb->op & 0x80))  {   
 328         SCpnt = scb->SCpnt;
 329         if (--(SCpnt->SCp.phase) <= 0)  {  
 330             host_error = scb->vue | (icmb_status << 8);
 331             scsi_error = scb->status;
 332             errstatus = make_code(host_error,scsi_error);    
 333             SCpnt->result = errstatus;
 334 
 335             if (SCpnt->host_scribble != NULL)
 336                 scsi_free(SCpnt->host_scribble,WD7000_SCRIBBLE);
 337             free_scb(scb);
 338 
 339             SCpnt->scsi_done(SCpnt);
 340         }
 341     }  else  {    
 342         icb = (unchar *) scb;
 343         icb[ICB_STATUS] = icmb_status;
 344         icb[ICB_PHASE] = 0;
 345     }
 346 
 347     wd7000_intr_ack();
 348     DEB(printk(".\n");)
 349     return;
 350 }
 351 
 352 
 353 int wd7000_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
     
 354 {
 355     Scb *scb;
 356     Sgb *sgb;
 357     unchar *cdb;
 358     unchar idlun;
 359     short cdblen;
 360 
 361     cdb = (unchar *) SCpnt->cmnd;
 362     cdblen = (*cdb <= 0x1f ? 6 : 10);
 363     idlun = ((SCpnt->target << 5) & 0xe0) | (SCpnt->lun & 7);
 364     SCpnt->scsi_done = done;
 365     SCpnt->SCp.phase = 1;
 366     scb = alloc_scb();
 367     scb->idlun = idlun;
 368     memcpy(scb->cdb, cdb, cdblen);
 369     scb->direc = 0x40;          
 370     scb->SCpnt = SCpnt;         
 371     SCpnt->host_scribble = NULL;
 372     DEB(printk("request_bufflen is %x, bufflen is %x\n",\
 373         SCpnt->request_bufflen, SCpnt->bufflen);)
 374 
 375     if (SCpnt->use_sg)  {
 376         struct scatterlist *sg = (struct scatterlist *) SCpnt->request_buffer;
 377         unsigned i;
 378 
 379         if (scsi_hosts[wd7000_host].sg_tablesize <= 0)  {
 380             panic("wd7000_queuecommand: scatter/gather not supported.\n");
 381         }
 382 #ifdef DEBUG
 383         printk("Using scatter/gather with %d elements.\n",SCpnt->use_sg);
 384 #endif
 385         
 386 
 387 
 388 
 389 #ifdef DEBUG
 390         if (SCpnt->use_sg > WD7000_SG)
 391             panic("WD7000: requesting too many scatterblocks\n");
 392 #endif
 393         SCpnt->host_scribble = scsi_malloc(WD7000_SCRIBBLE);
 394         sgb = (Sgb *) SCpnt->host_scribble;
 395         if (sgb == NULL)
 396             panic("wd7000_queuecommand: scsi_malloc() failed.\n");
 397 
 398         scb->op = 1;
 399         any2scsi(scb->dataptr, sgb);
 400         any2scsi(scb->maxlen, SCpnt->use_sg * sizeof (Sgb) );
 401 
 402         for (i = 0;  i < SCpnt->use_sg;  i++)  {
 403             any2scsi(sgb->ptr, sg[i].address);
 404             any2scsi(sgb->len, sg[i].length);
 405             sgb++;
 406         }
 407         DEB(printk("Using %d bytes for %d scatter/gather blocks\n",\
 408             scsi2int(scb->maxlen), SCpnt->use_sg);)
 409     }  else  {
 410         scb->op = 0;
 411         any2scsi(scb->dataptr, SCpnt->request_buffer);
 412         any2scsi(scb->maxlen, SCpnt->request_bufflen);
 413     }
 414 
 415     return mail_out(scb);
 416 }
 417 
 418 
 419 int wd7000_command(Scsi_Cmnd *SCpnt)
     
 420 {
 421     wd7000_queuecommand(SCpnt, wd7000_scsi_done);
 422 
 423     while (SCpnt->SCp.phase > 0);  
 424 
 425     return SCpnt->result;
 426 }
 427 
 428 
 429 int wd7000_init(void)
     
 430 {   int i;
 431     unchar init_block[] = {
 432         INITIALIZATION, 7, BUS_ON, BUS_OFF, 0, 0, 0, 0, OGMB_CNT, ICMB_CNT
 433     };
 434 
 435     
 436     outb(SCSI_RES|ASC_RES, CONTROL);
 437     delay(1);  
 438     outb(0,CONTROL);  controlstat = 0;
 439     
 440 
 441 
 442 
 443 
 444 
 445 
 446 
 447     delay(200);
 448 
 449     WAIT(ASC_STAT, STATMASK, CMD_RDY, 0);
 450     DEB(printk("wd7000_init: Power-on Diagnostics finished\n");)
 451     if ((i=inb(INTR_STAT)) != 1) {
 452         panic("wd7000_init: Power-on Diagnostics error\n"); 
 453         return 0;
 454     }
 455     
 456     
 457     memset(&mb,0,sizeof (mb));
 458     
 459     init_scbs();
 460 
 461     
 462     any2scsi(init_block+5,&mb);
 463     
 464     if (!command_out(init_block,sizeof(init_block)))  {
 465         panic("WD-7000 Initialization failed.\n"); 
 466         return 0;
 467     }
 468     
 469     
 470     WAIT(ASC_STAT, STATMASK, CMD_RDY | ASC_INI, 0);
 471     outb(DISABLE_UNS_INTR, COMMAND); 
 472     WAIT(ASC_STAT, STATMASK, CMD_RDY | ASC_INI, 0);
 473 
 474     
 475     if (request_irq(IRQ_LVL, wd7000_intr_handle)) {
 476       panic("Unable to allocate IRQ for WD-7000.\n");
 477       return 0;
 478     };
 479     if(request_dma(DMA_CH)) {
 480       panic("Unable to allocate DMA channel for WD-7000.\n");
 481       free_irq(IRQ_LVL);
 482       return 0;
 483     };
 484     wd7000_enable_dma();
 485     wd7000_enable_intr();
 486 
 487     printk("WD-7000 initialized.\n");
 488     return 1;
 489   fail:
 490     return 0;                                   
 491 }
 492 
 493 
 494 void wd7000_revision(void)
     
 495 {
 496     volatile unchar icb[ICB_LEN] = {0x8c};  
 497 
 498     icb[ICB_PHASE] = 1;
 499     mail_out( (struct scb *) icb );
 500     while (icb[ICB_PHASE]) ;
 501     rev_1 = icb[1];
 502     rev_2 = icb[2];
 503 
 504     
 505 
 506 
 507     if (rev_1 >= 7)  scsi_hosts[wd7000_host].sg_tablesize = WD7000_SG;
 508 }
 509 
 510 
 511 static const char *wd_bases[] = {(char *)0xce000};
 512 typedef struct {
 513     char * signature;
 514     unsigned offset;
 515     unsigned length;
 516 } Signature;
 517 
 518 static const Signature signatures[] = {{"SSTBIOS",0xd,0x7}};
 519 
 520 #define NUM_SIGNATURES (sizeof(signatures)/sizeof(Signature))
 521 
 522 
 523 int wd7000_detect(int hostnum)
     
 524 
 525 
 526 
 527 {
 528     int i,j;
 529     char const *base_address = NULL;
 530 
 531     for(i=0;i<(sizeof(wd_bases)/sizeof(char *));i++){
 532         for(j=0;j<NUM_SIGNATURES;j++){
 533             if(!memcmp((void *)(wd_bases[i] + signatures[j].offset),
 534                 (void *) signatures[j].signature,signatures[j].length)){
 535                     base_address=wd_bases[i];
 536                     printk("WD-7000 detected.\n");
 537             }   
 538         }
 539     }
 540     if (base_address == NULL) return 0;
 541 
 542     
 543     wd7000_host = hostnum;
 544 
 545     wd7000_init();    
 546     wd7000_revision();  
 547 
 548     return 1;
 549 }
 550 
 551 
 552 
 553 static void wd7000_append_info( char *info, const char *fmt, ... )
     
 554 
 555 
 556 
 557 {
 558     va_list args;
 559     extern int vsprintf(char *buf, const char *fmt, va_list args);
 560 
 561     va_start(args, fmt);
 562     vsprintf(info, fmt, args);
 563     va_end(args);
 564 
 565     return;
 566 }
 567 
 568 
 569 const char *wd7000_info(void)
     
 570 {
 571     static char info[80] = "Western Digital WD-7000, Firmware Revision ";
 572 
 573     wd7000_revision();
 574     wd7000_append_info( info+strlen(info), "%d.%d.\n", rev_1, rev_2 );
 575 
 576     return info;
 577 }
 578 
 579 
 580 void wd7000_set_sync(int id)
     
 581 {
 582     volatile unchar icb[ICB_LEN] = {0x8a};
 583     unchar speedval = 0x2c;     
 584     any2scsi(icb+2,1);          
 585     any2scsi(icb+5,&speedval);  
 586     icb[8]=0; icb[9]=2*id;      
 587 
 588     icb[ICB_PHASE] = 1;
 589     mail_out( (struct scb *) icb );
 590     while (icb[ICB_PHASE]) ;
 591 }
 592 
 593 
 594 int wd7000_abort(Scsi_Cmnd * SCpnt, int i)
     
 595 {
 596 #ifdef DEBUG
 597     printk("wd7000_abort: Scsi_Cmnd = 0x%08x, code = %d ", SCpnt, i);
 598     printk("id %d lun %d cdb", SCpnt->target, SCpnt->lun);
 599     {  int j;  unchar *cdbj = (unchar *) SCpnt->cmnd;
 600        for (j=0; j < (*cdbj <= 0x1f?6:10);  j++)  printk(" %02x", *(cdbj++));
 601        printk(" result %08x\n", SCpnt->result);
 602     }
 603 #endif
 604     return 0;
 605 }
 606 
 607 
 608 int wd7000_reset(void)
     
 609 {
 610 #ifdef DEBUG
 611     printk("wd7000_reset\n");
 612 #endif
 613     return 0;
 614 }
 615 
 616 
 617 int wd7000_biosparam(int size, int dev, int* info)
     
 618 
 619 
 620 
 621 
 622 {
 623   info[0] = 32;
 624   info[1] = 64;
 625   info[2] = (size + 2047) >> 11;
 626   if (info[2] >= 1024) info[2] = 1024;
 627   return 0;
 628 }
 629