patch-2.3.40 linux/drivers/scsi/megaraid.c

Next file: linux/drivers/scsi/megaraid.h
Previous file: linux/drivers/scsi/ide-scsi.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.39/linux/drivers/scsi/megaraid.c linux/drivers/scsi/megaraid.c
@@ -9,7 +9,7 @@
  *              as published by the Free Software Foundation; either version
  *              2 of the License, or (at your option) any later version.
  *
- * Version : 1.04
+ * Version : 1.05
  * 
  * Description: Linux device driver for AMI MegaRAID controller
  *
@@ -111,6 +111,16 @@
  *    The addtional 32 bit field for 64bit address in the newly defined
  *      mailbox64 structure is set to 0 at this point.
  *
+ * Version 1.05
+ *    Changed the queing implementation for handling SCBs and completed
+ *      commands.
+ *    Added spinlocks in the interrupt service routine to enable the dirver
+ *      function in the SMP environment.
+ *    Fixed the problem of unnecessary aborts in the abort entry point, which
+ *      also enables the driver to handle large amount of I/O requests for
+ *      long duration of time.
+ *
+ *
  * BUGS:
  *     Some older 2.1 kernels (eg. 2.1.90) have a bug in pci.c that
  *     fails to detect the controller as a pci device on the system.
@@ -125,7 +135,8 @@
 #define CRLFSTR "\n"
 #define IOCTL_CMD_NEW  0x81
 
-#define MEGARAID_VERSION "v1.04 (August 16, 1999)"
+#define MEGARAID_VERSION "v1.05 (October 27, 1999)"
+
 
 #include <linux/version.h>
 
@@ -143,8 +154,6 @@
 #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>
@@ -181,31 +190,6 @@
 #define MAX_SERBUF 160
 #define COM_BASE 0x2f8
 
