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

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

diff -urN linux-2.4.22/drivers/scsi/megaraid.c linux-2.4.23/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 : v1.18f (Dec 10, 2002)
+ * Version : v1.18k (Aug 28, 2003)
  *
  * Description: Linux device driver for LSI Logic MegaRAID controller
  *
@@ -512,6 +512,54 @@
  *
  * remove GFP_DMA flag for ioctl. This was causing overrun of DMA buffers.
  *
+ * Version 1.18g
+ * Fri Jan 31 18:29:25 EST 2003 - Atul Mukker <atul.mukker@lsil.com>
+ *
+ * Write the interrupt valid signature 0x10001234 as soon as reading it to
+ * flush memory caches.
+ *
+ * While sending back the inquiry information, check if the original request
+ * had an associated scatter-gather list and tranfer data from bounce buffer
+ * accordingly.
+ *
+ * Version 1.18h
+ * Thu Feb  6 17:18:48 EST 2003 - Atul Mukker <atul.mukker@lsil.com>
+ *
+ * Reduce the number of sectors per command to 128 from original value of
+ * 1024. Big IO sizes along with certain other operation going on in parallel,
+ * e.g., check consistency and rebuild put a heavy constraint on fW resources
+ * resulting in aborted commands.
+ *
+ * Version 1.18i
+ * Fri Jun 20 07:39:05 EDT 2003 - Atul Mukker <atulm@lsil.com>
+ *
+ * Request and reserve memory/IO regions. Otherwise a panic occurs if 2.00.x
+ * driver is loaded on top of 1.18x driver
+ *
+ * Prevent memory leak in cases when data transfer from/to application fails
+ * and ioctl is failing.
+ *
+ * Set the PCI dma_mask to default value of 0xFFFFFFFF when we get a handle to
+ * it. The previous value of 64-bit might be sticky and would cause the memory
+ * for mailbox and scatter lists to be allocated beyond 4GB. This was observed
+ * on an Itenium
+ *
+ * Version 1.18j
+ * Mon Jul  7 14:39:55 EDT 2003 - Atul Mukker <atulm@lsil.com>
+ *
+ * Disable /proc/megaraid/stat file to prevent buffer overflow error during
+ * read of this file.
+ *
+ * Add support for ioctls on AMD-64 bit platforms
+ *			- Sreenivas Bagalkote <sreenib@lsil.com>
+ *
+ * Version 1.18k
+ * Thu Aug 28 10:05:11 EDT 2003 - Atul Mukker <atulm@lsil.com>
+ *
+ * Make sure to read the correct status and command ids while in ISR. The
+ * numstatus and command id array is invalidated before issuing the commands.
+ * The ISR busy-waits till the correct values are updated in host memory.
+ *
  * 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.
@@ -575,12 +623,27 @@
 #include <linux/reboot.h>
 #include <linux/init.h>
 
+#ifdef __x86_64__
+#include <asm/ioctl32.h>
+#endif
+
 #include "sd.h"
 #include "scsi.h"
 #include "hosts.h"
 
 #include "megaraid.h"
 
