home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.0 / LINUX-1.0 / LINUX-1 / linux / drivers / scsi / wd7000.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-01-27  |  15.3 KB  |  623 lines

  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)
  86. {
  87.     controlstat |= INT_EN;
  88.     outb(controlstat,CONTROL);
  89. }
  90.  
  91.  
  92. static inline void wd7000_enable_dma(void)
  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.  *  Note: this can also be used for ICBs; just cast to the parm type.
  189.  */
  190. {
  191.     int i, ogmb;
  192.     unsigned long flags;
  193.  
  194.     DEB(printk("wd7000_scb_out: %06x");)
  195.  
  196.     /* We first look for a free outgoing mailbox */
  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.     /* Alternatively, issue "interrupt on free OGMB", and sleep... */
  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:    /* Reserved */
  244.         hosterr = DID_ERROR;
  245.         break;
  246.     case 1:    /* Command Complete, no errors */
  247.         hosterr = DID_OK;
  248.         break;
  249.     case 2: /* Command complete, error logged in scb status (scsierr) */ 
  250.         hosterr = DID_OK;
  251.         break;
  252.     case 4:    /* Command failed to complete - timeout */
  253.         hosterr = DID_TIME_OUT;
  254.         break;
  255.     case 5:    /* Command terminated; Bus reset by external device */
  256.         hosterr = DID_RESET;
  257.         break;
  258.     case 6:    /* Unexpected Command Received w/ host as target */
  259.         hosterr = DID_BAD_TARGET;
  260.         break;
  261.     case 80: /* Unexpected Reselection */
  262.         case 81: /* Unexpected Selection */
  263.         hosterr = DID_BAD_INTR;
  264.         break;
  265.         case 82: /* Abort Command Message  */
  266.         hosterr = DID_ABORT;
  267.         break;
  268.     case 83: /* SCSI Bus Software Reset */
  269.     case 84: /* SCSI Bus Hardware Reset */
  270.         hosterr = DID_RESET;
  271.         break;
  272.         default: /* Reserved */
  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;             /* for SCSI commands */
  297.     unchar *icb;          /* for host commands */
  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.     /* check for an incoming mailbox */
  310.     if ((flag & 0x40) == 0) {
  311.         /*  for a free OGMB - need code for this case... */
  312.         DEB(printk("wd7000_intr_handle: free outgoing mailbox\n");)
  313.         wd7000_intr_ack();
  314.     return;
  315.     }
  316.     /* The interrupt is for an incoming mailbox */
  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))  {   /* an SCB is done */
  328.         SCpnt = scb->SCpnt;
  329.     if (--(SCpnt->SCp.phase) <= 0)  {  /* all scbs for SCpnt are done */
  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  {    /* an ICB is done */
  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 = COMMAND_SIZE(*cdb);
  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;        /* Disable direction check */
  370.     scb->SCpnt = SCpnt;         /* so we can find stuff later */
  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.          Allocate memory for a scatter/gather-list in wd7000 format.
  387.          Save the pointer at host_scribble.
  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 = (unsigned char *) 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);  /* phase counts scbs down to 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.     /* Reset the adapter. */
  436.     outb(SCSI_RES|ASC_RES, CONTROL);
  437.     delay(1);  /* reset pulse: this is 10ms, only need 25us */
  438.     outb(0,CONTROL);  controlstat = 0;
  439.     /*
  440.        Wait 2 seconds, then expect Command Port Ready.
  441.  
  442.        I suspect something else needs to be done here, but I don't know
  443.        what.  The OEM doc says power-up diagnostics take 2 seconds, and
  444.        indeed, SCSI commands submitted before then will time out, but
  445.        none of what follows seems deterred by _not_ waiting 2 secs.
  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) && (i != 7)) {
  452.     panic("wd7000_init: Power-on Diagnostics error\n"); 
  453.     return 0;
  454.     }
  455.     
  456.     /* Clear mailboxes */
  457.     memset(&mb,0,sizeof (mb));
  458.     /* Set up SCB free list */
  459.     init_scbs();
  460.  
  461.     /* Set up init block */
  462.     any2scsi(init_block+5,&mb);
  463.     /* Execute init command */
  464.     if (!command_out(init_block,sizeof(init_block)))  {
  465.     panic("WD-7000 Initialization failed.\n"); 
  466.     return 0;
  467.     }
  468.     
  469.     /* Wait until init finished */
  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.     /* Enable Interrupt and DMA */
  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;                    /* 0 = not ok */
  491. }
  492.  
  493.  
  494. void wd7000_revision(void)
  495. {
  496.     volatile unchar icb[ICB_LEN] = {0x8c};  /* read firmware revision level */
  497.  
  498.     icb[ICB_PHASE] = 1;
  499.     mail_out( (struct scb *) icb );
  500.     while (icb[ICB_PHASE]) /* wait for completion */;
  501.     rev_1 = icb[1];
  502.     rev_2 = icb[2];
  503.  
  504.     /*
  505.         For boards at rev 7.0 or later, enable scatter/gather.
  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,(char *)0xd8000};
  512.  
  513. typedef struct {
  514.     char * signature;
  515.     unsigned offset;
  516.     unsigned length;
  517. } Signature;
  518.  
  519. static const Signature signatures[] = {{"SSTBIOS",0xd,0x7}};
  520.  
  521. #define NUM_SIGNATURES (sizeof(signatures)/sizeof(Signature))
  522.  
  523.  
  524. int wd7000_detect(int hostnum)
  525. /* 
  526.  *  return non-zero on detection
  527.  */
  528. {
  529.     int i,j;
  530.     char const *base_address = NULL;
  531.  
  532.     if(check_region(IO_BASE, 4)) return 0;  /* IO ports in use */
  533.     for(i=0;i<(sizeof(wd_bases)/sizeof(char *));i++){
  534.     for(j=0;j<NUM_SIGNATURES;j++){
  535.         if(!memcmp((void *)(wd_bases[i] + signatures[j].offset),
  536.         (void *) signatures[j].signature,signatures[j].length)){
  537.             base_address=wd_bases[i];
  538.             printk("WD-7000 detected.\n");
  539.         }    
  540.     }
  541.     }
  542.     if (base_address == NULL) return 0;
  543.  
  544.     snarf_region(IO_BASE, 4); /* Register our ports */
  545.     /* Store our host number */
  546.     wd7000_host = hostnum;
  547.  
  548.     wd7000_init();    
  549.     wd7000_revision();  /* will set scatter/gather by rev level */
  550.  
  551.     return 1;
  552. }
  553.  
  554.  
  555.  
  556. static void wd7000_append_info( char *info, const char *fmt, ... )
  557. /*
  558.  *  This is just so I can use vsprintf...
  559.  */
  560. {
  561.     va_list args;
  562.     extern int vsprintf(char *buf, const char *fmt, va_list args);
  563.  
  564.     va_start(args, fmt);
  565.     vsprintf(info, fmt, args);
  566.     va_end(args);
  567.  
  568.     return;
  569. }
  570.  
  571.  
  572. const char *wd7000_info(void)
  573. {
  574.     static char info[80] = "Western Digital WD-7000, Firmware Revision ";
  575.  
  576.     wd7000_revision();
  577.     wd7000_append_info( info+strlen(info), "%d.%d.\n", rev_1, rev_2 );
  578.  
  579.     return info;
  580. }
  581.  
  582. int wd7000_abort(Scsi_Cmnd * SCpnt, int i)
  583. {
  584. #ifdef DEBUG
  585.     printk("wd7000_abort: Scsi_Cmnd = 0x%08x, code = %d ", SCpnt, i);
  586.     printk("id %d lun %d cdb", SCpnt->target, SCpnt->lun);
  587.     {  int j;  unchar *cdbj = (unchar *) SCpnt->cmnd;
  588.        for (j=0; j < COMMAND_SIZE(*cdbj);  j++)  printk(" %02x", *(cdbj++));
  589.        printk(" result %08x\n", SCpnt->result);
  590.     }
  591. #endif
  592.     return 0;
  593. }
  594.  
  595.  
  596. /* We do not implement a reset function here, but the upper level code assumes
  597.    that it will get some kind of response for the command in SCpnt.  We must
  598.    oblige, or the command will hang the scsi system */
  599.  
  600. int wd7000_reset(Scsi_Cmnd * SCpnt)
  601. {
  602. #ifdef DEBUG
  603.     printk("wd7000_reset\n");
  604. #endif
  605.     if (SCpnt) SCpnt->flags |= NEEDS_JUMPSTART;
  606.     return 0;
  607. }
  608.  
  609.  
  610. int wd7000_biosparam(int size, int dev, int* ip)
  611. /*
  612.  *  This is borrowed directly from aha1542.c, but my disks are organized
  613.  *   this way, so I think it will work OK.
  614.  */
  615. {
  616.   ip[0] = 64;
  617.   ip[1] = 32;
  618.   ip[2] = size >> 11;
  619. /*  if (ip[2] >= 1024) ip[2] = 1024; */
  620.   return 0;
  621. }
  622.  
  623.