-#define ENQUEUE(obj,type,list,next) \
-{ type **node; long cpuflag; \
-  spin_lock_irqsave(&mega_lock,cpuflag);\
-  for(node=&(list); *node; node=(type **)&(*node)->##next); \
-  (*node) = obj; \
-  (*node)->##next = NULL; \
-  spin_unlock_irqrestore(&mega_lock,cpuflag);\
-}
-
-/* a non-locking version (if we already have the lock) */
-#define ENQUEUE_NL(obj,type,list,next) \
-{ type **node; \
-  for(node=&(list); *node; node=(type **)&(*node)->##next); \
-  (*node) = obj; \
-  (*node)->##next = NULL; \
-}
-
-#define DEQUEUE(obj,type,list,next) \
-{ long cpuflag; \
-  spin_lock_irqsave(&mega_lock,cpuflag);\
-  if ((obj=list) != NULL) {\
-    list = (type *)(list)->##next; \
-  } \
-  spin_unlock_irqrestore(&mega_lock,cpuflag);\
-};
 
 u32 RDINDOOR (mega_host_config * megaCfg)
 {
@@ -239,19 +223,67 @@
 			 u_char * mboxData,
 			 mega_scb * scb,
 			 int intr);
-static int build_sglist (mega_host_config * megaCfg, mega_scb * scb,
+static int mega_build_sglist (mega_host_config * megaCfg, mega_scb * scb,
 			 u32 * buffer, u32 * length);
 
 static int mega_busyWaitMbox(mega_host_config *);
 static void mega_runpendq (mega_host_config *);
-static void mega_rundoneq (void);
+static void mega_rundoneq (mega_host_config *);
 static void mega_cmd_done (mega_host_config *, mega_scb *, int);
 static mega_scb *mega_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt);
-static inline void freeSgList(mega_host_config *megaCfg);
+static inline void mega_freeSgList(mega_host_config *megaCfg);
 static void mega_Convert8ldTo40ld(  mega_RAIDINQ  *inquiry,
                                     mega_Enquiry3 *enquiry3,
                                     megaRaidProductInfo *productInfo );
 
+
+
+
+
+#if LINUX_VERSION_CODE > 0x020100
+#  include <asm/spinlock.h>
+#  include <linux/smp.h>
+#  define cpuid smp_processor_id()
+#  if LINUX_VERSION_CODE < 0x020195
+#    define DRIVER_LOCK_T unsigned long cpu_flags = 0;
+#    define DRIVER_LOCK_INIT(p) \
+       spin_lock_init(&p->mega_lock);
+#    define DRIVER_LOCK(p) \
+       if(!p->cpu_lock_count[cpuid]) { \
+         spin_lock_irqsave(&p->mega_lock, cpu_flags); \
+         p->cpu_lock_count[cpuid]++; \
+       } else { \
+         p->cpu_lock_count[cpuid]++; \
+       }
+#    define DRIVER_UNLOCK(p) \
+       if(--p->cpu_lock_count[cpuid] == 0) \
+         spin_unlock_irqrestore(&p->mega_lock, cpu_flags);
+#    define IO_LOCK(p)   spin_lock_irqsave(&io_request_lock,cpu_flags);
+#    define IO_UNLOCK(p) spin_unlock_irqrestore(&io_request_lock,cpu_flags);
+#  else
+#    define DRIVER_LOCK_T
+#    define DRIVER_LOCK_INIT(p)
+#    define DRIVER_LOCK(p)
+#    define DRIVER_UNLOCK(p)
+#    define IO_LOCK_T unsigned long io_flags = 0;
+#    define IO_LOCK spin_lock_irqsave(&io_request_lock,io_flags);
+#    define IO_UNLOCK spin_unlock_irqrestore(&io_request_lock,io_flags);
+#  endif
+#else
+#  define cpuid 0
+#  define DRIVER_LOCK_T long cpu_flags;
+#  define DRIVER_LOCK_INIT(p)
+#  define DRIVER_LOCK(p) \
+       save_flags(cpu_flags); \
+       cli();
+#  define DRIVER_UNLOCK(p) \
+       restore_flags(cpu_flags);
+#  define IO_LOCK(p)   DRIVER_LOCK(p)
+#  define IO_UNLOCK(p) DRIVER_UNLOCK(p)
+#  define le32_to_cpu(x) (x)
+#  define cpu_to_le32(x) (x)
+#endif
+
 /* set SERDEBUG to 1 to enable serial debugging */
 #define SERDEBUG 0
 #if SERDEBUG
@@ -286,13 +318,10 @@
 
 static mega_scb *pLastScb = NULL;
 
-/* Queue of pending/completed SCBs */
-static Scsi_Cmnd *qCompleted = NULL;
 
 #if SERDEBUG
 static spinlock_t serial_lock = SPIN_LOCK_UNLOCKED;
 #endif
-static spinlock_t mega_lock = SPIN_LOCK_UNLOCKED;
 
 #if SERDEBUG
 static char strbuf[MAX_SERBUF + 1];
@@ -352,7 +381,7 @@
 #define TRACE(A)
 #endif
 
-void callDone (Scsi_Cmnd * SCpnt)
+static void callDone (Scsi_Cmnd * SCpnt)
 {
   if (SCpnt->result) {
     TRACE (("*** %.08lx %.02x <%d.%d.%d> = %x\n", SCpnt->serial_number,
@@ -372,37 +401,66 @@
  * Free a SCB structure
  *=======================
  */
-static void freeSCB (mega_host_config *megaCfg, mega_scb * pScb)
+static void mega_freeSCB (mega_host_config *megaCfg, mega_scb * pScb)
 {
-  mega_scb **ppScb;
+
+  mega_scb *pScbtmp;
+
+  if ((pScb == NULL) || (pScb->idx >= 0xFE)) {
+    return ;
+  }
 
   /* Unlink from pending queue */
-  for(ppScb=&megaCfg->qPending; *ppScb; ppScb=&(*ppScb)->next) {
-    if (*ppScb == pScb) {
-	*ppScb = pScb->next;
+
+  if(pScb == megaCfg->qPendingH) {
+    if(megaCfg->qPendingH == megaCfg->qPendingT ) 
+      megaCfg->qPendingH = megaCfg->qPendingT = NULL;
+    else {
+      megaCfg->qPendingH = megaCfg->qPendingH->next;
+    }
+    megaCfg->qPcnt--;
+  }
+  else {
+    for(pScbtmp=megaCfg->qPendingH; pScbtmp; pScbtmp=pScbtmp->next) {
+      if (pScbtmp->next == pScb) {
+        pScbtmp->next = pScb->next;
+        if(pScb == megaCfg->qPendingT) {
+          megaCfg->qPendingT = pScbtmp;
+        }
+        megaCfg->qPcnt--;
 	break;
     }
   }
+  }
 
-  /* Link back into list */
+  /* Link back into free list */
   pScb->state = SCB_FREE;
   pScb->SCpnt = NULL;
 
-  pScb->next     = megaCfg->qFree;
-  megaCfg->qFree = pScb;
+  if(megaCfg->qFreeH == (mega_scb *) NULL ) {
+    megaCfg->qFreeH = megaCfg->qFreeT = pScb;
+  }
+  else {
+    megaCfg->qFreeT->next  = pScb;
+    megaCfg->qFreeT = pScb;
+  }
+  megaCfg->qFreeT->next = NULL;
+  megaCfg->qFcnt++;
+
 }
 
 /*===========================
  * Allocate a SCB structure
  *===========================
  */
-static mega_scb * allocateSCB (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt)
+static mega_scb * mega_allocateSCB (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt)
 {
   mega_scb *pScb;
 
   /* Unlink command from Free List */
-  if ((pScb = megaCfg->qFree) != NULL) {
-    megaCfg->qFree = pScb->next;
+  if ((pScb = megaCfg->qFreeH) != NULL) {
+    megaCfg->qFreeH = pScb->next;
+    megaCfg->qFcnt--;
     
     pScb->isrcount = jiffies;
     pScb->next  = NULL;
@@ -421,62 +479,72 @@
  * Initialize SCB structures
  *================================================
  */
-static int initSCB (mega_host_config * megaCfg)
+static int mega_initSCB (mega_host_config * megaCfg)
 {
   int idx;
 
-  megaCfg->qFree = NULL;
+  megaCfg->qFreeH = NULL;
+  megaCfg->qFcnt = 0;
+#if DEBUG
+if(megaCfg->max_cmds >= MAX_COMMANDS) {
+printk("megaraid:ctlr max cmds = %x : MAX_CMDS = %x", megaCfg->max_cmds, MAX_COMMANDS);
+}
+#endif
+
   for (idx = megaCfg->max_cmds-1; idx >= 0; idx--) {
     megaCfg->scbList[idx].idx    = idx;
     megaCfg->scbList[idx].sgList = kmalloc(sizeof(mega_sglist) * MAX_SGLIST,
 					   GFP_ATOMIC | GFP_DMA);
     if (megaCfg->scbList[idx].sgList == NULL) {
       printk(KERN_WARNING "Can't allocate sglist for id %d\n",idx);
-      freeSgList(megaCfg);
+      mega_freeSgList(megaCfg);
       return -1;
     }
     
     if (idx < MAX_COMMANDS) {
       /* Link to free list */
-      freeSCB(megaCfg, &megaCfg->scbList[idx]);
+      mega_freeSCB(megaCfg, &megaCfg->scbList[idx]);
     }
   }
   return 0;
 }
 
 /* Run through the list of completed requests */
-static void mega_rundoneq ()
+static void mega_rundoneq (mega_host_config *megaCfg)
 {
   Scsi_Cmnd *SCpnt;
 
-  while (1) {
-    DEQUEUE (SCpnt, Scsi_Cmnd, qCompleted, host_scribble);
-    if (SCpnt == NULL)
-      return;
+  while ((SCpnt = megaCfg->qCompletedH) != NULL) {
+    megaCfg->qCompletedH = (Scsi_Cmnd *)SCpnt->host_scribble;
+    megaCfg->qCcnt--;
 
+    SCpnt->host_scribble = (unsigned char *) NULL ; // XC : sep 14
     /* Callback */
     callDone (SCpnt);
   }
+  megaCfg->qCompletedH = megaCfg->qCompletedT = NULL;
 }
 
 /*
-  Runs through the list of pending requests
-  Assumes that mega_lock spin_lock has been acquired.
-*/
+ * Runs through the list of pending requests
+ * Assumes that mega_lock spin_lock has been acquired.
+ */
 static void mega_runpendq(mega_host_config *megaCfg)
 {
   mega_scb *pScb;
 
   /* Issue any pending commands to the card */
-  for(pScb=megaCfg->qPending; pScb; pScb=pScb->next) {
+  for(pScb=megaCfg->qPendingH; pScb; pScb=pScb->next) {
     if (pScb->state == SCB_ACTIVE) {
-      megaIssueCmd(megaCfg, pScb->mboxData, pScb, 1);
+      if(megaIssueCmd(megaCfg, pScb->mboxData, pScb, 1))
+	return;
     }
   }
 }
 
 /* Add command to the list of completed requests */
-static void mega_cmd_done (mega_host_config * megaCfg, mega_scb * pScb, 
+static void
+mega_cmd_done (mega_host_config * megaCfg, mega_scb * pScb, 
 			   int status)
 {
   int islogical;
@@ -499,7 +567,7 @@
 	TRACE(("pScb->idx = ",pScb->idx));
 	TRACE(("pScb->state = ",pScb->state));
 	TRACE(("pScb->state = ",pScb->state));
-	printk("Problem...!\n");
+	printk("megaraid:Problem...!\n");
 	while(1);
   }
 
@@ -554,10 +622,18 @@
   /* not IOCTL_CMD_NEW SCB, freeSCB()*/
   /* For IOCTL_CMD_NEW SCB, delay freeSCB() in megaraid_queue()
    * after copy data back to user space*/
-     freeSCB(megaCfg, pScb);
+     mega_freeSCB(megaCfg, pScb);
 
   /* Add Scsi_Command to end of completed queue */
-  ENQUEUE_NL(SCpnt, Scsi_Cmnd, qCompleted, host_scribble);
+    if( megaCfg->qCompletedH == NULL ) {
+      megaCfg->qCompletedH = megaCfg->qCompletedT = SCpnt;
+    }
+    else {
+      megaCfg->qCompletedT->host_scribble = (unsigned char *) SCpnt;
+      megaCfg->qCompletedT = SCpnt;
+   }
+   megaCfg->qCompletedT->host_scribble = (unsigned char *) NULL;
+   megaCfg->qCcnt++;
 }
 
 /*-------------------------------------------------------------------
@@ -627,7 +703,7 @@
     case READ_CAPACITY:
     case INQUIRY:
       /* Allocate a SCB and initialize passthru */
-      if ((pScb = allocateSCB (megaCfg, SCpnt)) == NULL) {
+      if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) {
 	SCpnt->result = (DID_ERROR << 16);
 	callDone (SCpnt);
 	return NULL;
@@ -658,7 +734,7 @@
     case READ_10:
     case WRITE_10:
       /* Allocate a SCB and initialize mailbox */
-      if ((pScb = allocateSCB (megaCfg, SCpnt)) == NULL) {
+      if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) {
 	SCpnt->result = (DID_ERROR << 16);
 	callDone (SCpnt);
 	return NULL;
@@ -694,7 +770,7 @@
       }
 
       /* Calculate Scatter-Gather info */
-      mbox->numsgelements = build_sglist (megaCfg, pScb,
+      mbox->numsgelements = mega_build_sglist (megaCfg, pScb,
 					  (u32 *) & mbox->xferaddr,
 					  (u32 *) & seg);
 
@@ -713,7 +789,7 @@
    *-----------------------------------------------------*/
   else {
     /* Allocate a SCB and initialize passthru */
-    if ((pScb = allocateSCB (megaCfg, SCpnt)) == NULL) {
+    if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) {
       SCpnt->result = (DID_ERROR << 16);
       callDone (SCpnt);
       return NULL;
@@ -734,7 +810,7 @@
     pthru->cdblen = SCpnt->cmd_len;
     memcpy (pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len);
 
-    pthru->numsgelements = build_sglist (megaCfg, pScb,
+    pthru->numsgelements = mega_build_sglist (megaCfg, pScb,
 					 (u32 *) & pthru->dataxferaddr,
 					 (u32 *) & pthru->dataxferlen);
 
@@ -761,19 +837,12 @@
   unsigned char *data = (unsigned char *)SCpnt->request_buffer;
   int i;
 
-  if ((pScb = allocateSCB (megaCfg, SCpnt)) == NULL) {
+  if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) {
     SCpnt->result = (DID_ERROR << 16);
     callDone (SCpnt);
     return NULL;
   }
 
-#if 0
-  printk("\nBUF: ");
-  for (i=0;i<18;i++) {
-     printk(" %x",data[i]);
-  }
-  printk("......\n");
-#endif
 
   mboxdata = (u8 *) & pScb->mboxData;
   mbox = (mega_ioctl_mbox *) & pScb->mboxData;
@@ -797,7 +866,7 @@
     mailbox->cmd = MEGA_MBOXCMD_PASSTHRU;
     mailbox->xferaddr = virt_to_bus (pthru);
 
-    pthru->numsgelements = build_sglist (megaCfg, pScb,
+    pthru->numsgelements = mega_build_sglist (megaCfg, pScb,
 					 (u32 *) & pthru->dataxferaddr,
 					 (u32 *) & pthru->dataxferlen);
 
@@ -856,7 +925,7 @@
   } 
   else {
 
-      mbox->numsgelements = build_sglist (megaCfg, pScb,
+      mbox->numsgelements = mega_build_sglist (megaCfg, pScb,
 				      (u32 *) & mbox->xferaddr,
 				      (u32 *) & seg);
 
@@ -884,30 +953,32 @@
 }
 #endif
 
+#if DEBUG
+static unsigned int cum_time = 0;
+static unsigned int cum_time_cnt = 0;
+#endif
+
 /*--------------------------------------------------------------------
  * Interrupt service routine
  *--------------------------------------------------------------------*/
 static void megaraid_isr (int irq, void *devp, struct pt_regs *regs)
 {
+  IO_LOCK_T
   mega_host_config    *megaCfg;
   u_char byte, idx, sIdx, tmpBox[MAILBOX_SIZE];
-  u32 dword;
+  u32 dword=0;
   mega_mailbox *mbox;
   mega_scb *pScb;
-  long flags;
-  int qCnt, qStatus;
+  u_char qCnt, qStatus;
+  u_char            completed[MAX_FIRMWARE_STATUS];
+  Scsi_Cmnd *SCpnt;
 
   megaCfg = (mega_host_config *) devp;
   mbox = (mega_mailbox *)tmpBox;
 
-  spin_lock_irqsave (&io_request_lock, flags);
-
-  while (megaCfg->host->irq == irq) {
-
-    spin_lock_irqsave (&mega_lock, flags);
-
+  if (megaCfg->host->irq == irq) {
     if (megaCfg->flag & IN_ISR) {
-      TRACE (("ISR called reentrantly!!\n"));
+      printk(KERN_ERR "ISR called reentrantly!!\n");
     }
 
     megaCfg->flag |= IN_ISR;
@@ -916,48 +987,73 @@
 	printk(KERN_WARNING "Error: mailbox busy in isr!\n");
     }
 
-
     /* Check if a valid interrupt is pending */
     if (megaCfg->flag & BOARD_QUARTZ) {
       dword = RDOUTDOOR (megaCfg);
       if (dword != 0x10001234) {
 	/* Spurious interrupt */
 	megaCfg->flag &= ~IN_ISR;
-	spin_unlock_irqrestore (&mega_lock, flags);
-	break;
+//#if LINUX_VERSION_CODE >= 0x20100
+//        IO_UNLOCK;
+//#endif
+//	break;
+	return;
       }
-      WROUTDOOR (megaCfg, dword);
-
-      /* Copy to temp location */
-      memcpy(tmpBox, (mega_mailbox *)megaCfg->mbox, MAILBOX_SIZE);
-
-      /* Acknowledge interrupt */
-      WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x2);
-      while (RDINDOOR (megaCfg) & 0x02);
     }
     else {
       byte = READ_PORT (megaCfg->host->io_port, INTR_PORT);
       if ((byte & VALID_INTR_BYTE) == 0) {
 	/* Spurious interrupt */
 	megaCfg->flag &= ~IN_ISR;
-	spin_unlock_irqrestore (&mega_lock, flags);
-	break;
+//#if LINUX_VERSION_CODE >= 0x20100
+//	IO_UNLOCK;
+//#endif
+//	break;
+	return;
       }
       WRITE_PORT (megaCfg->host->io_port, INTR_PORT, byte);
+    }
+
+    for(idx=0;idx<MAX_FIRMWARE_STATUS;idx++ ) completed[idx] = 0;
+
+    IO_LOCK;
 
-      /* Copy to temp location */
-      memcpy(tmpBox, (mega_mailbox *)megaCfg->mbox, MAILBOX_SIZE);
+    qCnt = 0xff;
+    while ((qCnt = megaCfg->mbox->numstatus) == 0xFF) 
+      ;
+
+    qStatus = 0xff;
+    while ((qStatus = megaCfg->mbox->status) == 0xFF)
+      ;
+
+    /* Get list of completed requests */
+    for (idx = 0; idx<qCnt; idx++) {
+      while ((sIdx = megaCfg->mbox->completed[idx]) == 0xFF) {
+	printk("p");
+      }
+      completed[idx] = sIdx;
+      sIdx = 0xFF;
+    }
 
+    if (megaCfg->flag & BOARD_QUARTZ) {
+      WROUTDOOR (megaCfg, dword);
       /* Acknowledge interrupt */
+      WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x2);
+      while (RDINDOOR (megaCfg) & 0x02);
+    }
+    else {
       CLEAR_INTR (megaCfg->host->io_port);
     }
 
-    qCnt = mbox->numstatus;
-    qStatus = mbox->status;
+#if DEBUG
+    if(qCnt >= MAX_FIRMWARE_STATUS) {
+      printk("megaraid_isr: cmplt=%d ", qCnt);
+    }
+#endif
 
     for (idx = 0; idx < qCnt; idx++) {
-      sIdx = mbox->completed[idx];
-      if (sIdx > 0) {
+      sIdx = completed[idx];
+      if ((sIdx > 0) && (sIdx <= MAX_COMMANDS)) {
 	pScb = &megaCfg->scbList[sIdx - 1];
 
 	/* ASSERT(pScb->state == SCB_ISSUED); */
@@ -965,12 +1061,33 @@
 #if DEBUG
 	if (((jiffies) - pScb->isrcount) > maxCmdTime) {
 	  maxCmdTime = (jiffies) - pScb->isrcount;
-	  printk("cmd time = %u\n", maxCmdTime);
+	  printk("megaraid_isr : cmd time = %u\n", maxCmdTime);
 	}
 #endif
-
+/*
+ * Assuming that the scsi command, for which an abort request was received
+ * earlier has completed.
+ */
 	if (pScb->state == SCB_ABORTED) {
-	  printk("Received aborted SCB! %u\n", (int)((jiffies)-pScb->isrcount));
+          SCpnt = pScb->SCpnt;
+#if DEBUG
+printk("megaraid_isr:fcnt=%d, pcnt=%d, qcnt=%d\n",megaCfg->qFcnt, megaCfg->qPcnt, megaCfg->qCcnt); 
+#endif
+	}
+	if (pScb->state == SCB_RESET) {
+          SCpnt = pScb->SCpnt;
+	  mega_freeSCB (megaCfg, pScb);
+	  SCpnt->result = (DID_RESET << 16) ;
+          if( megaCfg->qCompletedH == NULL ) {
+            megaCfg->qCompletedH = megaCfg->qCompletedT = SCpnt;
+          }
+          else {
+            megaCfg->qCompletedT->host_scribble = (unsigned char *) SCpnt;
+            megaCfg->qCompletedT = SCpnt;
+          }
+          megaCfg->qCompletedT->host_scribble = (unsigned char *) NULL;
+          megaCfg->qCcnt++;
+          continue;
 	}
 
         if (*(pScb->SCpnt->cmnd)==IOCTL_CMD_NEW) 
@@ -981,22 +1098,22 @@
 	mega_cmd_done(megaCfg, pScb, qStatus);
 
       }
-
+      else {
+        printk(KERN_ERR "megaraid: wrong cmd id completed from firmware:id=%x\n",sIdx);
+      }
     }
-    spin_unlock_irqrestore (&mega_lock, flags);
 
-    megaCfg->flag &= ~IN_ISR;
+    mega_rundoneq(megaCfg);
 
-    mega_rundoneq();
+    megaCfg->flag &= ~IN_ISR;
 
     /* Loop through any pending requests */
-    spin_lock_irqsave(&mega_lock, flags);
     mega_runpendq(megaCfg);
-    spin_unlock_irqrestore(&mega_lock,flags);
+#if LINUX_VERSION_CODE >= 0x20100
+    IO_UNLOCK;
+#endif
 
   }
-
-  spin_unlock_irqrestore (&io_request_lock, flags);
 }
 
 /*==================================================*/
@@ -1040,7 +1157,6 @@
   mega_mailbox *mbox = (mega_mailbox *) megaCfg->mbox;
   u_char byte;
   u32 cmdDone;
-  Scsi_Cmnd *SCpnt;
   u32 phys_mbox;
   u8 retval=-1;
 
@@ -1049,18 +1165,15 @@
 
   phys_mbox = virt_to_bus (megaCfg->mbox);
 
-#if 0
-  if (intr && mbox->busy) {
-    return 0;
-  }
-#endif
-
 #if DEBUG
   showMbox(pScb);
 #endif
 
   /* Wait until mailbox is free */
-  while (mega_busyWaitMbox (megaCfg)) {
+#if 0
+  while (mega_busyWaitMbox (megaCfg))
+#endif
+  if (mega_busyWaitMbox (megaCfg)) {
     printk("Blocked mailbox......!!\n");
     udelay(1000);
 
@@ -1070,14 +1183,10 @@
     
     /* Abort command */
     if (pScb == NULL) {
-	printk("NULL pScb in megaIssue\n");
 	TRACE(("NULL pScb in megaIssue\n"));
+	printk("NULL pScb in megaIssue\n");
     }
-    SCpnt = pScb->SCpnt;
-    freeSCB(megaCfg, pScb);
-
-    SCpnt->result = (DID_ABORT << 16);
-    callDone(SCpnt);
+    mega_cmd_done (megaCfg, pScb, 0x08);
     return -1;
   }
 
@@ -1116,7 +1225,7 @@
 
       if (pScb) {
 	mega_cmd_done (megaCfg, pScb, mbox->status);
-	mega_rundoneq ();
+//	mega_rundoneq (megaCfg);
       }
 
       WRINDOOR (megaCfg, phys_mbox | 0x2);
@@ -1130,26 +1239,26 @@
       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 (megaCfg, pScb, mbox->status);
-	mega_rundoneq ();
+//	mega_rundoneq (megaCfg);
       }
       else {
 	TRACE (("Error: NULL pScb!\n"));
       }
-
     }
     enable_irq(megaCfg->host->irq);
     retval=mbox->status;
   }
+#if DEBUG
   while (mega_busyWaitMbox (megaCfg)) {
     printk("Blocked mailbox on exit......!\n");
     udelay(1000);
   }
+#endif
 
   return retval;
 }
@@ -1157,7 +1266,7 @@
 /*-------------------------------------------------------------------
  * Copies data to SGLIST
  *-------------------------------------------------------------------*/
-static int build_sglist (mega_host_config * megaCfg, mega_scb * scb,
+static int mega_build_sglist (mega_host_config * megaCfg, mega_scb * scb,
 	      u32 * buffer, u32 * length)
 {
   struct scatterlist *sgList;
@@ -1216,9 +1325,7 @@
   paddr = (paddr + 4 + 16) & 0xfffffff0;
 
   /* Register mailbox area with the firmware */
-  if (megaCfg->flag & BOARD_QUARTZ) {
-  }
-  else {
+  if (!(megaCfg->flag & BOARD_QUARTZ)) {
     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);
@@ -1276,7 +1383,6 @@
   u32 paddr;
   u8 retval;
 
-  spin_lock_init (&mega_lock);
 
   /* Initialize adapter inquiry mailbox*/
   paddr = virt_to_bus (megaCfg->mega_buffer);
@@ -1337,9 +1443,17 @@
     /*(megaCfg->flag & BOARD_40LD)?FC_MAX_TARGETS_PER_CHANNEL:MAX_TARGET+1;*/ 
   megaCfg->host->max_lun =              /* max lun */
     (megaCfg->flag & BOARD_40LD) ? FC_MAX_LOGICAL_DRIVES : MAX_LOGICAL_DRIVES; 
+  megaCfg->host->cmd_per_lun = MAX_CMD_PER_LUN;
 
   megaCfg->numldrv = enquiry3Pnt->numLDrv;
   megaCfg->max_cmds = megaCfg->productInfo.MaxConcCmds;
+  if(megaCfg->max_cmds > MAX_COMMANDS) megaCfg->max_cmds = MAX_COMMANDS - 1;
+
+  megaCfg->host->can_queue   = megaCfg->max_cmds;
+
+  if (megaCfg->host->can_queue >= MAX_COMMANDS) {
+    megaCfg->host->can_queue = MAX_COMMANDS-1;
+  }
 
 #if 0 
   int i;
@@ -1405,7 +1519,7 @@
   return 0;
 }
 
-int findCard (Scsi_Host_Template * pHostTmpl,
+int mega_findCard (Scsi_Host_Template * pHostTmpl,
 	  u16 pciVendor, u16 pciDev,
 	  long flag)
 {
@@ -1429,6 +1543,21 @@
 	    pciDev,
 	    pdev->slot_name);
 
+    /*
+     *	Dont crash on boot with AMI cards configured for I2O. 
+     *  (our I2O code will find them then they will fail oddly until
+     *   we figure why they upset our I2O code). This driver will die
+     *   if it tries to boot an I2O mode board and we dont stop it now.
+     *     - Alan Cox , Red Hat Software, Jan 2000
+     */
+     	    
+    if((pdev->class >> 8) == PCI_CLASS_INTELLIGENT_I2O)
+    {
+    	printk( KERN_INFO "megaraid: Board configured for I2O, ignoring this card. Reconfigure the card\n"
+		KERN_INFO "megaraid: in the BIOS for \"mass storage\" to use it with this driver.\n");
+	continue;
+    }		
+
     /* Read the base port and IRQ from PCI */
     megaBase = pdev->resource[0].start;
     megaIrq  = pdev->irq;
@@ -1452,8 +1581,15 @@
 	    host->host_no, (u_int) megaBase, megaIrq);
 
     /* Copy resource info into structure */
-    megaCfg->qPending = NULL;
-    megaCfg->qFree    = NULL;
+    megaCfg->qCompletedH = NULL;
+    megaCfg->qCompletedT = NULL;
+    megaCfg->qPendingH = NULL;
+    megaCfg->qPendingT = NULL;
+    megaCfg->qFreeH    = NULL;
+    megaCfg->qFreeT    = NULL;
+    megaCfg->qFcnt = 0;
+    megaCfg->qPcnt = 0;
+    megaCfg->qCcnt = 0;
     megaCfg->flag = flag;
     megaCfg->host = host;
     megaCfg->base = megaBase;
@@ -1485,7 +1621,7 @@
     mega_i_query_adapter (megaCfg);
     
     /* Initialize SCBs */
-    if (initSCB (megaCfg)) {
+    if (mega_initSCB (megaCfg)) {
       scsi_unregister (host);
       continue;
     }
@@ -1511,9 +1647,9 @@
 
   printk ("megaraid: " MEGARAID_VERSION CRLFSTR);
 
-  count += findCard (pHostTmpl, 0x101E, 0x9010, 0);
-  count += findCard (pHostTmpl, 0x101E, 0x9060, 0);
-  count += findCard (pHostTmpl, 0x8086, 0x1960, BOARD_QUARTZ);
+  count += mega_findCard (pHostTmpl, 0x101E, 0x9010, 0);
+  count += mega_findCard (pHostTmpl, 0x101E, 0x9060, 0);
+  count += mega_findCard (pHostTmpl, 0x8086, 0x1960, BOARD_QUARTZ);
 
   return count;
 }
@@ -1548,13 +1684,13 @@
     release_region (megaCfg->host->io_port, 16);
   }
 
-  freeSgList(megaCfg);
+  mega_freeSgList(megaCfg);
   scsi_unregister (pSHost);
 
   return 0;
 }
 
-static inline void freeSgList(mega_host_config *megaCfg)
+static inline void mega_freeSgList(mega_host_config *megaCfg)
 {
   int i;
 
@@ -1600,13 +1736,12 @@
  *-----------------------------------------------------------------*/
 int megaraid_queue (Scsi_Cmnd * SCpnt, void (*pktComp) (Scsi_Cmnd *))
 {
+  DRIVER_LOCK_T
   mega_host_config *megaCfg;
   mega_scb *pScb;
-  long flags;
-
-  spin_lock_irqsave(&mega_lock,flags);
 
   megaCfg = (mega_host_config *) SCpnt->host->hostdata;
+  DRIVER_LOCK(megaCfg);
 
   if (!(megaCfg->flag & (1L << SCpnt->channel))) {
     if (SCpnt->channel < SCpnt->host->max_channel)
@@ -1623,33 +1758,69 @@
 
   /* If driver in abort or reset.. cancel this command */
   if (megaCfg->flag & IN_ABORT) {
+#if DEBUG
+printk("mq: got a request while in abort\n");
+#endif
     SCpnt->result = (DID_ABORT << 16);
-    ENQUEUE_NL(SCpnt, Scsi_Cmnd, qCompleted, host_scribble);
+    /* Add Scsi_Command to end of completed queue */
+    if( megaCfg->qCompletedH == NULL ) {
+      megaCfg->qCompletedH = megaCfg->qCompletedT = SCpnt;
+    }
+    else {
+      megaCfg->qCompletedT->host_scribble = (unsigned char *) SCpnt;
+      megaCfg->qCompletedT = SCpnt;
+    }
+    megaCfg->qCompletedT->host_scribble = (unsigned char *) NULL;
+    megaCfg->qCcnt++;
 
-    spin_unlock_irqrestore(&mega_lock,flags);
+    DRIVER_UNLOCK(megaCfg);
     return 0;
   }
   else if (megaCfg->flag & IN_RESET) {
+#if DEBUG
+printk("mq: got a request while in reset\n");
+#endif
     SCpnt->result = (DID_RESET << 16);
-    ENQUEUE_NL(SCpnt, Scsi_Cmnd, qCompleted, host_scribble);
+    /* Add Scsi_Command to end of completed queue */
+    if( megaCfg->qCompletedH == NULL ) {
+      megaCfg->qCompletedH = megaCfg->qCompletedT = SCpnt;
+    }
+    else {
+      megaCfg->qCompletedT->host_scribble = (unsigned char *) SCpnt;
+      megaCfg->qCompletedT = SCpnt;
+    }
+    megaCfg->qCompletedT->host_scribble = (unsigned char *) NULL;
+    megaCfg->qCcnt++;
 
-    spin_unlock_irqrestore(&mega_lock,flags);
+    DRIVER_UNLOCK(megaCfg);
     return 0;
   }
 
+  megaCfg->flag |= IN_QUEUE;
   /* Allocate and build a SCB request */
   if ((pScb = mega_build_cmd (megaCfg, SCpnt)) != NULL) {
               /*build SCpnt for IOCTL_CMD_NEW cmd in mega_ioctl()*/
     /* Add SCB to the head of the pending queue */
-    ENQUEUE_NL (pScb, mega_scb, megaCfg->qPending, next);
-
-    /* Issue any pending command to the card if not in ISR */
-    if (!(megaCfg->flag & IN_ISR)) {
-      mega_runpendq(megaCfg);
+    /* Add SCB to the head of the pending queue */
+    if( megaCfg->qPendingH == NULL ) {
+      megaCfg->qPendingH = megaCfg->qPendingT = pScb;
     }
     else {
-      printk("IRQ pend...\n");
+      megaCfg->qPendingT->next = pScb;
+      megaCfg->qPendingT = pScb;
     }
+    megaCfg->qPendingT->next = NULL;
+    megaCfg->qPcnt++;
+
+
+    /* Issue any pending command to the card if not in ISR */
+//    if (!(megaCfg->flag & IN_ISR)) {
+      mega_runpendq(megaCfg);
+//    }
+/* 
+ * try running the pend queue, irrespective of the driver's context.
+ * -cn 
+ */
 
     if ( SCpnt->cmnd[0]==IOCTL_CMD_NEW )
     {  /* user data from external user buffer */
@@ -1666,12 +1837,12 @@
 
           kfree(pScb->kern_area);
 
-          freeSCB(megaCfg, pScb);
+          mega_freeSCB(megaCfg, pScb);
     }
-
   }
 
-  spin_unlock_irqrestore(&mega_lock,flags);
+  megaCfg->flag &= ~IN_QUEUE;
+  DRIVER_UNLOCK(megaCfg);
 
   return 0;
 }
@@ -1709,41 +1880,70 @@
 /*---------------------------------------------------------------------
  * Abort a previous SCSI request
  *---------------------------------------------------------------------*/
-int megaraid_abort (Scsi_Cmnd * SCpnt)
+int
+megaraid_abort (Scsi_Cmnd * SCpnt)
 {
   mega_host_config *megaCfg;
-  int   rc, idx;
-  long  flags;
+  int   rc; //, idx;
   mega_scb *pScb;
 
-  rc = SCSI_ABORT_SUCCESS;
-
-  spin_lock_irqsave (&mega_lock, flags);
+  rc = SCSI_ABORT_NOT_RUNNING;
 
   megaCfg = (mega_host_config *) SCpnt->host->hostdata;
 
   megaCfg->flag |= IN_ABORT;
 
-  for(pScb=megaCfg->qPending; pScb; pScb=pScb->next) {
+#if DEBUG
+printk("ma:fcnt=%d, pcnt=%d, qcnt=%d\n",megaCfg->qFcnt, megaCfg->qPcnt, megaCfg->qCcnt); 
+#endif
+  for(pScb=megaCfg->qPendingH; pScb; pScb=pScb->next) {
     if (pScb->SCpnt == SCpnt) {
       /* Found an aborting command */
 #if DEBUG
       showMbox(pScb);
 #endif
 
-      printk("Abort: %d %u\n", 
-	     SCpnt->timeout_per_command,
-	     (uint)((jiffies) - pScb->isrcount));
+/*
+ * If the command is queued to be issued to the firmware, abort the scsi cmd,
+ * If the command is already aborted in a previous call to the _abort entry
+ *  point, return SCSI_ABORT_SNOOZE, suggesting a reset.
+ * If the command is issued to the firmware, which might complete after
+ *  some time, we will mark the scb as aborted, and return to the mid layer, 
+ *  that abort could not be done.
+ *  In the ISR, when this command actually completes, we will perform a normal
+ *  completion.
+ *
+ * Oct 27, 1999
+ */
 
       switch(pScb->state) {
       case SCB_ABORTED: /* Already aborted */
 	rc = SCSI_ABORT_SNOOZE;
 	break;
       case SCB_ISSUED: /* Waiting on ISR result */
-	rc = SCSI_ABORT_PENDING;
+	rc = SCSI_ABORT_NOT_RUNNING;
 	pScb->state = SCB_ABORTED;
 	break;
+      case SCB_ACTIVE: /* still on the pending queue */
+	mega_freeSCB (megaCfg, pScb);
+	SCpnt->result = (DID_ABORT << 16) ;
+        if( megaCfg->qCompletedH == NULL ) {
+          megaCfg->qCompletedH = megaCfg->qCompletedT = SCpnt;
+        }
+        else {
+          megaCfg->qCompletedT->host_scribble = (unsigned char *) SCpnt;
+          megaCfg->qCompletedT = SCpnt;
+        }
+        megaCfg->qCompletedT->host_scribble = (unsigned char *) NULL;
+        megaCfg->qCcnt++;
+	rc = SCSI_ABORT_SUCCESS;
+        break;
+      default:
+        printk("megaraid_abort: unknown command state!!\n");
+        rc = SCSI_ABORT_NOT_RUNNING;
+	break;
       }
+      break;
     }
   }
 
@@ -1761,26 +1961,29 @@
     }
   }
 #endif
-
-  /*
-   * Walk list of SCBs for any that are still outstanding
-   */
-  for (idx = 0; idx < megaCfg->max_cmds; idx++) {
-    if (megaCfg->scbList[idx].state != SCB_FREE) {
-      if (megaCfg->scbList[idx].SCpnt == SCpnt) {
-	freeSCB (megaCfg, &megaCfg->scbList[idx]);
-
-	SCpnt->result = (DID_ABORT << 16) | (SUGGEST_RETRY << 24);
-	ENQUEUE_NL(SCpnt, Scsi_Cmnd, qCompleted, host_scribble);
-      }
-    }
-  }
-  
   megaCfg->flag &= ~IN_ABORT;
 
-  spin_unlock_irqrestore (&mega_lock, flags);
+#if DEBUG
+if(megaCfg->flag & IN_QUEUE)  printk("ma:flag is in queue\n");
+if(megaCfg->qCompletedH == NULL) printk("ma:qchead == null\n");
+#endif
+  
+/*
+ * This is required here to complete any completed requests to be communicated
+ * over to the mid layer.
+ * Calling just mega_rundoneq() did not work.
+ */
+if(megaCfg->qCompletedH) {
+  SCpnt = megaCfg->qCompletedH;
+  megaCfg->qCompletedH = (Scsi_Cmnd *)SCpnt->host_scribble;
+  megaCfg->qCcnt--;
+
+  SCpnt->host_scribble = (unsigned char *) NULL ; // XC : sep 14
+  /* Callback */
+  callDone (SCpnt);
+}
+  mega_rundoneq(megaCfg);
 
-  mega_rundoneq();
 
   return rc;
 }
@@ -1792,14 +1995,18 @@
 {
   mega_host_config *megaCfg;
   int idx;
-  long flags;
-
-  spin_lock_irqsave (&mega_lock, flags);
+  int rc;
+  mega_scb *pScb;
 
+  rc = SCSI_RESET_NOT_RUNNING;
   megaCfg = (mega_host_config *) SCpnt->host->hostdata;
 
   megaCfg->flag |= IN_RESET;
 
+  printk ("megaraid_RESET: %.08lx cmd=%.02x <c=%d.t=%d.l=%d>, flag = %x\n",
+	SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target,
+	  SCpnt->lun, rstflags);
+
   TRACE (("RESET: %.08lx %.02x <%d.%d.%d>\n",
 	SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target,
 	  SCpnt->lun));
@@ -1810,20 +2017,18 @@
   for (idx = 0; idx < megaCfg->max_cmds; idx++) {
     if (megaCfg->scbList[idx].state != SCB_FREE) {
       SCpnt = megaCfg->scbList[idx].SCpnt;
+      pScb = &megaCfg->scbList[idx];
       if (SCpnt != NULL) {
-	freeSCB (megaCfg, &megaCfg->scbList[idx]);
-	SCpnt->result = (DID_RESET << 16) | (SUGGEST_RETRY << 24);
-	ENQUEUE_NL(SCpnt, Scsi_Cmnd, qCompleted, host_scribble);
+        pScb->state = SCB_RESET;
+        break;
       }
     }
   }
 
   megaCfg->flag &= ~IN_RESET;
 
-  spin_unlock_irqrestore (&mega_lock, flags);
-
-  mega_rundoneq();
-  return SCSI_RESET_PUNT;
+  mega_rundoneq(megaCfg);
+  return rc;
 }
 
 /*-------------------------------------------------------------
@@ -1886,4 +2091,3 @@
 
 #include "scsi_module.c"
 #endif
-

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)