root/drivers/scsi/wd7000.c

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

DEFINITIONS

This source file includes following definitions.
  1. wd7000_enable_intr
  2. wd7000_enable_dma
  3. delay
  4. command_out
  5. alloc_scb
  6. free_scb
  7. init_scbs
  8. mail_out
  9. make_code
  10. wd7000_scsi_done
  11. wd7000_intr_handle
  12. wd7000_queuecommand
  13. wd7000_command
  14. wd7000_init
  15. wd7000_revision
  16. wd7000_detect
  17. wd7000_append_info
  18. wd7000_info
  19. wd7000_abort
  20. wd7000_reset
  21. wd7000_biosparam

   1 /* $Id: wd7000.c,v 1.2 1994/01/15 06:02:32 drew Exp $
   2  *  linux/kernel/wd7000.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  *  Revised (and renamed) by John Boyd <boyd@cis.ohio-state.edu> to
   9  *  accomodate Eric Youngdale's modifications to scsi.c.  Nov 1992.
  10  *
  11  *  Additional changes to support scatter/gather.  Dec. 1992.  tw/jb
  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 <linux/ioport.h>
  24 
  25 #include "../block/blk.h"
  26 #include "scsi.h"
  27 #include "hosts.h"
  28 
  29 /* #define DEBUG  */
  30 
  31 #include "wd7000.h"
  32 
  33 
  34 #ifdef DEBUG
  35 #define DEB(x) x
  36 #else
  37 #define DEB(x)
  38 #endif
  39 
  40 
  41 /*
  42    Driver data structures:
  43    - mb and scbs are required for interfacing with the host adapter.
  44      An SCB has extra fields not visible to the adapter; mb's
  45      _cannot_ do this, since the adapter assumes they are contiguous in
  46      memory, 4 bytes each, with ICMBs following OGMBs, and uses this fact
  47      to access them.
  48    - An icb is for host-only (non-SCSI) commands.  ICBs are 16 bytes each;
  49      the additional bytes are used only by the driver.
  50    - For now, a pool of SCBs are kept in global storage by this driver,
  51      and are allocated and freed as needed.
  52 
  53   The 7000-FASST2 marks OGMBs empty as soon as it has _started_ a command,
  54   not when it has finished.  Since the SCB must be around for completion,
  55   problems arise when SCBs correspond to OGMBs, which may be reallocated
  56   earlier (or delayed unnecessarily until a command completes).
  57   Mailboxes are used as transient data structures, simply for
  58   carrying SCB addresses to/from the 7000-FASST2.
  59 
  60   Note also since SCBs are not "permanently" associated with mailboxes,
  61   there is no need to keep a global list of Scsi_Cmnd pointers indexed
  62   by OGMB.   Again, SCBs reference their Scsi_Cmnds directly, so mailbox
  63   indices need not be involved.
  64 */
  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;   /* to reduce contention at mailboxes */
  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;  /* filled in by wd7000_revision */
  79 
  80 #define wd7000_intr_ack()  outb(0,INTR_ACK)
  81 
  82 #define WAITnexttimeout 3000000
  83 
  84 
  85 static inline void wd7000_enable_intr(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  86 {
  87     controlstat |= INT_EN;
  88     outb(controlstat,CONTROL);
  89 }
  90 
  91 
  92 static inline void wd7000_enable_dma(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  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 )
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 122 {
 123   if(len == 1) {
 124     while(1==1){
 125       WAIT(ASC_STAT, STATMASK, CMD_RDY, 0);
 126       cli();
 127       if(!(inb(ASC_STAT) & CMD_RDY)) {sti(); continue;}
 128       outb(*cmdp, COMMAND);
 129       sti();
 130       return 1;
 131     }
 132   } else {
 133     cli();
 134     while (len--)  {
 135       WAIT(ASC_STAT, STATMASK, CMD_RDY, 0);
 136       outb(*cmdp++, COMMAND);
 137     }
 138     sti();
 139   }
 140     return 1;
 141 
 142 fail:
 143     sti();
 144     printk("wd7000_out WAIT failed(%d): ", len+1);
 145     return 0;
 146 }
 147 
 148 static inline Scb *alloc_scb(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 149 {
 150     Scb *scb;
 151     unsigned long flags;
 152 
 153     save_flags(flags);
 154     cli();
 155 
 156     if (scbfree == NULL)  {
 157         panic("wd7000: can't allocate free SCB.\n");
 158         restore_flags(flags);
 159         return NULL;
 160     }
 161     scb = scbfree;  scbfree = scb->next;
 162     memset(scb, 0, sizeof(Scb));  scb->next = NULL;
 163 
 164     restore_flags(flags);
 165 
 166     return scb;
 167 }
 168 
 169 
 170 static inline void free_scb( Scb *scb )
     /* [previous][next][first][last][top][bottom][index][help] */
 171 {
 172     unsigned long flags;
 173 
 174     save_flags(flags);
 175     cli();
 176 
 177     memset(scb, 0, sizeof(Scb));
 178     scb->next = scbfree;  scbfree = scb;
 179 
 180     restore_flags(flags);
 181 }
 182 
 183 
 184 static inline void init_scbs(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 185 {
 186     int i;
 187     unsigned long flags;
 188 
 189     save_flags(flags);
 190     cli();
 191 
 192     scbfree = &(scbs[0]);
 193     for (i = 0;  i < MAX_SCBS-1;  i++)  scbs[i].next = &(scbs[i+1]);
 194     scbs[MAX_SCBS-1].next = NULL;
 195 
 196     restore_flags(flags);
 197 }    
 198     
 199 
 200 static int mail_out( Scb *scbptr )
     /* [previous][next][first][last][top][bottom][index][help] */
 201 /*
 202  *  Note: this can also be used for ICBs; just cast to the parm type.
 203  */
 204 {
 205     int i, ogmb;
 206     unsigned char start_cmd;
 207     unsigned long flags;
 208 
 209     DEB(printk("wd7000_scb_out: %06x");)
 210 
 211     /* We first look for a free outgoing mailbox */
 212     save_flags(flags);
 213     cli();
 214     ogmb = next_ogmb;
 215     for (i = 0; i < OGMB_CNT; i++) {
 216         if (mb.ogmb[ogmb].status == 0)  {
 217             DEB(printk(" using OGMB %x",ogmb));
 218             mb.ogmb[ogmb].status = 1;
 219             any2scsi(mb.ogmb[ogmb].scbptr, scbptr);
 220 
 221             next_ogmb = (ogmb+1) % OGMB_CNT;
 222             break;
 223         }  else
 224             ogmb = (++ogmb) % OGMB_CNT;
 225     }
 226     restore_flags(flags);
 227     DEB(printk(", scb is %x",scbptr);)
 228 
 229     if (i >= OGMB_CNT) {
 230         DEB(printk(", no free OGMBs.\n");)
 231         /* Alternatively, issue "interrupt on free OGMB", and sleep... */
 232         return 0;
 233     }
 234 
 235     start_cmd = START_OGMB | ogmb;
 236 
 237     wd7000_enable_intr(); 
 238     do  {
 239         command_out(&start_cmd, 1);
 240         WAIT(ASC_STAT,STATMASK,CMD_RDY,0);
 241     }  while (inb(ASC_STAT) & CMD_REJ);
 242 
 243     DEB(printk(", awaiting interrupt.\n");)
 244     return 1;
 245 
 246 fail:
 247     DEB(printk(", WAIT timed out.\n");)
 248     return 0;
 249 }
 250 
 251 
 252 int make_code(unsigned hosterr, unsigned scsierr)
     /* [previous][next][first][last][top][bottom][index][help] */
 253 {   
 254 #ifdef DEBUG
 255     int in_error = hosterr;
 256 #endif
 257 
 258     switch ((hosterr>>8)&0xff){
 259         case 0: /* Reserved */
 260                 hosterr = DID_ERROR;
 261                 break;
 262         case 1: /* Command Complete, no errors */
 263                 hosterr = DID_OK;
 264                 break;
 265         case 2: /* Command complete, error logged in scb status (scsierr) */ 
 266                 hosterr = DID_OK;
 267                 break;
 268         case 4: /* Command failed to complete - timeout */
 269                 hosterr = DID_TIME_OUT;
 270                 break;
 271         case 5: /* Command terminated; Bus reset by external device */
 272                 hosterr = DID_RESET;
 273                 break;
 274         case 6: /* Unexpected Command Received w/ host as target */
 275                 hosterr = DID_BAD_TARGET;
 276                 break;
 277         case 80: /* Unexpected Reselection */
 278         case 81: /* Unexpected Selection */
 279                 hosterr = DID_BAD_INTR;
 280                 break;
 281         case 82: /* Abort Command Message  */
 282                 hosterr = DID_ABORT;
 283                 break;
 284         case 83: /* SCSI Bus Software Reset */
 285         case 84: /* SCSI Bus Hardware Reset */
 286                 hosterr = DID_RESET;
 287                 break;
 288         default: /* Reserved */
 289                 hosterr = DID_ERROR;
 290                 break;
 291         }
 292 #ifdef DEBUG
 293     if (scsierr||hosterr)
 294         printk("\nSCSI command error: SCSI %02x host %04x return %d",
 295                scsierr,in_error,hosterr);
 296 #endif
 297     return scsierr | (hosterr << 16);
 298 }
 299 
 300 
 301 static void wd7000_scsi_done(Scsi_Cmnd * SCpnt)
     /* [previous][next][first][last][top][bottom][index][help] */
 302 {
 303     DEB(printk("wd7000_scsi_done: %06x\n",SCpnt);)
 304     SCpnt->SCp.phase = 0;
 305 }
 306 
 307 
 308 void wd7000_intr_handle(int irq)
     /* [previous][next][first][last][top][bottom][index][help] */
 309 {
 310     int flag, icmb, errstatus, icmb_status;
 311     int host_error, scsi_error;
 312     Scb *scb;             /* for SCSI commands */
 313     unchar *icb;          /* for host commands */
 314     Scsi_Cmnd *SCpnt;
 315 
 316     flag = inb(INTR_STAT);
 317     DEB(printk("wd7000_intr_handle: intr stat = %02x",flag);)
 318 
 319     if (!(inb(ASC_STAT)&0x80)){ 
 320         DEB(printk("\nwd7000_intr_handle: phantom interrupt...\n");)
 321         wd7000_intr_ack();
 322         return; 
 323     }
 324 
 325     /* check for an incoming mailbox */
 326     if ((flag & 0x40) == 0) {
 327         /*  for a free OGMB - need code for this case... */
 328         DEB(printk("wd7000_intr_handle: free outgoing mailbox\n");)
 329         wd7000_intr_ack();
 330         return;
 331     }
 332     /* The interrupt is for an incoming mailbox */
 333     icmb = flag & 0x3f;
 334     scb = (struct scb *) scsi2int(mb.icmb[icmb].scbptr);
 335     icmb_status = mb.icmb[icmb].status;
 336     mb.icmb[icmb].status = 0;
 337 
 338 #ifdef DEBUG
 339     printk(" ICMB %d posted for SCB/ICB %06x, status %02x, vue %02x",
 340            icmb, scb, icmb_status, scb->vue );
 341 #endif
 342 
 343     if (!(scb->op & 0x80))  {   /* an SCB is done */
 344         SCpnt = scb->SCpnt;
 345         if (--(SCpnt->SCp.phase) <= 0)  {  /* all scbs for SCpnt are done */
 346             host_error = scb->vue | (icmb_status << 8);
 347             scsi_error = scb->status;
 348             errstatus = make_code(host_error,scsi_error);    
 349             SCpnt->result = errstatus;
 350 
 351             if (SCpnt->host_scribble != NULL)
 352                 scsi_free(SCpnt->host_scribble,WD7000_SCRIBBLE);
 353             free_scb(scb);
 354 
 355             SCpnt->scsi_done(SCpnt);
 356         }
 357     }  else  {    /* an ICB is done */
 358         icb = (unchar *) scb;
 359         icb[ICB_STATUS] = icmb_status;
 360         icb[ICB_PHASE] = 0;
 361     }
 362 
 363     wd7000_intr_ack();
 364     DEB(printk(".\n");)
 365     return;
 366 }
 367 
 368 
 369 int wd7000_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
     /* [previous][next][first][last][top][bottom][index][help] */
 370 {
 371     Scb *scb;
 372     Sgb *sgb;
 373     unchar *cdb;
 374     unchar idlun;
 375     short cdblen;
 376 
 377     cdb = (unchar *) SCpnt->cmnd;
 378     cdblen = COMMAND_SIZE(*cdb);
 379     idlun = ((SCpnt->target << 5) & 0xe0) | (SCpnt->lun & 7);
 380     SCpnt->scsi_done = done;
 381     SCpnt->SCp.phase = 1;
 382     scb = alloc_scb();
 383     scb->idlun = idlun;
 384     memcpy(scb->cdb, cdb, cdblen);
 385     scb->direc = 0x40;          /* Disable direction check */
 386     scb->SCpnt = SCpnt;         /* so we can find stuff later */
 387     SCpnt->host_scribble = NULL;
 388     DEB(printk("request_bufflen is %x, bufflen is %x\n",\
 389         SCpnt->request_bufflen, SCpnt->bufflen);)
 390 
 391     if (SCpnt->use_sg)  {
 392         struct scatterlist *sg = (struct scatterlist *) SCpnt->request_buffer;
 393         unsigned i;
 394 
 395         if (scsi_hosts[wd7000_host].sg_tablesize <= 0)  {
 396             panic("wd7000_queuecommand: scatter/gather not supported.\n");
 397         }
 398 #ifdef DEBUG
 399         printk("Using scatter/gather with %d elements.\n",SCpnt->use_sg);
 400 #endif
 401         /*
 402             Allocate memory for a scatter/gather-list in wd7000 format.
 403             Save the pointer at host_scribble.
 404         */
 405 #ifdef DEBUG
 406         if (SCpnt->use_sg > WD7000_SG)
 407             panic("WD7000: requesting too many scatterblocks\n");
 408 #endif
 409         SCpnt->host_scribble = (unsigned char *) scsi_malloc(WD7000_SCRIBBLE);
 410         sgb = (Sgb *) SCpnt->host_scribble;
 411         if (sgb == NULL)
 412             panic("wd7000_queuecommand: scsi_malloc() failed.\n");
 413 
 414         scb->op = 1;
 415         any2scsi(scb->dataptr, sgb);
 416         any2scsi(scb->maxlen, SCpnt->use_sg * sizeof (Sgb) );
 417 
 418         for (i = 0;  i < SCpnt->use_sg;  i++)  {
 419             any2scsi(sgb->ptr, sg[i].address);
 420             any2scsi(sgb->len, sg[i].length);
 421             sgb++;
 422         }
 423         DEB(printk("Using %d bytes for %d scatter/gather blocks\n",\
 424             scsi2int(scb->maxlen), SCpnt->use_sg);)
 425     }  else  {
 426         scb->op = 0;
 427         any2scsi(scb->dataptr, SCpnt->request_buffer);
 428         any2scsi(scb->maxlen, SCpnt->request_bufflen);
 429     }
 430 
 431     return mail_out(scb);
 432 }
 433 
 434 
 435 int wd7000_command(Scsi_Cmnd *SCpnt)
     /* [previous][next][first][last][top][bottom][index][help] */
 436 {
 437     wd7000_queuecommand(SCpnt, wd7000_scsi_done);
 438 
 439     while (SCpnt->SCp.phase > 0);  /* phase counts scbs down to 0 */
 440 
 441     return SCpnt->result;
 442 }
 443 
 444 
 445 int wd7000_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 446 {   int i;
 447     unchar init_block[] = {
 448         INITIALIZATION, 7, BUS_ON, BUS_OFF, 0, 0, 0, 0, OGMB_CNT, ICMB_CNT
 449     };
 450 
 451     /* Reset the adapter. */
 452     outb(SCSI_RES|ASC_RES, CONTROL);
 453     delay(1);  /* reset pulse: this is 10ms, only need 25us */
 454     outb(0,CONTROL);  controlstat = 0;
 455     /*
 456        Wait 2 seconds, then expect Command Port Ready.
 457 
 458        I suspect something else needs to be done here, but I don't know
 459        what.  The OEM doc says power-up diagnostics take 2 seconds, and
 460        indeed, SCSI commands submitted before then will time out, but
 461        none of what follows seems deterred by _not_ waiting 2 secs.
 462     */
 463     delay(200);
 464 
 465     WAIT(ASC_STAT, STATMASK, CMD_RDY, 0);
 466     DEB(printk("wd7000_init: Power-on Diagnostics finished\n");)
 467     if (((i=inb(INTR_STAT)) != 1) && (i != 7)) {
 468         panic("wd7000_init: Power-on Diagnostics error\n"); 
 469         return 0;
 470     }
 471     
 472     /* Clear mailboxes */
 473     memset(&mb,0,sizeof (mb));
 474     /* Set up SCB free list */
 475     init_scbs();
 476 
 477     /* Set up init block */
 478     any2scsi(init_block+5,&mb);
 479     /* Execute init command */
 480     if (!command_out(init_block,sizeof(init_block)))  {
 481         panic("WD-7000 Initialization failed.\n"); 
 482         return 0;
 483     }
 484     
 485     /* Wait until init finished */
 486     WAIT(ASC_STAT, STATMASK, CMD_RDY | ASC_INI, 0);
 487     outb(DISABLE_UNS_INTR, COMMAND); 
 488     WAIT(ASC_STAT, STATMASK, CMD_RDY | ASC_INI, 0);
 489 
 490     /* Enable Interrupt and DMA */
 491     if (request_irq(IRQ_LVL, wd7000_intr_handle)) {
 492       panic("Unable to allocate IRQ for WD-7000.\n");
 493       return 0;
 494     };
 495     if(request_dma(DMA_CH)) {
 496       panic("Unable to allocate DMA channel for WD-7000.\n");
 497       free_irq(IRQ_LVL);
 498       return 0;
 499     };
 500     wd7000_enable_dma();
 501     wd7000_enable_intr();
 502 
 503     printk("WD-7000 initialized.\n");
 504     return 1;
 505   fail:
 506     return 0;                                   /* 0 = not ok */
 507 }
 508 
 509 
 510 void wd7000_revision(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 511 {
 512     volatile unchar icb[ICB_LEN] = {0x8c};  /* read firmware revision level */
 513 
 514     icb[ICB_PHASE] = 1;
 515     mail_out( (struct scb *) icb );
 516     while (icb[ICB_PHASE]) /* wait for completion */;
 517     rev_1 = icb[1];
 518     rev_2 = icb[2];
 519 
 520     /*
 521         For boards at rev 7.0 or later, enable scatter/gather.
 522     */
 523     if (rev_1 >= 7)  scsi_hosts[wd7000_host].sg_tablesize = WD7000_SG;
 524 }
 525 
 526 
 527 static const char *wd_bases[] = {(char *)0xce000,(char *)0xd8000};
 528 
 529 typedef struct {
 530     char * signature;
 531     unsigned offset;
 532     unsigned length;
 533 } Signature;
 534 
 535 static const Signature signatures[] = {{"SSTBIOS",0xd,0x7}};
 536 
 537 #define NUM_SIGNATURES (sizeof(signatures)/sizeof(Signature))
 538 
 539 
 540 int wd7000_detect(int hostnum)
     /* [previous][next][first][last][top][bottom][index][help] */
 541 /* 
 542  *  return non-zero on detection
 543  */
 544 {
 545     int i,j;
 546     char const *base_address = NULL;
 547 
 548     if(check_region(IO_BASE, 4)) return 0;  /* IO ports in use */
 549     for(i=0;i<(sizeof(wd_bases)/sizeof(char *));i++){
 550         for(j=0;j<NUM_SIGNATURES;j++){
 551             if(!memcmp((void *)(wd_bases[i] + signatures[j].offset),
 552                 (void *) signatures[j].signature,signatures[j].length)){
 553                     base_address=wd_bases[i];
 554                     printk("WD-7000 detected.\n");
 555             }   
 556         }
 557     }
 558     if (base_address == NULL) return 0;
 559 
 560     snarf_region(IO_BASE, 4); /* Register our ports */
 561     /* Store our host number */
 562     wd7000_host = hostnum;
 563 
 564     wd7000_init();    
 565     wd7000_revision();  /* will set scatter/gather by rev level */
 566 
 567     return 1;
 568 }
 569 
 570 
 571 
 572 static void wd7000_append_info( char *info, const char *fmt, ... )
     /* [previous][next][first][last][top][bottom][index][help] */
 573 /*
 574  *  This is just so I can use vsprintf...
 575  */
 576 {
 577     va_list args;
 578     extern int vsprintf(char *buf, const char *fmt, va_list args);
 579 
 580     va_start(args, fmt);
 581     vsprintf(info, fmt, args);
 582     va_end(args);
 583 
 584     return;
 585 }
 586 
 587 
 588 const char *wd7000_info(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 589 {
 590     static char info[80] = "Western Digital WD-7000, Firmware Revision ";
 591 
 592     wd7000_revision();
 593     wd7000_append_info( info+strlen(info), "%d.%d.\n", rev_1, rev_2 );
 594 
 595     return info;
 596 }
 597 
 598 int wd7000_abort(Scsi_Cmnd * SCpnt, int i)
     /* [previous][next][first][last][top][bottom][index][help] */
 599 {
 600 #ifdef DEBUG
 601     printk("wd7000_abort: Scsi_Cmnd = 0x%08x, code = %d ", SCpnt, i);
 602     printk("id %d lun %d cdb", SCpnt->target, SCpnt->lun);
 603     {  int j;  unchar *cdbj = (unchar *) SCpnt->cmnd;
 604        for (j=0; j < COMMAND_SIZE(*cdbj);  j++)  printk(" %02x", *(cdbj++));
 605        printk(" result %08x\n", SCpnt->result);
 606     }
 607 #endif
 608     return 0;
 609 }
 610 
 611 
 612 /* We do not implement a reset function here, but the upper level code assumes
 613    that it will get some kind of response for the command in SCpnt.  We must
 614    oblige, or the command will hang the scsi system */
 615 
 616 int wd7000_reset(Scsi_Cmnd * SCpnt)
     /* [previous][next][first][last][top][bottom][index][help] */
 617 {
 618 #ifdef DEBUG
 619     printk("wd7000_reset\n");
 620 #endif
 621     if (SCpnt) SCpnt->flags |= NEEDS_JUMPSTART;
 622     return 0;
 623 }
 624 
 625 
 626 int wd7000_biosparam(int size, int dev, int* ip)
     /* [previous][next][first][last][top][bottom][index][help] */
 627 /*
 628  *  This is borrowed directly from aha1542.c, but my disks are organized
 629  *   this way, so I think it will work OK.
 630  */
 631 {
 632   ip[0] = 64;
 633   ip[1] = 32;
 634   ip[2] = size >> 11;
 635 /*  if (ip[2] >= 1024) ip[2] = 1024; */
 636   return 0;
 637 }
 638 

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