+#ifdef __x86_64__
+/*
+ * The IOCTL cmd received from 32 bit compiled applications
+ */
+
+extern int register_ioctl32_conversion( unsigned int cmd,
+				int(*handler)(unsigned int, unsigned int, unsigned long,
+						struct file* ));
+extern int unregister_ioctl32_conversion( unsigned int cmd );
+#endif
+
 /*
  *================================================================
  *  #Defines
@@ -1141,8 +1204,14 @@
 	switch (SCpnt->cmnd[0]) {
 	case INQUIRY:
 	case READ_CAPACITY:
-		memcpy (SCpnt->request_buffer,
-			pScb->bounce_buffer, SCpnt->request_bufflen);
+		if ( SCpnt->use_sg ) {
+			sgList = (struct scatterlist *)SCpnt->request_buffer;
+			memcpy(sgList[0].address, pScb->bounce_buffer,
+							SCpnt->request_bufflen);
+		} else {
+				memcpy (SCpnt->request_buffer, pScb->bounce_buffer,
+								SCpnt->request_bufflen);
+		}
 		break;
 	}
 #endif
@@ -2202,30 +2271,22 @@
 	megaCfg = (mega_host_config *) devp;
 	mbox = (mega_mailbox *) tmpBox;
 
-	if (megaCfg->host->irq == irq) {
-		if (megaCfg->flag & IN_ISR) {
-			TRACE (("ISR called reentrantly!!\n"));
-			printk ("ISR called reentrantly!!\n");
-		}
-		megaCfg->flag |= IN_ISR;
-
-		if (mega_busyWaitMbox (megaCfg)) {
-			printk (KERN_WARNING "Error: mailbox busy in isr!\n");
-		}
+		IO_LOCK;
 
 		/* Check if a valid interrupt is pending */
 		if (megaCfg->flag & BOARD_QUARTZ) {
 			dword = RDOUTDOOR (megaCfg);
 			if (dword != 0x10001234) {
 				/* Spurious interrupt */
-				megaCfg->flag &= ~IN_ISR;
+				IO_UNLOCK;
 				return;
 			}
+			WROUTDOOR (megaCfg, 0x10001234);
 		} else {
 			byte = READ_PORT (megaCfg->host->io_port, INTR_PORT);
 			if ((byte & VALID_INTR_BYTE) == 0) {
 				/* Spurious interrupt */
-				megaCfg->flag &= ~IN_ISR;
+				IO_UNLOCK;
 				return;
 			}
 			WRITE_PORT (megaCfg->host->io_port, INTR_PORT, byte);
@@ -2234,58 +2295,27 @@
 		for (idx = 0; idx < MAX_FIRMWARE_STATUS; idx++)
 			completed[idx] = 0;
 
-		IO_LOCK;
 
 		megaCfg->nInterrupts++;
-		qCnt = 0xff;
 		while ((qCnt = megaCfg->mbox->numstatus) == 0xFF) ;
-
-		qStatus = 0xff;
-		while ((qStatus = megaCfg->mbox->status) == 0xFF) ;
+		megaCfg->mbox->numstatus = 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;
+			while ((completed[idx] = megaCfg->mbox->completed[idx]) == 0xFF);
+			megaCfg->mbox->completed[idx] = 0xFF;
 		}
 
+		qStatus = megaCfg->mbox->status;
+
 		if (megaCfg->flag & BOARD_QUARTZ) {
-			WROUTDOOR (megaCfg, dword);
 			/* Acknowledge interrupt */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-			/* In this case mbox contains physical address */
-#if 0
-			WRINDOOR (megaCfg, megaCfg->adjdmahandle64 | 0x2);
-#else
-			WRINDOOR (megaCfg, 0x2);
-#endif
-
-#else
-
-#if 0
-			WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x2);
-#else
 			WRINDOOR (megaCfg, 0x2);
-#endif
-
-#endif
-
-#if 0
 			while (RDINDOOR (megaCfg) & 0x02) ;
-#endif
 		} else {
 			CLEAR_INTR (megaCfg->host->io_port);
 		}
 
-#if DEBUG
-		if (qCnt >= MAX_FIRMWARE_STATUS) {
-			printk ("megaraid_isr: cmplt=%d ", qCnt);
-		}
-#endif
-
 		for (idx = 0; idx < qCnt; idx++) {
 			sIdx = completed[idx];
 			if ((sIdx > 0) && (sIdx <= MAX_COMMANDS)) {
@@ -2355,26 +2385,24 @@
 		mega_runpendq (megaCfg);
 		IO_UNLOCK;
 
-	}
-
 }
 
 /*==================================================*/
 /* Wait until the controller's mailbox is available */
 /*==================================================*/
 
