patch -p0 -s -d /usr/src << '_EOF_'

diff -urN linux/drivers/scsi/Config.in linux-2.0.32-megaraid/drivers/scsi/Config.in

--- linux/drivers/scsi/Config.in	Mon Sep 15 12:41:28 1997

+++ linux-2.0.32-megaraid/drivers/scsi/Config.in	Tue Aug 11 09:40:32 1998

@@ -32,6 +32,7 @@

 dep_tristate 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS $CONFIG_SCSI

 dep_tristate 'Always IN2000 SCSI support' CONFIG_SCSI_IN2000 $CONFIG_SCSI

 dep_tristate 'AM53/79C974 PCI SCSI support' CONFIG_SCSI_AM53C974 $CONFIG_SCSI

+dep_tristate 'AMI MegaRAID support' CONFIG_SCSI_MEGARAID $CONFIG_SCSI

 dep_tristate 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC $CONFIG_SCSI

 if [ "$CONFIG_SCSI_BUSLOGIC" != "n" ]; then

     bool '  Omit FlashPoint support' CONFIG_SCSI_OMIT_FLASHPOINT

diff -urN linux/drivers/scsi/Makefile linux-2.0.32-megaraid/drivers/scsi/Makefile

--- linux/drivers/scsi/Makefile	Thu Aug 14 13:31:20 1997

+++ linux-2.0.32-megaraid/drivers/scsi/Makefile	Tue Aug 11 18:09:11 1998

@@ -363,6 +363,13 @@

   endif

 endif

 

+ifeq ($(CONFIG_SCSI_MEGARAID),y)

+L_OBJS += megaraid.o

+else

+  ifeq ($(CONFIG_SCSI_MEGARAID),m)

+  M_OBJS += megaraid.o

+  endif

+endif

 

 ifeq ($(CONFIG_BLK_DEV_IDESCSI),y)

 L_OBJS += ide-scsi.o

@@ -400,6 +407,9 @@

 

 g_NCR5380.o: g_NCR5380.c

 	$(CC) $(CFLAGS) -DGENERIC_NCR5380_OVERRIDE="{{(NCR5380_map_type)0x350,5,0, BOARD_NCR53C400}};" -c g_NCR5380.c

+

+megaraid.o: megaraid.c

+	$(CC) $(CFLAGS) -c megaraid.c

 

 scsi_mod.o: $(MX_OBJS) hosts.o scsi.o scsi_ioctl.o constants.o \

 		scsicam.o scsi_proc.o

diff -urN linux/drivers/scsi/hosts.c linux-2.0.32-megaraid/drivers/scsi/hosts.c

--- linux/drivers/scsi/hosts.c	Thu Aug 14 13:31:20 1997

+++ linux-2.0.32-megaraid/drivers/scsi/hosts.c	Tue Aug 11 09:42:40 1998

@@ -161,6 +161,10 @@

 #include "AM53C974.h"

 #endif

 

+#ifdef CONFIG_SCSI_MEGARAID

+#include "megaraid.h"

+#endif

+

 #ifdef CONFIG_SCSI_PPA

 #include "ppa.h"

 #endif

@@ -311,6 +315,9 @@

 #endif

 #ifdef CONFIG_SCSI_AM53C974

     AM53C974,

+#endif

+#ifdef CONFIG_SCSI_MEGARAID

+    MEGARAID,

 #endif

 #ifdef CONFIG_SCSI_PPA

     PPA,

diff -urN linux/drivers/scsi/megaraid.c linux-2.0.32-megaraid/drivers/scsi/megaraid.c

--- linux/drivers/scsi/megaraid.c	Wed Dec 31 19:00:00 1969

+++ linux-2.0.32-megaraid/drivers/scsi/megaraid.c	Wed Aug 19 18:53:01 1998

@@ -0,0 +1,1299 @@

+/*===================================================================

+ *

+ *                    Linux MegaRAID device driver

+ * 

+ * Copyright 1998 American Megatrends Inc.

+ *

+ * Version : 0.91

+ * 

+ * Description: Linux device driver for AMI MegaRAID controller

+ *

+ * History:

+ *

+ * Version 0.90:

+ *     Works and has been tested with the MegaRAID 428 controller, and

+ *     the MegaRAID 438 controller.  Probably works with the 466 also,

+ *     but not tested.

+ *

+ * Version 0.91:

+ *     Aligned mailbox area on 16-byte boundry.

+ *     Added schedule() at the end to properly clean up.

+ *     Made improvements for conformity to linux driver standards.

+ *

+ *

+ *===================================================================*/

+#define QISR 1

+

+#define CRLFSTR "\n"

+

+#define MULTIQ 1

+

+#include <linux/config.h>

+

+#ifdef MODULE

+#include <linux/version.h>

+#include <linux/module.h>

+

+#if LINUX_VERSION_CODE > 0x20118

+char kernel_version[] = UTS_RELEASE;

+

+/* originally ported by Dell Corporation; updated, released, and maintained by

+   American Megatrends */

+MODULE_AUTHOR("American Megatrends Inc."); 

+MODULE_DESCRIPTION("AMI MegaRAID driver");    

+#endif

+#endif

+

+#include <linux/types.h>

+#include <linux/errno.h>

+#include <linux/kernel.h>

+#include <linux/sched.h>

+#include <linux/malloc.h>

+#include <linux/ioport.h>

+#include <linux/fcntl.h>

+#include <linux/delay.h>

+#include <linux/pci.h>

+#include <linux/proc_fs.h>

+#include <linux/blk.h>

+#include <linux/wait.h>

+#include <linux/tqueue.h>

+#include <linux/interrupt.h>

+

+#include <linux/sched.h>

+#include <linux/stat.h>

+#include <linux/malloc.h>	/* for kmalloc() */

+#include <linux/config.h>	/* for CONFIG_PCI */

+#if LINUX_VERSION_CODE <= 0x20100

+#include <linux/bios32.h>

+#endif

+

+#include <asm/io.h>

+#include <asm/irq.h>

+

+#include "sd.h"

+#include "scsi.h"

+#include "hosts.h"

+

+#include "megaraid.h"

+

+//================================================================

+//

+//                          #Defines

+//

+//================================================================

+#if LINUX_VERSION_CODE < 0x020100

+#define ioremap vremap

+#define iounmap vfree

+#endif

+

+#define MAX_SERBUF 160

+#define COM_BASE 0x2f8

+

+#define ENQUEUE(obj,type,list,next) \