-static int mega_busyWaitMbox (mega_host_config * megaCfg)
+static inline int mega_busyWaitMbox (mega_host_config * megaCfg)
 {
 	mega_mailbox *mbox = (mega_mailbox *) megaCfg->mbox;
 	long counter;
 
-	for (counter = 0; counter < 10000; counter++) {
+	for (counter = 0; counter < 10; counter++) {
 		if (!mbox->busy) {
 			return 0;
 		}
-		udelay (100);
+		udelay (1);
 	}
-	return -1;		/* give up after 1 second */
+	return -1;		/* give up after 10 usecs */
 }
 
 /*=====================================================
@@ -2409,6 +2437,7 @@
 	u32 phys_mbox;
 #endif
 	u8 retval = -1;
+	int	i;
 
 	mboxData[0x1] = (pScb ? pScb->idx + 1 : 0xFE);	/* Set cmdid */
 	mboxData[0xF] = 1;	/* Set busy */
@@ -2420,25 +2449,8 @@
 	phys_mbox = virt_to_bus (megaCfg->mbox);
 #endif
 
-#if DEBUG
-	ShowMbox (pScb);
-#endif
-
 	/* Wait until mailbox is free */
 	if (mega_busyWaitMbox (megaCfg)) {
-		printk ("Blocked mailbox......!!\n");
-		udelay (1000);
-
-#if DEBUG
-		showMbox (pLastScb);
-#endif
-
-		/* Abort command */
-		if (pScb == NULL) {
-			TRACE (("NULL pScb in megaIssue\n"));
-			printk ("NULL pScb in megaIssue\n");
-		}
-		mega_cmd_done (megaCfg, pScb, 0x08);
 		return -1;
 	}
 
@@ -2486,13 +2498,10 @@
 			WRINDOOR (megaCfg, phys_mbox | 0x1);
 
 			while (mbox->numstatus == 0xFF) ;
-			while (mbox->status == 0xFF) ;
 			while (mbox->mraid_poll != 0x77) ;
 			mbox->mraid_poll = 0;
 			mbox->mraid_ack = 0x77;
-
-			/* while ((cmdDone = RDOUTDOOR (megaCfg)) != 0x10001234);
-			   WROUTDOOR (megaCfg, cmdDone); */
+			mbox->numstatus = 0xFF;
 
 			if (pScb) {
 				mega_cmd_done (megaCfg, pScb, mbox->status);
@@ -2520,15 +2529,14 @@
 				TRACE (("Error: NULL pScb!\n"));
 			}
 		}
+
+		for (i = 0; i < MAX_FIRMWARE_STATUS; i++) {
+				mbox->completed[i] = 0xFF;
+		}
+
 		enable_irq (megaCfg->host->irq);
 		retval = mbox->status;
 	}
-#if DEBUG
-	while (mega_busyWaitMbox (megaCfg)) {
-		printk(KERN_ERR "Blocked mailbox on exit......!\n");
-		udelay (1000);
-	}
-#endif
 
 	return retval;
 }
@@ -2964,15 +2972,15 @@
 
 	int		i, j;
 
-#if BITS_PER_LONG==64
-	u64 megaBase;
-#else
-	u32 megaBase;
-#endif
+	unsigned long megaBase;
+	unsigned long tbase;
 
 	u16 pciIdx = 0;
 	u16 numFound = 0;
 	u16 subsysid, subsysvid;
+	u8 did_mem_map_f = 0;
+	u8 did_io_map_f = 0;
+	u8 did_scsi_register_f = 0;
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)	/* 0x20100 */
 	while (!pcibios_find_device
@@ -2991,6 +2999,17 @@
 		pciBus = pdev->bus->number;
 		pciDevFun = pdev->devfn;
 #endif
+
+		/*
+		 * Set the dma_mask to default value. It might be sticky from previous
+		 * insmod-rmmod sequence
+		 */
+		pdev->dma_mask = 0xFFFFFFFF;
+
+		did_mem_map_f = 0;
+		did_io_map_f = 0;
+		did_scsi_register_f = 0;
+
 		if ((flag & BOARD_QUARTZ) && (skip_id == -1)) {
 				if( (pciVendor == PCI_VENDOR_ID_PERC4_DI_YSTONE &&
 					pciDev == PCI_DEVICE_ID_PERC4_DI_YSTONE) ||
@@ -3041,6 +3060,7 @@
 			if( (subsysvid != AMI_SUBSYS_ID) &&
 					(subsysvid != DELL_SUBSYS_ID) &&
 					(subsysvid != LSI_SUBSYS_ID) &&
+					(subsysvid != INTEL_SUBSYS_ID) &&
 					(subsysvid != HP_SUBSYS_ID) ) continue;
 
 		}
@@ -3065,22 +3085,55 @@
 		megaIrq = pdev->irq;
 #endif
 
+		tbase = megaBase;
+
 		pciIdx++;
 
 		if (flag & BOARD_QUARTZ) {
+
 			megaBase &= PCI_BASE_ADDRESS_MEM_MASK;
+
+			if( ! request_mem_region(megaBase, 128,
+									"MegaRAID: LSI Logic Corporation" ) ) {
+
+					printk(KERN_WARNING "megaraid: mem region busy!\n");
+
+					continue;
+			}
+
 			megaBase = (long) ioremap (megaBase, 128);
-			if (!megaBase)
+
+			if (!megaBase) {
+
+				printk(KERN_WARNING "megaraid: could not map hba memory!\n");
+
+				release_mem_region(tbase, 128);
+
 				continue;
+			}
+			did_mem_map_f = 1;
+
 		} else {
 			megaBase &= PCI_BASE_ADDRESS_IO_MASK;
 			megaBase += 0x10;
+
+			if( ! request_region(megaBase, 16,
+									"MegaRAID: LSI Logic Corporation") ) {
+
+					printk(KERN_WARNING "megaraid: region busy.\n");
+
+					continue;
+			}
+			did_io_map_f = 1;
+
 		}
 
 		/* Initialize SCSI Host structure */
 		host = scsi_register (pHostTmpl, sizeof (mega_host_config));
 		if (!host)
-			goto err_unmap;
+			goto fail_attach;
+
+		did_scsi_register_f = 1;
 
 		/*
 		 * Comment the following initialization if you know 'max_sectors' is
@@ -3088,7 +3141,7 @@
 		 * This field was introduced in Linus's kernel 2.4.7pre3 and it
 		 * greatly increases the IO performance - AM
 		 */
-		host->max_sectors = 1024;
+		host->max_sectors = 128;
 
 		scsi_set_pci_device(host, pdev);
 		megaCfg = (mega_host_config *) host->hostdata;
@@ -3130,11 +3183,8 @@
 		megaCfg->host->unique_id = (pciBus << 8) | pciDevFun;
 		megaCtlrs[numCtlrs] = megaCfg;
 
-		if (!(flag & BOARD_QUARTZ)) {
-
-			/* Request our IO Range */
-			if( !request_region(megaBase, 16, "megaraid") )
-				goto err_unregister;
+		if (flag & BOARD_QUARTZ) {
+				megaCfg->host->base = tbase;
 		}
 
 		/* Request our IRQ */
@@ -3143,7 +3193,7 @@
 			printk (KERN_WARNING
 				"megaraid: Couldn't register IRQ %d!\n",
 				megaIrq);
-			goto err_release;
+			goto fail_attach;
 		}
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
@@ -3265,8 +3315,7 @@
 					     sizeof (mega_mailbox64),
 					     (void *) megaCfg->mailbox64ptr,
 					     megaCfg->dma_handle64);
-			scsi_unregister (host);
-			continue;
+			goto fail_attach;
 		}
 
 		/*
@@ -3301,14 +3350,17 @@
 #endif
 #endif
 		continue;
-	      err_release:
-		if (flag & BOARD_QUARTZ)
-			release_region (megaBase, 16);
-	      err_unregister:
-		scsi_unregister (host);
-	      err_unmap:
-		if (flag & BOARD_QUARTZ)
-			iounmap ((void *) megaBase);
+fail_attach:
+		if( did_mem_map_f ) {
+				iounmap((void *)megaBase);
+				release_mem_region(tbase, 128);
+		}
+		if( did_io_map_f ) {
+				release_region(megaBase, 16);
+		}
+		if( did_scsi_register_f ) {
+				scsi_unregister (host);
+		}
 	}
 	return numFound;
 }
@@ -3408,6 +3460,12 @@
 		}
 
 		init_MUTEX (&mimd_entry_mtx);
+#ifdef __x86_64__
+		/*
+		 * Register the 32-bit ioctl conversion
+		 */
+		register_ioctl32_conversion( MEGAIOCCMD, sys_ioctl );
+#endif
 	}
 
 	return count;
@@ -3439,6 +3497,7 @@
 	/* Free our resources */
 	if (megaCfg->flag & BOARD_QUARTZ) {
 		iounmap ((void *) megaCfg->base);
+		release_mem_region(megaCfg->host->base, 128);
 	} else {
 		release_region (megaCfg->host->io_port, 16);
 	}
@@ -3485,6 +3544,9 @@
 
 	unregister_chrdev (major, "megadev");
 	unregister_reboot_notifier (&mega_notifier);
+#ifdef __x86_64__
+	unregister_ioctl32_conversion( MEGAIOCCMD );
+#endif
 
 	return 0;
 }