+{ type **node; long cpuflag; \

+  save_flags(cpuflag); cli(); \

+  for(node=&(list); *node; node=(type **)&(*node)->##next); \

+  (*node) = obj; \

+  (*node)->##next = NULL; \

+  restore_flags(cpuflag); \

+};

+

+#define DEQUEUE(obj,type,list,next) \

+{ long cpuflag; \

+  save_flags(cpuflag); cli(); \

+  if ((obj=list) != NULL) {\

+    list = (type *)(list)->##next; \

+  } \

+  restore_flags(cpuflag); \

+};

+

+u_long RDINDOOR(mega_host_config *megaCfg)

+{

+  return readl(megaCfg->base + 0x20);

+}

+

+void WRINDOOR(mega_host_config *megaCfg, u_long value)

+{

+  writel(value,megaCfg->base+0x20);

+}

+

+u_long RDOUTDOOR(mega_host_config *megaCfg)

+{

+  return readl(megaCfg->base+0x2C);

+}

+

+void WROUTDOOR(mega_host_config *megaCfg, u_long value)

+{

+  writel(value,megaCfg->base+0x2C);

+}

+

+//================================================================

+//

+//                    Function prototypes

+//

+//================================================================

+static int  MegaIssueCmd(mega_host_config *megaCfg,

+			 u_char *mboxData,

+			 mega_scb *scb,

+			 int intr);

+static int  build_sglist(mega_host_config *megaCfg, mega_scb *scb, 

+			 u_long *buffer, u_long *length);

+

+static void mega_runque(void *);

+static void mega_rundoneq(void);

+static void mega_cmd_done(mega_scb *, int);

+

+#define SERDEBUG 0

+#if SERDEBUG

+static void ser_init(void);

+static void ser_puts(char *str);

+static void ser_putc(char c);

+static int  ser_printk(const char *fmt, ...);

+#endif

+

+//================================================================

+//

+//                    Global variables

+//

+//================================================================

+static int               numCtlrs = 0;

+static mega_host_config *megaCtlrs[4] = { 0 };

+

+/* Change this to 0 if you want to see the raw drives */

+static int use_raid   = 1;

+

+/* Queue of pending/completed SCBs */

+static mega_scb  *qPending   = NULL;

+static Scsi_Cmnd *qCompleted = NULL;

+

+static struct tq_struct runq = {0,0,mega_runque,NULL};

+

+struct proc_dir_entry proc_scsi_megaraid = {

+  PROC_SCSI_MEGARAID, 8, "megaraid",

+  S_IFDIR | S_IRUGO | S_IXUGO, 2

+};

+

+#if SERDEBUG

+static char strbuf[MAX_SERBUF+1];

+

+static void ser_init()

+{

+    unsigned port=COM_BASE;

+

+    outb(0x80,port+3);

+    outb(0,port+1);

+    /* 9600 Baud, if 19200: outb(6,port) */

+    outb(12, port);

+    outb(3,port+3);

+    outb(0,port+1);

+}

+

+static void ser_puts(char *str)

+{

+    char *ptr;

+

+    ser_init();

+    for (ptr=str;*ptr;++ptr)

+        ser_putc(*ptr);

+}

+

+static void ser_putc(char c)

+{

+    unsigned port=COM_BASE;

+

+    while ((inb(port+5) & 0x20)==0);

+    outb(c,port);

+    if (c==0x0a)

+    {

+        while ((inb(port+5) & 0x20)==0);

+        outb(0x0d,port);

+    }

+}

+

+static int ser_printk(const char *fmt, ...)

+{

+    va_list args;

+    int i;

+    long flags;

+

+    save_flags(flags);

+    cli();

+    va_start(args,fmt);

+    i = vsprintf(strbuf,fmt,args);

+    ser_puts(strbuf);

+    va_end(args);

+    restore_flags(flags);

+

+    return i;

+}

+

+#define TRACE(a)    { ser_printk a;}

+

+#else

+#define TRACE(A)

+#endif

+

+void callDone(Scsi_Cmnd *SCpnt)

+{

+  long flags;

+

+  if (SCpnt->result) {

+    TRACE(("*** %.08lx %.02x <%d.%d.%d> = %x\n", SCpnt->serial_number, 

+	   SCpnt->cmnd[0], SCpnt->channel, SCpnt->target, SCpnt->lun, 

+	   SCpnt->result));

+  }

+  save_flags(flags);

+  sti();

+  SCpnt->scsi_done(SCpnt);

+  restore_flags(flags);

+}

+

+/*-------------------------------------------------------------------------

+ *

+ *                      Local functions

+ *

+ *-------------------------------------------------------------------------*/

+

+//================================================

+// Initialize SCB structures

+//================================================

+static void initSCB(mega_host_config *megaCfg)

+{

+  int idx;

+

+  for(idx=0; idx<megaCfg->max_cmds; idx++) {

+    megaCfg->scbList[idx].idx    = -1;

+    megaCfg->scbList[idx].flag   = 0;

+    megaCfg->scbList[idx].sgList = NULL;

+    megaCfg->scbList[idx].SCpnt  = NULL;

+  }

+}

+

+//===========================

+// Allocate a SCB structure

+//===========================

+static mega_scb *allocateSCB(mega_host_config *megaCfg, Scsi_Cmnd *SCpnt)

+{

+  int        idx;

+  long       flags;

+

+  save_flags(flags);

+  cli();

+  for(idx=0; idx<megaCfg->max_cmds; idx++) {

+    if (megaCfg->scbList[idx].idx < 0) {

+

+      /* Set Index and SCB pointer */ 

+      megaCfg->scbList[idx].flag  = 0;

+      megaCfg->scbList[idx].idx   = idx;

+      megaCfg->scbList[idx].SCpnt = SCpnt;

+      megaCfg->scbList[idx].next  = NULL;

+

+      /* Lazy allocate Scatter-gather list */

+      if (megaCfg->scbList[idx].sgList == NULL) {

+	megaCfg->scbList[idx].sgList = kmalloc(sizeof(mega_sglist)*MAX_SGLIST,

+					       GFP_ATOMIC|GFP_DMA);

+      }

+#if 0

+      TRACE(("kmalloc() = 0x%x\n",megaCfg->scbList[idx].sgList));

+#endif

+      restore_flags(flags);

+

+      return &megaCfg->scbList[idx];

+    }

+  }

+  restore_flags(flags);

+

+  printk("Megaraid: Could not allocate free SCB!!!\n");

+  

+  return NULL;

+}

+

+//=======================

+// Free a SCB structure

+//=======================

+static void freeSCB(mega_scb *scb)

+{

+  long flags;

+

+  save_flags(flags);

+  cli();

+  scb->flag  = 0;

+  scb->idx   = -1;

+  scb->next  = NULL;

+  scb->SCpnt = NULL;

+  restore_flags(flags);

+}

+

+/* Run through the list of completed requests */

+static void mega_rundoneq()

+{

+  mega_host_config *megaCfg;

+  Scsi_Cmnd        *SCpnt;

+  long              islogical;

+

+  while(1) {

+    DEQUEUE(SCpnt, Scsi_Cmnd, qCompleted, host_scribble);

+    if (SCpnt == NULL) return;

+

+    megaCfg = (mega_host_config *)SCpnt->host->hostdata;

+

+    /* Check if we're allowing access to RAID drives or physical

+     *  if use_raid == 1 and this wasn't a disk on the max channel or

+     *  if use_raid == 0 and this was a disk on the max channel

+     *  then fail.

+     */

+    islogical = (SCpnt->channel == megaCfg->host->max_channel) ? 1 : 0;

+    if (SCpnt->cmnd[0] == INQUIRY &&

+	((((u_char*)SCpnt->request_buffer)[0] & 0x1F) == TYPE_DISK) &&

+	(islogical != use_raid)) {

+       SCpnt->result = 0xF0;

+    }

+

+    /* Convert result to error */

+    switch(SCpnt->result) {

+    case 0x00: case 0x02:

+      SCpnt->result |= (DID_OK << 16);

+      break;

+    case 0x8:

+      SCpnt->result |= (DID_BUS_BUSY << 16);

+      break;

+    default:

+      SCpnt->result |= (DID_BAD_TARGET << 16);

+      break;

+    }

+

+    /* Callback */

+    callDone(SCpnt);

+  }

+}

+

+/* Add command to the list of completed requests */

+static void mega_cmd_done(mega_scb *pScb, int status)

+{

+  pScb->SCpnt->result = status;

+  ENQUEUE(pScb->SCpnt, Scsi_Cmnd, qCompleted, host_scribble);

+  freeSCB(pScb);

+}

+

+/*----------------------------------------------------

+ * Process pending queue list

+ *

+ * Run as a scheduled task 

+ *----------------------------------------------------*/

+static void mega_runque(void *dummy)

+{

+  mega_host_config *megaCfg;

+  mega_scb         *pScb;

+  long              flags;

+

+  /* Take care of any completed requests */

+  mega_rundoneq();

+

+  DEQUEUE(pScb,mega_scb,qPending,next);

+

+  if (pScb) {

+    megaCfg = (mega_host_config *)pScb->SCpnt->host->hostdata;

+

+    if (megaCfg->mbox->busy || megaCfg->flag & (IN_ISR|PENDING)) {

+      printk("PENDING = %x, IN_ISR = %x, mbox.busy = %x\n",(u_int)(megaCfg->flag

+            & PENDING), (u_int)(megaCfg->flag & IN_ISR), megaCfg->mbox->busy);

+      TRACE(("%.08lx %.02x <%d.%d.%d> intr%d busy%d isr%d pending%d\n",

+	     pScb->SCpnt->serial_number,

+	     pScb->SCpnt->cmnd[0],

+	     pScb->SCpnt->channel,

+	     pScb->SCpnt->target,

+	     pScb->SCpnt->lun,

+	     intr_count,

+	     megaCfg->mbox->busy,

+	     (megaCfg->flag & IN_ISR)  ? 1 : 0,

+	     (megaCfg->flag & PENDING) ? 1 : 0));

+    }

+    if (MegaIssueCmd(megaCfg, pScb->mboxData, pScb, 1)) {

+      printk("MegaIssueCmd returned BUSY.  Rescheduling command.\n");

+      /* We're BUSY... come back later */

+      save_flags(flags);

+      cli();

+      pScb->next = qPending;

+      qPending   = pScb;

+      restore_flags(flags);

+

+      if (!(megaCfg->flag & PENDING)) { /* If PENDING, irq will schedule task */

+          queue_task(&runq, &tq_scheduler);

+      }

+    }

+  }

+}

+

+/*-------------------------------------------------------------------

+ *

+ *                 Build a SCB from a Scsi_Cmnd

+ *

+ * Returns a SCB pointer, or NULL

+ * If NULL is returned, the scsi_done function MUST have been called

+ *

+ *-------------------------------------------------------------------*/

+static mega_scb *mega_build_cmd(mega_host_config *megaCfg, Scsi_Cmnd *SCpnt)

+{

+  mega_scb      *pScb;

+  mega_mailbox  *mbox;

+  mega_passthru *pthru;

+  long           seg;

+

+  /* We don't support multi-luns */

+  if (SCpnt->lun != 0) {

+    SCpnt->result = (DID_BAD_TARGET << 16);

+    callDone(SCpnt);

+    return NULL;

+  }

+

+  /*-----------------------------------------------------

+   *

+   *               Logical drive commands

+   *

+   *-----------------------------------------------------*/

+  if (SCpnt->channel == megaCfg->host->max_channel) {

+    switch(SCpnt->cmnd[0]) {

+    case TEST_UNIT_READY:

+      memset(SCpnt->request_buffer, 0, SCpnt->request_bufflen);

+      SCpnt->result = (DID_OK << 16);

+      callDone(SCpnt);

+      return NULL;

+

+    case MODE_SENSE:

+      memset(SCpnt->request_buffer, 0, SCpnt->cmnd[4]);

+      SCpnt->result = (DID_OK << 16);

+      callDone(SCpnt);

+      return NULL;

+

+    case READ_CAPACITY:

+    case INQUIRY:

+      /* Allocate a SCB and initialize passthru */

+      if ((pScb = allocateSCB(megaCfg, SCpnt)) == NULL) {

+	SCpnt->result = (DID_ERROR << 16);

+	callDone(SCpnt);

+	return NULL;

+      }

+      pthru = &pScb->pthru;

+      mbox  = (mega_mailbox *)&pScb->mboxData;

+

+      memset(mbox,  0, sizeof(pScb->mboxData));

+      memset(pthru, 0, sizeof(mega_passthru));

+      pthru->timeout      = 0;

+      pthru->ars          = 0;

+      pthru->islogical    = 1;

+      pthru->logdrv       = SCpnt->target;

+      pthru->cdblen       = SCpnt->cmd_len;

+      pthru->dataxferaddr = (u_long)SCpnt->request_buffer;

+      pthru->dataxferlen  = SCpnt->request_bufflen;

+      memcpy(pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len);

+

+      /* Initialize mailbox area */

+      mbox->cmd      = MEGA_MBOXCMD_PASSTHRU;

+      mbox->xferaddr = (u_long)pthru;

+

+      return pScb;

+

+    case READ_6:

+    case WRITE_6:

+    case READ_10:

+    case WRITE_10:

+      /* Allocate a SCB and initialize mailbox */

+      if ((pScb = allocateSCB(megaCfg, SCpnt)) == NULL) {

+	SCpnt->result = (DID_ERROR << 16);

+	callDone(SCpnt);

+	return NULL;

+      }

+      mbox = (mega_mailbox *)&pScb->mboxData;

+

+      memset(mbox, 0, sizeof(pScb->mboxData));

+      mbox->logdrv = SCpnt->target;

+      mbox->cmd    = (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == READ_10) ?

+	MEGA_MBOXCMD_LREAD : MEGA_MBOXCMD_LWRITE;

+      

+      /* 6-byte */

+      if (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == WRITE_6) {

+	mbox->numsectors = 

+	  (u_long)SCpnt->cmnd[4];

+	mbox->lba = 

+	  ((u_long)SCpnt->cmnd[1] << 16) |

+	  ((u_long)SCpnt->cmnd[2] << 8) |

+	  (u_long)SCpnt->cmnd[3];

+	mbox->lba &= 0x1FFFFF;

+      }

+      

+      /* 10-byte */

+      if (*SCpnt->cmnd == READ_10 || *SCpnt->cmnd == WRITE_10) {

+	mbox->numsectors = 

+	  (u_long)SCpnt->cmnd[8] |

+	  ((u_long)SCpnt->cmnd[7] << 8);

+	mbox->lba =

+	  ((u_long)SCpnt->cmnd[2] << 24) |

+	  ((u_long)SCpnt->cmnd[3] << 16) |

+	  ((u_long)SCpnt->cmnd[4] << 8) |

+	  (u_long)SCpnt->cmnd[5];

+      }

+      

+      /* Calculate Scatter-Gather info */

+      mbox->numsgelements = build_sglist(megaCfg, pScb, 

+					 (u_long*)&mbox->xferaddr,

+					 (u_long*)&seg);

+

+      return pScb;

+      

+    default:

+      SCpnt->result = (DID_BAD_TARGET << 16);

+      callDone(SCpnt);

+      return NULL;

+    }

+  }

+  /*-----------------------------------------------------

+   *

+   *               Passthru drive commands

+   *

+   *-----------------------------------------------------*/

+  else {

+    /* Allocate a SCB and initialize passthru */

+    if ((pScb = allocateSCB(megaCfg, SCpnt)) == NULL) {

+      SCpnt->result = (DID_ERROR << 16);

+      callDone(SCpnt);

+      return NULL;

+    }

+    pthru = &pScb->pthru;

+    mbox  = (mega_mailbox *)pScb->mboxData;

+    

+    memset(mbox,  0, sizeof(pScb->mboxData));

+    memset(pthru, 0, sizeof(mega_passthru));

+    pthru->timeout   = 0;

+    pthru->ars       = 0;

+    pthru->islogical = 0;

+    pthru->channel   = SCpnt->channel;

+    pthru->target    = SCpnt->target;

+    pthru->cdblen    = SCpnt->cmd_len;

+    memcpy(pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len);

+    

+    pthru->numsgelements = build_sglist(megaCfg, pScb,

+					(u_long *)&pthru->dataxferaddr,

+					(u_long *)&pthru->dataxferlen);

+    

+    /* Initialize mailbox */

+    mbox->cmd      = MEGA_MBOXCMD_PASSTHRU;

+    mbox->xferaddr = (u_long)pthru;

+

+    return pScb;

+  }

+  return NULL;

+}

+

+/*--------------------------------------------------------------------

+ * Interrupt service routine

+ *--------------------------------------------------------------------*/

+static void megaraid_isr(int irq, void *devp, struct pt_regs *regs)

+{

+  mega_host_config *megaCfg;

+  u_char            byte, idx, sIdx;

+  u_long            dword;

+  mega_mailbox     *mbox;

+  mega_scb         *pScb;

+  long              flags;

+  int               qCnt, qStatus;

+

+  megaCfg = (mega_host_config *)devp;

+  mbox    = (mega_mailbox *)megaCfg->mbox;

+

+  if (megaCfg->host->irq == irq) {

+    save_flags(flags);

+    cli();

+

+    if (megaCfg->flag & IN_ISR) {

+      TRACE(("ISR called reentrantly!!\n"));

+    }

+

+    megaCfg->flag |= IN_ISR;

+

+    /* Check if a valid interrupt is pending */

+    if (megaCfg->flag & BOARD_QUARTZ) {

+        dword = RDOUTDOOR(megaCfg);

+        if (dword != 0x10001234) {

+            /* Spurious interrupt */

+            megaCfg->flag &= ~IN_ISR;

+            restore_flags(flags);

+            return;

+        }

+        WROUTDOOR(megaCfg,dword);

+    } else {

+        byte = READ_PORT(megaCfg->host->io_port, INTR_PORT);

+        if ((byte & VALID_INTR_BYTE) == 0) {

+          /* Spurious interrupt */

+          megaCfg->flag &= ~IN_ISR;

+          restore_flags(flags);

+          return;

+        }

+        WRITE_PORT(megaCfg->host->io_port, INTR_PORT, byte);

+    }

+    

+    qCnt    = mbox->numstatus;

+    qStatus = mbox->status;

+

+    if (qCnt > 1) {TRACE(("ISR: Received %d status\n", qCnt))

+        printk("Got numstatus = %d\n",qCnt);

+    }

+    

+    for(idx=0; idx<qCnt; idx++) {

+      sIdx = mbox->completed[idx];

+      if (sIdx > 0) {

+	pScb = &megaCfg->scbList[sIdx-1];

+	mega_cmd_done(&megaCfg->scbList[sIdx-1], qStatus);

+      }

+    }

+    if (megaCfg->flag & BOARD_QUARTZ) {

+        WRINDOOR(megaCfg,virt_to_bus(megaCfg->mbox)|0x2);

+        while (RDINDOOR(megaCfg) & 0x02);

+    } else {

+        CLEAR_INTR(megaCfg->host->io_port);

+    }

+

+    megaCfg->flag &= ~IN_ISR;

+    megaCfg->flag &= ~PENDING;

+

+    /* Queue as a delayed ISR routine */

+    queue_task_irq_off(&runq, &tq_immediate);

+    mark_bh(IMMEDIATE_BH);

+

+    restore_flags(flags);

+  }

+}

+

+/*==================================================*/

+/* Wait until the controller's mailbox is available */

+/*==================================================*/

+static int busyWaitMbox(mega_host_config *megaCfg)

+{

+  mega_mailbox *mbox = (mega_mailbox *)megaCfg->mbox;

+  long          counter;

+

+  for(counter=0; counter<0xFFFFFF; counter++) {

+    if (!mbox->busy) return 0;

+  }

+  return -1;

+}

+

+//=====================================================

+// Post a command to the card

+//

+// Arguments:

+//   mega_host_config *megaCfg - Controller structure

+//   u_char *mboxData - Mailbox area, 16 bytes

+//   mega_scb *pScb   - SCB posting (or NULL if N/A)

+//   int intr         - if 1, interrupt, 0 is blocking

+//=====================================================

+static int MegaIssueCmd(mega_host_config *megaCfg,

+			u_char *mboxData,

+			mega_scb *pScb,

+			int intr)

+{

+  mega_mailbox *mbox = (mega_mailbox *)megaCfg->mbox;

+  long          flags;

+  u_char        byte;

+  u_long        cmdDone;

+

+#if 0

+    if (pScb) {

+      pScb->SCpnt->result = DID_BAD_TARGET << 16;

+      callDone(pScb->SCpnt);

+      freeSCB(pScb);

+    }

+    return 0;

+#endif

+

+  mboxData[0x1] = (pScb ? pScb->idx+1 : 0x00);  /* Set cmdid */

+  mboxData[0xF] = 1;                            /* Set busy */

+

+  /* gah.. issuing a command while pending seems to fall through

+   * the cracks.. 

+   */

+  if (megaCfg->flag & PENDING) {

+    return -1;

+  }

+

+  /* Wait until mailbox is free */

+  if (busyWaitMbox(megaCfg)) {

+    if (pScb) {

+      TRACE(("Mailbox busy %.08lx <%d.%d.%d>\n", pScb->SCpnt->serial_number,

+	     pScb->SCpnt->channel, pScb->SCpnt->target, pScb->SCpnt->lun));

+    }

+    return -1;

+  }

+

+  /* Copy mailbox data into host structure */

+  save_flags(flags);

+  cli();

+  memset(mbox, 0, sizeof(mega_mailbox));

+  memcpy(mbox, mboxData, 16);

+  restore_flags(flags);

+

+  /* Kick IO */

+  megaCfg->flag |= PENDING;

+  if (intr) {

+    /* Issue interrupt (non-blocking) command */

+    if (megaCfg->flag & BOARD_QUARTZ) {

+        mbox->mraid_poll = 0; 

+        mbox->mraid_ack = 0; 

+        WRINDOOR(megaCfg, virt_to_bus(megaCfg->mbox) | 0x1);

+    } else {

+        ENABLE_INTR(megaCfg->host->io_port);

+        ISSUE_COMMAND(megaCfg->host->io_port);

+    }

+  }

+  else {      /* Issue non-ISR (blocking) command */

+

+    if (megaCfg->flag & BOARD_QUARTZ) {

+

+      mbox->mraid_poll = 0; 

+      mbox->mraid_ack = 0; 

+      WRINDOOR(megaCfg, virt_to_bus(megaCfg->mbox) | 0x1);

+

+      while((cmdDone=RDOUTDOOR(megaCfg)) != 0x10001234);

+      WROUTDOOR(megaCfg, cmdDone);

+

+      if (pScb) {

+	mega_cmd_done(pScb, mbox->status);

+	mega_rundoneq();

+      }

+

+      WRINDOOR(megaCfg,virt_to_bus(megaCfg->mbox) | 0x2);

+      while(RDINDOOR(megaCfg) & 0x2);

+

+      megaCfg->flag &= ~PENDING;

+    }

+    else {

+      DISABLE_INTR(megaCfg->host->io_port);

+      ISSUE_COMMAND(megaCfg->host->io_port);

+      

+      while(!((byte=READ_PORT(megaCfg->host->io_port,INTR_PORT))&INTR_VALID));

+      WRITE_PORT(megaCfg->host->io_port, INTR_PORT, byte);

+      

+      ENABLE_INTR(megaCfg->host->io_port);

+      CLEAR_INTR(megaCfg->host->io_port);

+      

+      if (pScb) {

+	mega_cmd_done(pScb, mbox->status);

+	mega_rundoneq();

+      }

+      megaCfg->flag &= ~PENDING;

+    }

+  }

+

+  return 0;

+}

+

+/*-------------------------------------------------------------------

+ * Copies data to SGLIST

+ *-------------------------------------------------------------------*/

+static int build_sglist(mega_host_config *megaCfg, mega_scb *scb, 

+			u_long *buffer, u_long *length)

+{

+  struct scatterlist *sgList;

+  int idx;

+

+  /* Scatter-gather not used */

+  if (scb->SCpnt->use_sg == 0) {

+    *buffer = (u_long)scb->SCpnt->request_buffer;

+    *length = (u_long)scb->SCpnt->request_bufflen;

+    return 0;

+  }

+

+  sgList = (struct scatterlist *)scb->SCpnt->buffer;

+  if (scb->SCpnt->use_sg == 1) {

+    *buffer = (u_long)sgList[0].address;

+    *length = (u_long)sgList[0].length;

+    return 0;

+  }

+

+  /* Copy Scatter-Gather list info into controller structure */

+  for(idx=0; idx<scb->SCpnt->use_sg; idx++) {

+    scb->sgList[idx].address = (u_long)sgList[idx].address;

+    scb->sgList[idx].length  = (u_long)sgList[idx].length;

+  }

+  

+  /* Reset pointer and length fields */

+  *buffer = (u_long)scb->sgList;

+  *length = 0;

+

+  /* Return count of SG requests */

+  return scb->SCpnt->use_sg;

+}

+    

+/*--------------------------------------------------------------------

+ * Initializes the adress of the controller's mailbox register

+ *  The mailbox register is used to issue commands to the card.

+ *  Format of the mailbox area:

+ *   00 01 command

+ *   01 01 command id

+ *   02 02 # of sectors

+ *   04 04 logical bus address

+ *   08 04 physical buffer address

+ *   0C 01 logical drive #

+ *   0D 01 length of scatter/gather list

+ *   0E 01 reserved

+ *   0F 01 mailbox busy

+ *   10 01 numstatus byte

+ *   11 01 status byte

+ *--------------------------------------------------------------------*/

+static int mega_register_mailbox(mega_host_config *megaCfg, u_long paddr)

+{

+  /* align on 16-byte boundry */

+  megaCfg->mbox = &megaCfg->mailbox;

+  megaCfg->mbox = (mega_mailbox *) ((((ulong)megaCfg->mbox) + 16)&0xfffffff0);

+  paddr = (paddr+16)&0xfffffff0;

+

+  /* Register mailbox area with the firmware */

+  if (megaCfg->flag & BOARD_QUARTZ) {

+  }

+  else {

+    WRITE_PORT(megaCfg->host->io_port, MBOX_PORT0, paddr         & 0xFF);

+    WRITE_PORT(megaCfg->host->io_port, MBOX_PORT1, (paddr >>  8) & 0xFF);

+    WRITE_PORT(megaCfg->host->io_port, MBOX_PORT2, (paddr >> 16) & 0xFF);

+    WRITE_PORT(megaCfg->host->io_port, MBOX_PORT3, (paddr >> 24) & 0xFF);

+    WRITE_PORT(megaCfg->host->io_port, ENABLE_MBOX_REGION, ENABLE_MBOX_BYTE);

+    

+    CLEAR_INTR(megaCfg->host->io_port);

+    ENABLE_INTR(megaCfg->host->io_port);

+  }

+  return 0;

+}

+

+/*-------------------------------------------------------------------

+ * Issue an adapter info query to the controller

+ *-------------------------------------------------------------------*/

+static int mega_i_query_adapter(mega_host_config *megaCfg)

+{

+  mega_RAIDINQ *adapterInfo;

+  mega_mailbox *mbox;

+  u_char        mboxData[16];

+  u_long        paddr;

+

+  /* Initialize adapter inquiry */

+  paddr = virt_to_bus(megaCfg->mega_buffer);

+  mbox  = (mega_mailbox *)mboxData;

+

+  memset((void *)megaCfg->mega_buffer, 0, sizeof(megaCfg->mega_buffer));

+  memset(mbox, 0, 16);

+

+  /* Initialize mailbox registers */

+  mbox->cmd      = MEGA_MBOXCMD_ADAPTERINQ;

+  mbox->xferaddr = paddr;

+

+  /* Issue a blocking command to the card */

+  MegaIssueCmd(megaCfg, mboxData, NULL, 0);

+  

+  /* Initialize host/local structures with Adapter info */

+  adapterInfo = (mega_RAIDINQ *)megaCfg->mega_buffer;

+  megaCfg->host->max_channel = adapterInfo->AdpInfo.ChanPresent;

+  megaCfg->host->max_id      = adapterInfo->AdpInfo.MaxTargPerChan;

+  megaCfg->numldrv           = adapterInfo->LogdrvInfo.NumLDrv;

+

+#if 0

+  printk("---- Logical drive info ----\n");

+  for(i=0; i<megaCfg->numldrv; i++) {

+    printk("%d: size: %ld prop: %x state: %x\n",i,

+	   adapterInfo->LogdrvInfo.LDrvSize[i],

+	   adapterInfo->LogdrvInfo.LDrvProp[i],

+	   adapterInfo->LogdrvInfo.LDrvState[i]);

+  }

+  printk("---- Physical drive info ----\n");

+  for(i=0; i<MAX_PHYSICAL_DRIVES; i++) {

+    if (i && !(i % 8)) printk("\n");

+    printk("%d: %x   ", i, adapterInfo->PhysdrvInfo.PDrvState[i]);

+  }

+  printk("\n");

+#endif

+

+  megaCfg->max_cmds = adapterInfo->AdpInfo.MaxConcCmds;

+

+#ifdef HP            /* use HP firmware and bios version encoding */

+      sprintf(megaCfg->fwVer,"%c%d%d.%d%d",

+          adapterInfo->AdpInfo.FwVer[2],

+          adapterInfo->AdpInfo.FwVer[1] >> 8,

+          adapterInfo->AdpInfo.FwVer[1] & 0x0f,

+          adapterInfo->AdpInfo.FwVer[2] >> 8,

+          adapterInfo->AdpInfo.FwVer[2] & 0x0f);

+      sprintf(megaCfg->biosVer,"%c%d%d.%d%d",

+          adapterInfo->AdpInfo.BiosVer[2],

+          adapterInfo->AdpInfo.BiosVer[1] >> 8,

+          adapterInfo->AdpInfo.BiosVer[1] & 0x0f,

+          adapterInfo->AdpInfo.BiosVer[2] >> 8,

+          adapterInfo->AdpInfo.BiosVer[2] & 0x0f);

+#else

+      memcpy(megaCfg->fwVer, adapterInfo->AdpInfo.FwVer, 4);

+      megaCfg->fwVer[4] = 0;

+

+      memcpy(megaCfg->biosVer, adapterInfo->AdpInfo.BiosVer, 4);

+      megaCfg->biosVer[4] = 0;

+#endif

+

+  printk("megaraid: [%s:%s] detected %d logical drives" CRLFSTR,

+	 megaCfg->fwVer,

+	 megaCfg->biosVer,

+	 megaCfg->numldrv);

+  return 0;

+}

+

+/*-------------------------------------------------------------------------

+ *

+ *                      Driver interface functions

+ *

+ *-------------------------------------------------------------------------*/

+

+/*----------------------------------------------------------

+ * Returns data to be displayed in /proc/scsi/megaraid/X

+ *----------------------------------------------------------*/

+int megaraid_proc_info(char *buffer, char **start, off_t offset,

+		       int length, int inode, int inout)

+{

+  *start = buffer;

+  return 0;

+}

+

+int findCard(Scsi_Host_Template *pHostTmpl, 

+	     u_short pciVendor, u_short pciDev,

+	     long flag)

+{

+  mega_host_config *megaCfg;

+  struct Scsi_Host *host;

+  u_char            pciBus, pciDevFun, megaIrq;

+  u_long            megaBase;

+  u_short           pciIdx;

+

+  pciIdx = 0;

+  while(!pcibios_find_device(pciVendor, pciDev, pciIdx,&pciBus,&pciDevFun)) {

+    printk("megaraid: found 0x%4.04x:0x%4.04x:idx %d:bus %d:slot %d:fun %d\n",

+	   pciVendor, 

+	   pciDev, 

+	   pciIdx, pciBus, 

+	   PCI_SLOT(pciDevFun), 

+	   PCI_FUNC(pciDevFun));

+    

+    /* Read the base port and IRQ from PCI */

+    pcibios_read_config_dword(pciBus, pciDevFun,

+			     PCI_BASE_ADDRESS_0,

+			     (u_int *)&megaBase);

+    pcibios_read_config_byte(pciBus, pciDevFun,			       

+			     PCI_INTERRUPT_LINE,

+			     &megaIrq);

+    pciIdx++;

+

+    if (flag & BOARD_QUARTZ) {

+      megaBase &= PCI_BASE_ADDRESS_MEM_MASK;

+      megaBase = (long) ioremap(megaBase,128);

+    }

+    else {

+      megaBase &= PCI_BASE_ADDRESS_IO_MASK;

+      megaBase += 0x10;

+    }

+

+    /* Initialize SCSI Host structure */

+    host    = scsi_register(pHostTmpl, sizeof(mega_host_config));

+    megaCfg = (mega_host_config *)host->hostdata;

+    memset(megaCfg, 0, sizeof(mega_host_config));

+

+    printk(" scsi%d: Found a MegaRAID controller at 0x%x, IRQ: %d" CRLFSTR, 

+	   host->host_no, (u_int)megaBase, megaIrq);

+    

+    /* Copy resource info into structure */

+    megaCfg->flag            = flag;

+    megaCfg->host            = host;

+    megaCfg->base            = megaBase;

+    megaCfg->host->irq       = megaIrq;

+    megaCfg->host->io_port   = megaBase;

+    megaCfg->host->n_io_port = 16;

+    megaCfg->host->unique_id = (pciBus << 8) | pciDevFun;

+    megaCtlrs[numCtlrs++]    = megaCfg;

+

+    if (flag != BOARD_QUARTZ) {

+      /* Request our IO Range */

+      if (check_region(megaBase, 16)) {

+	printk(KERN_WARNING "megaraid: Couldn't register I/O range!" CRLFSTR);

+	scsi_unregister(host);

+	continue;

+      }

+      request_region(megaBase, 16, "megaraid");

+    }

+

+    /* Request our IRQ */

+    if (request_irq(megaIrq, megaraid_isr, SA_INTERRUPT|SA_SHIRQ, 

+		    "megaraid", megaCfg)) {

+      printk(KERN_WARNING "megaraid: Couldn't register IRQ %d!" CRLFSTR,

+	     megaIrq);

+      scsi_unregister(host);

+      continue;

+    }

+

+    mega_register_mailbox(megaCfg, virt_to_bus((void*)&megaCfg->mailbox));

+    mega_i_query_adapter(megaCfg);

+

+    /* Initialize SCBs */

+    initSCB(megaCfg);

+

+  }

+  return pciIdx;

+}

+

+/*---------------------------------------------------------

+ * Detects if a megaraid controller exists in this system

+ *---------------------------------------------------------*/

+int megaraid_detect(Scsi_Host_Template *pHostTmpl)

+{

+  int count = 0;

+

+  pHostTmpl->proc_dir = &proc_scsi_megaraid;

+

+  if (!pcibios_present()) 

+    {

+      printk("megaraid: PCI bios not present." CRLFSTR);

+      return 0;

+    }

+

+  count += findCard(pHostTmpl, 0x101E, 0x9010, 0);

+  count += findCard(pHostTmpl, 0x101E, 0x9060, 0);

+  count += findCard(pHostTmpl, 0x8086, 0x1960, BOARD_QUARTZ);

+

+  return count;

+}

+

+/*---------------------------------------------------------------------

+ * Release the controller's resources

+ *---------------------------------------------------------------------*/

+int megaraid_release(struct Scsi_Host *pSHost)

+{

+  mega_host_config *megaCfg;

+  mega_mailbox         *mbox;

+  u_char                mboxData[16];

+

+  megaCfg = (mega_host_config*)pSHost->hostdata;

+  mbox    = (mega_mailbox *)mboxData;

+

+  /* Flush cache to disk */

+  memset(mbox, 0, 16);

+  mboxData[0] = 0xA;

+

+  /* Issue a blocking (interrupts disabled) command to the card */

+  MegaIssueCmd(megaCfg, mboxData, NULL, 0);

+

+  schedule();

+

+  /* Free our resources */

+  if (megaCfg->flag & BOARD_QUARTZ) {

+      iounmap((void *)megaCfg->base);

+  } else {

+      release_region(megaCfg->host->io_port, 16);

+  }

+  free_irq(megaCfg->host->irq, megaCfg); /* Must be freed first, otherwise

+                                            extra interrupt is generated */

+  scsi_unregister(pSHost);

+

+  return 0;

+}

+

+/*----------------------------------------------

+ * Get information about the card/driver 

+ *----------------------------------------------*/

+const char *megaraid_info(struct Scsi_Host *pSHost)

+{

+  static char           buffer[512];

+  mega_host_config  *megaCfg;

+  mega_RAIDINQ          *adapterInfo;

+

+  megaCfg     = (mega_host_config *)pSHost->hostdata;

+  adapterInfo = (mega_RAIDINQ *)megaCfg->mega_buffer;

+

+  sprintf(buffer, "AMI MegaRAID %s %d commands %d targs %d chans",

+	  megaCfg->fwVer,

+	  adapterInfo->AdpInfo.MaxConcCmds,

+	  megaCfg->host->max_id,

+	  megaCfg->host->max_channel);

+  return buffer;

+}

+

+/*-----------------------------------------------------------------

+ * Perform a SCSI command

+ * Mailbox area:

+ *   00 01 command

+ *   01 01 command id

+ *   02 02 # of sectors

+ *   04 04 logical bus address

+ *   08 04 physical buffer address

+ *   0C 01 logical drive #

+ *   0D 01 length of scatter/gather list

+ *   0E 01 reserved

+ *   0F 01 mailbox busy

+ *   10 01 numstatus byte

+ *   11 01 status byte 

+ *-----------------------------------------------------------------*/

+int megaraid_queue(Scsi_Cmnd *SCpnt, void (*pktComp)(Scsi_Cmnd *))

+{

+  mega_host_config *megaCfg;

+  mega_scb         *pScb;

+

+  megaCfg = (mega_host_config *)SCpnt->host->hostdata;

+

+  if (!(megaCfg->flag & (1L << SCpnt->channel))) {

+    printk("scsi%d: scanning channel %c for devices.\n",

+	   megaCfg->host->host_no,

+	   SCpnt->channel + 'A');

+    megaCfg->flag |= (1L << SCpnt->channel);

+  }

+

+  SCpnt->scsi_done = pktComp;

+

+  /* Allocate and build a SCB request */

+  if ((pScb = mega_build_cmd(megaCfg, SCpnt)) != NULL) {

+    /* Add SCB to the head of the pending queue */

+    ENQUEUE(pScb, mega_scb, qPending, next);

+

+    /* Issue the command to the card */

+      mega_runque(NULL);

+  }

+

+#if 0

+  SCpnt->result = (DID_BAD_TARGET << 16);

+  SCpnt->scsi_done = pktComp;

+  callDone(SCpnt);

+#endif

+  return 0;

+}

+

+/*----------------------------------------------------------------------

+ * Issue a blocking command to the controller

+ *----------------------------------------------------------------------*/

+volatile static int internal_done_flag    = 0;

+volatile static int internal_done_errcode = 0;

+

+static void internal_done(Scsi_Cmnd *SCpnt)

+{

+  internal_done_errcode = SCpnt->result;

+  internal_done_flag++;

+}

+

+int megaraid_command(Scsi_Cmnd *SCpnt)

+{

+  internal_done_flag = 0;

+

+  /* Queue command, and wait until it has completed */

+  megaraid_queue(SCpnt, internal_done);

+

+  while(!internal_done_flag)

+    barrier();

+

+  return internal_done_errcode;

+}

+

+/*---------------------------------------------------------------------

+ * Abort a previous SCSI request

+ *---------------------------------------------------------------------*/

+int megaraid_abort(Scsi_Cmnd *SCpnt)

+{

+  mega_host_config *megaCfg;

+  int       idx;

+  long      flags;

+

+  save_flags(flags);

+  cli();

+

+  megaCfg = (mega_host_config *)SCpnt->host->hostdata;

+

+  TRACE(("ABORT!!! %.08lx %.02x <%d.%d.%d>\n",

+	 SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target, 

+	 SCpnt->lun));

+  /*

+   * Walk list of SCBs for any that are still outstanding

+   */

+  for(idx=0; idx<megaCfg->max_cmds; idx++) {

+    if (megaCfg->scbList[idx].idx >= 0) {

+      if (megaCfg->scbList[idx].SCpnt == SCpnt) {

+	freeSCB(&megaCfg->scbList[idx]);

+

+	SCpnt->result = (DID_RESET << 16) | (SUGGEST_RETRY<<24);

+	callDone(SCpnt);

+      }

+    }

+  }

+  restore_flags(flags);

+  return SCSI_ABORT_SNOOZE;

+}

+

+/*---------------------------------------------------------------------

+ * Reset a previous SCSI request

+ *---------------------------------------------------------------------*/

+int megaraid_reset(Scsi_Cmnd *SCpnt, unsigned int rstflags)

+{

+  mega_host_config *megaCfg;

+  int       idx;

+  long      flags;

+

+  save_flags(flags);

+  cli();

+

+  megaCfg = (mega_host_config *)SCpnt->host->hostdata;

+

+  TRACE(("RESET: %.08lx %.02x <%d.%d.%d>\n",

+	 SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target, 

+	 SCpnt->lun));

+

+  /*

+   * Walk list of SCBs for any that are still outstanding

+   */

+  for(idx=0; idx<megaCfg->max_cmds; idx++) {

+    if (megaCfg->scbList[idx].idx >= 0) {

+      SCpnt = megaCfg->scbList[idx].SCpnt;

+      freeSCB(&megaCfg->scbList[idx]);

+      SCpnt->result = (DID_RESET << 16) | (SUGGEST_RETRY<<24);

+      callDone(SCpnt);

+    }

+  }

+  restore_flags(flags);

+  return SCSI_RESET_PUNT;

+} 

+

+/*-------------------------------------------------------------

+ * Return the disk geometry for a particular disk

+ * Input:

+ *   Disk *disk - Disk geometry

+ *   kdev_t dev - Device node

+ *   int *geom  - Returns geometry fields

+ *     geom[0] = heads

+ *     geom[1] = sectors

+ *     geom[2] = cylinders

+ *-------------------------------------------------------------*/

+int megaraid_biosparam(Disk *disk, kdev_t dev, int *geom)

+{

+  int                   heads, sectors, cylinders;

+  mega_host_config *megaCfg;

+

+  /* Get pointer to host config structure */

+  megaCfg = (mega_host_config *)disk->device->host->hostdata;

+

+  /* Default heads (64) & sectors (32) */

+  heads     = 64;

+  sectors   = 32;

+  cylinders = disk->capacity / (heads * sectors);

+

+  /* Handle extended translation size for logical drives > 1Gb */

+  if (disk->capacity >= 0x200000) {

+    heads     = 255;

+    sectors   = 63;

+    cylinders = disk->capacity / (heads * sectors);

+  }

+

+  /* return result */

+  geom[0] = heads;

+  geom[1] = sectors;

+  geom[2] = cylinders;

+

+  return 0;

+}

+

+#ifdef MODULE

+Scsi_Host_Template driver_template = MEGARAID;

+

+#include "scsi_module.c"

+#endif

diff -urN linux/drivers/scsi/megaraid.h linux-2.0.32-megaraid/drivers/scsi/megaraid.h

--- linux/drivers/scsi/megaraid.h	Wed Dec 31 19:00:00 1969

+++ linux-2.0.32-megaraid/drivers/scsi/megaraid.h	Mon Aug 17 17:38:49 1998

@@ -0,0 +1,291 @@

+#ifndef __MEGARAID_H__

+#define __MEGARAID_H__

+

+#define IN_ISR                  0x80000000L

+#define NO_INTR                 0x40000000L

+#define IN_TIMEOUT              0x20000000L

+#define PENDING                 0x10000000L

+#define BOARD_QUARTZ            0x08000000L

+

+#define SCB_ACTIVE 0x1

+#define SCB_WAITQ  0x2

+#define SCB_ISSUED 0x4

+

+#define SCB_FREE                -1

+#define SCB_RESET               -2

+#define SCB_ABORT               -3

+#define SCB_LOCKED              -4

+

+#define MEGA_CMD_TIMEOUT        10

+

+#define MAX_SGLIST              20

+#define MAX_COMMANDS            254

+

+#define MAX_LOGICAL_DRIVES      8

+#define MAX_CHANNEL             5

+#define MAX_TARGET              15

+#define MAX_PHYSICAL_DRIVES     MAX_CHANNEL*MAX_TARGET

+

+#define INQUIRY_DATA_SIZE       0x24

+#define MAX_CDB_LEN             0x0A

+#define MAX_REQ_SENSE_LEN       0x20

+

+#define INTR_VALID              0x40

+

+/* Mailbox commands */

+#define MEGA_MBOXCMD_LREAD      0x01

+#define MEGA_MBOXCMD_LWRITE     0x02

+#define MEGA_MBOXCMD_PASSTHRU   0x03

+#define MEGA_MBOXCMD_ADAPTERINQ 0x05

+

+/* Offsets into Mailbox */

+#define COMMAND_PORT       0x00

+#define COMMAND_ID_PORT    0x01

+#define SG_LIST_PORT0      0x08

+#define SG_LIST_PORT1      0x09

+#define SG_LIST_PORT2      0x0a

+#define SG_LIST_PORT3      0x0b

+#define SG_ELEMENT_PORT    0x0d

+#define NO_FIRED_PORT      0x0f

+

+/* I/O Port offsets */

+#define I_CMD_PORT         0x00

+#define I_ACK_PORT         0x00

+#define I_TOGGLE_PORT      0x01

+#define INTR_PORT          0x0a

+

+#define MAILBOX_SIZE       70

+#define MBOX_BUSY_PORT     0x00

+#define MBOX_PORT0         0x04

+#define MBOX_PORT1         0x05

+#define MBOX_PORT2         0x06

+#define MBOX_PORT3         0x07

+#define ENABLE_MBOX_REGION 0x0B

+

+/* I/O Port Values */

+#define ISSUE_BYTE         0x10

+#define ACK_BYTE           0x08

+#define ENABLE_INTR_BYTE   0xc0

+#define DISABLE_INTR_BYTE  0x00

+#define VALID_INTR_BYTE    0x40

+#define MBOX_BUSY_BYTE     0x10

+#define ENABLE_MBOX_BYTE   0x00

+

+/* Setup some port macros here */

+#define WRITE_MAILBOX(base,offset,value)   *(base+offset)=value

+#define READ_MAILBOX(base,offset)          *(base+offset)

+

+#define WRITE_PORT(base,offset,value)      outb_p(value,base+offset)

+#define READ_PORT(base,offset)             inb_p(base+offset)

+

+#define ISSUE_COMMAND(base)   WRITE_PORT(base,I_CMD_PORT,ISSUE_BYTE)

+#define CLEAR_INTR(base)      WRITE_PORT(base,I_ACK_PORT,ACK_BYTE)

+#define ENABLE_INTR(base)     WRITE_PORT(base,I_TOGGLE_PORT,ENABLE_INTR_BYTE)

+#define DISABLE_INTR(base)    WRITE_PORT(base,I_TOGGLE_PORT,DISABLE_INTR_BYTE)

+

+/* Define AMI's PCI codes */

+#undef PCI_VENDOR_ID_AMI

+#undef PCI_DEVICE_ID_AMI_MEGARAID

+

+#ifndef PCI_VENDOR_ID_AMI

+#define PCI_VENDOR_ID_AMI          0x101E

+#define PCI_DEVICE_ID_AMI_MEGARAID 0x9010

+#endif

+

+#define PCI_CONF_BASE_ADDR_OFFSET  0x10

+#define PCI_CONF_IRQ_OFFSET        0x3c

+

+#if LINUX_VERSION_CODE < 0x20100

+#define MEGARAID \

+  { NULL,                               /* Next                      */\

+    NULL,                               /* Usage Count Pointer       */\

+    NULL,                               /* /proc Directory Entry     */\

+    megaraid_proc_info,                 /* /proc Info Function       */\

+    "MegaRAID",                         /* Driver Name               */\

+    megaraid_detect,                    /* Detect Host Adapter       */\

+    megaraid_release,                   /* Release Host Adapter      */\

+    megaraid_info,                      /* Driver Info Function      */\

+    megaraid_command,                   /* Command Function          */\

+    megaraid_queue,                     /* Queue Command Function    */\

+    megaraid_abort,                     /* Abort Command Function    */\

+    megaraid_reset,                     /* Reset Command Function    */\

+    NULL,                               /* Slave Attach Function     */\

+    megaraid_biosparam,                 /* Disk BIOS Parameters      */\

+    1,                                  /* # of cmds that can be\

+                                           outstanding at any time */\

+    7,                                  /* HBA Target ID             */\

+    MAX_SGLIST,                         /* Scatter/Gather Table Size */\

+    1,                                  /* SCSI Commands per LUN     */\

+    0,                                  /* Present                   */\

+    0,                                  /* Default Unchecked ISA DMA */\

+    ENABLE_CLUSTERING }                 /* Enable Clustering         */

+#else

+#define MEGARAID \

+  { NULL,                               /* Next                      */\

+    NULL,                               /* Module                    */\

+    NULL,                               /* /proc Directory Entry     */\

+    NULL,                               /* /proc/fs entry            */\

+    "MegaRAID",                         /* Driver Name               */\

+    megaraid_detect,                    /* Detect Host Adapter       */\

+    megaraid_release,                   /* Release Host Adapter      */\

+    megaraid_info,                      /* Driver Info Function      */\

+    NULL,                               /* Ioctl interface           */\

+    megaraid_command,                   /* Command Function          */\

+    megaraid_queue,                     /* Queue Command Function    */\

+    NULL,\

+    NULL,\

+    NULL,\

+    NULL,\

+    NULL,\

+    megaraid_abort,                     /* Abort Command Function    */\

+    megaraid_reset,                     /* Reset Command Function    */\

+    NULL,                               /* Slave Attach Function     */\

+    megaraid_biosparam,                 /* Disk BIOS Parameters      */\

+    255,                                /* Can Queue                 */\

+    7,                                  /* HBA Target ID             */\

+    MAX_SGLIST,                         /* Scatter/Gather Table Size */\

+    1,                                  /* SCSI Commands per LUN     */\

+    0,                                  /* Present                   */\

+    0,                                  /* Default Unchecked ISA DMA */\

+    ENABLE_CLUSTERING }                 /* Enable Clustering         */

+#endif

+

+

+/* Structures */

+typedef struct _mega_ADP_INFO

+{

+  u_char    MaxConcCmds;

+  u_char    RbldRate;

+  u_char    MaxTargPerChan;

+  u_char    ChanPresent;

+  u_char    FwVer[4];

+  u_short   AgeOfFlash;

+  u_char    ChipSet;

+  u_char    DRAMSize;

+  u_char    CacheFlushInterval;

+  u_char    BiosVer[4];

+  u_char    resvd[7];

+} mega_ADP_INFO;

+

+typedef struct _mega_LDRV_INFO

+{

+  u_char   NumLDrv;

+  u_char   resvd[3];

+  u_long   LDrvSize[MAX_LOGICAL_DRIVES];

+  u_char   LDrvProp[MAX_LOGICAL_DRIVES];

+  u_char   LDrvState[MAX_LOGICAL_DRIVES];

+} mega_LDRV_INFO;

+

+typedef struct _mega_PDRV_INFO

+{

+  u_char   PDrvState[MAX_PHYSICAL_DRIVES];

+  u_char   resvd;

+} mega_PDRV_INFO;

+

+// RAID inquiry: Mailbox command 0x5

+typedef struct _mega_RAIDINQ

+{

+  mega_ADP_INFO    AdpInfo;

+  mega_LDRV_INFO   LogdrvInfo;

+  mega_PDRV_INFO   PhysdrvInfo;

+} mega_RAIDINQ;

+

+// Passthrough command: Mailbox command 0x3

+typedef struct mega_passthru

+{

+  u_char            timeout:3;              /* 0=6sec/1=60sec/2=10min/3=3hrs */

+  u_char            ars:1;

+  u_char            reserved:3;

+  u_char            islogical:1;

+  u_char            logdrv;                 /* if islogical == 1 */

+  u_char            channel;                /* if islogical == 0 */

+  u_char            target;                 /* if islogical == 0 */

+  u_char            queuetag;               /* unused */

+  u_char            queueaction;            /* unused */

+  u_char            cdb[MAX_CDB_LEN];

+  u_char            cdblen;

+  u_char            reqsenselen;

+  u_char            reqsensearea[MAX_REQ_SENSE_LEN];

+  u_char            numsgelements;

+  u_char            scsistatus;

+  u_long            dataxferaddr;

+  u_long            dataxferlen;

+} mega_passthru;

+

+typedef struct _mega_mailbox

+{

+  /* 0x0 */ u_char    cmd;

+  /* 0x1 */ u_char    cmdid;

+  /* 0x2 */ u_short   numsectors;

+  /* 0x4 */ u_long    lba;

+  /* 0x8 */ u_long    xferaddr;

+  /* 0xC */ u_char    logdrv;

+  /* 0xD */ u_char    numsgelements;

+  /* 0xE */ u_char    resvd;

+  /* 0xF */ u_char    busy;

+  /* 0x10*/ u_char    numstatus;

+  /* 0x11*/ u_char    status;

+  /* 0x12*/ u_char    completed[46];

+            u_char    mraid_poll;

+            u_char    mraid_ack;

+            u_char    pad[16];

+} mega_mailbox;

+

+typedef struct _mega_sglist

+{

+  u_long     address;

+  u_long     length;

+} mega_sglist;

+

+/* Queued command data */

+typedef struct _mega_scb mega_scb;

+

+struct _mega_scb

+{

+  int             idx;

+  u_long          flag;

+  Scsi_Cmnd      *SCpnt;

+  u_char          mboxData[16];

+  mega_passthru   pthru;

+  mega_sglist    *sgList;

+  mega_scb       *next;

+};

+

+/* Per-controller data */

+typedef struct _mega_host_config

+{

+  u_char               numldrv;

+  u_long               flag;

+  u_long               base;

+

+  struct tq_struct     megaTq;

+

+  /* Host adapter parameters */

+  u_char               fwVer[7];

+  u_char               biosVer[7];

+

+  struct Scsi_Host     *host;

+

+  /* The following must be DMA-able!! */

+  volatile mega_mailbox *mbox;

+  volatile mega_mailbox mailbox;

+  volatile u_char       mega_buffer[2*1024L];

+

+  u_char                max_cmds;

+  mega_scb              scbList[MAX_COMMANDS];

+} mega_host_config;

+

+extern struct proc_dir_entry proc_scsi_megaraid;

+

+const char *megaraid_info( struct Scsi_Host * );

+int        megaraid_detect( Scsi_Host_Template * );

+int        megaraid_release(struct Scsi_Host *);

+int        megaraid_command( Scsi_Cmnd * );

+int        megaraid_abort( Scsi_Cmnd * );

+int        megaraid_reset( Scsi_Cmnd *, unsigned int); 

+int        megaraid_queue( Scsi_Cmnd *, void (*done)(Scsi_Cmnd *) );

+int        megaraid_biosparam( Disk *, kdev_t, int * );

+int        megaraid_proc_info( char *buffer, char **start, off_t offset,

+			       int length, int hostno, int inout );

+

+#endif

diff -urN linux/include/linux/proc_fs.h linux-2.0.32-megaraid/include/linux/proc_fs.h

--- linux/include/linux/proc_fs.h	Tue Nov 18 14:46:46 1997

+++ linux-2.0.32-megaraid/include/linux/proc_fs.h	Tue Aug 11 10:54:47 1998

@@ -137,6 +137,7 @@

 	PROC_SCSI_AM53C974,

 	PROC_SCSI_SSC,

 	PROC_SCSI_NCR53C406A,

+	PROC_SCSI_MEGARAID,

 	PROC_SCSI_PPA,

 	PROC_SCSI_ESP,

 	PROC_SCSI_A3000,