@@ -4235,7 +4297,6 @@
 static int proc_read_stat (char *page, char **start, off_t offset,
 		int count, int *eof, void *data)
 {
-	int i;
 	mega_host_config *megaCfg = (mega_host_config *) data;
 
 	*start = page;
@@ -4244,6 +4305,11 @@
 	proc_printf (megaCfg, "Interrupts Collected = %lu\n",
 		     megaCfg->nInterrupts);
 
+	proc_printf (megaCfg, "INTERFACE DISABLED\n");
+	COPY_BACK;
+	return count;
+
+#if 0	// can cause buffer overrun with 40 logical drives and IO information
 	for (i = 0; i < megaCfg->numldrv; i++) {
 		proc_printf (megaCfg, "Logical Drive %d:\n", i);
 
@@ -4259,6 +4325,7 @@
 
 	COPY_BACK;
 	return count;
+#endif
 }
 
 static int proc_read_status (char *page, char **start, off_t offset,
@@ -4896,16 +4963,16 @@
 			if( kvaddr == NULL ) {
 				printk(KERN_WARNING "megaraid:allocation failed\n");
 				ret = -ENOMEM;
-				goto out;
+				goto out_ioctl_cmd_new;
 			}
 
 			ioc.ui.fcs.buffer = kvaddr;
 
 			if (inlen) {
 				/* copyin the user data */
-				if (copy_from_user(kvaddr, (char *)uaddr, length )) {
-					ret = -EFAULT;
-					goto out;
+				if( copy_from_user(kvaddr, (char *)uaddr, length ) ) {
+						ret = -EFAULT;
+						goto out_ioctl_cmd_new;
 				}
 			}
 		}
@@ -4923,10 +4990,9 @@
 		down(&mimd_ioctl_sem);
 
 		if( !scsicmd->result && outlen ) {
-			if (copy_to_user(uaddr, kvaddr, length))
-			{
-				ret = -EFAULT;
-				goto out;
+			if (copy_to_user(uaddr, kvaddr, length)) {
+				return -EFAULT;
+				goto out_ioctl_cmd_new;
 			}
 		}
 
@@ -4946,7 +5012,8 @@
 			put_user (scsicmd->result, &uioc->mbox[17]);
 		}
 
-out:
+out_ioctl_cmd_new:
+
 		if (kvaddr) {
 			dma_free_consistent(pdevp, length, kvaddr, dma_addr);
 		}
@@ -5047,12 +5114,8 @@
 
 			if( kvaddr == NULL ) {
 				printk (KERN_WARNING "megaraid:allocation failed\n");
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)	/*0x20400 */
-				kfree(scsicmd);
-#else
-				scsi_init_free((char *)scsicmd, sizeof(Scsi_Cmnd));
-#endif
-				return -ENOMEM;
+				ret = -ENOMEM;
+				goto out_ioctl_cmd;
 			}
 
 			ioc.data = kvaddr;
@@ -5060,9 +5123,15 @@
 			if (inlen) {
 				if (ioc.mbox[0] == MEGA_MBOXCMD_PASSTHRU) {
 					/* copyin the user data */
-					copy_from_user (kvaddr, uaddr, ioc.pthru.dataxferlen);
+					if( copy_from_user (kvaddr, uaddr, ioc.pthru.dataxferlen)){
+							ret = -EFAULT;
+							goto out_ioctl_cmd;
+					}
 				} else {
-					copy_from_user (kvaddr, uaddr, inlen);
+					if( copy_from_user (kvaddr, uaddr, inlen) ) {
+							ret = -EFAULT;
+							goto out_ioctl_cmd;
+					}
 				}
 			}
 		}
@@ -5080,11 +5149,15 @@
 
 		if (!scsicmd->result && outlen) {
 			if (ioc.mbox[0] == MEGA_MBOXCMD_PASSTHRU) {
-				if (copy_to_user (uaddr, kvaddr, ioc.pthru.dataxferlen))	
+				if (copy_to_user (uaddr, kvaddr, ioc.pthru.dataxferlen)) {
 					ret = -EFAULT;
+					goto out_ioctl_cmd;
+				}
 			} else {
-				if (copy_to_user (uaddr, kvaddr, outlen)) 
+				if (copy_to_user (uaddr, kvaddr, outlen)) {
 					ret = -EFAULT;
+					goto out_ioctl_cmd;
+				}
 			}
 		}
 
@@ -5109,6 +5182,8 @@
 			put_user (scsicmd->result, &uioc->mbox[17]); /* status */
 		}
 
+out_ioctl_cmd:
+
 		if (kvaddr) {
 			dma_free_consistent(pdevp, PAGE_SIZE, kvaddr, dma_addr );
 		}

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