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

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

diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/megaraid.c linux/drivers/scsi/megaraid.c
@@ -2,25 +2,24 @@
  *
  *                    Linux MegaRAID device driver
  *
- * Copyright 1999 American Megatrends Inc.
+ * Copyright 2001  American Megatrends Inc.
  *
  *              This program is free software; you can redistribute it and/or
  *              modify it under the terms of the GNU General Public License
  *              as published by the Free Software Foundation; either version
  *              2 of the License, or (at your option) any later version.
  *
- * Version : 1.07b
- * 
+ * Version : v1.14g (Feb 5, 2001)
+ *
  * Description: Linux device driver for AMI MegaRAID controller
  *
- * Supported controllers: MegaRAID 418, 428, 438, 466, 762, 467, 490
- * 
+ * Supported controllers: MegaRAID 418, 428, 438, 466, 762, 467, 471, 490
+ *                                      493.
  * History:
  *
  * Version 0.90:
  *     Original source contributed by Dell; integrated it into the kernel and
  *     cleaned up some things.  Added support for 438/466 controllers.
- *
  * Version 0.91:
  *     Aligned mailbox area on 16-byte boundry.
  *     Added schedule() at the end to properly clean up.
@@ -42,10 +41,10 @@
  *     8 Oct 98        Alan Cox <alan.cox@linux.org>
  *
  *     Merged with 2.1.131 source tree.
- *     12 Dec 98       K. Baranowski <kgb@knm.org.pl>                          
+ *     12 Dec 98       K. Baranowski <kgb@knm.org.pl>
  *
  * Version 0.93:
- *     Added support for vendor specific ioctl commands (0x80+xxh)
+ *     Added support for vendor specific ioctl commands (M_RD_IOCTL_CMD+xxh)
  *     Changed some fields in MEGARAID struct to better values.
  *     Added signature check for Rp controllers under 2.0 kernels
  *     Changed busy-wait loop to be time-based
@@ -74,9 +73,7 @@
  *
  * Version 0.97:
  *     Changed megaraid_command to use wait_queue.
- *     Fixed bug of undesirably detecting HP onboard controllers which
- *       are disabled.
- *     
+ *
  * Version 1.00:
  *     Checks to see if an irq ocurred while in isr, and runs through
  *       routine again.
@@ -89,13 +86,13 @@
  *
  * Version 1.01:
  *     Fixed bug in mega_cmd_done() for megamgr control commands,
- *       the host_byte in the result code from the scsi request to 
- *       scsi midlayer is set to DID_BAD_TARGET when adapter's 
- *       returned codes are 0xF0 and 0xF4.  
+ *       the host_byte in the result code from the scsi request to
+ *       scsi midlayer is set to DID_BAD_TARGET when adapter's
+ *       returned codes are 0xF0 and 0xF4.
  *
  * Version 1.02:
  *     Fixed the tape drive bug by extending the adapter timeout value
- *       for passthrough command to 60 seconds in mega_build_cmd(). 
+ *       for passthrough command to 60 seconds in mega_build_cmd().
  *
  * Version 1.03:
  *    Fixed Madrona support.
@@ -104,7 +101,7 @@
  *    Added driver version printout at driver loadup time
  *
  * Version 1.04
- *    Added code for 40 ld FW support. 
+ *    Added code for 40 ld FW support.
  *    Added new ioctl command 0x81 to support NEW_READ/WRITE_CONFIG with
  *      data area greater than 4 KB, which is the upper bound for data
  *      tranfer through scsi_ioctl interface.
@@ -119,15 +116,182 @@
  *    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.
- *
+ * Version 1.06
+ *              Intel Release
  * Version 1.07
  *    Removed the usage of uaccess.h file for kernel versions less than
  *    2.0.36, as this file is not present in those versions.
  *
- * Version 1.07b
- *    The MegaRAID 466 cards with 3.00 firmware lockup and seem to very
- *    occasionally hang. We check such cards and report them. You can
- *    get firmware upgrades to flash the board to 3.10 for free.
+ * Version 108
+ *    Modified mega_ioctl so that 40LD megamanager would run
+ *    Made some changes for 2.3.XX compilation , esp wait structures
+ *    Code merge between 1.05 and 1.06 .
+ *    Bug fixed problem with ioctl interface for concurrency between
+ *    8ld and 40ld firwmare
+ *    Removed the flawed semaphore logic for handling new config command
+ *    Added support for building own scatter / gather list for big user
+ *    mode buffers
+ *    Added /proc file system support ,so that information is available in
+ *    human readable format
+ *
+ * Version 1a08
+ *    Changes for IA64 kernels. Checked for CONFIG_PROC_FS flag
+ *
+ * Version 1b08
+ *    Include file changes.
+ * Version 1b08b
+ *    Change PCI ID value for the 471 card, use #defines when searching
+ *    for megaraid cards.
+ *
+ * Version 1.10
+ *
+ *      I) Changes made to make following ioctl commands work in 0x81 interface
+ *              a)DCMD_DELETE_LOGDRV
+ *              b)DCMD_GET_DISK_CONFIG
+ *              c)DCMD_DELETE_DRIVEGROUP
+ *              d)NC_SUBOP_ENQUIRY3
+ *              e)DCMD_CHANGE_LDNO
+ *              f)DCMD_CHANGE_LOOPID
+ *              g)DCMD_FC_READ_NVRAM_CONFIG
+ *      h)DCMD_WRITE_CONFIG
+ *      II) Added mega_build_kernel_sg function
+ *  III)Firmware flashing option added
+ *
+ * Version 1.10a
+ *
+ *      I)Dell updates included in the source code.
+ *              Note:   This change is not tested due to the unavailability of IA64 kernel
+ *      and it is in the #ifdef DELL_MODIFICATION macro which is not defined
+ *
+ * Version 1.10b
+ *
+ *      I)In M_RD_IOCTL_CMD_NEW command the wrong way of copying the data
+ *    to the user address corrected
+ *
+ * Version 1.10c
+ *
+ *      I) DCMD_GET_DISK_CONFIG opcode updated for the firmware changes.
+ *
+ * Version 1.11
+ *      I)  Version number changed from 1.10c to 1.11
+ *  II) DCMD_WRITE_CONFIG(0x0D) command in the driver changed from
+ *      scatter/gather list mode to direct pointer mode..
+ *     Fixed bug of undesirably detecting HP onboard controllers which
+ *       are disabled.
+ *
+ *      Version 1.12 (Sep 21, 2000)
+ *
+ *     I. Changes have been made for Dynamic DMA mapping in IA64 platform.
+ *                To enable all these changes define M_RD_DYNAMIC_DMA_SUPPORT in megaraid.h
+ *        II. Got rid of windows mode comments
+ *       III. Removed unwanted code segments
+ *    IV. Fixed bug of HP onboard controller information (commented with
+ *                 MEGA_HP_FIX)
+ *
+ *      Version 1a12
+ *      I.      reboot notifer and new ioctl changes ported from 1c09
+ *
+ *      Veriosn 1b12
+ *      I.      Changes in new ioctl interface routines ( Nov 06, 2000 )
+ *
+ *      Veriosn 1c12
+ *      I.      Changes in new ioctl interface routines ( Nov 07, 2000 )
+ *
+ *      Veriosn 1d12
+ *      I.      Compilation error under kernel 2.4.0 for 32-bit machine in mega_ioctl
+ *
+ *      Veriosn 1e12, 1f12
+ *      1.  Fixes for pci_map_single, pci_alloc_consistent along with mailbox
+ *          alignment
+ *
+ *	Version 1.13beta
+ *	Added Support for Full 64bit address space support. If firmware
+ *	supports 64bit, it goes to 64 bit mode even on x86 32bit 
+ *	systems. Data Corruption Issues while running on test9 kernel
+ *	on IA64 systems. This issue not seen on test11 on x86 system
+ *
+ *	Version 1.13c
+ *	1. Resolved Memory Leak when using M_RD_IOCTL_CMD interface
+ *	2. Resolved Queuing problem when MailBox Blocks
+ *	3. Added unregister_reboot_notifier support
+ * 
+ *	Version 1.13d
+ *	Experimental changes in interfacing with the controller in ISR
+ *
+ *	Version 1.13e
+ *	Fixed Broken 2.2.XX compilation changes + misc changes
+ *
+ *	Version 1.13f to 1.13i
+ *	misc changes + code clean up
+ *	Cleaned up the ioctl code and added set_mbox_xfer_addr()
+ *	Support for START_DEV (6)
+ * 	
+ *	Version 1.13j
+ *	Moved some code to megaraid.h file, replaced some hard coded values 
+ *      with respective macros. Chaged some funtions to static
+ *
+ *	Version 1.13k
+ *	Only some idendation correction to 1.13j 
+ *
+ *	Version 1.13l , 1.13m, 1.13n, 1.13o
+ *	Minor Identation changes + misc changes
+ *
+ *	Version 1.13q
+ *	Paded the new uioctl_t MIMD structure for maintaining alignment 
+ *	and size across 32 / 64 bit platforms
+ *	Changed the way MIMD IOCTL interface used virt_to_bus() to use pci
+ *	memory location
+ *
+ *	Version 1.13r
+ *	2.4.xx SCSI Changes.
+ *
+ *	Version 1.13s
+ *	Stats counter fixes
+ *	Temporary fix for some 64 bit firmwares in 2.4.XX kernels
+ *
+ *	Version	1.13t
+ *	Support for 64bit version of READ/WRITE/VIEW DISK CONFIG
+ *
+ *	Version 1.14
+ *	Did away with MEGADEV_IOCTL flag. It is now standard part of driver
+ *	without need for a special #define flag
+ *	Disabled old scsi ioctl path for kernel versions > 2.3.xx. This is due
+ *	to the nature in which the new scsi code queues a new scsi command to 
+ *	controller during SCSI IO Completion
+ *	Driver now checks for sub-system vendor id before taking ownership of
+ *	the controller
+ *
+ *	Version 1.14a
+ *	Added Host re-ordering
+ *
+ *	Version 1.14b
+ *	Corrected some issue which caused the older cards not to work
+ *	
+ *	Version 1.14c
+ *	IOCTL changes for not handling the non-64bit firmwares under 2.4.XX
+ *	kernel
+ *
+ *	Version 1.14d
+ *	Fixed Various MIMD Synchronization Issues
+ *	
+ *	Version 1.14e
+ *	Fixed the error handling during card initialization
+ *
+ *	Version 1.14f
+ *	Multiple invocations of mimd phase I ioctl stalls the cpu. Replaced
+ *	spinlock with semaphore(mutex)
+ *
+ *	Version 1.14g
+ *	Fixed running out of scbs issues while running MIMD apps under heavy IO
+ *
+ *	Version 1.14g-ac - 02/03/01
+ *	Reformatted to Linux format so I could compare to old one and cross
+ *	check bug fixes
+ *	Re fixed the assorted missing 'static' cases
+ *	Removed some unneeded version checks
+ *	Cleaned up some of the VERSION checks in the code
+ *	Left 2.0 support but removed 2.1.x support.
+ *	Collected much of the compat glue into one spot
  *
  * BUGS:
  *     Some older 2.1 kernels (eg. 2.1.90) have a bug in pci.c that
@@ -135,31 +299,23 @@
  *
  *     Timeout period for upper scsi layer, i.e. SD_TIMEOUT in
  *     /drivers/scsi/sd.c, is too short for this controller. SD_TIMEOUT
- *     value must be increased to (30 * HZ) otherwise false timeouts 
+ *     value must be increased to (30 * HZ) otherwise false timeouts
  *     will occur in the upper layer.
  *
+ *     Never set skip_id. The existing PCI code the megaraid uses fails
+ *     to properly check the vendor subid in some cases. Setting this then
+ *     makes it steal other i960's and crashes some boxes
+ *
+ *     Far too many ifdefs for versions.
+ *
  *===================================================================*/
 
-#define CRLFSTR "\n"
-#define IOCTL_CMD_NEW  0x81
-
-#define MEGARAID_VERSION "v107 (December 22, 1999)"
-
-
+#include <linux/config.h>
 #include <linux/version.h>
-
-#ifdef MODULE
 #include <linux/module.h>
-
-char kernel_version[] = UTS_RELEASE;
-
-MODULE_AUTHOR ("American Megatrends Inc.");
-MODULE_DESCRIPTION ("AMI MegaRAID driver");
-#endif
-
-#include <linux/init.h>
 #include <linux/types.h>
 #include <linux/errno.h>
+#include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/ioport.h>
 #include <linux/fcntl.h>
@@ -170,83 +326,115 @@
 #include <linux/wait.h>
 #include <linux/tqueue.h>
 #include <linux/interrupt.h>
+#include <linux/mm.h>
+#include <asm/pgtable.h>
 
+#include <linux/sched.h>
 #include <linux/stat.h>
+#include <linux/malloc.h>	/* for kmalloc() */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)	/* 0x20100 */
+#include <linux/bios32.h>
+#else
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)	/* 0x20300 */
+#include <asm/spinlock.h>
+#else
 #include <linux/spinlock.h>
+#endif
+#endif
 
 #include <asm/io.h>
 #include <asm/irq.h>
-#if LINUX_VERSION_CODE > 0x020024
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,0,24)	/* 0x020024 */
 #include <asm/uaccess.h>
 #endif
 
+/*
+ * These header files are required for Shutdown Notification routines
+ */
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+
 #include "sd.h"
 #include "scsi.h"
 #include "hosts.h"
 
 #include "megaraid.h"
 
-/*================================================================
- *
- *                          #Defines
- *
+/*
+ *================================================================
+ *  #Defines
  *================================================================
  */
 
 #define MAX_SERBUF 160
 #define COM_BASE 0x2f8
 
-
-u32 RDINDOOR (mega_host_config * megaCfg)
+static ulong RDINDOOR (mega_host_config * megaCfg)
 {
-  return readl (megaCfg->base + 0x20);
+	return readl (megaCfg->base + 0x20);
 }
 
-void WRINDOOR (mega_host_config * megaCfg, u32 value)
+static void WRINDOOR (mega_host_config * megaCfg, ulong value)
 {
-  writel (value, megaCfg->base + 0x20);
+	writel (value, megaCfg->base + 0x20);
 }
 
-u32 RDOUTDOOR (mega_host_config * megaCfg)
+static ulong RDOUTDOOR (mega_host_config * megaCfg)
 {
-  return readl (megaCfg->base + 0x2C);
+	return readl (megaCfg->base + 0x2C);
 }
 
-void WROUTDOOR (mega_host_config * megaCfg, u32 value)
+static void WROUTDOOR (mega_host_config * megaCfg, ulong value)
 {
-  writel (value, megaCfg->base + 0x2C);
+	writel (value, megaCfg->base + 0x2C);
 }
 
-/*================================================================
- *
- *                    Function prototypes
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)	/* 0x020100 */
+
+/*
+ *	Linux 2.4 and higher
  *
- *================================================================
+ *	No driver private lock
+ *	Use the io_request_lock not cli/sti
+ *	queue task is a simple api without irq forms
  */
-static int __init megaraid_setup(char *);
 
-static int megaIssueCmd (mega_host_config * megaCfg,
-			 u_char * mboxData,
-			 mega_scb * scb,
-			 int intr);
-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 (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 mega_freeSgList(mega_host_config *megaCfg);
-static void mega_Convert8ldTo40ld(  mega_RAIDINQ  *inquiry,
-                                    mega_Enquiry3 *enquiry3,
-                                    megaRaidProductInfo *productInfo );
+#include <linux/smp.h>
+#define cpuid smp_processor_id()
+
+MODULE_AUTHOR ("American Megatrends Inc.");
+MODULE_DESCRIPTION ("AMI MegaRAID driver");
 
+#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);
 
-#include <linux/smp.h>
+#define queue_task_irq(a,b)     queue_task(a,b)
+#define queue_task_irq_off(a,b) queue_task(a,b)
 
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)	/* 0x020200 */
 
+/*
+ *	Linux 2.2 and higher
+ *
+ *	No driver private lock
+ *	Use the io_request_lock not cli/sti
+ *	No pci region api
+ *	queue_task is now a single simple API
+ */
+ 
+#include <linux/smp.h>
 #define cpuid smp_processor_id()
+
+MODULE_AUTHOR ("American Megatrends Inc.");
+MODULE_DESCRIPTION ("AMI MegaRAID driver");
+
 #define DRIVER_LOCK_T
 #define DRIVER_LOCK_INIT(p)
 #define DRIVER_LOCK(p)
@@ -255,95 +443,220 @@
 #define IO_LOCK spin_lock_irqsave(&io_request_lock,io_flags);
 #define IO_UNLOCK spin_unlock_irqrestore(&io_request_lock,io_flags);
 
+#define pci_free_consistent(a,b,c,d)
+#define pci_unmap_single(a,b,c,d,e)
+
+#define init_MUTEX_LOCKED(x)	((x)=MUTEX_LOCKED)
+#define init_MUTEX(x)		((x)=MUTEX)
+
+#define queue_task_irq(a,b)     queue_task(a,b)
+#define queue_task_irq_off(a,b) queue_task(a,b)
+
+#define DECLARE_WAIT_QUEUE_HEAD(x)	struct wait_queue *x = NULL
+#else
+
+/*
+ *	Linux 2.0 macros. Here we have to provide some of our own
+ *	functionality. We also only work little endian 32bit.
+ *	Again no pci_alloc/free api
+ *	IO_LOCK/IO_LOCK_T were never used in 2.0 so now are empty 
+ */
+ 
+#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_T
+#define IO_LOCK(p)
+#define IO_UNLOCK(p)
+#define le32_to_cpu(x) (x)
+#define cpu_to_le32(x) (x)
+
+#define pci_free_consistent(a,b,c,d)
+#define pci_unmap_single(a,b,c,d,e)
+
+#define init_MUTEX_LOCKED(x)	((x)=MUTEX_LOCKED)
+#define init_MUTEX(x)		((x)=MUTEX)
+
+/*
+ *	2.0 lacks spinlocks, iounmap/ioremap
+ */
+
+#define ioremap vremap
+#define iounmap vfree
+
+ /* simulate spin locks */
+typedef struct {
+	volatile char lock;
+} spinlock_t;
+
+#define spin_lock_init(x) { (x)->lock = 0;}
+#define spin_lock_irqsave(x,flags) { while ((x)->lock) barrier();\
+                                        (x)->lock=1; save_flags(flags);\
+                                        cli();}
+#define spin_unlock_irqrestore(x,flags) { (x)->lock=0; restore_flags(flags);}
+
+#define DECLARE_WAIT_QUEUE_HEAD(x)	struct wait_queue *x = NULL
+
+#endif
+
+
+
 /* set SERDEBUG to 1 to enable serial debugging */
 #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,...);
+static int ser_printk (const char *fmt, ...);
 #endif
 
-/*================================================================
- *
+#ifdef CONFIG_PROC_FS
+#define COPY_BACK if (offset > megaCfg->procidx) { \
+		*eof = TRUE; \
+        megaCfg->procidx = 0; \
+        megaCfg->procbuf[0] = 0; \
+        return 0;} \
+ if ((count + offset) > megaCfg->procidx) { \
+      count = megaCfg->procidx - offset; \
+      *eof = TRUE; } \
+      memcpy(page, &megaCfg->procbuf[offset], count); \
+      megaCfg->procidx = 0; \
+      megaCfg->procbuf[0] = 0;
+#endif
+
+/*
+ * ================================================================
  *                    Global variables
- *
  *================================================================
  */
 
 /*  Use "megaraid=skipXX" as LILO option to prohibit driver from scanning
     XX scsi id on each channel.  Used for Madrona motherboard, where SAF_TE
     processor id cannot be scanned */
+
+static char *megaraid;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0)	/* 0x20100 */
 #ifdef MODULE
-static char *megaraid = NULL;
-MODULE_PARM(megaraid, "s");
+MODULE_PARM (megaraid, "s");
 #endif
-static int skip_id;
-
+#endif
+static int skip_id = -1;
 static int numCtlrs = 0;
-static mega_host_config *megaCtlrs[FC_MAX_CHANNELS] = {0};
+static mega_host_config *megaCtlrs[FC_MAX_CHANNELS] = { 0 };
+static struct proc_dir_entry *mega_proc_dir_entry;
 
 #if DEBUG
 static u32 maxCmdTime = 0;
 #endif
 
 static mega_scb *pLastScb = NULL;
+static struct notifier_block mega_notifier = {
+	megaraid_reboot_notify,
+	NULL,
+	0
+};
+
+/* For controller re-ordering */
+struct mega_hbas mega_hbas[MAX_CONTROLLERS];
+
+/*
+ * The File Operations structure for the serial/ioctl interface of the driver
+ */
+/* For controller re-ordering */ 
+
+static struct file_operations megadev_fops = {
+	ioctl:megadev_ioctl_entry,
+	open:megadev_open,
+	release:megadev_close,
+};
+
+/*
+ * Array to structures for storing the information about the controllers. This
+ * information is sent to the user level applications, when they do an ioctl
+ * for this information.
+ */
+static struct mcontroller mcontroller[MAX_CONTROLLERS];
+
+/* The current driver version */
+static u32 driver_ver = 114;
+
+/* major number used by the device for character interface */
+static int major;
 
+static struct semaphore mimd_ioctl_sem;
+static struct semaphore mimd_entry_mtx;
 
 #if SERDEBUG
-static spinlock_t serial_lock = SPIN_LOCK_UNLOCKED;
+volatile static spinlock_t serial_lock;
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)	/* 0x20300 */
+static struct proc_dir_entry proc_scsi_megaraid = {
+	PROC_SCSI_MEGARAID, 8, "megaraid",
+	S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
+#endif
+
+#ifdef CONFIG_PROC_FS
+extern struct proc_dir_entry proc_root;
 #endif
 
+
 #if SERDEBUG
 static char strbuf[MAX_SERBUF + 1];
 
-static void ser_init ()
+static void ser_init (void)
 {
-  unsigned port = COM_BASE;
+	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);
+	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;
+	char *ptr;
 
-  ser_init ();
-  for (ptr = str; *ptr; ++ptr)
-    ser_putc (*ptr);
+	ser_init ();
+	for (ptr = str; *ptr; ++ptr)
+		ser_putc (*ptr);
 }
 
 static void ser_putc (char c)
 {
-  unsigned port = COM_BASE;
+	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);
+	}
+}
 
-  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;
-
-  spin_lock_irqsave(&serial_lock,flags);
-  va_start (args, fmt);
-  i = vsprintf (strbuf, fmt, args);
-  ser_puts (strbuf);
-  va_end (args);
-  spin_unlock_irqrestore(&serial_lock,flags);
+static int ser_printk (const char *fmt, ...)
+{
+	va_list args;
+	int i;
+	long flags;
+
+	spin_lock_irqsave (&serial_lock, flags);
+	va_start (args, fmt);
+	i = vsprintf (strbuf, fmt, args);
+	ser_puts (strbuf);
+	va_end (args);
+	spin_unlock_irqrestore (&serial_lock, flags);
 
-  return i;
+	return i;
 }
 
 #define TRACE(a)    { ser_printk a;}
@@ -352,14 +665,16 @@
 #define TRACE(A)
 #endif
 
+#define TRACE1(a)
+
 static void callDone (Scsi_Cmnd * SCpnt)
 {
-  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));
-  }
-  SCpnt->scsi_done (SCpnt);
+	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));
+	}
+	SCpnt->scsi_done (SCpnt);
 }
 
 /*-------------------------------------------------------------------------
@@ -372,51 +687,92 @@
  * Free a SCB structure
  *=======================
  */
-static void mega_freeSCB (mega_host_config *megaCfg, mega_scb * pScb)
+static void mega_freeSCB (mega_host_config * megaCfg, mega_scb * pScb)
 {
 
-  mega_scb *pScbtmp;
+	mega_scb *pScbtmp;
+
+	if ((pScb == NULL) || (pScb->idx >= 0xFE)) {
+		return;
+	}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	switch (pScb->dma_type) {
+	case M_RD_DMA_TYPE_NONE:
+		break;
+	case M_RD_PTHRU_WITH_BULK_DATA:
+		pci_unmap_single (megaCfg->dev, pScb->dma_h_bulkdata,
+				  pScb->pthru->dataxferlen,
+				  pScb->dma_direction);
+		break;
+	case M_RD_PTHRU_WITH_SGLIST:
+	{
+		int count;
+		for (count = 0; count < pScb->sglist_count; count++) {
+			pci_unmap_single (megaCfg->dev,
+					  pScb->dma_h_sglist[count],
+					  pScb->sgList[count].length,
+					  pScb->dma_direction);
+
+		}
+		break;
+	}
+	case M_RD_BULK_DATA_ONLY:
+		pci_unmap_single (megaCfg->dev,
+				  pScb->dma_h_bulkdata,
+				  pScb->iDataSize, pScb->dma_direction);
+
+		break;
+	case M_RD_SGLIST_ONLY:
+		pci_unmap_sg (megaCfg->dev,
+			      pScb->SCpnt->request_buffer,
+			      pScb->SCpnt->use_sg, pScb->dma_direction);
+		break;
+	default:
+		break;
+	}
+#endif
+
+	/* Unlink from pending queue */
+	if (pScb == megaCfg->qPendingH) {
+
+		if (megaCfg->qPendingH == megaCfg->qPendingT)
+			megaCfg->qPendingH = megaCfg->qPendingT = NULL;
+		else
+			megaCfg->qPendingH = megaCfg->qPendingH->next;
+
+		megaCfg->qPcnt--;
 
-  if ((pScb == NULL) || (pScb->idx >= 0xFE)) {
-    return ;
-  }
-
-  /* Unlink from pending queue */
-
-  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 free list */
-  pScb->state = SCB_FREE;
-  pScb->SCpnt = NULL;
-
-  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++;
+	} 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 free list */
+	pScb->state = SCB_FREE;
+	pScb->SCpnt = NULL;
+
+	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++;
 
 }
 
@@ -424,186 +780,173 @@
  * Allocate a SCB structure
  *===========================
  */
-static mega_scb * mega_allocateSCB (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt)
+static mega_scb *mega_allocateSCB (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt)
 {
-  mega_scb *pScb;
+	mega_scb *pScb;
 
-  /* Unlink command from Free List */
-  if ((pScb = megaCfg->qFreeH) != NULL) {
-    megaCfg->qFreeH = pScb->next;
-    megaCfg->qFcnt--;
-    
-    pScb->isrcount = jiffies;
-    pScb->next  = NULL;
-    pScb->state = SCB_ACTIVE;
-    pScb->SCpnt = SCpnt;
+	/* Unlink command from Free List */
+	if ((pScb = megaCfg->qFreeH) != NULL) {
+		megaCfg->qFreeH = pScb->next;
+		megaCfg->qFcnt--;
+
+		pScb->isrcount = jiffies;
+		pScb->next = NULL;
+		pScb->state = SCB_ACTIVE;
+		pScb->SCpnt = SCpnt;
 
-    return pScb;
-  }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+		pScb->dma_type = M_RD_DMA_TYPE_NONE;
+#endif
+
+		return pScb;
+	}
 
-  printk (KERN_WARNING "Megaraid: Could not allocate free SCB!!!\n");
+	printk (KERN_WARNING "Megaraid: Could not allocate free SCB!!!\n");
 
-  return NULL;
+	return NULL;
 }
 
-/*================================================
- * Initialize SCB structures
- *================================================
- */
-static int mega_initSCB (mega_host_config * megaCfg)
+/* Run through the list of completed requests  and finish it */
+static void mega_rundoneq (mega_host_config * megaCfg)
 {
-  int idx;
+	Scsi_Cmnd *SCpnt;
 
-  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
+	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);
+	}
 
-  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);
-      mega_freeSgList(megaCfg);
-      return -1;
-    }
-    
-    if (idx < MAX_COMMANDS) {
-      /* Link to free list */
-      mega_freeSCB(megaCfg, &megaCfg->scbList[idx]);
-    }
-  }
-  return 0;
-}
-
-/* Run through the list of completed requests */
-static void mega_rundoneq (mega_host_config *megaCfg)
-{
-  Scsi_Cmnd *SCpnt;
-
-  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;
+	megaCfg->qCompletedH = megaCfg->qCompletedT = NULL;
 }
 
 /*
  * Runs through the list of pending requests
  * Assumes that mega_lock spin_lock has been acquired.
  */
-static void mega_runpendq(mega_host_config *megaCfg)
+static int mega_runpendq (mega_host_config * megaCfg)
 {
-  mega_scb *pScb;
+	mega_scb *pScb;
+	int rc;
 
-  /* Issue any pending commands to the card */
-  for(pScb=megaCfg->qPendingH; pScb; pScb=pScb->next) {
-    if (pScb->state == SCB_ACTIVE) {
-      if(megaIssueCmd(megaCfg, pScb->mboxData, pScb, 1))
-	return;
-    }
-  }
+	/* Issue any pending commands to the card */
+	for (pScb = megaCfg->qPendingH; pScb; pScb = pScb->next) {
+		if (pScb->state == SCB_ACTIVE) {
+			if ((rc =
+			     megaIssueCmd (megaCfg, pScb->mboxData, pScb, 1)) == -1)
+				return rc;
+		}
+	}
+	return 0;
 }
 
 /* Add command to the list of completed requests */
-static void
-mega_cmd_done (mega_host_config * megaCfg, mega_scb * pScb, 
-			   int status)
+
+static void mega_cmd_done (mega_host_config * megaCfg, mega_scb * pScb, int status)
 {
-  int islogical;
-  Scsi_Cmnd *SCpnt;
-  mega_passthru *pthru;
-  mega_mailbox *mbox;
-
-  if (pScb == NULL) {
-	TRACE(("NULL pScb in mega_cmd_done!"));
-	printk("NULL pScb in mega_cmd_done!");
-  }
-
-  SCpnt = pScb->SCpnt;
-  pthru = &pScb->pthru;
-  mbox = (mega_mailbox *) &pScb->mboxData;
-
-  if (SCpnt == NULL) {
-	TRACE(("NULL SCpnt in mega_cmd_done!"));
-	TRACE(("pScb->idx = ",pScb->idx));
-	TRACE(("pScb->state = ",pScb->state));
-	TRACE(("pScb->state = ",pScb->state));
-	printk("megaraid:Problem...!\n");
-	while(1);
-  }
-
-  islogical = (SCpnt->channel == megaCfg->host->max_channel);
-
-  if (SCpnt->cmnd[0] == INQUIRY &&
-      ((((u_char *) SCpnt->request_buffer)[0] & 0x1F) == TYPE_DISK) &&
-      !islogical) {
-    status = 0xF0;
-  }
-
-/* clear result; otherwise, success returns corrupt value */ 
- SCpnt->result = 0;  
-
-if ((SCpnt->cmnd[0] & 0x80) ) {/* i.e. ioctl cmd such as 0x80, 0x81 of megamgr*/
-    switch (status) {
-      case 0xF0:
-      case 0xF4:
-	SCpnt->result=(DID_BAD_TARGET<<16)|status;
-        break;
-      default:
-	SCpnt->result|=status;
-   }/*end of switch*/
-}
-else{
-  /* Convert MegaRAID status to Linux error code */
-  switch (status) {
-  case 0x00: /* SUCCESS , i.e. SCSI_STATUS_GOOD*/
-    SCpnt->result |= (DID_OK << 16);
-    break;
-  case 0x02: /* ERROR_ABORTED, i.e. SCSI_STATUS_CHECK_CONDITION */
-	/*set sense_buffer and result fields*/
-       if( mbox->cmd==MEGA_MBOXCMD_PASSTHRU ){
-	  memcpy( SCpnt->sense_buffer , pthru->reqsensearea, 14);
-          SCpnt->result = (DRIVER_SENSE<<24)|(DID_ERROR << 16)|status; 
-       }
-       else{
- 	  SCpnt->sense_buffer[0]=0x70;
-	  SCpnt->sense_buffer[2]=ABORTED_COMMAND;
-          SCpnt->result |= (CHECK_CONDITION << 1);
-       }
-    break;
-  case 0x08:  /* ERR_DEST_DRIVE_FAILED, i.e. SCSI_STATUS_BUSY */
-    SCpnt->result |= (DID_BUS_BUSY << 16)|status;
-    break;
-  default: 
-    SCpnt->result |= (DID_BAD_TARGET << 16)|status;
-    break;
-  }
- }
-  if ( SCpnt->cmnd[0]!=IOCTL_CMD_NEW ) 
-  /* not IOCTL_CMD_NEW SCB, freeSCB()*/
-  /* For IOCTL_CMD_NEW SCB, delay freeSCB() in megaraid_queue()
-   * after copy data back to user space*/
-     mega_freeSCB(megaCfg, pScb);
-
-  /* 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++;
+	int islogical;
+	Scsi_Cmnd *SCpnt;
+	mega_passthru *pthru;
+	mega_mailbox *mbox;
+
+	if (pScb == NULL) {
+		TRACE (("NULL pScb in mega_cmd_done!"));
+		printk(KERN_CRIT "NULL pScb in mega_cmd_done!");
+	}
+
+	SCpnt = pScb->SCpnt;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	pthru = pScb->pthru;
+#else
+	pthru = &pScb->pthru;
+#endif
+
+	mbox = (mega_mailbox *) & pScb->mboxData;
+
+	if (SCpnt == NULL) {
+		TRACE (("NULL SCpnt in mega_cmd_done!"));
+		TRACE (("pScb->idx = ", pScb->idx));
+		TRACE (("pScb->state = ", pScb->state));
+		TRACE (("pScb->state = ", pScb->state));
+		panic(KERN_ERR "megaraid:Problem...!\n");
+	}
+
+	islogical = (SCpnt->channel == megaCfg->host->max_channel);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	/* Special Case to handle PassThrough->XferAddrress > 4GB */
+	switch (SCpnt->cmnd[0]) {
+	case INQUIRY:
+	case READ_CAPACITY:
+		memcpy (SCpnt->request_buffer,
+			pScb->bounce_buffer, SCpnt->request_bufflen);
+		break;
+	}
+#endif
+
+	mega_freeSCB (megaCfg, pScb);
+
+	if (SCpnt->cmnd[0] == INQUIRY && ((((u_char *) SCpnt->request_buffer)[0] & 0x1F) == TYPE_DISK) && !islogical) {
+		status = 0xF0;
+	}
+
+	/* clear result; otherwise, success returns corrupt value */
+	SCpnt->result = 0;
+
+	if ((SCpnt->cmnd[0] & M_RD_IOCTL_CMD)) {	/* i.e. ioctl cmd such as M_RD_IOCTL_CMD, M_RD_IOCTL_CMD_NEW of megamgr */
+		switch (status) {
+		case 2:
+		case 0xF0:
+		case 0xF4:
+			SCpnt->result = (DID_BAD_TARGET << 16) | status;
+			break;
+		default:
+			SCpnt->result |= status;
+		}		/*end of switch */
+	} else {
+		/* Convert MegaRAID status to Linux error code */
+		switch (status) {
+		case 0x00:	/* SUCCESS , i.e. SCSI_STATUS_GOOD */
+			SCpnt->result |= (DID_OK << 16);
+			break;
+
+		case 0x02:	/* ERROR_ABORTED, i.e. SCSI_STATUS_CHECK_CONDITION */
+
+			/*set sense_buffer and result fields */
+			if (mbox->cmd == MEGA_MBOXCMD_PASSTHRU) {
+				memcpy (SCpnt->sense_buffer, pthru->reqsensearea, 14);
+				SCpnt->result = (DRIVER_SENSE << 24) | (DID_ERROR << 16) | status;
+			} else {
+				SCpnt->sense_buffer[0] = 0x70;
+				SCpnt->sense_buffer[2] = ABORTED_COMMAND;
+				SCpnt->result |= (CHECK_CONDITION << 1);
+			}
+			break;
+
+		case 0x08:	/* ERR_DEST_DRIVE_FAILED, i.e. SCSI_STATUS_BUSY */
+			SCpnt->result |= (DID_BUS_BUSY << 16) | status;
+			break;
+
+		default:
+			SCpnt->result |= (DID_BAD_TARGET << 16) | status;
+			break;
+		}
+	}
+
+	/* 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++;
 }
 
 /*-------------------------------------------------------------------
@@ -614,491 +957,859 @@
  * 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;
-  char islogical;
-  char lun = SCpnt->lun;
 
-  if ((SCpnt->cmnd[0] == 0x80)  || (SCpnt->cmnd[0] == IOCTL_CMD_NEW) )  /* ioctl */
-    return mega_ioctl (megaCfg, SCpnt);
- 
-  islogical = (SCpnt->channel == megaCfg->host->max_channel);
+static mega_scb *mega_build_cmd (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt)
+{
+	mega_scb *pScb;
+	mega_mailbox *mbox;
+	mega_passthru *pthru;
+	long seg;
+	char islogical;
+	char lun = SCpnt->lun;
+
+	if ((SCpnt->cmnd[0] == MEGADEVIOC))
+		return megadev_doioctl (megaCfg, SCpnt);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
+	if ((SCpnt->cmnd[0] == M_RD_IOCTL_CMD)
+	    || (SCpnt->cmnd[0] == M_RD_IOCTL_CMD_NEW))
+		return mega_ioctl (megaCfg, SCpnt);	/* Handle IOCTL command */
+#endif
 
-  if (!islogical && lun != 0) {
-    SCpnt->result = (DID_BAD_TARGET << 16);
-    callDone (SCpnt);
-    return NULL;
-  }
+	islogical = (SCpnt->channel == megaCfg->host->max_channel);
 
-  if (!islogical && SCpnt->target == skip_id) {
-	SCpnt->result = (DID_BAD_TARGET << 16);
-	callDone (SCpnt);
-	return NULL;
-  }
+	if (!islogical && lun != 0) {
+		SCpnt->result = (DID_BAD_TARGET << 16);
+		callDone (SCpnt);
+		return NULL;
+	}
 
-  if ( islogical ) {
-	lun = (SCpnt->target * 8) + lun;
-        if ( lun > FC_MAX_LOGICAL_DRIVES ){
-            SCpnt->result = (DID_BAD_TARGET << 16);
-            callDone (SCpnt);
-            return NULL;
-        }
-  }
-  /*-----------------------------------------------------
-   *
-   *               Logical drive commands
-   *
-   *-----------------------------------------------------*/
-  if (islogical) {
-    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 = mega_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 = 1;
-      pthru->reqsenselen = 14;
-      pthru->islogical = 1;
-      pthru->logdrv = lun;
-      pthru->cdblen = SCpnt->cmd_len;
-      pthru->dataxferaddr = virt_to_bus (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 = virt_to_bus (pthru);
-
-      return pScb;
-
-    case READ_6:
-    case WRITE_6:
-    case READ_10:
-    case WRITE_10:
-      /* Allocate a SCB and initialize mailbox */
-      if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) {
-	SCpnt->result = (DID_ERROR << 16);
-	callDone (SCpnt);
-	return NULL;
-      }
-      mbox = (mega_mailbox *) & pScb->mboxData;
+	if (!islogical && SCpnt->target == skip_id) {
+		SCpnt->result = (DID_BAD_TARGET << 16);
+		callDone (SCpnt);
+		return NULL;
+	}
 
-      memset (mbox, 0, sizeof (pScb->mboxData));
-      mbox->logdrv = lun;
-      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 =
-	  (u32) SCpnt->cmnd[4];
-	mbox->lba =
-	  ((u32) SCpnt->cmnd[1] << 16) |
-	  ((u32) SCpnt->cmnd[2] << 8) |
-	  (u32) SCpnt->cmnd[3];
-	mbox->lba &= 0x1FFFFF;
-      }
-
-      /* 10-byte */
-      if (*SCpnt->cmnd == READ_10 || *SCpnt->cmnd == WRITE_10) {
-	mbox->numsectors =
-	  (u32) SCpnt->cmnd[8] |
-	  ((u32) SCpnt->cmnd[7] << 8);
-	mbox->lba =
-	  ((u32) SCpnt->cmnd[2] << 24) |
-	  ((u32) SCpnt->cmnd[3] << 16) |
-	  ((u32) SCpnt->cmnd[4] << 8) |
-	  (u32) SCpnt->cmnd[5];
-      }
-
-      /* Calculate Scatter-Gather info */
-      mbox->numsgelements = mega_build_sglist (megaCfg, pScb,
-					  (u32 *) & mbox->xferaddr,
-					  (u32 *) & 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 = mega_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 = 2; /*set adapter timeout value to 10 min. for tape drive*/
-     		        /* 0=6sec/1=60sec/2=10min/3=3hrs */
-    pthru->ars = 1;
-    pthru->reqsenselen = 14;
-    pthru->islogical = 0;
-    pthru->channel = (megaCfg->flag & BOARD_40LD) ? 0 : SCpnt->channel;
-    pthru->target = (megaCfg->flag & BOARD_40LD) ? /*BOARD_40LD*/
-                     (SCpnt->channel<<4)|SCpnt->target : SCpnt->target;
-    pthru->cdblen = SCpnt->cmd_len;
-    memcpy (pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len);
-
-    pthru->numsgelements = mega_build_sglist (megaCfg, pScb,
-					 (u32 *) & pthru->dataxferaddr,
-					 (u32 *) & pthru->dataxferlen);
-
-    /* Initialize mailbox */
-    mbox->cmd = MEGA_MBOXCMD_PASSTHRU;
-    mbox->xferaddr = virt_to_bus (pthru);
-
-    return pScb;
-  }
-  return NULL;
-}
+	if (islogical) {
+		lun = (SCpnt->target * 8) + lun;
+		if (lun > FC_MAX_LOGICAL_DRIVES) {
+			SCpnt->result = (DID_BAD_TARGET << 16);
+			callDone (SCpnt);
+			return NULL;
+		}
+	}
+	/*-----------------------------------------------------
+	 *
+	 *               Logical drive commands
+	 *
+	 *-----------------------------------------------------*/
+	if (islogical) {
+		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 = mega_allocateSCB (megaCfg, SCpnt)) == NULL) {
+				SCpnt->result = (DID_ERROR << 16);
+				callDone (SCpnt);
+				return NULL;
+			}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+			pthru = pScb->pthru;
+#else
+			pthru = &pScb->pthru;
+#endif
 
-/*--------------------------------------------------------------------
- * build RAID commands for controller, passed down through ioctl()
- *--------------------------------------------------------------------*/
-static mega_scb * mega_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt)
-{
-  mega_scb *pScb;
-  mega_ioctl_mbox *mbox;
-  mega_mailbox *mailbox;
-  mega_passthru *pthru;
-  u8 *mboxdata;
-  long seg;
-  unsigned char *data = (unsigned char *)SCpnt->request_buffer;
-  int i;
-
-  if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) {
-    SCpnt->result = (DID_ERROR << 16);
-    callDone (SCpnt);
-    return NULL;
-  }
-
-  mboxdata = (u8 *) & pScb->mboxData;
-  mbox = (mega_ioctl_mbox *) & pScb->mboxData;
-  mailbox = (mega_mailbox *) & pScb->mboxData;
-  memset (mailbox, 0, sizeof (pScb->mboxData));
-
-  if (data[0] == 0x03) {	/* passthrough command */
-    unsigned char cdblen = data[2];
-    pthru = &pScb->pthru;
-    memset (pthru, 0, sizeof (mega_passthru));
-    pthru->islogical = (data[cdblen+3] & 0x80) ? 1:0;
-    pthru->timeout = data[cdblen+3] & 0x07;
-    pthru->reqsenselen = 14;
-    pthru->ars = (data[cdblen+3] & 0x08) ? 1:0;
-    pthru->logdrv = data[cdblen+4];
-    pthru->channel = data[cdblen+5];
-    pthru->target = data[cdblen+6];
-    pthru->cdblen = cdblen;
-    memcpy (pthru->cdb, &data[3], cdblen);
-
-    mailbox->cmd = MEGA_MBOXCMD_PASSTHRU;
-    mailbox->xferaddr = virt_to_bus (pthru);
-
-    pthru->numsgelements = mega_build_sglist (megaCfg, pScb,
-					 (u32 *) & pthru->dataxferaddr,
-					 (u32 *) & pthru->dataxferlen);
-
-    for (i=0;i<(SCpnt->request_bufflen-cdblen-7);i++) {
-       data[i] = data[i+cdblen+7];
-    }
-
-    return pScb;
-  }
-  /* else normal (nonpassthru) command */
+			mbox = (mega_mailbox *) & pScb->mboxData;
+			memset (mbox, 0, sizeof (pScb->mboxData));
+			memset (pthru, 0, sizeof (mega_passthru));
+			pthru->timeout = 0;
+			pthru->ars = 1;
+			pthru->reqsenselen = 14;
+			pthru->islogical = 1;
+			pthru->logdrv = lun;
+			pthru->cdblen = SCpnt->cmd_len;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+			/*Not sure about the direction */
+			pScb->dma_direction = PCI_DMA_BIDIRECTIONAL;
+			pScb->dma_type = M_RD_PTHRU_WITH_BULK_DATA;
+
+#if 0
+/* Normal Code w/o the need for bounce buffer */
+			pScb->dma_h_bulkdata
+			    = pci_map_single (megaCfg->dev,
+					      SCpnt->request_buffer,
+					      SCpnt->request_bufflen,
+					      pScb->dma_direction);
 
-#if LINUX_VERSION_CODE > 0x020024
-/*
- * usage of the function copy from user is used in case of data more than
- * 4KB.  This is used only with adapters which supports more than 8 logical
- * drives.  This feature is disabled on kernels earlier or same as 2.0.36
- * as the uaccess.h file is not available with those kernels.
- */
+			pthru->dataxferaddr = pScb->dma_h_bulkdata;
+#else
+/* Special Code to use bounce buffer for READ_CAPA/INQ */
+			pthru->dataxferaddr = pScb->dma_bounce_buffer;
+			pScb->dma_type = M_RD_DMA_TYPE_NONE;
+#endif
 
-  if (SCpnt->cmnd[0] == IOCTL_CMD_NEW) { 
-            /* use external data area for large xfers  */
-     /* If cmnd[0] is set to IOCTL_CMD_NEW then *
-      *   cmnd[4..7] = external user buffer     *
-      *   cmnd[8..11] = length of buffer        *
-      *                                         */
-      char *kern_area;
-      char *user_area = *((char **)&SCpnt->cmnd[4]);
-      u32 xfer_size = *((u32 *)&SCpnt->cmnd[8]);
-      if (verify_area(VERIFY_READ, user_area, xfer_size)) {
-          printk("megaraid: Got bad user address.\n");
-          SCpnt->result = (DID_ERROR << 16);
-          callDone (SCpnt);
-          return NULL;
-      }
-      kern_area = kmalloc(xfer_size, GFP_ATOMIC | GFP_DMA);
-      if (kern_area == NULL) {
-          printk("megaraid: Couldn't allocate kernel mem.\n");
-	  SCpnt->result = (DID_ERROR << 16);
-	  callDone (SCpnt);
-	  return NULL;
-      }
-      copy_from_user(kern_area,user_area,xfer_size);
-      pScb->kern_area = kern_area;
-  }
-#endif
-
-  mbox->cmd = data[0];
-  mbox->channel = data[1];
-  mbox->param = data[2];
-  mbox->pad[0] = data[3];
-  mbox->logdrv = data[4];
-
-  if(SCpnt->cmnd[0] == IOCTL_CMD_NEW) {
-      if(data[0]==DCMD_FC_CMD){ /*i.e. 0xA1, then override some mbox data */
-          *(mboxdata+0) = data[0]; /*mailbox byte 0: DCMD_FC_CMD*/
-          *(mboxdata+2) = data[2]; /*sub command*/
-          *(mboxdata+3) = 0;       /*number of elements in SG list*/
-          mbox->xferaddr           /*i.e. mboxdata byte 0x8 to 0xb*/
-                        = virt_to_bus(pScb->kern_area);
-      }
-      else{
-         mbox->xferaddr = virt_to_bus(pScb->kern_area);
-         mbox->numsgelements = 0;
-      }
-  } 
-  else {
-
-      mbox->numsgelements = mega_build_sglist (megaCfg, pScb,
-				      (u32 *) & mbox->xferaddr,
-				      (u32 *) & seg);
-
-      for (i=0;i<(SCpnt->request_bufflen-6);i++) {
-          data[i] = data[i+6];
-      }
-  }
+#else
+			pthru->dataxferaddr =
+			    virt_to_bus (SCpnt->request_buffer);
+#endif
 
-  return (pScb);
-}
+			pthru->dataxferlen = SCpnt->request_bufflen;
+			memcpy (pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len);
 
-#if DEBUG
-static void showMbox(mega_scb *pScb)
-{
-  mega_mailbox *mbox;
+			/* Initialize mailbox area */
+			mbox->cmd = MEGA_MBOXCMD_PASSTHRU;
 
-  if (pScb == NULL) return;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+			mbox->xferaddr = pScb->dma_passthruhandle64;
+			TRACE1 (("M_RD_PTHRU_WITH_BULK_DATA Enabled \n"));
+#else
+			mbox->xferaddr = virt_to_bus (pthru);
+#endif
+			return pScb;
 
-  mbox = (mega_mailbox *)pScb->mboxData;
-  printk("%u cmd:%x id:%x #scts:%x lba:%x addr:%x logdrv:%x #sg:%x\n",
-	 pScb->SCpnt->pid, 
-	 mbox->cmd, mbox->cmdid, mbox->numsectors,
-	 mbox->lba, mbox->xferaddr, mbox->logdrv,
-	 mbox->numsgelements);
-}
+		case READ_6:
+		case WRITE_6:
+		case READ_10:
+		case WRITE_10:
+			/* Allocate a SCB and initialize mailbox */
+			if ((pScb = mega_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 = lun;
+
+			if (megaCfg->flag & BOARD_64BIT) {
+				mbox->cmd = (*SCpnt->cmnd == READ_6
+					     || *SCpnt->cmnd ==
+					     READ_10) ? MEGA_MBOXCMD_LREAD64 :
+				    MEGA_MBOXCMD_LWRITE64;
+			} else {
+				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 = (u32) SCpnt->cmnd[4];
+				mbox->lba =
+				    ((u32) SCpnt->cmnd[1] << 16) |
+				    ((u32) SCpnt->cmnd[2] << 8) |
+				    (u32) SCpnt->cmnd[3];
+				mbox->lba &= 0x1FFFFF;
+
+				if (*SCpnt->cmnd == READ_6) {
+					megaCfg->nReads[(int) lun]++;
+					megaCfg->nReadBlocks[(int) lun] +=
+					    mbox->numsectors;
+				} else {
+					megaCfg->nWrites[(int) lun]++;
+					megaCfg->nWriteBlocks[(int) lun] +=
+					    mbox->numsectors;
+				}
+			}
+
+			/* 10-byte */
+			if (*SCpnt->cmnd == READ_10 || *SCpnt->cmnd == WRITE_10) {
+				mbox->numsectors =
+				    (u32) SCpnt->cmnd[8] |
+				    ((u32) SCpnt->cmnd[7] << 8);
+				mbox->lba =
+				    ((u32) SCpnt->cmnd[2] << 24) |
+				    ((u32) SCpnt->cmnd[3] << 16) |
+				    ((u32) SCpnt->cmnd[4] << 8) |
+				    (u32) SCpnt->cmnd[5];
+
+				if (*SCpnt->cmnd == READ_10) {
+					megaCfg->nReads[(int) lun]++;
+					megaCfg->nReadBlocks[(int) lun] +=
+					    mbox->numsectors;
+				} else {
+					megaCfg->nWrites[(int) lun]++;
+					megaCfg->nWriteBlocks[(int) lun] +=
+					    mbox->numsectors;
+				}
+			}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+			if (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == READ_10) {
+				pScb->dma_direction = PCI_DMA_FROMDEVICE;
+			} else {	/*WRITE_6 or WRITE_10 */
+				pScb->dma_direction = PCI_DMA_TODEVICE;
+			}
 #endif
 
-#if DEBUG
-static unsigned int cum_time = 0;
-static unsigned int cum_time_cnt = 0;
+			/* Calculate Scatter-Gather info */
+			mbox->numsgelements = mega_build_sglist (megaCfg, pScb,
+								 (u32 *) &
+								 mbox->xferaddr,
+								 (u32 *) & seg);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+			pScb->iDataSize = seg;
+
+			if (mbox->numsgelements) {
+				pScb->dma_type = M_RD_SGLIST_ONLY;
+				TRACE1 (("M_RD_SGLIST_ONLY Enabled \n"));
+			} else {
+				pScb->dma_type = M_RD_BULK_DATA_ONLY;
+				TRACE1 (("M_RD_BULK_DATA_ONLY Enabled \n"));
+			}
 #endif
 
-/*--------------------------------------------------------------------
- * Interrupt service routine
- *--------------------------------------------------------------------*/
-static void megaraid_isr (int irq, void *devp, struct pt_regs *regs)
-{
-#if LINUX_VERSION_CODE >= 0x20100
-  IO_LOCK_T
+			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 = mega_allocateSCB (megaCfg, SCpnt)) == NULL) {
+			SCpnt->result = (DID_ERROR << 16);
+			callDone (SCpnt);
+			return NULL;
+		}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+		pthru = pScb->pthru;
+#else
+		pthru = &pScb->pthru;
 #endif
-  mega_host_config    *megaCfg;
-  u_char byte, idx, sIdx, tmpBox[MAILBOX_SIZE];
-  u32 dword=0;
-  mega_mailbox *mbox;
-  mega_scb *pScb;
-  u_char qCnt, qStatus;
-  u_char            completed[MAX_FIRMWARE_STATUS];
-  Scsi_Cmnd *SCpnt;
-
-  megaCfg = (mega_host_config *) devp;
-  mbox = (mega_mailbox *)tmpBox;
-
-  if (megaCfg->host->irq == irq) {
-    if (megaCfg->flag & IN_ISR) {
-      printk(KERN_ERR "ISR called reentrantly!!\n");
-    }
-
-    megaCfg->flag |= IN_ISR;
-
-    if (mega_busyWaitMbox(megaCfg)) {
-	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;
-	return;
-      }
-    }
-    else {
-      byte = READ_PORT (megaCfg->host->io_port, INTR_PORT);
-      if ((byte & VALID_INTR_BYTE) == 0) {
-	/* Spurious interrupt */
-	megaCfg->flag &= ~IN_ISR;
-	return;
-      }
-      WRITE_PORT (megaCfg->host->io_port, INTR_PORT, byte);
-    }
-
-    for(idx=0;idx<MAX_FIRMWARE_STATUS;idx++ ) completed[idx] = 0;
-
-    IO_LOCK;
-
-    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);
-    }
+		mbox = (mega_mailbox *) pScb->mboxData;
 
-#if DEBUG
-    if(qCnt >= MAX_FIRMWARE_STATUS) {
-      printk("megaraid_isr: cmplt=%d ", qCnt);
-    }
+		memset (mbox, 0, sizeof (pScb->mboxData));
+		memset (pthru, 0, sizeof (mega_passthru));
+
+		/* set adapter timeout value to 10 min. for tape drive	*/
+		/* 0=6sec/1=60sec/2=10min/3=3hrs 			*/
+		pthru->timeout = 2;
+		pthru->ars = 1;
+		pthru->reqsenselen = 14;
+		pthru->islogical = 0;
+		pthru->channel =
+		    (megaCfg->flag & BOARD_40LD) ? 0 : SCpnt->channel;
+		pthru->target = (megaCfg->flag & BOARD_40LD) ?	/*BOARD_40LD */
+		    (SCpnt->channel << 4) | SCpnt->target : SCpnt->target;
+		pthru->cdblen = SCpnt->cmd_len;
+
+		memcpy (pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+		/* Not sure about the direction */
+		pScb->dma_direction = PCI_DMA_BIDIRECTIONAL;
+
+		/* Special Code for Handling READ_CAPA/ INQ using bounce buffers */
+		switch (SCpnt->cmnd[0]) {
+		case INQUIRY:
+		case READ_CAPACITY:
+			pthru->numsgelements = 0;
+			pthru->dataxferaddr = pScb->dma_bounce_buffer;
+			pthru->dataxferlen = SCpnt->request_bufflen;
+			break;
+		default:
+			pthru->numsgelements = mega_build_sglist (megaCfg, pScb,
+								  (u32 *) &
+								  pthru->
+								  dataxferaddr,
+								  (u32 *) &
+								  pthru->
+								  dataxferlen);
+			break;
+		}
+#else
+		pthru->numsgelements = mega_build_sglist (megaCfg, pScb,
+							  (u32 *) & pthru->
+							  dataxferaddr,
+							  (u32 *) & pthru->
+							  dataxferlen);
 #endif
 
-    for (idx = 0; idx < qCnt; idx++) {
-      sIdx = completed[idx];
-      if ((sIdx > 0) && (sIdx <= MAX_COMMANDS)) {
-	pScb = &megaCfg->scbList[sIdx - 1];
+		/* Initialize mailbox */
+		mbox->cmd = MEGA_MBOXCMD_PASSTHRU;
 
-	/* ASSERT(pScb->state == SCB_ISSUED); */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+		mbox->xferaddr = pScb->dma_passthruhandle64;
 
-#if DEBUG
-	if (((jiffies) - pScb->isrcount) > maxCmdTime) {
-	  maxCmdTime = (jiffies) - pScb->isrcount;
-	  printk("megaraid_isr : cmd time = %u\n", maxCmdTime);
-	}
+		if (pthru->numsgelements) {
+			pScb->dma_type = M_RD_PTHRU_WITH_SGLIST;
+			TRACE1 (("M_RD_PTHRU_WITH_SGLIST Enabled \n"));
+		} else {
+			pScb->dma_type = M_RD_PTHRU_WITH_BULK_DATA
+			    TRACE1 (("M_RD_PTHRU_WITH_BULK_DATA Enabled \n"));
+		}
+#else
+		mbox->xferaddr = virt_to_bus (pthru);
 #endif
-/*
- * Assuming that the scsi command, for which an abort request was received
- * earlier has completed.
- */
-	if (pScb->state == SCB_ABORTED) {
-          SCpnt = pScb->SCpnt;
+
+		return pScb;
+	}
+	return NULL;
+}
+
+/* Handle Driver Level IOCTLs
+ * Return value of 0 indicates this function could not handle , so continue
+ * processing
+*/
+
+static int mega_driver_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt)
+{
+	unsigned char *data = (unsigned char *) SCpnt->request_buffer;
+	mega_driver_info driver_info;
+
+	/* If this is not our command dont do anything */
+	if (SCpnt->cmnd[0] != M_RD_DRIVER_IOCTL_INTERFACE)
+		return 0;
+
+	switch (SCpnt->cmnd[1]) {
+	case GET_DRIVER_INFO:
+		if (SCpnt->request_bufflen < sizeof (driver_info)) {
+			SCpnt->result = DID_BAD_TARGET << 16;
+			callDone (SCpnt);
+			return 1;
+		}
+
+		driver_info.size = sizeof (driver_info) - sizeof (int);
+		driver_info.version = MEGARAID_IOCTL_VERSION;
+		memcpy (data, &driver_info, sizeof (driver_info));
+		break;
+	default:
+		SCpnt->result = DID_BAD_TARGET << 16;
+	}
+
+	callDone (SCpnt);
+	return 1;
+}
+
+static void inline set_mbox_xfer_addr (mega_host_config * megaCfg, mega_scb * pScb,
+		    mega_ioctl_mbox * mbox, u32 direction)
+{
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	switch (direction) {
+	case TO_DEVICE:
+		pScb->dma_direction = PCI_DMA_TODEVICE;
+		break;
+	case FROM_DEVICE:
+		pScb->dma_direction = PCI_DMA_FROMDEVICE;
+		break;
+	case FROMTO_DEVICE:
+		pScb->dma_direction = PCI_DMA_BIDIRECTIONAL;
+		break;
 	}
-	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) 
-        {    /* external user buffer */
-           up(&pScb->sem);
-        }
-	/* Mark command as completed */
-	mega_cmd_done(megaCfg, pScb, qStatus);
-
-      }
-      else {
-        printk(KERN_ERR "megaraid: wrong cmd id completed from firmware:id=%x\n",sIdx);
-      }
-    }
-
-    mega_rundoneq(megaCfg);
-
-    megaCfg->flag &= ~IN_ISR;
-
-    /* Loop through any pending requests */
-    mega_runpendq(megaCfg);
-#if LINUX_VERSION_CODE >= 0x20100
-    IO_UNLOCK;
+
+	pScb->dma_h_bulkdata
+	    = pci_map_single (megaCfg->dev,
+			      pScb->buff_ptr,
+			      pScb->iDataSize, pScb->dma_direction);
+	mbox->xferaddr = pScb->dma_h_bulkdata;
+	pScb->dma_type = M_RD_BULK_DATA_ONLY;
+	TRACE1 (("M_RD_BULK_DATA_ONLY Enabled \n"));
+#else
+	mbox->xferaddr = virt_to_bus (pScb->buff_ptr);
+#endif
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
+
+/*--------------------------------------------------------------------
+ * build RAID commands for controller, passed down through ioctl()
+ *--------------------------------------------------------------------*/
+static mega_scb *mega_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt)
+{
+	mega_scb *pScb;
+	mega_ioctl_mbox *mbox;
+	mega_mailbox *mailbox;
+	mega_passthru *pthru;
+	u8 *mboxdata;
+	long seg, i = 0;
+	unsigned char *data = (unsigned char *) SCpnt->request_buffer;
+
+	if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) {
+		SCpnt->result = (DID_ERROR << 16);
+		callDone (SCpnt);
+		return NULL;
+	}
+	pthru = &pScb->pthru;
+
+	mboxdata = (u8 *) & pScb->mboxData;
+	mbox = (mega_ioctl_mbox *) & pScb->mboxData;
+	mailbox = (mega_mailbox *) & pScb->mboxData;
+	memset (mailbox, 0, sizeof (pScb->mboxData));
+
+	if (data[0] == 0x03) {	/* passthrough command */
+		unsigned char cdblen = data[2];
+		memset (pthru, 0, sizeof (mega_passthru));
+		pthru->islogical = (data[cdblen + 3] & 0x80) ? 1 : 0;
+		pthru->timeout = data[cdblen + 3] & 0x07;
+		pthru->reqsenselen = 14;
+		pthru->ars = (data[cdblen + 3] & 0x08) ? 1 : 0;
+		pthru->logdrv = data[cdblen + 4];
+		pthru->channel = data[cdblen + 5];
+		pthru->target = data[cdblen + 6];
+		pthru->cdblen = cdblen;
+		memcpy (pthru->cdb, &data[3], cdblen);
+
+		mailbox->cmd = MEGA_MBOXCMD_PASSTHRU;
+
+
+		pthru->numsgelements = mega_build_sglist (megaCfg, pScb,
+							  (u32 *) & pthru->
+							  dataxferaddr,
+							  (u32 *) & pthru->
+							  dataxferlen);
+
+		mailbox->xferaddr = virt_to_bus (pthru);
+
+		for (i = 0; i < (SCpnt->request_bufflen - cdblen - 7); i++) {
+			data[i] = data[i + cdblen + 7];
+		}
+		return pScb;
+	}
+	/* else normal (nonpassthru) command */
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,0,24)	/*0x020024 */
+	/*
+	 *usage of the function copy from user is used in case of data more than
+	 *4KB.This is used only with adapters which supports more than 8 logical
+	 * drives.This feature is disabled on kernels earlier or same as 2.0.36
+	 * as the uaccess.h file is not available with those kernels.
+	 */
+
+	if (SCpnt->cmnd[0] == M_RD_IOCTL_CMD_NEW) {
+		/* use external data area for large xfers  */
+		/* If cmnd[0] is set to M_RD_IOCTL_CMD_NEW then *
+		 *   cmnd[4..7] = external user buffer     *
+		 *   cmnd[8..11] = length of buffer        *
+		 *                                         */
+		char *user_area = *((char **) &SCpnt->cmnd[4]);
+		u32 xfer_size = *((u32 *) & SCpnt->cmnd[8]);
+		switch (data[0]) {
+		case FW_FIRE_WRITE:
+		case FW_FIRE_FLASH:
+			if ((ulong) user_area & (PAGE_SIZE - 1)) {
+				printk
+				    ("megaraid:user address not aligned on 4K boundary.Error.\n");
+				SCpnt->result = (DID_ERROR << 16);
+				callDone (SCpnt);
+				return NULL;
+			}
+			break;
+		default:
+			break;
+		}
+
+		if (!(pScb->buff_ptr = kmalloc (xfer_size, GFP_KERNEL))) {
+			printk
+			    ("megaraid: Insufficient mem for M_RD_IOCTL_CMD_NEW.\n");
+			SCpnt->result = (DID_ERROR << 16);
+			callDone (SCpnt);
+			return NULL;
+		}
+
+		copy_from_user (pScb->buff_ptr, user_area, xfer_size);
+		pScb->iDataSize = xfer_size;
+
+		switch (data[0]) {
+		case DCMD_FC_CMD:
+			switch (data[1]) {
+			case DCMD_FC_READ_NVRAM_CONFIG:
+			case DCMD_GET_DISK_CONFIG:
+				{
+					if ((ulong) pScb->
+					    buff_ptr & (PAGE_SIZE - 1)) {
+						printk
+						    ("megaraid:user address not sufficient Error.\n");
+						SCpnt->result =
+						    (DID_ERROR << 16);
+						callDone (SCpnt);
+						return NULL;
+					}
+
+					/*building SG list */
+					mega_build_kernel_sg (pScb->buff_ptr,
+							      xfer_size,
+							      pScb, mbox);
+					break;
+				}
+			default:
+				break;
+			}	/*switch (data[1]) */
+			break;
+		}
+
+	}
+#endif
+
+	mbox->cmd = data[0];
+	mbox->channel = data[1];
+	mbox->param = data[2];
+	mbox->pad[0] = data[3];
+	mbox->logdrv = data[4];
+
+	if (SCpnt->cmnd[0] == M_RD_IOCTL_CMD_NEW) {
+		switch (data[0]) {
+		case FW_FIRE_WRITE:
+			mbox->cmd = FW_FIRE_WRITE;
+			mbox->channel = data[1];	/* Current Block Number */
+			set_mbox_xfer_addr (megaCfg, pScb, mbox, TO_DEVICE);
+			mbox->numsgelements = 0;
+			break;
+		case FW_FIRE_FLASH:
+			mbox->cmd = FW_FIRE_FLASH;
+			mbox->channel = data[1] | 0x80;	/* Origin */
+			set_mbox_xfer_addr (megaCfg, pScb, mbox, TO_DEVICE);
+			mbox->numsgelements = 0;
+			break;
+		case DCMD_FC_CMD:
+			*(mboxdata + 0) = data[0];	/*mailbox byte 0: DCMD_FC_CMD */
+			*(mboxdata + 2) = data[1];	/*sub command */
+			switch (data[1]) {
+			case DCMD_FC_READ_NVRAM_CONFIG:
+			case DCMD_FC_READ_NVRAM_CONFIG_64:
+				/* number of elements in SG list */
+				*(mboxdata + 3) = mbox->numsgelements;
+				if (megaCfg->flag & BOARD_64BIT)
+					*(mboxdata + 2) =
+					    DCMD_FC_READ_NVRAM_CONFIG_64;
+				break;
+			case DCMD_WRITE_CONFIG:
+			case DCMD_WRITE_CONFIG_64:
+				if (megaCfg->flag & BOARD_64BIT)
+					*(mboxdata + 2) = DCMD_WRITE_CONFIG_64;
+				set_mbox_xfer_addr (megaCfg, pScb, mbox,
+						    TO_DEVICE);
+				mbox->numsgelements = 0;
+				break;
+			case DCMD_GET_DISK_CONFIG:
+			case DCMD_GET_DISK_CONFIG_64:
+				if (megaCfg->flag & BOARD_64BIT)
+					*(mboxdata + 2) =
+					    DCMD_GET_DISK_CONFIG_64;
+				*(mboxdata + 3) = data[2];	/*number of elements in SG list */
+				/*nr of elements in SG list */
+				*(mboxdata + 4) = mbox->numsgelements;
+				break;
+			case DCMD_DELETE_LOGDRV:
+			case DCMD_DELETE_DRIVEGROUP:
+			case NC_SUBOP_ENQUIRY3:
+				*(mboxdata + 3) = data[2];
+				set_mbox_xfer_addr (megaCfg, pScb, mbox,
+						    FROMTO_DEVICE);
+				mbox->numsgelements = 0;
+				break;
+			case DCMD_CHANGE_LDNO:
+			case DCMD_CHANGE_LOOPID:
+				*(mboxdata + 3) = data[2];
+				*(mboxdata + 4) = data[3];
+				set_mbox_xfer_addr (megaCfg, pScb, mbox,
+						    TO_DEVICE);
+				mbox->numsgelements = 0;
+				break;
+			default:
+				set_mbox_xfer_addr (megaCfg, pScb, mbox,
+						    FROMTO_DEVICE);
+				mbox->numsgelements = 0;
+				break;
+			}	/*switch */
+			break;
+		default:
+			set_mbox_xfer_addr (megaCfg, pScb, mbox, FROMTO_DEVICE);
+			mbox->numsgelements = 0;
+			break;
+		}
+	} else {
+
+		mbox->numsgelements = mega_build_sglist (megaCfg, pScb,
+							 (u32 *) & mbox->
+							 xferaddr,
+							 (u32 *) & seg);
+
+		/* Handling some of the fw special commands */
+		switch (data[0]) {
+		case 6:	/* START_DEV */
+			mbox->xferaddr = *((u32 *) & data[i + 6]);
+			break;
+		default:
+			break;
+		}
+
+		for (i = 0; i < (SCpnt->request_bufflen - 6); i++) {
+			data[i] = data[i + 6];
+		}
+	}
+
+	return (pScb);
+}
+
+
+static void mega_build_kernel_sg (char *barea, ulong xfersize, mega_scb * pScb, mega_ioctl_mbox * mbox)
+{
+	ulong i, buffer_area, len, end, end_page, x, idx = 0;
+
+	buffer_area = (ulong) barea;
+	i = buffer_area;
+	end = buffer_area + xfersize;
+	end_page = (end) & ~(PAGE_SIZE - 1);
+
+	do {
+		len = PAGE_SIZE - (i % PAGE_SIZE);
+		x = pScb->sgList[idx].address =
+		    virt_to_bus ((volatile void *) i);
+		pScb->sgList[idx].length = len;
+		i += len;
+		idx++;
+	} while (i < end_page);
+
+	if ((end - i) < 0) {
+		printk ("megaraid:Error in user address\n");
+	}
+
+	if (end - i) {
+		pScb->sgList[idx].address = virt_to_bus ((volatile void *) i);
+		pScb->sgList[idx].length = end - i;
+		idx++;
+	}
+	mbox->xferaddr = virt_to_bus (pScb->sgList);
+	mbox->numsgelements = idx;
+}
+
+#endif				/* KERNEL_VERSION(2,3,0) */
+
+#if DEBUG
+static unsigned int cum_time = 0;
+static unsigned int cum_time_cnt = 0;
+
+static void showMbox (mega_scb * pScb)
+{
+	mega_mailbox *mbox;
+
+	if (pScb == NULL)
+		return;
+
+	mbox = (mega_mailbox *) pScb->mboxData;
+	printk ("%u cmd:%x id:%x #scts:%x lba:%x addr:%x logdrv:%x #sg:%x\n",
+		pScb->SCpnt->pid,
+		mbox->cmd, mbox->cmdid, mbox->numsectors,
+		mbox->lba, mbox->xferaddr, mbox->logdrv, mbox->numsgelements);
+}
+
+#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 = 0;
+	mega_mailbox *mbox;
+	mega_scb *pScb;
+	u_char qCnt, qStatus;
+	u_char completed[MAX_FIRMWARE_STATUS];
+	Scsi_Cmnd *SCpnt;
+
+	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");
+		}
+
+		/* Check if a valid interrupt is pending */
+		if (megaCfg->flag & BOARD_QUARTZ) {
+			dword = RDOUTDOOR (megaCfg);
+			if (dword != 0x10001234) {
+				/* Spurious interrupt */
+				megaCfg->flag &= ~IN_ISR;
+				return;
+			}
+		} else {
+			byte = READ_PORT (megaCfg->host->io_port, INTR_PORT);
+			if ((byte & VALID_INTR_BYTE) == 0) {
+				/* Spurious interrupt */
+				megaCfg->flag &= ~IN_ISR;
+				return;
+			}
+			WRITE_PORT (megaCfg->host->io_port, INTR_PORT, byte);
+		}
+
+		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) ;
+
+		/* 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 */
+#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)) {
+				pScb = &megaCfg->scbList[sIdx - 1];
+
+				/* ASSERT(pScb->state == SCB_ISSUED); */
+
+#if DEBUG
+				if (((jiffies) - pScb->isrcount) > maxCmdTime) {
+					maxCmdTime = (jiffies) - pScb->isrcount;
+					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) {
+					SCpnt = pScb->SCpnt;
+				}
+				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;
+				}
+
+				/* We don't want the ISR routine to touch M_RD_IOCTL_CMD_NEW commands, so
+				 * don't mark them as complete, instead we pop their semaphore so
+				 * that the queue routine can finish them off
+				 */
+				if (pScb->SCpnt->cmnd[0] == M_RD_IOCTL_CMD_NEW) {
+					/* save the status byte for the queue routine to use */
+					pScb->SCpnt->result = qStatus;
+					up (&pScb->ioctl_sem);
+				} else {
+					/* Mark command as completed */
+					mega_cmd_done (megaCfg, pScb, qStatus);
+				}
+			} else {
+				printk
+				    ("megaraid: wrong cmd id completed from firmware:id=%x\n",
+				     sIdx);
+			}
+		}
+
+		mega_rundoneq (megaCfg);
+
+		megaCfg->flag &= ~IN_ISR;
+		/* Loop through any pending requests */
+		mega_runpendq (megaCfg);
+		IO_UNLOCK;
+
+	}
+
 }
 
 /*==================================================*/
 /* Wait until the controller's mailbox is available */
 /*==================================================*/
+
 static int mega_busyWaitMbox (mega_host_config * megaCfg)
 {
-  mega_mailbox *mbox = (mega_mailbox *) megaCfg->mbox;
-  long counter;
+	mega_mailbox *mbox = (mega_mailbox *) megaCfg->mbox;
+	long counter;
 
-  for (counter = 0; counter < 10000; counter++) {
-    if (!mbox->busy) {
-      return 0;
-    }
-    udelay (100);
-    barrier();
-  }
-  return -1;			/* give up after 1 second */
+	for (counter = 0; counter < 10000; counter++) {
+		if (!mbox->busy) {
+			return 0;
+		}
+		udelay (100);
+		barrier ();
+	}
+	return -1;		/* give up after 1 second */
 }
 
 /*=====================================================
@@ -1113,153 +1824,278 @@
  *   -1: the command was not actually issued out
  *   othercases:
  *     intr==0, return ScsiStatus, i.e. mbox->status
- *     intr==1, return 0 
+ *     intr==1, return 0
  *=====================================================
  */
-static int megaIssueCmd (mega_host_config * megaCfg,
-	      u_char * mboxData,
-	      mega_scb * pScb,
-	      int intr)
-{
-  mega_mailbox *mbox = (mega_mailbox *) megaCfg->mbox;
-  u_char byte;
-  u32 cmdDone;
-  u32 phys_mbox;
-  u8 retval=-1;
+static int megaIssueCmd (mega_host_config * megaCfg, u_char * mboxData, 
+		mega_scb * pScb, int intr)
+{
+	volatile mega_mailbox *mbox = (mega_mailbox *) megaCfg->mbox;
 
-  mboxData[0x1] = (pScb ? pScb->idx + 1: 0x0);   /* Set cmdid */
-  mboxData[0xF] = 1;		/* Set busy */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	volatile mega_mailbox64 *mbox64 = (mega_mailbox64 *) megaCfg->mbox64;
+#endif
+
+	u_char byte;
 
-  phys_mbox = virt_to_bus (megaCfg->mbox);
+#ifdef __LP64__
+	u64 phys_mbox;
+#else
+	u32 phys_mbox;
+#endif
+	u8 retval = -1;
+
+	mboxData[0x1] = (pScb ? pScb->idx + 1 : 0xFE);	/* Set cmdid */
+	mboxData[0xF] = 1;	/* Set busy */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	/* In this case mbox contains physical address */
+	phys_mbox = megaCfg->adjdmahandle64;
+#else
+	phys_mbox = virt_to_bus (megaCfg->mbox);
+#endif
 
 #if DEBUG
-  showMbox(pScb);
+	ShowMbox (pScb);
 #endif
 
-  /* Wait until mailbox is free */
-  if (mega_busyWaitMbox (megaCfg)) {
-    printk("Blocked mailbox......!!\n");
-    udelay(1000);
+	/* Wait until mailbox is free */
+	if (mega_busyWaitMbox (megaCfg)) {
+		printk ("Blocked mailbox......!!\n");
+		udelay (1000);
 
 #if DEBUG
-    showMbox(pLastScb);
+		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;
+	}
+
+	pLastScb = pScb;
+
+	/* Copy mailbox data into host structure */
+	megaCfg->mbox64->xferSegment_lo = 0;
+	megaCfg->mbox64->xferSegment_hi = 0;
+
+	memcpy ((char *) mbox, mboxData, 16);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	switch (mboxData[0]) {
+	case MEGA_MBOXCMD_LREAD64:
+	case MEGA_MBOXCMD_LWRITE64:
+		mbox64->xferSegment_lo = mbox->xferaddr;
+		mbox64->xferSegment_hi = 0;
+		mbox->xferaddr = 0xFFFFFFFF;
+		break;
+	}
 #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;
-  }
-
-  pLastScb = pScb;
-
-  /* Copy mailbox data into host structure */
-  megaCfg->mbox64->xferSegment = 0;
-  memcpy (mbox, mboxData, 16);
-
-  /* Kick IO */
-  if (intr) {
-
-    /* Issue interrupt (non-blocking) command */
-    if (megaCfg->flag & BOARD_QUARTZ) {
-       mbox->mraid_poll = 0;
-      mbox->mraid_ack = 0;
-      WRINDOOR (megaCfg, phys_mbox | 0x1);
-    }
-    else {
-      ENABLE_INTR (megaCfg->host->io_port);
-      ISSUE_COMMAND (megaCfg->host->io_port);
-    }
-    pScb->state = SCB_ISSUED;
-
-    retval=0;
-  }
-  else {			/* Issue non-ISR (blocking) command */
-    disable_irq(megaCfg->host->irq);
-    if (megaCfg->flag & BOARD_QUARTZ) {
-      mbox->mraid_poll = 0;
-      mbox->mraid_ack = 0;
-      WRINDOOR (megaCfg, phys_mbox | 0x1);
-
-      while ((cmdDone = RDOUTDOOR (megaCfg)) != 0x10001234);
-      WROUTDOOR (megaCfg, cmdDone);
-
-      if (pScb) {
-	mega_cmd_done (megaCfg, pScb, mbox->status);
-      }
-
-      WRINDOOR (megaCfg, phys_mbox | 0x2);
-      while (RDINDOOR (megaCfg) & 0x2);
-
-    }
-    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 (megaCfg, pScb, mbox->status);
-      }
-      else {
-	TRACE (("Error: NULL pScb!\n"));
-      }
-    }
-    enable_irq(megaCfg->host->irq);
-    retval=mbox->status;
-  }
+
+	/* Kick IO */
+	if (intr) {
+		/* Issue interrupt (non-blocking) command */
+		if (megaCfg->flag & BOARD_QUARTZ) {
+			mbox->mraid_poll = 0;
+			mbox->mraid_ack = 0;
+
+			WRINDOOR (megaCfg, phys_mbox | 0x1);
+		} else {
+			ENABLE_INTR (megaCfg->host->io_port);
+			ISSUE_COMMAND (megaCfg->host->io_port);
+		}
+		pScb->state = SCB_ISSUED;
+
+		retval = 0;
+	} else {		/* Issue non-ISR (blocking) command */
+		disable_irq (megaCfg->host->irq);
+		if (megaCfg->flag & BOARD_QUARTZ) {
+			mbox->mraid_poll = 0;
+			mbox->mraid_ack = 0;
+			mbox->numstatus = 0xFF;
+			mbox->status = 0xFF;
+			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); */
+
+			if (pScb) {
+				mega_cmd_done (megaCfg, pScb, mbox->status);
+			}
+
+			WRINDOOR (megaCfg, phys_mbox | 0x2);
+			while (RDINDOOR (megaCfg) & 0x2) ;
+
+		} 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 (megaCfg, pScb, mbox->status);
+			} 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);
-  }
+	while (mega_busyWaitMbox (megaCfg)) {
+		printk(KERN_ERR "Blocked mailbox on exit......!\n");
+		udelay (1000);
+	}
 #endif
 
-  return retval;
+	return retval;
 }
 
 /*-------------------------------------------------------------------
  * Copies data to SGLIST
  *-------------------------------------------------------------------*/
-static int mega_build_sglist (mega_host_config * megaCfg, mega_scb * scb,
-	      u32 * buffer, u32 * length)
+/* Note:
+	For 64 bit cards, we need a minimum of one SG element for read/write
+*/
+
+static int
+mega_build_sglist (mega_host_config * megaCfg, mega_scb * scb,
+		   u32 * buffer, u32 * length)
 {
-  struct scatterlist *sgList;
-  int idx;
+	struct scatterlist *sgList;
+	int idx;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	int sgcnt;
+#endif
+
+	mega_mailbox *mbox = NULL;
+
+	mbox = (mega_mailbox *) scb->mboxData;
+	/* Scatter-gather not used */
+	if (scb->SCpnt->use_sg == 0) {
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+		scb->dma_h_bulkdata = pci_map_single (megaCfg->dev,
+				      scb->SCpnt->request_buffer,
+				      scb->SCpnt->request_bufflen,
+				      scb->dma_direction);
+		/* We need to handle special commands like READ64, WRITE64
+		   as they need a minimum of 1 SG irrespective of actaully SG
+		 */
+		if ((megaCfg->flag & BOARD_64BIT) &&
+		    ((mbox->cmd == MEGA_MBOXCMD_LREAD64) ||
+		     (mbox->cmd == MEGA_MBOXCMD_LWRITE64))) {
+			scb->sg64List[0].address = scb->dma_h_bulkdata;
+			scb->sg64List[0].length = scb->SCpnt->request_bufflen;
+			*buffer = scb->dma_sghandle64;
+			*length = 0;
+			scb->sglist_count = 1;
+			return 1;
+		} else {
+			*buffer = scb->dma_h_bulkdata;
+			*length = (u32) scb->SCpnt->request_bufflen;
+		}
+#else
+		*buffer = virt_to_bus (scb->SCpnt->request_buffer);
+		*length = (u32) scb->SCpnt->request_bufflen;
+#endif
+		return 0;
+	}
+
+	sgList = (struct scatterlist *) scb->SCpnt->request_buffer;
 
-  /* Scatter-gather not used */
-  if (scb->SCpnt->use_sg == 0) {
-    *buffer = virt_to_bus (scb->SCpnt->request_buffer);
-    *length = (u32) scb->SCpnt->request_bufflen;
-    return 0;
-  }
-
-  sgList = (struct scatterlist *) scb->SCpnt->request_buffer;
-  if (scb->SCpnt->use_sg == 1) {
-    *buffer = virt_to_bus (sgList[0].address);
-    *length = (u32) 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 = virt_to_bus (sgList[idx].address);
-    scb->sgList[idx].length = (u32) sgList[idx].length;
-  }
-
-  /* Reset pointer and length fields */
-  *buffer = virt_to_bus (scb->sgList);
-  *length = 0;
+	if (scb->SCpnt->use_sg == 1) {
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+		scb->dma_h_bulkdata = pci_map_single (megaCfg->dev,
+				      sgList[0].address,
+				      sgList[0].length, scb->dma_direction);
+
+		if ((megaCfg->flag & BOARD_64BIT) &&
+		    ((mbox->cmd == MEGA_MBOXCMD_LREAD64) ||
+		     (mbox->cmd == MEGA_MBOXCMD_LWRITE64))) {
+			scb->sg64List[0].address = scb->dma_h_bulkdata;
+			scb->sg64List[0].length = scb->SCpnt->request_bufflen;
+			*buffer = scb->dma_sghandle64;
+			*length = 0;
+			scb->sglist_count = 1;
+			return 1;
+		} else {
+			*buffer = scb->dma_h_bulkdata;
+			*length = (u32) sgList[0].length;
+		}
+#else
+		*buffer = virt_to_bus (sgList[0].address);
+		*length = (u32) sgList[0].length;
+#endif
 
-  /* Return count of SG requests */
-  return scb->SCpnt->use_sg;
+		return 0;
+	}
+
+	/* Copy Scatter-Gather list info into controller structure */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	sgcnt = pci_map_sg (megaCfg->dev,
+			    sgList, scb->SCpnt->use_sg, scb->dma_direction);
+
+	/* Determine the validity of the new count  */
+	if (sgcnt == 0)
+		printk ("pci_map_sg returned zero!!! ");
+
+	for (idx = 0; idx < sgcnt; idx++, sgList++) {
+
+		if ((megaCfg->flag & BOARD_64BIT) &&
+		    ((mbox->cmd == MEGA_MBOXCMD_LREAD64) ||
+		     (mbox->cmd == MEGA_MBOXCMD_LWRITE64))) {
+			scb->sg64List[idx].address = sg_dma_address (sgList);
+			scb->sg64List[idx].length = sg_dma_len (sgList);
+		} else {
+			scb->sgList[idx].address = sg_dma_address (sgList);
+			scb->sgList[idx].length = sg_dma_len (sgList);
+		}
+
+	}
+
+#else
+	for (idx = 0; idx < scb->SCpnt->use_sg; idx++) {
+		scb->sgList[idx].address = virt_to_bus (sgList[idx].address);
+		scb->sgList[idx].length = (u32) sgList[idx].length;
+	}
+#endif
+
+	/* Reset pointer and length fields */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	*buffer = scb->dma_sghandle64;
+	scb->sglist_count = scb->SCpnt->use_sg;
+#else
+	*buffer = virt_to_bus (scb->sgList);
+#endif
+	*length = 0;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	/* Return count of SG requests */
+	return sgcnt;
+#else
+	/* Return count of SG requests */
+	return scb->SCpnt->use_sg;
+#endif
 }
 
 /*--------------------------------------------------------------------
@@ -1278,169 +2114,243 @@
  *   10 01 numstatus byte
  *   11 01 status byte
  *--------------------------------------------------------------------*/
-static int mega_register_mailbox (mega_host_config * megaCfg, u32 paddr)
+static int
+mega_register_mailbox (mega_host_config * megaCfg, u32 paddr)
 {
-  /* align on 16-byte boundry */
-  megaCfg->mbox = &megaCfg->mailbox64.mailbox;
-  megaCfg->mbox = (mega_mailbox *) ((((u32) megaCfg->mbox) + 16) & 0xfffffff0);
-  megaCfg->mbox64 = (mega_mailbox64 *) (megaCfg->mbox - 4);
-  paddr = (paddr + 4 + 16) & 0xfffffff0;
-
-  /* Register mailbox area with the firmware */
-  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);
-    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;
-}
+	/* align on 16-byte boundry */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	megaCfg->mbox = &megaCfg->mailbox64ptr->mailbox;
+#else
+	megaCfg->mbox = &megaCfg->mailbox64.mailbox;
+#endif
+
+#ifdef __LP64__
+	megaCfg->mbox = (mega_mailbox *) ((((u64) megaCfg->mbox) + 16) & ((u64) (-1) ^ 0x0F));
+	megaCfg->adjdmahandle64 = (megaCfg->dma_handle64 + 16) & ((u64) (-1) ^ 0x0F);
+	megaCfg->mbox64 = (mega_mailbox64 *) ((u_char *) megaCfg->mbox - sizeof (u64));
+	paddr = (paddr + 4 + 16) & ((u64) (-1) ^ 0x0F);
+#else
+	megaCfg->mbox
+	    = (mega_mailbox *) ((((u32) megaCfg->mbox) + 16) & 0xFFFFFFF0);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	megaCfg->adjdmahandle64 = ((megaCfg->dma_handle64 + 16) & 0xFFFFFFF0);
+#endif
+
+	megaCfg->mbox64 = (mega_mailbox64 *) ((u_char *) megaCfg->mbox - 8);
+	paddr = (paddr + 4 + 16) & 0xFFFFFFF0;
+#endif
 
+	/* Register mailbox area with the firmware */
+	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);
+		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;
+}
 
 /*---------------------------------------------------------------------------
  * mega_Convert8ldTo40ld() -- takes all info in AdapterInquiry structure and
  * puts it into ProductInfo and Enquiry3 structures for later use
  *---------------------------------------------------------------------------*/
-static void mega_Convert8ldTo40ld(  mega_RAIDINQ  *inquiry,
-                                    mega_Enquiry3 *enquiry3,
-                                    megaRaidProductInfo *productInfo )
-{
-        int i;
-
-        productInfo->MaxConcCmds = inquiry->AdpInfo.MaxConcCmds;
-        enquiry3->rbldRate = inquiry->AdpInfo.RbldRate;
-        productInfo->SCSIChanPresent = inquiry->AdpInfo.ChanPresent;
-        for (i=0;i<4;i++) {
-                productInfo->FwVer[i] = inquiry->AdpInfo.FwVer[i];
-                productInfo->BiosVer[i] = inquiry->AdpInfo.BiosVer[i];
-        }
-        enquiry3->cacheFlushInterval = inquiry->AdpInfo.CacheFlushInterval;
-        productInfo->DramSize = inquiry->AdpInfo.DramSize;
-
-        enquiry3->numLDrv = inquiry->LogdrvInfo.NumLDrv;
-        for (i=0;i<MAX_LOGICAL_DRIVES;i++) {
-                enquiry3->lDrvSize[i] = inquiry->LogdrvInfo.LDrvSize[i];
-                enquiry3->lDrvProp[i] = inquiry->LogdrvInfo.LDrvProp[i];
-                enquiry3->lDrvState[i] = inquiry->LogdrvInfo.LDrvState[i];
-        }
-
-        for (i=0;i<(MAX_PHYSICAL_DRIVES);i++) {
-                enquiry3->pDrvState[i] = inquiry->PhysdrvInfo.PDrvState[i];
-        }
-}
+static void mega_Convert8ldTo40ld (mega_RAIDINQ * inquiry,
+		       mega_Enquiry3 * enquiry3,
+		       megaRaidProductInfo * productInfo)
+{
+	int i;
 
+	productInfo->MaxConcCmds = inquiry->AdpInfo.MaxConcCmds;
+	enquiry3->rbldRate = inquiry->AdpInfo.RbldRate;
+	productInfo->SCSIChanPresent = inquiry->AdpInfo.ChanPresent;
+
+	for (i = 0; i < 4; i++) {
+		productInfo->FwVer[i] = inquiry->AdpInfo.FwVer[i];
+		productInfo->BiosVer[i] = inquiry->AdpInfo.BiosVer[i];
+	}
+	enquiry3->cacheFlushInterval = inquiry->AdpInfo.CacheFlushInterval;
+	productInfo->DramSize = inquiry->AdpInfo.DramSize;
+
+	enquiry3->numLDrv = inquiry->LogdrvInfo.NumLDrv;
+
+	for (i = 0; i < MAX_LOGICAL_DRIVES; i++) {
+		enquiry3->lDrvSize[i] = inquiry->LogdrvInfo.LDrvSize[i];
+		enquiry3->lDrvProp[i] = inquiry->LogdrvInfo.LDrvProp[i];
+		enquiry3->lDrvState[i]
+		    = inquiry->LogdrvInfo.LDrvState[i];
+	}
+
+	for (i = 0; i < (MAX_PHYSICAL_DRIVES); i++) {
+		enquiry3->pDrvState[i]
+		    = inquiry->PhysdrvInfo.PDrvState[i];
+	}
+}
 
 /*-------------------------------------------------------------------
  * Issue an adapter info query to the controller
  *-------------------------------------------------------------------*/
 static int mega_i_query_adapter (mega_host_config * megaCfg)
 {
-  mega_Enquiry3 *enquiry3Pnt;
-  mega_mailbox *mbox;
-  u_char mboxData[16];
-  u32 paddr;
-  u8 retval;
-
-  /* Initialize adapter inquiry mailbox*/
-  paddr = virt_to_bus (megaCfg->mega_buffer);
-  mbox = (mega_mailbox *) mboxData;
+	mega_Enquiry3 *enquiry3Pnt;
+	mega_mailbox *mbox;
+	u_char mboxData[16];
 
-  memset ((void *) megaCfg->mega_buffer, 0, sizeof (megaCfg->mega_buffer));
-  memset (mbox, 0, 16);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	dma_addr_t raid_inq_dma_handle = 0, prod_info_dma_handle = 0, enquiry3_dma_handle = 0;
+#endif
+	u8 retval;
+
+	/* Initialize adapter inquiry mailbox */
+
+	mbox = (mega_mailbox *) mboxData;
+
+	memset ((void *) megaCfg->mega_buffer, 0,
+		sizeof (megaCfg->mega_buffer));
+	memset (mbox, 0, 16);
 
 /*
- * Try to issue Enquiry3 command 
- * if not suceeded, then issue MEGA_MBOXCMD_ADAPTERINQ command and 
+ * Try to issue Enquiry3 command
+ * if not suceeded, then issue MEGA_MBOXCMD_ADAPTERINQ command and
  * update enquiry3 structure
  */
-  mbox->xferaddr = virt_to_bus ( (void*) megaCfg->mega_buffer); 
-             /* Initialize mailbox databuffer addr */
-  enquiry3Pnt = (mega_Enquiry3 *) megaCfg->mega_buffer; 
-             /* point mega_Enguiry3 to the data buf */
-
-  mboxData[0]=FC_NEW_CONFIG ;          /* i.e. mbox->cmd=0xA1 */
-  mboxData[2]=NC_SUBOP_ENQUIRY3;       /* i.e. 0x0F */
-  mboxData[3]=ENQ3_GET_SOLICITED_FULL; /* i.e. 0x02 */
-
-  /* Issue a blocking command to the card */
-  if ( (retval=megaIssueCmd(megaCfg, mboxData, NULL, 0)) != 0 )
-  {  /* the adapter does not support 40ld*/
-
-     mega_RAIDINQ adapterInquiryData;
-     mega_RAIDINQ *adapterInquiryPnt = &adapterInquiryData;
-
-     mbox->xferaddr = virt_to_bus ( (void*) adapterInquiryPnt);
-
-     mbox->cmd = MEGA_MBOXCMD_ADAPTERINQ;  /*issue old 0x05 command to adapter*/
-     /* Issue a blocking command to the card */;
-     retval=megaIssueCmd (megaCfg, mboxData, NULL, 0);
-
-     /*update Enquiry3 and ProductInfo structures with mega_RAIDINQ structure*/
-     mega_Convert8ldTo40ld(  adapterInquiryPnt, 
-                             enquiry3Pnt, 
-                             (megaRaidProductInfo * ) &megaCfg->productInfo );
-
-  }
-  else{ /* adapter supports 40ld */
-    megaCfg->flag |= BOARD_40LD;
-
-    /*get productInfo, which is static information and will be unchanged*/
-    mbox->xferaddr = virt_to_bus ( (void*) &megaCfg->productInfo );
-
-    mboxData[0]=FC_NEW_CONFIG ;         /* i.e. mbox->cmd=0xA1 */
-    mboxData[2]=NC_SUBOP_PRODUCT_INFO;  /* i.e. 0x0E */
-   
-    if( (retval=megaIssueCmd(megaCfg, mboxData, NULL, 0)) != 0  ) 
-        printk("ami:Product_info (0x0E) cmd failed with error: %d\n", retval);
-
-  }
-
-  megaCfg->host->max_channel = megaCfg->productInfo.SCSIChanPresent;
-  megaCfg->host->max_id = 16;              /* max targets per channel */
-    /*(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;
-  }
-
-#ifdef HP			/* use HP firmware and bios version encoding */
-  sprintf (megaCfg->fwVer, "%c%d%d.%d%d",
-	   megaCfg->productInfo.FwVer[2],
-	   megaCfg->productInfo.FwVer[1] >> 8,
-	   megaCfg->productInfo.FwVer[1] & 0x0f,
-	   megaCfg->productInfo.FwVer[2] >> 8,
-	   megaCfg->productInfo.FwVer[2] & 0x0f);
-  sprintf (megaCfg->biosVer, "%c%d%d.%d%d",
-	   megaCfg->productInfo.BiosVer[2],
-	   megaCfg->productInfo.BiosVer[1] >> 8,
-	   megaCfg->productInfo.BiosVer[1] & 0x0f,
-	   megaCfg->productInfo.BiosVer[2] >> 8,
-	   megaCfg->productInfo.BiosVer[2] & 0x0f);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	enquiry3_dma_handle = pci_map_single (megaCfg->dev,
+			      (void *) megaCfg->mega_buffer,
+			      (2 * 1024L), PCI_DMA_FROMDEVICE);
+
+	mbox->xferaddr = enquiry3_dma_handle;
+#else
+	/*Taken care */
+	mbox->xferaddr = virt_to_bus ((void *) megaCfg->mega_buffer);
+#endif
+
+	/* Initialize mailbox databuffer addr */
+	enquiry3Pnt = (mega_Enquiry3 *) megaCfg->mega_buffer;
+	/* point mega_Enguiry3 to the data buf */
+
+	mboxData[0] = FC_NEW_CONFIG;	/* i.e. mbox->cmd=0xA1 */
+	mboxData[2] = NC_SUBOP_ENQUIRY3;	/* i.e. 0x0F */
+	mboxData[3] = ENQ3_GET_SOLICITED_FULL;	/* i.e. 0x02 */
+
+	/* Issue a blocking command to the card */
+	if ((retval = megaIssueCmd (megaCfg, mboxData, NULL, 0)) != 0) {	/* the adapter does not support 40ld */
+		mega_RAIDINQ adapterInquiryData;
+		mega_RAIDINQ *adapterInquiryPnt = &adapterInquiryData;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+		raid_inq_dma_handle = pci_map_single (megaCfg->dev,
+				      (void *) adapterInquiryPnt,
+				      sizeof (mega_RAIDINQ),
+				      PCI_DMA_FROMDEVICE);
+		mbox->xferaddr = raid_inq_dma_handle;
+#else
+		/*taken care */
+		mbox->xferaddr = virt_to_bus ((void *) adapterInquiryPnt);
+#endif
+
+		mbox->cmd = MEGA_MBOXCMD_ADAPTERINQ;	/*issue old 0x05 command to adapter */
+		/* Issue a blocking command to the card */ ;
+		retval = megaIssueCmd (megaCfg, mboxData, NULL, 0);
+
+		pci_unmap_single (megaCfg->dev,
+				  raid_inq_dma_handle,
+				  sizeof (mega_RAIDINQ), PCI_DMA_FROMDEVICE);
+
+		/*update Enquiry3 and ProductInfo structures with mega_RAIDINQ structure*/
+		mega_Convert8ldTo40ld (adapterInquiryPnt,
+				       enquiry3Pnt,
+				       (megaRaidProductInfo *) & megaCfg->
+				       productInfo);
+
+	} else {		/* adapter supports 40ld */
+		megaCfg->flag |= BOARD_40LD;
+
+		pci_unmap_single (megaCfg->dev,
+				  enquiry3_dma_handle,
+				  (2 * 1024L), PCI_DMA_FROMDEVICE);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+/*get productInfo, which is static information and will be unchanged*/
+		prod_info_dma_handle
+		    = pci_map_single (megaCfg->dev,
+				      (void *) &megaCfg->productInfo,
+				      sizeof (megaRaidProductInfo),
+				      PCI_DMA_FROMDEVICE);
+		mbox->xferaddr = prod_info_dma_handle;
+#else
+		/*taken care */
+		mbox->xferaddr = virt_to_bus ((void *) &megaCfg->productInfo);
+#endif
+
+		mboxData[0] = FC_NEW_CONFIG;	/* i.e. mbox->cmd=0xA1 */
+		mboxData[2] = NC_SUBOP_PRODUCT_INFO;	/* i.e. 0x0E */
+
+		if ((retval = megaIssueCmd (megaCfg, mboxData, NULL, 0)) != 0)
+			printk ("ami:Product_info cmd failed with error: %d\n",
+				retval);
+
+		pci_unmap_single (megaCfg->dev,
+				  prod_info_dma_handle,
+				  sizeof (megaRaidProductInfo),
+				  PCI_DMA_FROMDEVICE);
+	}
+
+	megaCfg->host->max_channel = megaCfg->productInfo.SCSIChanPresent;
+	megaCfg->host->max_id = 16;	/* max targets per channel */
+	/*(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 - 1;
+
+#if 0
+	if (megaCfg->host->can_queue >= MAX_COMMANDS) {
+		megaCfg->host->can_queue = MAX_COMMANDS - 16;
+	}
+#endif
+
+#ifdef MEGA_HP_FIX		/* use HP firmware and bios version encoding */
+	sprintf (megaCfg->fwVer, "%c%d%d.%d%d",
+		 megaCfg->productInfo.FwVer[2],
+		 megaCfg->productInfo.FwVer[1] >> 8,
+		 megaCfg->productInfo.FwVer[1] & 0x0f,
+		 megaCfg->productInfo.FwVer[2] >> 8,
+		 megaCfg->productInfo.FwVer[2] & 0x0f);
+	sprintf (megaCfg->biosVer, "%c%d%d.%d%d",
+		 megaCfg->productInfo.BiosVer[2],
+		 megaCfg->productInfo.BiosVer[1] >> 8,
+		 megaCfg->productInfo.BiosVer[1] & 0x0f,
+		 megaCfg->productInfo.BiosVer[2] >> 8,
+		 megaCfg->productInfo.BiosVer[2] & 0x0f);
 #else
-	memcpy (megaCfg->fwVer, (void *)megaCfg->productInfo.FwVer, 4);
+	memcpy (megaCfg->fwVer, (char *) megaCfg->productInfo.FwVer, 4);
 	megaCfg->fwVer[4] = 0;
 
-	memcpy (megaCfg->biosVer, (void *)megaCfg->productInfo.BiosVer, 4);
+	memcpy (megaCfg->biosVer, (char *) megaCfg->productInfo.BiosVer, 4);
 	megaCfg->biosVer[4] = 0;
 #endif
 
-	printk ("megaraid: [%s:%s] detected %d logical drives" CRLFSTR,
-        	megaCfg->fwVer,
-		megaCfg->biosVer,
-		megaCfg->numldrv);
+	printk (KERN_INFO "megaraid: [%s:%s] detected %d logical drives" M_RD_CRLFSTR,
+		megaCfg->fwVer, megaCfg->biosVer, megaCfg->numldrv);
+	/*
+	 * I hope that I can unmap here, reason DMA transaction is not required any more
+	 * after this
+	 */
 
 	return 0;
 }
@@ -1454,227 +2364,665 @@
 /*----------------------------------------------------------
  * Returns data to be displayed in /proc/scsi/megaraid/X
  *----------------------------------------------------------*/
-int megaraid_proc_info (char *buffer, char **start, off_t offset,
+
+static int megaraid_proc_info (char *buffer, char **start, off_t offset,
 		    int length, int host_no, int inout)
 {
-  *start = buffer;
-  return 0;
+	*start = buffer;
+	return 0;
 }
 
-int mega_findCard (Scsi_Host_Template * pHostTmpl,
-	  u16 pciVendor, u16 pciDev,
-	  long flag)
-{
-  mega_host_config *megaCfg;
-  struct Scsi_Host *host;
-  u_char megaIrq;
-  u32 megaBase;
-  u16 numFound = 0;
-
-  struct pci_dev *pdev = NULL;
-  
-  while ((pdev = pci_find_device (pciVendor, pciDev, pdev))) {
-    if (pci_enable_device(pdev))
-    	continue;
-    if ((flag & BOARD_QUARTZ) && (skip_id == -1)) {
-      u16 magic;
-      pci_read_config_word(pdev, PCI_CONF_AMISIG, &magic);
-      if ((magic != AMI_SIGNATURE) && (magic != AMI_SIGNATURE_471))
-	continue;		/* not an AMI board */
-    }
-    printk (KERN_INFO "megaraid: found 0x%4.04x:0x%4.04x: in %s\n",
-	    pciVendor,
-	    pciDev,
-	    pdev->slot_name);
-
-    /* Read the base port and IRQ from PCI */
-    megaBase = pci_resource_start (pdev, 0);
-    megaIrq  = pdev->irq;
-
-    if (flag & BOARD_QUARTZ)
-      megaBase = (long) ioremap (megaBase, 128);
-    else
-      megaBase += 0x10;
-
-    /* Initialize SCSI Host structure */
-    host = scsi_register (pHostTmpl, sizeof (mega_host_config));
-    if(host == NULL)
-    	continue;
-    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->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;
-    megaCfg->host->irq = megaIrq;
-    megaCfg->host->io_port = megaBase;
-    megaCfg->host->n_io_port = 16;
-    megaCfg->host->unique_id = (pdev->bus->number << 8) | pdev->devfn;
-    megaCtlrs[numCtlrs++] = megaCfg; 
-    if (flag != BOARD_QUARTZ) {
-      /* Request our IO Range */
-      if (request_region (megaBase, 16, "megaraid")) {
-	printk (KERN_WARNING "megaraid: Couldn't register I/O range!" CRLFSTR);
-	scsi_unregister (host);
-	continue;
-      }
-    }
-
-    /* Request our IRQ */
-    if (request_irq (megaIrq, megaraid_isr, 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->mailbox64));
-    mega_i_query_adapter (megaCfg);
-   
-    if (flag == BOARD_QUARTZ) {
-      /* Check to see if this is a Dell PERC RAID controller model 466 */
-      u16 subsysid, subsysvid;
-#if LINUX_VERSION_CODE < 0x20100
-      pcibios_read_config_word (pciBus, pciDevFun,
-				PCI_SUBSYSTEM_VENDOR_ID,
-				&subsysvid);
-      pcibios_read_config_word (pciBus, pciDevFun,
-				PCI_SUBSYSTEM_ID,
-				&subsysid);
-#else
-      pci_read_config_word (pdev, PCI_SUBSYSTEM_VENDOR_ID, &subsysvid);
-      pci_read_config_word (pdev, PCI_SUBSYSTEM_ID, &subsysid);
-#endif
-      if ( (subsysid == 0x1111) && (subsysvid == 0x1111) &&
-           (!strcmp(megaCfg->fwVer,"3.00") || !strcmp(megaCfg->fwVer,"3.01"))) {
-	printk(KERN_WARNING
-"megaraid: Your card is a Dell PERC 2/SC RAID controller with firmware\n"
-"megaraid: 3.00 or 3.01.  This driver is known to have corruption issues\n"
-"megaraid: with those firmware versions on this specific card.  In order\n"
-"megaraid: to protect your data, please upgrade your firmware to version\n"
-"megaraid: 3.10 or later, available from the Dell Technical Support web\n"
-"megaraid: site at\n"
-"http://support.dell.com/us/en/filelib/download/index.asp?fileid=2940\n");
-	megaraid_release (host);
-#ifdef MODULE	
-	continue;
-#else
-	while(1) schedule_timeout(1 * HZ);
-#endif	
-      }
-    }
-
-    /* Initialize SCBs */
-    if (mega_initSCB (megaCfg)) {
-      megaraid_release (host);
-      continue;
-    }
-
-    numFound++;
-  }
-  return numFound;
+static int mega_findCard (Scsi_Host_Template * pHostTmpl,
+	       u16 pciVendor, u16 pciDev, long flag)
+{
+	mega_host_config *megaCfg = NULL;
+	struct Scsi_Host *host = NULL;
+	u_char pciBus, pciDevFun, megaIrq;
+
+	u16 magic;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	u32 magic64;
+#endif
+
+	int i;
+
+#ifdef __LP64__
+	u64 megaBase;
+#else
+	u32 megaBase;
+#endif
+
+	u16 pciIdx = 0;
+	u16 numFound = 0;
+	u16 subsysid, subsysvid;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)	/* 0x20100 */
+	while (!pcibios_find_device
+	       (pciVendor, pciDev, pciIdx, &pciBus, &pciDevFun)) {
+#else
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0)	/*0x20300 */
+	struct pci_dev *pdev = NULL;
+#else
+	struct pci_dev *pdev = pci_devices;
+#endif
+
+	while ((pdev = pci_find_device (pciVendor, pciDev, pdev))) {
+		if (pci_enable_device (pdev))
+			continue;
+		pciBus = pdev->bus->number;
+		pciDevFun = pdev->devfn;
+#endif
+		if ((flag & BOARD_QUARTZ) && (skip_id == -1)) {
+			pcibios_read_config_word (pciBus, pciDevFun,
+						  PCI_CONF_AMISIG, &magic);
+			if ((magic != AMI_SIGNATURE)
+			    && (magic != AMI_SIGNATURE_471)) {
+				pciIdx++;
+				continue;	/* not an AMI board */
+			}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+			pcibios_read_config_dword (pciBus, pciDevFun,
+						   PCI_CONF_AMISIG64, &magic64);
+
+			if (magic64 == AMI_64BIT_SIGNATURE)
+				flag |= BOARD_64BIT;
+#endif
+		}
+
+		/* Hmmm...Should we not make this more modularized so that in future we dont add
+		   for each firmware */
+
+		if (flag & BOARD_QUARTZ) {
+			/* Check to see if this is a Dell PERC RAID controller model 466 */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)	/* 0x20100 */
+			pcibios_read_config_word (pciBus, pciDevFun,
+						  PCI_SUBSYSTEM_VENDOR_ID,
+						  &subsysvid);
+			pcibios_read_config_word (pciBus, pciDevFun,
+						  PCI_SUBSYSTEM_ID, &subsysid);
+#else
+			pci_read_config_word (pdev,
+					      PCI_SUBSYSTEM_VENDOR_ID,
+					      &subsysvid);
+			pci_read_config_word (pdev,
+					      PCI_SUBSYSTEM_ID, &subsysid);
+#endif
+			if ((subsysid == 0x1111) && (subsysvid == 0x1111) &&
+			    (!strcmp (megaCfg->fwVer, "3.00")
+			     || !strcmp (megaCfg->fwVer, "3.01"))) {
+				printk (KERN_WARNING
+					"megaraid: Your card is a Dell PERC 2/SC RAID controller with firmware\n"
+					"megaraid: 3.00 or 3.01.  This driver is known to have corruption issues\n"
+					"megaraid: with those firmware versions on this specific card.  In order\n"
+					"megaraid: to protect your data, please upgrade your firmware to version\n"
+					"megaraid: 3.10 or later, available from the Dell Technical Support web\n"
+					"megaraid: site at\n"
+					"http://support.dell.com/us/en/filelib/download/index.asp?fileid=2940\n");
+				continue;
+			}
+
+			/* If we dont detect this valid subsystem vendor id's 
+			   we refuse to load the driver 
+			   PART of PC200X compliance
+			 */
+
+			if ((subsysvid != AMI_SUBSYS_ID)
+			    && (subsysvid != DELL_SUBSYS_ID)
+			    && (subsysvid != HP_SUBSYS_ID))
+				continue;
+		}
+
+		printk (KERN_INFO
+			"megaraid: found 0x%4.04x:0x%4.04x:idx %d:bus %d:slot %d:func %d\n",
+			pciVendor, pciDev, pciIdx, pciBus, PCI_SLOT (pciDevFun),
+			PCI_FUNC (pciDevFun));
+		/* Read the base port and IRQ from PCI */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)	/* 0x20100 */
+		pcibios_read_config_dword (pciBus, pciDevFun,
+					   PCI_BASE_ADDRESS_0,
+					   (u_int *) & megaBase);
+		pcibios_read_config_byte (pciBus, pciDevFun,
+					  PCI_INTERRUPT_LINE, &megaIrq);
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)	/*0x20300 */
+		megaBase = pdev->base_address[0];
+		megaIrq = pdev->irq;
+#else
+
+		megaBase = pci_resource_start (pdev, 0);
+		megaIrq = pdev->irq;
+#endif
+
+		pciIdx++;
+
+		if (flag & BOARD_QUARTZ) {
+			megaBase = (long) ioremap (megaBase, 128);
+			if (!megaBase)
+				continue;
+		} else
+			megaBase += 0x10;
+
+		/* Initialize SCSI Host structure */
+		host = scsi_register (pHostTmpl, sizeof (mega_host_config));
+		if (!host)
+			goto err_unmap;
+
+		megaCfg = (mega_host_config *) host->hostdata;
+		memset (megaCfg, 0, sizeof (mega_host_config));
+
+		printk (KERN_INFO "scsi%d : Found a MegaRAID controller at 0x%x, IRQ: %d"
+			M_RD_CRLFSTR, host->host_no, (u_int) megaBase, megaIrq);
+
+		if (flag & BOARD_64BIT)
+			printk (KERN_INFO "scsi%d : Enabling 64 bit support\n",
+				host->host_no);
+
+		/* Copy resource info into structure */
+		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->lock_free = SPIN_LOCK_UNLOCKED;
+		megaCfg->lock_pend = SPIN_LOCK_UNLOCKED;
+		megaCfg->lock_scsicmd = SPIN_LOCK_UNLOCKED;
+		megaCfg->flag = flag;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+		megaCfg->dev = pdev;
+#endif
+		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 (!request_region(megaBase, 16, "megaraid")) {
+				printk (KERN_WARNING "megaraid: Couldn't register I/O range!" M_RD_CRLFSTR);
+				goto err_unregister;
+			}
+		}
+
+		/* Request our IRQ */
+		if (request_irq (megaIrq, megaraid_isr, SA_SHIRQ,
+				 "megaraid", megaCfg)) {
+			printk (KERN_WARNING
+				"megaraid: Couldn't register IRQ %d!\n",
+				megaIrq);
+			goto err_release;
+		}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+		/*
+		 * unmap while releasing the driver, Is it required to be 
+		 * PCI_DMA_BIDIRECTIONAL 
+		*/
+
+		megaCfg->mailbox64ptr
+		    = pci_alloc_consistent (megaCfg->dev,
+					    sizeof (mega_mailbox64),
+					    &(megaCfg->dma_handle64));
+
+		mega_register_mailbox (megaCfg,
+				       virt_to_bus ((void *) megaCfg->
+						    mailbox64ptr));
+#else
+		/*Taken care */
+		mega_register_mailbox (megaCfg,
+				       virt_to_bus ((void *) &megaCfg->
+						    mailbox64));
+#endif
+
+		mega_i_query_adapter (megaCfg);
+
+		if (mega_is_bios_enabled (megaCfg)) {
+			mega_hbas[numCtlrs].is_bios_enabled = 1;
+		}
+		mega_hbas[numCtlrs].hostdata_addr = megaCfg;
+
+		/* Initialize SCBs */
+		if (mega_init_scb (megaCfg)) {
+			pci_free_consistent (megaCfg->dev,
+					     sizeof (mega_mailbox64),
+					     (void *) megaCfg->mailbox64ptr,
+					     megaCfg->dma_handle64);
+			scsi_unregister (host);
+			continue;
+		}
+
+		/*
+		 * Fill in the structure which needs to be passed back to the
+		 * application when it does an ioctl() for controller related
+		 * information.
+		 */
+
+		i = numCtlrs;
+		numCtlrs++;
+
+		mcontroller[i].base = megaBase;
+		mcontroller[i].irq = megaIrq;
+		mcontroller[i].numldrv = megaCfg->numldrv;
+		mcontroller[i].pcibus = pciBus;
+		mcontroller[i].pcidev = pciDev;
+		mcontroller[i].pcifun = PCI_FUNC (pciDevFun);
+		mcontroller[i].pciid = pciIdx;
+		mcontroller[i].pcivendor = pciVendor;
+		mcontroller[i].pcislot = PCI_SLOT (pciDevFun);
+		mcontroller[i].uid = (pciBus << 8) | pciDevFun;
+
+		numFound++;
+
+		/* Set the Mode of addressing to 64 bit */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+		if ((megaCfg->flag & BOARD_64BIT) && BITS_PER_LONG == 64)
+#ifdef __LP64__
+			pdev->dma_mask = 0xffffffffffffffff;
+#else
+			pdev->dma_mask = 0xffffffff;
+#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);
+	}
+	return numFound;
 }
 
 /*---------------------------------------------------------
  * Detects if a megaraid controller exists in this system
  *---------------------------------------------------------*/
+
 int megaraid_detect (Scsi_Host_Template * pHostTmpl)
 {
-  int count = 0;
+	int ctlridx = 0, count = 0;
 
-#ifdef MODULE
-  if (megaraid)
-      megaraid_setup(megaraid);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)	/*0x20300 */
+	pHostTmpl->proc_dir = &proc_scsi_megaraid;
+#else
+	pHostTmpl->proc_name = "megaraid";
 #endif
 
-  pHostTmpl->proc_name = "megaraid";
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)	/* 0x20100 */
+	if (!pcibios_present ()) {
+		printk (KERN_WARNING "megaraid: PCI bios not present."
+			M_RD_CRLFSTR);
+		return 0;
+	}
+#endif
+	skip_id = -1;
+	if (megaraid && !strncmp (megaraid, "skip", strlen ("skip"))) {
+		if (megaraid[4] != '\0') {
+			skip_id = megaraid[4] - '0';
+			if (megaraid[5] != '\0') {
+				skip_id = (skip_id * 10) + (megaraid[5] - '0');
+			}
+		}
+		skip_id = (skip_id > 15) ? -1 : skip_id;
+	}
+
+	printk (KERN_INFO "megaraid: " MEGARAID_VERSION M_RD_CRLFSTR);
 
-  printk ("megaraid: " MEGARAID_VERSION CRLFSTR);
+	memset (mega_hbas, 0, sizeof (mega_hbas));
 
-  count += mega_findCard (pHostTmpl, 0x101E, 0x9010, 0);
-  count += mega_findCard (pHostTmpl, 0x101E, 0x9060, 0);
-  count += mega_findCard (pHostTmpl, 0x8086, 0x1960, BOARD_QUARTZ);
+	count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_AMI,
+				PCI_DEVICE_ID_AMI_MEGARAID, 0);
+	count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_AMI,
+				PCI_DEVICE_ID_AMI_MEGARAID2, 0);
+	count += mega_findCard (pHostTmpl, 0x8086,
+				PCI_DEVICE_ID_AMI_MEGARAID3, BOARD_QUARTZ);
+	count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_AMI,
+				PCI_DEVICE_ID_AMI_MEGARAID3, BOARD_QUARTZ);
+
+	mega_reorder_hosts ();
+
+#ifdef CONFIG_PROC_FS
+	if (count) {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0)	/*0x20300 */
+		mega_proc_dir_entry = proc_mkdir ("megaraid", &proc_root);
+#else
+		mega_proc_dir_entry = create_proc_entry ("megaraid",
+							 S_IFDIR | S_IRUGO |
+							 S_IXUGO, &proc_root);
+#endif
+		if (!mega_proc_dir_entry)
+			printk ("megaraid: failed to create megaraid root\n");
+		else
+			for (ctlridx = 0; ctlridx < count; ctlridx++)
+				mega_create_proc_entry (ctlridx,
+							mega_proc_dir_entry);
+	}
+#endif
 
-  return count;
+	/*
+	 * Register the driver as a character device, for appliactions to access
+	 * it for ioctls.
+	 * Ideally, this should go in the init_module() routine, but since it is
+	 * hidden in the file "scsi_module.c" ( included in the end ), we define
+	 * it here
+	 * First argument (major) to register_chrdev implies a dynamic major
+	 * number allocation.
+	 */
+	major = register_chrdev (0, "megadev", &megadev_fops);
+
+	/*
+	 * Register the Shutdown Notification hook in kernel
+	 */
+	if (register_reboot_notifier (&mega_notifier)) {
+		printk ("MegaRAID Shutdown routine not registered!!\n");
+	}
+	init_MUTEX (&mimd_entry_mtx);
+
+	return count;
 }
 
 /*---------------------------------------------------------------------
  * Release the controller's resources
  *---------------------------------------------------------------------*/
-int megaraid_release (struct Scsi_Host *pSHost)
+static int megaraid_release (struct Scsi_Host *pSHost)
 {
-  mega_host_config *megaCfg;
-  mega_mailbox *mbox;
-  u_char mboxData[16];
+	mega_host_config *megaCfg;
+	mega_mailbox *mbox;
+	u_char mboxData[16];
+	int i;
+
+	megaCfg = (mega_host_config *) pSHost->hostdata;
+	mbox = (mega_mailbox *) mboxData;
+
+	/* Flush cache to disk */
+	memset (mbox, 0, 16);
+	mboxData[0] = 0xA;
+
+	free_irq (megaCfg->host->irq, megaCfg);	/* Must be freed first, otherwise
+						   extra interrupt is generated */
+
+	/* Issue a blocking (interrupts disabled) command to the card */
+	megaIssueCmd (megaCfg, mboxData, NULL, 0);
+
+	/* Free our resources */
+	if (megaCfg->flag & BOARD_QUARTZ) {
+		iounmap ((void *) megaCfg->base);
+	} else {
+		release_region (megaCfg->host->io_port, 16);
+	}
 
-  megaCfg = (mega_host_config *) pSHost->hostdata;
-  mbox = (mega_mailbox *) mboxData;
+	mega_freeSgList (megaCfg);
+	pci_free_consistent (megaCfg->dev,
+			     sizeof (mega_mailbox64),
+			     (void *) megaCfg->mailbox64ptr,
+			     megaCfg->dma_handle64);
+	scsi_unregister (pSHost);
+
+#ifdef CONFIG_PROC_FS
+	if (megaCfg->controller_proc_dir_entry) {
+		remove_proc_entry ("stat", megaCfg->controller_proc_dir_entry);
+		remove_proc_entry ("status",
+				   megaCfg->controller_proc_dir_entry);
+		remove_proc_entry ("config",
+				   megaCfg->controller_proc_dir_entry);
+		remove_proc_entry ("mailbox",
+				   megaCfg->controller_proc_dir_entry);
+		for (i = 0; i < numCtlrs; i++) {
+			char buf[12] = { 0 };
+			sprintf (buf, "%d", i);
+			remove_proc_entry (buf, mega_proc_dir_entry);
+		}
+		remove_proc_entry ("megaraid", &proc_root);
+	}
+#endif
 
-  /* Flush cache to disk */
-  memset (mbox, 0, 16);
-  mboxData[0] = 0xA;
+	/*
+	 * Unregister the character device interface to the driver. Ideally this
+	 * should have been done in cleanup_module routine. Since this is hidden
+	 * in file "scsi_module.c", we do it here.
+	 * major is the major number of the character device returned by call to
+	 * register_chrdev() routine.
+	 */
+	unregister_chrdev (major, "megadev");
+	unregister_reboot_notifier (&mega_notifier);
+
+	return 0;
+}
+
+static int mega_is_bios_enabled (mega_host_config * megacfg)
+{
+	mega_mailbox *mboxpnt;
+	unsigned char mbox[16];
+	int ret;
 
-  free_irq (megaCfg->host->irq, megaCfg);/* Must be freed first, otherwise
-					   extra interrupt is generated */
+	mboxpnt = (mega_mailbox *) mbox;
 
-  /* Issue a blocking (interrupts disabled) command to the card */
-  megaIssueCmd (megaCfg, mboxData, NULL, 0);
+	memset (mbox, 0, sizeof (mbox));
+	memset ((void *) megacfg->mega_buffer,
+		0, sizeof (megacfg->mega_buffer));
 
-  /* Free our resources */
-  if (megaCfg->flag & BOARD_QUARTZ) {
-    iounmap ((void *) megaCfg->base);
-  }
-  else {
-    release_region (megaCfg->host->io_port, 16);
-  }
+	/*
+	 * issue command to find out if the BIOS is enbled for this controller
+	 */
+	mbox[0] = IS_BIOS_ENABLED;
+	mbox[2] = GET_BIOS;
 
-  mega_freeSgList(megaCfg);
-  scsi_unregister (pSHost);
+	mboxpnt->xferaddr = virt_to_bus ((void *) megacfg->mega_buffer);
 
-  return 0;
+	ret = megaIssueCmd (megacfg, mbox, NULL, 0);
+
+	return (*(char *) megacfg->mega_buffer);
 }
 
-static inline void mega_freeSgList(mega_host_config *megaCfg)
+static void mega_reorder_hosts (void)
 {
-  int i;
+	struct Scsi_Host *shpnt;
+	struct Scsi_Host *shone;
+	struct Scsi_Host *shtwo;
+	mega_host_config *boot_host;
+	int i;
+
+	/*
+	 * Find the (first) host which has it's BIOS enabled
+	 */
+	boot_host = NULL;
+	for (i = 0; i < MAX_CONTROLLERS; i++) {
+		if (mega_hbas[i].is_bios_enabled) {
+			boot_host = mega_hbas[i].hostdata_addr;
+			break;
+		}
+	}
+
+	if (boot_host == NULL) {
+		printk (KERN_WARNING "megaraid: no BIOS enabled.\n");
+		return;
+	}
 
-  for (i = 0; i < megaCfg->max_cmds; i++) {
-    if (megaCfg->scbList[i].sgList)
-      kfree (megaCfg->scbList[i].sgList);	/* free sgList */
-  }
+	/*
+	 * Traverse through the list of SCSI hosts for our HBA locations
+	 */
+	shone = shtwo = NULL;
+	for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
+		/* Is it one of ours? */
+		for (i = 0; i < MAX_CONTROLLERS; i++) {
+			if ((mega_host_config *) shpnt->hostdata ==
+			    mega_hbas[i].hostdata_addr) {
+				/* Does this one has BIOS enabled */
+				if (mega_hbas[i].hostdata_addr == boot_host) {
+
+					/* Are we first */
+					if (shtwo == NULL)	/* Yes! */
+						return;
+					else {	/* :-( */
+						shone = shpnt;
+					}
+				} else {
+					if (!shtwo) {
+						/* were we here before? xchng first */
+						shtwo = shpnt;
+					}
+				}
+				break;
+			}
+		}
+		/*
+		 * Have we got the boot host and one which does not have the bios
+		 * enabled.
+		 */
+		if (shone && shtwo)
+			break;
+	}
+	if (shone && shtwo) {
+		mega_swap_hosts (shone, shtwo);
+	}
+
+	return;
+}
+
+static void mega_swap_hosts (struct Scsi_Host *shone, struct Scsi_Host *shtwo)
+{
+	struct Scsi_Host *prevtoshtwo;
+	struct Scsi_Host *prevtoshone;
+	struct Scsi_Host *save = NULL;;
+
+	/* Are these two nodes adjacent */
+	if (shtwo->next == shone) {
+
+		if (shtwo == scsi_hostlist && shone->next == NULL) {
+
+			/* just two nodes */
+			scsi_hostlist = shone;
+			shone->next = shtwo;
+			shtwo->next = NULL;
+		} else if (shtwo == scsi_hostlist) {
+			/* first two nodes of the list */
+
+			scsi_hostlist = shone;
+			shtwo->next = shone->next;
+			scsi_hostlist->next = shtwo;
+		} else if (shone->next == NULL) {
+			/* last two nodes of the list */
+
+			prevtoshtwo = scsi_hostlist;
+
+			while (prevtoshtwo->next != shtwo)
+				prevtoshtwo = prevtoshtwo->next;
+
+			prevtoshtwo->next = shone;
+			shone->next = shtwo;
+			shtwo->next = NULL;
+		} else {
+			prevtoshtwo = scsi_hostlist;
+
+			while (prevtoshtwo->next != shtwo)
+				prevtoshtwo = prevtoshtwo->next;
+
+			prevtoshtwo->next = shone;
+			shtwo->next = shone->next;
+			shone->next = shtwo;
+		}
+
+	} else if (shtwo == scsi_hostlist && shone->next == NULL) {
+		/* shtwo at head, shone at tail, not adjacent */
+
+		prevtoshone = scsi_hostlist;
+
+		while (prevtoshone->next != shone)
+			prevtoshone = prevtoshone->next;
+
+		scsi_hostlist = shone;
+		shone->next = shtwo->next;
+		prevtoshone->next = shtwo;
+		shtwo->next = NULL;
+	} else if (shtwo == scsi_hostlist && shone->next != NULL) {
+		/* shtwo at head, shone is not at tail */
+
+		prevtoshone = scsi_hostlist;
+		while (prevtoshone->next != shone)
+			prevtoshone = prevtoshone->next;
+
+		scsi_hostlist = shone;
+		prevtoshone->next = shtwo;
+		save = shtwo->next;
+		shtwo->next = shone->next;
+		shone->next = save;
+	} else if (shone->next == NULL) {
+		/* shtwo not at head, shone at tail */
+
+		prevtoshtwo = scsi_hostlist;
+		prevtoshone = scsi_hostlist;
+
+		while (prevtoshtwo->next != shtwo)
+			prevtoshtwo = prevtoshtwo->next;
+		while (prevtoshone->next != shone)
+			prevtoshone = prevtoshone->next;
+
+		prevtoshtwo->next = shone;
+		shone->next = shtwo->next;
+		prevtoshone->next = shtwo;
+		shtwo->next = NULL;
+
+	} else {
+		prevtoshtwo = scsi_hostlist;
+		prevtoshone = scsi_hostlist;
+		save = NULL;;
+
+		while (prevtoshtwo->next != shtwo)
+			prevtoshtwo = prevtoshtwo->next;
+		while (prevtoshone->next != shone)
+			prevtoshone = prevtoshone->next;
+
+		prevtoshtwo->next = shone;
+		save = shone->next;
+		shone->next = shtwo->next;
+		prevtoshone->next = shtwo;
+		shtwo->next = save;
+	}
+	return;
+}
+
+static inline void mega_freeSgList (mega_host_config * megaCfg)
+{
+	int i;
+
+	for (i = 0; i < megaCfg->max_cmds; i++) {
+		if (megaCfg->scbList[i].sgList)
+			pci_free_consistent (megaCfg->dev,
+					     sizeof (mega_64sglist) *
+					     MAX_SGLIST,
+					     megaCfg->scbList[i].sgList,
+					     megaCfg->scbList[i].
+					     dma_sghandle64);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)	/* 0x020400 */
+			kfree (megaCfg->scbList[i].sgList);	/* free sgList */
+#endif
+	}
 }
 
 /*----------------------------------------------
- * Get information about the card/driver 
+ * Get information about the card/driver
  *----------------------------------------------*/
-const char * megaraid_info (struct Scsi_Host *pSHost)
+static const char *megaraid_info (struct Scsi_Host *pSHost)
 {
-  static char buffer[512];
-  mega_host_config *megaCfg;
+	static char buffer[512];
+	mega_host_config *megaCfg;
 
-  megaCfg = (mega_host_config *) pSHost->hostdata;
+	megaCfg = (mega_host_config *) pSHost->hostdata;
 
-  sprintf (buffer, "AMI MegaRAID %s %d commands %d targs %d chans %d luns",
-	   megaCfg->fwVer,
-           megaCfg->productInfo.MaxConcCmds,
-	   megaCfg->host->max_id,
-	   megaCfg->host->max_channel,
-           megaCfg->host->max_lun);
-  return buffer;
+	sprintf (buffer,
+		 "AMI MegaRAID %s %d commands %d targs %d chans %d luns",
+		 megaCfg->fwVer, megaCfg->productInfo.MaxConcCmds,
+		 megaCfg->host->max_id, megaCfg->host->max_channel,
+		 megaCfg->host->max_lun);
+	return buffer;
 }
 
 /*-----------------------------------------------------------------
@@ -1690,107 +3038,115 @@
  *   0E 01 reserved
  *   0F 01 mailbox busy
  *   10 01 numstatus byte
- *   11 01 status byte 
+ *   11 01 status byte
  *-----------------------------------------------------------------*/
-int megaraid_queue (Scsi_Cmnd * SCpnt, void (*pktComp) (Scsi_Cmnd *))
+static int megaraid_queue (Scsi_Cmnd * SCpnt, void (*pktComp) (Scsi_Cmnd *))
 {
-  DRIVER_LOCK_T
-  mega_host_config *megaCfg;
-  mega_scb *pScb;
-
-  megaCfg = (mega_host_config *) SCpnt->host->hostdata;
-  DRIVER_LOCK(megaCfg);
-
-  if (!(megaCfg->flag & (1L << SCpnt->channel))) {
-    if (SCpnt->channel < SCpnt->host->max_channel)
-       printk (/*KERN_INFO*/ "scsi%d: scanning channel %c for devices.\n",
-	    megaCfg->host->host_no,
-	    SCpnt->channel + '1');
-    else
-       printk(/*KERN_INFO*/ "scsi%d: scanning virtual channel for logical drives.\n", megaCfg->host->host_no);
-       
-    megaCfg->flag |= (1L << SCpnt->channel);
-  }
-
-  SCpnt->scsi_done = pktComp;
-
-  /* If driver in abort or reset.. cancel this command */
-  if (megaCfg->flag & IN_ABORT) {
-    SCpnt->result = (DID_ABORT << 16);
-    /* 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++;
-
-    DRIVER_UNLOCK(megaCfg);
-    return 0;
-  }
-  else if (megaCfg->flag & IN_RESET) {
-    SCpnt->result = (DID_RESET << 16);
-    /* 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++;
-
-    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 */
-    /* Add SCB to the head of the pending queue */
-    if( megaCfg->qPendingH == NULL ) {
-      megaCfg->qPendingH = megaCfg->qPendingT = pScb;
-    }
-    else {
-      megaCfg->qPendingT->next = pScb;
-      megaCfg->qPendingT = pScb;
-    }
-    megaCfg->qPendingT->next = NULL;
-    megaCfg->qPcnt++;
-
-      mega_runpendq(megaCfg);
-
-#if LINUX_VERSION_CODE > 0x020024
-    if ( SCpnt->cmnd[0]==IOCTL_CMD_NEW )
-    {  /* user data from external user buffer */
-          char *user_area;
-          u32  xfer_size;
-
-          init_MUTEX_LOCKED(&pScb->sem);
-          down(&pScb->sem);
-
-          user_area = *((char **)&pScb->SCpnt->cmnd[4]);
-          xfer_size = *((u32 *)&pScb->SCpnt->cmnd[8]);
-
-          copy_to_user(user_area,pScb->kern_area,xfer_size);
-
-          kfree(pScb->kern_area);
-
-          mega_freeSCB(megaCfg, pScb);
-    }
-#endif
-  }
+	DRIVER_LOCK_T mega_host_config * megaCfg;
+	mega_scb *pScb;
+	char *user_area = NULL;
+
+	megaCfg = (mega_host_config *) SCpnt->host->hostdata;
+	DRIVER_LOCK (megaCfg);
+
+	if (!(megaCfg->flag & (1L << SCpnt->channel))) {
+		if (SCpnt->channel < SCpnt->host->max_channel)
+			printk ( /*KERN_INFO */
+				"scsi%d: scanning channel %c for devices.\n",
+				megaCfg->host->host_no, SCpnt->channel + '1');
+		else
+			printk ( /*KERN_INFO */
+				"scsi%d: scanning virtual channel for logical drives.\n",
+				megaCfg->host->host_no);
+
+		megaCfg->flag |= (1L << SCpnt->channel);
+	}
+
+	SCpnt->scsi_done = pktComp;
+
+	if (mega_driver_ioctl (megaCfg, SCpnt))
+		return 0;
+
+	/* If driver in abort or reset.. cancel this command */
+	if (megaCfg->flag & IN_ABORT) {
+		SCpnt->result = (DID_ABORT << 16);
+		/* 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++;
+
+		DRIVER_UNLOCK (megaCfg);
+		return 0;
+	} else if (megaCfg->flag & IN_RESET) {
+		SCpnt->result = (DID_RESET << 16);
+		/* 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++;
+
+		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 M_RD_IOCTL_CMD_NEW cmd in mega_ioctl() */
+		/* Add SCB to the head of the pending queue */
+		/* Add SCB to the head of the pending queue */
+		if (megaCfg->qPendingH == NULL) {
+			megaCfg->qPendingH = megaCfg->qPendingT = pScb;
+		} else {
+			megaCfg->qPendingT->next = pScb;
+			megaCfg->qPendingT = pScb;
+		}
+		megaCfg->qPendingT->next = NULL;
+		megaCfg->qPcnt++;
+
+		if (mega_runpendq (megaCfg) == -1) {
+			DRIVER_UNLOCK (megaCfg);
+			return 0;
+		}
+
+		if (pScb->SCpnt->cmnd[0] == M_RD_IOCTL_CMD_NEW) {
+			init_MUTEX_LOCKED (&pScb->ioctl_sem);
+			spin_unlock_irq (&io_request_lock);
+			down (&pScb->ioctl_sem);
+			user_area = *((char **) &pScb->SCpnt->cmnd[4]);
+			if (copy_to_user
+			    (user_area, pScb->buff_ptr, pScb->iDataSize)) {
+				printk
+				    ("megaraid: Error copying ioctl return value to user buffer.\n");
+				pScb->SCpnt->result = (DID_ERROR << 16);
+			}
+			spin_lock_irq (&io_request_lock);
+			DRIVER_LOCK (megaCfg);
+			kfree (pScb->buff_ptr);
+			pScb->buff_ptr = NULL;
+			mega_cmd_done (megaCfg, pScb, pScb->SCpnt->result);
+			mega_rundoneq (megaCfg);
+			mega_runpendq (megaCfg);
+			DRIVER_UNLOCK (megaCfg);
+		}
 
-  megaCfg->flag &= ~IN_QUEUE;
-  DRIVER_UNLOCK(megaCfg);
+		megaCfg->flag &= ~IN_QUEUE;
 
-  return 0;
+	}
+
+	DRIVER_UNLOCK (megaCfg);
+	return 0;
 }
 
 /*----------------------------------------------------------------------
@@ -1798,167 +3154,404 @@
  *----------------------------------------------------------------------*/
 volatile static int internal_done_flag = 0;
 volatile static int internal_done_errcode = 0;
-static DECLARE_WAIT_QUEUE_HEAD(internal_wait);
+
+static DECLARE_WAIT_QUEUE_HEAD (internal_wait);
 
 static void internal_done (Scsi_Cmnd * SCpnt)
 {
-  internal_done_errcode = SCpnt->result;
-  internal_done_flag++;
-  wake_up(&internal_wait);
+	internal_done_errcode = SCpnt->result;
+	internal_done_flag++;
+	wake_up (&internal_wait);
 }
 
 /* shouldn't be used, but included for completeness */
 
-int megaraid_command (Scsi_Cmnd * SCpnt)
+static int megaraid_command (Scsi_Cmnd * SCpnt)
 {
-  internal_done_flag = 0;
+	internal_done_flag = 0;
 
-  /* Queue command, and wait until it has completed */
-  megaraid_queue (SCpnt, internal_done);
+	/* Queue command, and wait until it has completed */
+	megaraid_queue (SCpnt, internal_done);
 
-  while (!internal_done_flag) {
-	interruptible_sleep_on(&internal_wait);
-  }
+	while (!internal_done_flag) {
+		interruptible_sleep_on (&internal_wait);
+	}
 
-  return internal_done_errcode;
+	return internal_done_errcode;
 }
 
 /*---------------------------------------------------------------------
  * Abort a previous SCSI request
  *---------------------------------------------------------------------*/
-int
-megaraid_abort (Scsi_Cmnd * SCpnt)
+static int megaraid_abort (Scsi_Cmnd * SCpnt)
 {
-  mega_host_config *megaCfg;
-  int   rc; //, idx;
-  mega_scb *pScb;
+	mega_host_config *megaCfg;
+	int rc;			/*, idx; */
+	mega_scb *pScb;
 
-  rc = SCSI_ABORT_NOT_RUNNING;
+	rc = SCSI_ABORT_NOT_RUNNING;
 
-  megaCfg = (mega_host_config *) SCpnt->host->hostdata;
+	megaCfg = (mega_host_config *) SCpnt->host->hostdata;
 
-  megaCfg->flag |= IN_ABORT;
+	megaCfg->flag |= IN_ABORT;
 
-  for(pScb=megaCfg->qPendingH; pScb; pScb=pScb->next) {
-    if (pScb->SCpnt == SCpnt) {
-      /* Found an aborting command */
+	for (pScb = megaCfg->qPendingH; pScb; pScb = pScb->next) {
+		if (pScb->SCpnt == SCpnt) {
+			/* Found an aborting command */
 #if DEBUG
-      showMbox(pScb);
+			showMbox (pScb);
 #endif
 
-/*
- * 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_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;
-    }
-  }
+	/*
+	 * 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_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;
+		}
+	}
 
-  megaCfg->flag &= ~IN_ABORT;
+	megaCfg->flag &= ~IN_ABORT;
 
 #if DEBUG
-if(megaCfg->flag & IN_QUEUE)  printk("ma:flag is in queue\n");
-if(megaCfg->qCompletedH == NULL) printk("ma:qchead == null\n");
+	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 ;
-  /* Callback */
-  callDone (SCpnt);
-}
-  mega_rundoneq(megaCfg);
 
-  return rc;
+	/*
+	 * 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;
+		/* Callback */
+		callDone (SCpnt);
+	}
+	mega_rundoneq (megaCfg);
+
+	return rc;
 }
 
 /*---------------------------------------------------------------------
  * Reset a previous SCSI request
  *---------------------------------------------------------------------*/
-int megaraid_reset (Scsi_Cmnd * SCpnt, unsigned int rstflags)
+
+static int megaraid_reset (Scsi_Cmnd * SCpnt, unsigned int rstflags)
+{
+	mega_host_config *megaCfg;
+	int idx;
+	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));
+
+	/*
+	 * 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) {
+			SCpnt = megaCfg->scbList[idx].SCpnt;
+			pScb = &megaCfg->scbList[idx];
+			if (SCpnt != NULL) {
+				pScb->state = SCB_RESET;
+				break;
+			}
+		}
+	}
+
+	megaCfg->flag &= ~IN_RESET;
+
+	mega_rundoneq (megaCfg);
+	return rc;
+}
+
+#ifdef CONFIG_PROC_FS
+/* Following code handles /proc fs  */
+static int proc_printf (mega_host_config * megaCfg, const char *fmt, ...)
 {
-  mega_host_config *megaCfg;
-  int idx;
-  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));
-
-  /*
-   * 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) {
-      SCpnt = megaCfg->scbList[idx].SCpnt;
-      pScb = &megaCfg->scbList[idx];
-      if (SCpnt != NULL) {
-        pScb->state = SCB_RESET;
-        break;
-      }
-    }
-  }
+	va_list args;
+	int i;
 
-  megaCfg->flag &= ~IN_RESET;
+	if (megaCfg->procidx > PROCBUFSIZE)
+		return 0;
 
-  mega_rundoneq(megaCfg);
-  return rc;
+	va_start (args, fmt);
+	i = vsprintf ((megaCfg->procbuf + megaCfg->procidx), fmt, args);
+	va_end (args);
+
+	megaCfg->procidx += i;
+	return i;
 }
 
+static int proc_read_config (char *page, char **start, off_t offset,
+		  int count, int *eof, void *data)
+{
+
+	mega_host_config *megaCfg = (mega_host_config *) data;
+
+	*start = page;
+
+	if (megaCfg->productInfo.ProductName[0] != 0)
+		proc_printf (megaCfg, "%s\n", megaCfg->productInfo.ProductName);
+
+	proc_printf (megaCfg, "Controller Type: ");
+
+	if (megaCfg->flag & BOARD_QUARTZ)
+		proc_printf (megaCfg, "438/466/467/471/493\n");
+	else
+		proc_printf (megaCfg, "418/428/434\n");
+
+	if (megaCfg->flag & BOARD_40LD)
+		proc_printf (megaCfg,
+			     "Controller Supports 40 Logical Drives\n");
+
+	if (megaCfg->flag & BOARD_64BIT)
+		proc_printf (megaCfg,
+			     "Controller / Driver uses 64 bit memory addressing\n");
+
+	proc_printf (megaCfg, "Base = %08x, Irq = %d, ", megaCfg->base,
+		     megaCfg->host->irq);
+
+	proc_printf (megaCfg, "Logical Drives = %d, Channels = %d\n",
+		     megaCfg->numldrv, megaCfg->productInfo.SCSIChanPresent);
+
+	proc_printf (megaCfg, "Version =%s:%s, DRAM = %dMb\n",
+		     megaCfg->fwVer, megaCfg->biosVer,
+		     megaCfg->productInfo.DramSize);
+
+	proc_printf (megaCfg,
+		     "Controller Queue Depth = %d, Driver Queue Depth = %d\n",
+		     megaCfg->productInfo.MaxConcCmds, megaCfg->max_cmds);
+	COPY_BACK;
+	return count;
+}
+
+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;
+
+	proc_printf (megaCfg, "Statistical Information for this controller\n");
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)	/* 0x020100 */
+	proc_printf (megaCfg, "Interrupts Collected = %Lu\n",
+		     megaCfg->nInterrupts);
+#else
+	proc_printf (megaCfg, "Interrupts Collected = %u\n",
+		     (u32) megaCfg->nInterrupts);
+#endif
+
+	for (i = 0; i < megaCfg->numldrv; i++) {
+		proc_printf (megaCfg, "Logical Drive %d:\n", i);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+		proc_printf (megaCfg,
+			     "\tReads Issued = %Lu, Writes Issued = %Lu\n",
+			     megaCfg->nReads[i], megaCfg->nWrites[i]);
+
+		proc_printf (megaCfg,
+			     "\tSectors Read = %Lu, Sectors Written = %Lu\n\n",
+			     megaCfg->nReadBlocks[i], megaCfg->nWriteBlocks[i]);
+#else
+		proc_printf (megaCfg,
+			     "\tReads Issued = %10u, Writes Issued = %10u\n",
+			     (u32) megaCfg->nReads[i],
+			     (u32) megaCfg->nWrites[i]);
+
+		proc_printf (megaCfg,
+			     "\tSectors Read = %10u, Sectors Written = %10u\n\n",
+			     (u32) megaCfg->nReadBlocks[i],
+			     (u32) megaCfg->nWriteBlocks[i]);
+#endif
+
+	}
+
+	COPY_BACK;
+	return count;
+}
+
+static int proc_read_status (char *page, char **start, off_t offset,
+		  int count, int *eof, void *data)
+{
+	mega_host_config *megaCfg = (mega_host_config *) data;
+	*start = page;
+
+	proc_printf (megaCfg, "TBD\n");
+	COPY_BACK;
+	return count;
+}
+
+static int proc_read_mbox (char *page, char **start, off_t offset,
+		int count, int *eof, void *data)
+{
+
+	mega_host_config *megaCfg = (mega_host_config *) data;
+	volatile mega_mailbox *mbox = megaCfg->mbox;
+
+	*start = page;
+
+	proc_printf (megaCfg, "Contents of Mail Box Structure\n");
+	proc_printf (megaCfg, "  Fw Command   = 0x%02x\n", mbox->cmd);
+	proc_printf (megaCfg, "  Cmd Sequence = 0x%02x\n", mbox->cmdid);
+	proc_printf (megaCfg, "  No of Sectors= %04d\n", mbox->numsectors);
+	proc_printf (megaCfg, "  LBA          = 0x%02x\n", mbox->lba);
+	proc_printf (megaCfg, "  DTA          = 0x%08x\n", mbox->xferaddr);
+	proc_printf (megaCfg, "  Logical Drive= 0x%02x\n", mbox->logdrv);
+	proc_printf (megaCfg, "  No of SG Elmt= 0x%02x\n", mbox->numsgelements);
+	proc_printf (megaCfg, "  Busy         = %01x\n", mbox->busy);
+	proc_printf (megaCfg, "  Status       = 0x%02x\n", mbox->status);
+
+	/* proc_printf(megaCfg, "Dump of MailBox\n");
+	for (i = 0; i < 16; i++)
+        	proc_printf(megaCfg, "%02x ",*(mbox + i));
+
+	proc_printf(megaCfg, "\n\nNumber of Status = %02d\n",mbox->numstatus);
+
+	for (i = 0; i < 46; i++) {
+        	proc_printf(megaCfg,"%02d ",*(mbox + 16 + i));
+        if (i%16)
+                proc_printf(megaCfg,"\n");
+	}
+
+	if (!mbox->numsgelements) {
+	        dta = phys_to_virt(mbox->xferaddr);
+	        for (i = 0; i < mbox->numsgelements; i++)
+	                if (dta) {
+	                        proc_printf(megaCfg,"Addr = %08x\n", (ulong)*(dta + i));                        proc_printf(megaCfg,"Length = %08x\n",
+	                                (ulong)*(dta + i + 4));
+	                }
+	}*/
+	COPY_BACK;
+	return count;
+}
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0)	/*0x20300 */
+#define CREATE_READ_PROC(string, fxn) create_proc_read_entry(string, \
+                                         S_IRUSR | S_IFREG,\
+                                         controller_proc_dir_entry,\
+                                         fxn, megaCfg)
+#else
+#define CREATE_READ_PROC(string, fxn) create_proc_read_entry(string,S_IRUSR | S_IFREG, controller_proc_dir_entry, fxn, megaCfg)
+
+static struct proc_dir_entry *
+create_proc_read_entry (const char *string,
+			int mode,
+			struct proc_dir_entry *parent,
+			read_proc_t * fxn, mega_host_config * megaCfg)
+{
+	struct proc_dir_entry *temp = NULL;
+
+	temp = kmalloc (sizeof (struct proc_dir_entry), GFP_KERNEL);
+	if (!temp)
+		return NULL;
+	memset (temp, 0, sizeof (struct proc_dir_entry));
+
+	if ((temp->name = kmalloc (strlen (string) + 1, GFP_KERNEL)) == NULL) {
+		kfree (temp);
+		return NULL;
+	}
+
+	strcpy ((char *) temp->name, string);
+	temp->namelen = strlen (string);
+	temp->mode = mode; /*S_IFREG | S_IRUSR */ ;
+	temp->data = (void *) megaCfg;
+	temp->read_proc = fxn;
+	proc_register (parent, temp);
+	return temp;
+}
+#endif
+
+static void mega_create_proc_entry (int index, struct proc_dir_entry *parent)
+{
+	u_char string[64] = { 0 };
+	mega_host_config *megaCfg = megaCtlrs[index];
+	struct proc_dir_entry *controller_proc_dir_entry = NULL;
+
+	sprintf (string, "%d", index);
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0)	/*0x20300 */
+	controller_proc_dir_entry =
+	    megaCfg->controller_proc_dir_entry = proc_mkdir (string, parent);
+#else
+	controller_proc_dir_entry =
+	    megaCfg->controller_proc_dir_entry =
+	    create_proc_entry (string, S_IFDIR | S_IRUGO | S_IXUGO, parent);
+#endif
+
+	if (!controller_proc_dir_entry)
+		printk ("\nmegaraid: proc_mkdir failed\n");
+	else {
+		megaCfg->proc_read =
+		    CREATE_READ_PROC ("config", proc_read_config);
+		megaCfg->proc_status =
+		    CREATE_READ_PROC ("status", proc_read_status);
+		megaCfg->proc_stat = CREATE_READ_PROC ("stat", proc_read_stat);
+		megaCfg->proc_mbox =
+		    CREATE_READ_PROC ("mailbox", proc_read_mbox);
+	}
+
+}
+#endif				/* CONFIG_PROC_FS */
+
 /*-------------------------------------------------------------
  * Return the disk geometry for a particular disk
  * Input:
@@ -1969,51 +3562,749 @@
  *     geom[1] = sectors
  *     geom[2] = cylinders
  *-------------------------------------------------------------*/
-int megaraid_biosparam (Disk * disk, kdev_t dev, int *geom)
+static 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;
+}
+
+/*
+ * This routine will be called when the use has done a forced shutdown on the
+ * system. Flush the Adapter cache, that's the most we can do.
+ */
+static int megaraid_reboot_notify (struct notifier_block *this, unsigned long code,
+			void *unused)
 {
-  int heads, sectors, cylinders;
-  mega_host_config *megaCfg;
+	struct Scsi_Host *pSHost;
+	mega_host_config *megaCfg;
+	mega_mailbox *mbox;
+	u_char mboxData[16];
+	int i;
+
+	if (code == SYS_DOWN || code == SYS_HALT) {
+		for (i = 0; i < numCtlrs; i++) {
+			pSHost = megaCtlrs[i]->host;
+
+			megaCfg = (mega_host_config *) pSHost->hostdata;
+			mbox = (mega_mailbox *) mboxData;
+
+			/* Flush cache to disk */
+			memset (mbox, 0, 16);
+			mboxData[0] = 0xA;
+
+			/*
+			 * Free irq, otherwise extra interrupt is generated
+			 */
+			free_irq (megaCfg->host->irq, megaCfg);
+
+			/*
+			   * Issue a blocking (interrupts disabled) command to
+			   * the card
+			 */
+			megaIssueCmd (megaCfg, mboxData, NULL, 0);
+		}
+	}
+	return NOTIFY_DONE;
+}
+
+static int mega_init_scb (mega_host_config * megacfg)
+{
+	int idx;
 
-  /* Get pointer to host config structure */
-  megaCfg = (mega_host_config *) disk->device->host->hostdata;
+#if DEBUG
+	if (megacfg->max_cmds >= MAX_COMMANDS) {
+		printk ("megaraid:ctlr max cmds = %x : MAX_CMDS = %x",
+			megacfg->max_cmds, MAX_COMMANDS);
+	}
+#endif
 
-  /* 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;
-}
-
-static int __init megaraid_setup(char *str)
-{
-  skip_id = -1;
-  if (str && !strncmp(str, "skip", strlen("skip"))) {
-      if (str[4] != '\0') {
-          skip_id = str[4] - '0';
-          if (str[5] != '\0') {
-              skip_id = (skip_id * 10) + (str[5] - '0');
-          }
-      }
-      skip_id = (skip_id > 15) ? -1 : skip_id;
-  }
-  return 1;
+	for (idx = megacfg->max_cmds - 1; idx >= 0; idx--) {
+
+		megacfg->scbList[idx].idx = idx;
+
+		/*
+		 * ISR will make this flag zero to indicate the command has been
+		 * completed. This is only for user ioctl calls. Rest of the driver
+		 * and the mid-layer operations are not connected with this flag.
+		 */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+		megacfg->scbList[idx].sgList =
+		    pci_alloc_consistent (megacfg->dev,
+					  sizeof (mega_64sglist) * MAX_SGLIST,
+					  &(megacfg->scbList[idx].
+					    dma_sghandle64));
+
+		megacfg->scbList[idx].sg64List =
+		    (mega_64sglist *) megacfg->scbList[idx].sgList;
+#else
+		megacfg->scbList[idx].sgList = kmalloc (sizeof (mega_sglist) * MAX_SGLIST, GFP_ATOMIC | GFP_DMA);
+#endif
+
+		if (megacfg->scbList[idx].sgList == NULL) {
+			printk (KERN_WARNING
+				"Can't allocate sglist for id %d\n", idx);
+			mega_freeSgList (megacfg);
+			return -1;
+		}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+		megacfg->scbList[idx].pthru = pci_alloc_consistent (megacfg->dev,
+					  sizeof (mega_passthru),
+					  &(megacfg->scbList[idx].
+					    dma_passthruhandle64));
+
+		if (megacfg->scbList[idx].pthru == NULL) {
+			printk (KERN_WARNING
+				"Can't allocate passthru for id %d\n", idx);
+		}
+		/* 
+		 * Allocate a 256 Byte Bounce Buffer for handling INQ/RD_CAPA 
+		 */
+		megacfg->scbList[idx].bounce_buffer = pci_alloc_consistent (megacfg->dev,
+					  256,
+					  &(megacfg->scbList[idx].
+					    dma_bounce_buffer));
+
+		if (!megacfg->scbList[idx].bounce_buffer)
+			printk
+			    ("megaraid: allocation for bounce buffer failed\n");
+
+		megacfg->scbList[idx].dma_type = M_RD_DMA_TYPE_NONE;
+#endif
+
+		if (idx < MAX_COMMANDS) {
+			/*
+			 * Link to free list
+			 * lock not required since we are loading the driver, so no
+			 * commands possible right now.
+			 */
+			enq_scb_freelist (megacfg, &megacfg->scbList[idx],
+					  NO_LOCK, INTR_ENB);
+
+		}
+	}
+
+	return 0;
 }
 
-__setup("megaraid=", megaraid_setup);
+/*
+ * Enqueues a SCB
+ */
+static void enq_scb_freelist (mega_host_config * megacfg, mega_scb * scb, int lock,
+		  int intr)
+{
+
+	if (lock == INTERNAL_LOCK || intr == INTR_DIS) {
+		if (intr == INTR_DIS)
+			spin_lock_irq (&megacfg->lock_free);
+		else
+			spin_lock (&megacfg->lock_free);
+	}
+
+	scb->state = SCB_FREE;
+	scb->SCpnt = NULL;
+
+	if (megacfg->qFreeH == (mega_scb *) NULL) {
+		megacfg->qFreeH = megacfg->qFreeT = scb;
+	} else {
+		megacfg->qFreeT->next = scb;
+		megacfg->qFreeT = scb;
+	}
+
+	megacfg->qFreeT->next = NULL;
+	megacfg->qFcnt++;
+
+	if (lock == INTERNAL_LOCK || intr == INTR_DIS) {
+		if (intr == INTR_DIS)
+			spin_unlock_irq (&megacfg->lock_free);
+		else
+			spin_unlock (&megacfg->lock_free);
+	}
+}
+
+/*
+ * Routines for the character/ioctl interface to the driver
+ */
+static int megadev_open (struct inode *inode, struct file *filep)
+{
+	MOD_INC_USE_COUNT;
+	return 0;		/* success */
+}
+
+static int megadev_ioctl_entry (struct inode *inode, struct file *filep,
+		     unsigned int cmd, unsigned long arg)
+{
+	int ret = -1;
+
+	/*
+	 * We do not allow parallel ioctls to the driver as of now.
+	 */
+	down (&mimd_entry_mtx);
+	ret = megadev_ioctl (inode, filep, cmd, arg);
+	up (&mimd_entry_mtx);
+
+	return ret;
+
+}
+
+static int megadev_ioctl (struct inode *inode, struct file *filep,
+	       unsigned int cmd, unsigned long arg)
+{
+	int adapno;
+	kdev_t dev;
+	u32 inlen;
+	struct uioctl_t ioc;
+	char *kphysaddr = NULL;
+	int nadap = numCtlrs;
+	int npages;
+	u8 opcode;
+	int order = 0;
+	u32 outlen;
+	int ret;
+	u8 subopcode;
+	Scsi_Cmnd *scsicmd;
+	struct Scsi_Host *shpnt;
+	char *uaddr;
+	struct uioctl_t *uioc;
+	IO_LOCK_T;
+
+	if (!inode || !(dev = inode->i_rdev))
+		return -EINVAL;
+
+	if (_IOC_TYPE (cmd) != MEGAIOC_MAGIC)
+		return (-EINVAL);
+
+	/*
+	 * We do not transfer more than IOCTL_MAX_DATALEN (see megaraid.h) with
+	 * this interface.If the user needs to transfer more than this,he should
+	 * use 0x81 command op-code.
+	 */
+
+	/*
+	 * Get the user ioctl structure
+	 */
+	ret = verify_area (VERIFY_WRITE, (char *) arg, sizeof (struct uioctl_t));
+
+	if (ret)
+		return ret;
+
+	if(copy_from_user (&ioc, (char *) arg, sizeof (struct uioctl_t)))
+		return -EFAULT;
+
+	/*
+	 * The first call the applications should make is to find out the number
+	 * of controllers in the system. The next logical call should be for
+	 * getting the list of controllers in the system as detected by the
+	 * driver.
+	 */
+
+	/*
+	 * Get the opcode and subopcode for the commands
+	 */
+	opcode = ioc.ui.fcs.opcode;
+	subopcode = ioc.ui.fcs.subopcode;
+
+	switch (opcode) {
+	case M_RD_DRIVER_IOCTL_INTERFACE:
+		switch (subopcode) {
+		case MEGAIOC_QDRVRVER:	/* Query driver version */
+			put_user (driver_ver, (u32 *) ioc.data);
+			return 0;
+
+		case MEGAIOC_QNADAP:	/* Get # of adapters */
+			put_user (nadap, (int *) ioc.data);
+			return nadap;
+
+		case MEGAIOC_QADAPINFO:	/* Get adapter information */
+			/*
+			 * which adapter?
+			 */
+			adapno = ioc.ui.fcs.adapno;
+
+			/*
+			 * The adapter numbers do not start with 0, at least in
+			 * the user space. This is just to make sure, 0 is not the
+			 * default value which will refer to adapter 1. So the
+			 * user needs to make use of macros MKADAP() and GETADAP()
+			 * (See megaraid.h) while making ioctl() call.
+			 */
+			adapno = GETADAP (adapno);
+
+			if (adapno >= numCtlrs)
+				return (-ENODEV);
+
+			ret = verify_area (VERIFY_WRITE,
+					   ioc.data,
+					   sizeof (struct mcontroller));
+			if (ret)
+				return ret;
+
+			/*
+			 * Copy struct mcontroller to user area
+			 */
+			copy_to_user (ioc.data,
+				      mcontroller + adapno,
+				      sizeof (struct mcontroller));
+			return 0;
+
+		default:
+			return (-EINVAL);
+
+		}		/* inner switch */
+		break;
+
+	case M_RD_IOCTL_CMD_NEW:
+		/* which adapter?  */
+		adapno = ioc.ui.fcs.adapno;
+
+		/* See comment above: MEGAIOC_QADAPINFO */
+		adapno = GETADAP (adapno);
+
+		if (adapno >= numCtlrs)
+			return (-ENODEV);
+
+		/* Check for zero length buffer. */
+		if (!ioc.ui.fcs.length)
+			return -EINVAL;
+
+		/* save the user address */
+		uaddr = ioc.ui.fcs.buffer;
 
+/*
+* For M_RD_IOCTL_CMD_NEW commands, the fields outlen and inlen of uioctl_t
+* structure are treated as flags. If outlen is 1, the data is
+* transferred from the device and if inlen is 1, the data is
+* transferred to the device.
+*/
+		outlen = ioc.outlen;
+		inlen = ioc.inlen;
+#if 0
+		if (inlen && outlen)
+			return -EINVAL;
+#endif
+		if (outlen) {
+			ret = verify_area (VERIFY_WRITE,
+					   (char *) ioc.ui.fcs.buffer,
+					   ioc.ui.fcs.length);
+			if (ret)
+				return ret;
+		} else if (inlen) {
+			ret = verify_area (VERIFY_READ,
+					   (char *) ioc.ui.fcs.buffer,
+					   ioc.ui.fcs.length);
+
+			if (ret)
+				return ret;
+		}
+
+		/* How many pages required of size PAGE_SIZE */
+		npages = ioc.ui.fcs.length / PAGE_SIZE;
+		/* Do we need one more? */
+
+		if (ioc.ui.fcs.length % PAGE_SIZE)
+			npages++;
+
+		/* ioctl does not support data xfer > 32KB */
+		if (npages == 1)
+			order = 0;
+		else if (npages == 2)
+			order = 1;
+		else if (npages <= 4)
+			order = 2;
+		else if (npages <= 8)
+			order = 3;
+		else
+			return -EINVAL;
+
+		if (outlen || inlen) {
+			/*
+			 * Allocate kernel space for npages.
+			 *
+			 * Since we need the memory for DMA, it needs to be physically
+			 * contiguous. __get_free_pags() return consecutive free pages
+			 * in kernel space.
+			 * Note: We don't do __get_dma_pages(), since for PCI devices,
+			 * the DMA memory is not restriceted to 16M, which is ensured
+			 * by __get_dma_pages()
+			 */
+
+			if ((kphysaddr = (char *) __get_free_pages (GFP_KERNEL,
+								    order)) ==
+			    0) {
+				printk (KERN_INFO
+					"megaraid:allocation failed\n");
+				return -ENOMEM;
+			}
+
+			memset (kphysaddr, 0, npages * PAGE_SIZE);
+			ioc.ui.fcs.buffer = kphysaddr;
+
+			if (inlen) {
+				/* copyin the user data */
+				copy_from_user (kphysaddr,
+						(char *) uaddr,
+						ioc.ui.fcs.length);
+			}
+		}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+		scsicmd = (Scsi_Cmnd *) kmalloc (sizeof (Scsi_Cmnd),
+						 GFP_KERNEL | GFP_DMA);
+		memset (scsicmd, 0, sizeof (Scsi_Cmnd));
+#else
+		scsicmd = (Scsi_Cmnd *) scsi_init_malloc (sizeof (Scsi_Cmnd),
+							  GFP_ATOMIC | GFP_DMA);
+#endif
+		if (!scsicmd) {
+			if (kphysaddr)
+				free_pages ((unsigned long) kphysaddr, order);
+			return -ENOMEM;
+		}
+
+		scsicmd->host = NULL;
+
+		/*
+		 * Find this host
+		 */
+		for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
+			if (shpnt->hostdata ==
+			    (unsigned long *) megaCtlrs[adapno])
+				scsicmd->host = shpnt;
+		}
+
+		if (scsicmd->host == NULL) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+			kfree (scsicmd);
+#else
+			scsi_init_free ((char *) scsicmd, sizeof (Scsi_Cmnd));
+#endif
+			if (kphysaddr)
+				free_pages ((unsigned long) kphysaddr, order);
+			return -ENODEV;
+		}
+
+		scsicmd->cmnd[0] = MEGADEVIOC;
+		scsicmd->request_buffer = (void *) &ioc;
+
+		init_MUTEX_LOCKED (&mimd_ioctl_sem);
+
+		IO_LOCK;
+		megaraid_queue (scsicmd, megadev_ioctl_done);
+
+		IO_UNLOCK;
+
+		down (&mimd_ioctl_sem);
+
+		if (!scsicmd->result && outlen) {
+			copy_to_user (uaddr, kphysaddr, ioc.ui.fcs.length);
+		}
+
+		/*
+		 * copyout the result
+		 */
+		uioc = (struct uioctl_t *) arg;
+
+		if (ioc.mbox[0] == MEGA_MBOXCMD_PASSTHRU) {
+			put_user (scsicmd->result, &uioc->pthru.scsistatus);
+		} else {
+			put_user (1, &uioc->mbox[16]);	/* numstatus */
+			/* status */
+			put_user (scsicmd->result, &uioc->mbox[17]);
+		}
+
+		if (kphysaddr) {
+			free_pages ((ulong) kphysaddr, order);
+		}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)	/*0x20400 */
+		kfree (scsicmd);
+#else
+		scsi_init_free ((char *) scsicmd, sizeof (Scsi_Cmnd));
+#endif
+
+		return ret;
+
+	case M_RD_IOCTL_CMD:
+		/* which adapter?  */
+		adapno = ioc.ui.fcs.adapno;
+		/* See comment above: MEGAIOC_QADAPINFO */
+		adapno = GETADAP (adapno);
+
+		if (adapno >= numCtlrs)
+			return (-ENODEV);
+
+		/* save the user address */
+		uaddr = ioc.data;
+		outlen = ioc.outlen;
+		inlen = ioc.inlen;
+
+		if ((outlen >= IOCTL_MAX_DATALEN)
+		    || (inlen >= IOCTL_MAX_DATALEN))
+			return (-EINVAL);
+
+		if (outlen) {
+			ret = verify_area (VERIFY_WRITE, ioc.data, outlen);
+			if (ret)
+				return ret;
+		} else if (inlen) {
+			ret = verify_area (VERIFY_READ, ioc.data, inlen);
+
+			if (ret)
+				return ret;
+		}
+
+		if (outlen || inlen) {
+			/*
+			 * Allocate a page of kernel space.
+			 */
+			if ((kphysaddr =
+			     (char *) __get_free_pages (GFP_KERNEL, 0)) == 0) {
+
+				printk (KERN_INFO
+					"megaraid:allocation failed\n");
+				return -ENOMEM;
+			}
+
+			memset (kphysaddr, 0, PAGE_SIZE);
+			ioc.data = kphysaddr;
+
+			if (inlen) {
+				if (ioc.mbox[0] == MEGA_MBOXCMD_PASSTHRU) {
+					/* copyin the user data */
+					copy_from_user (kphysaddr,
+							uaddr,
+							ioc.pthru.dataxferlen);
+				} else {
+					copy_from_user (kphysaddr,
+							uaddr, inlen);
+				}
+			}
+		}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)	/* 0x020400 */
+		scsicmd = (Scsi_Cmnd *) kmalloc (sizeof (Scsi_Cmnd),
+						 GFP_KERNEL | GFP_DMA);
+		memset (scsicmd, 0, sizeof (Scsi_Cmnd));
+#else
+		scsicmd = (Scsi_Cmnd *) scsi_init_malloc (sizeof (Scsi_Cmnd),
+							  GFP_ATOMIC | GFP_DMA);
+#endif
+
+		if (!scsicmd) {
+			if (kphysaddr)
+				free_pages ((unsigned long) kphysaddr, 0);
+			return -ENOMEM;
+		}
+
+		scsicmd->host = NULL;
+
+		/*
+		 * Find this host in the hostlist
+		 */
+		for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
+			if (shpnt->hostdata ==
+			    (unsigned long *) megaCtlrs[adapno])
+				scsicmd->host = shpnt;
+		}
+
+		if (scsicmd->host == NULL) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+			kfree (scsicmd);
+#else
+			scsi_init_free ((char *) scsicmd, sizeof (Scsi_Cmnd));
+#endif
+			if (kphysaddr)
+				free_pages ((unsigned long) kphysaddr, 0);
+
+			return -ENODEV;
+		}
+
+		scsicmd->cmnd[0] = MEGADEVIOC;
+		scsicmd->request_buffer = (void *) &ioc;
+
+		init_MUTEX_LOCKED (&mimd_ioctl_sem);
+
+		IO_LOCK;
+		megaraid_queue (scsicmd, megadev_ioctl_done);
+
+		IO_UNLOCK;
+		down (&mimd_ioctl_sem);
+
+		if (!scsicmd->result && outlen) {
+			if (ioc.mbox[0] == MEGA_MBOXCMD_PASSTHRU) {
+				copy_to_user (uaddr,
+					      kphysaddr, ioc.pthru.dataxferlen);
+			} else {
+				copy_to_user (uaddr, kphysaddr, outlen);
+			}
+		}
+
+		/*
+		 * copyout the result
+		 */
+		uioc = (struct uioctl_t *) arg;
+
+		if (ioc.mbox[0] == MEGA_MBOXCMD_PASSTHRU) {
+			put_user (scsicmd->result, &uioc->pthru.scsistatus);
+		} else {
+			put_user (1, &uioc->mbox[16]);	/* numstatus */
+			/* status */
+			put_user (scsicmd->result, &uioc->mbox[17]);
+		}
+
+		if (kphysaddr)
+			free_pages ((unsigned long) kphysaddr, 0);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+		kfree (scsicmd);
+#else
+		scsi_init_free ((char *) scsicmd, sizeof (Scsi_Cmnd));
+#endif
+		return ret;
+
+	default:
+		return (-EINVAL);
+
+	}			/* Outer switch */
+
+	return 0;
+}
+
+static void
+megadev_ioctl_done (Scsi_Cmnd * sc)
+{
+	up (&mimd_ioctl_sem);
+}
+
+static mega_scb *
+megadev_doioctl (mega_host_config * megacfg, Scsi_Cmnd * sc)
+{
+	u8 cmd;
+	struct uioctl_t *ioc = NULL;
+	mega_mailbox *mbox = NULL;
+	mega_ioctl_mbox *mboxioc = NULL;
+	struct mbox_passthru *mboxpthru = NULL;
+	mega_scb *scb = NULL;
+	mega_passthru *pthru = NULL;
+
+	if ((scb = mega_allocateSCB (megacfg, sc)) == NULL) {
+		sc->result = (DID_ERROR << 16);
+		callDone (sc);
+		return NULL;
+	}
+
+	ioc = (struct uioctl_t *) sc->request_buffer;
+
+	memcpy (scb->mboxData, ioc->mbox, sizeof (scb->mboxData));
+
+	/* The generic mailbox */
+	mbox = (mega_mailbox *) ioc->mbox;
+
+	/*
+	 * Get the user command
+	 */
+	cmd = ioc->mbox[0];
+
+	switch (cmd) {
+	case MEGA_MBOXCMD_PASSTHRU:
+		/*
+		   * prepare the SCB with information from the user ioctl structure
+		 */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+		pthru = scb->pthru;
+#else
+		pthru = &scb->pthru;
+#endif
+		memcpy (pthru, &ioc->pthru, sizeof (mega_passthru));
+		mboxpthru = (struct mbox_passthru *) scb->mboxData;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+		if (megacfg->flag & BOARD_64BIT) {
+			/* This is just a sample with one element 
+			   * This if executes onlu on 2.4 kernels
+			 */
+			mboxpthru->dataxferaddr = scb->dma_passthruhandle64;
+			scb->sg64List[0].address =
+			    pci_map_single (megacfg->dev,
+					    ioc->data,
+					    4096, PCI_DMA_BIDIRECTIONAL);
+			scb->sg64List[0].length = 4096;	// TODO: Check this
+			pthru->dataxferaddr = scb->dma_sghandle64;
+			pthru->numsgelements = 1;
+			mboxpthru->cmd = 0xC3;
+		} else {
+			mboxpthru->dataxferaddr = scb->dma_passthruhandle64;
+			pthru->dataxferaddr =
+			    pci_map_single (megacfg->dev,
+					    ioc->data,
+					    4096, PCI_DMA_BIDIRECTIONAL);
+			pthru->numsgelements = 0;
+		}
+
+#else
+		{
+			mboxpthru->dataxferaddr = virt_to_bus (&scb->pthru);
+			pthru->dataxferaddr = virt_to_bus (ioc->data);
+			pthru->numsgelements = 0;
+		}
+#endif
+
+		pthru->reqsenselen = 14;
+		break;
+
+	default:		/* Normal command */
+		mboxioc = (mega_ioctl_mbox *) scb->mboxData;
+
+		if (ioc->ui.fcs.opcode == M_RD_IOCTL_CMD_NEW) {
+			scb->buff_ptr = ioc->ui.fcs.buffer;
+			scb->iDataSize = ioc->ui.fcs.length;
+		} else {
+			scb->buff_ptr = ioc->data;
+			scb->iDataSize = 4096;	// TODO:check it
+		}
+
+		set_mbox_xfer_addr (megacfg, scb, mboxioc, FROMTO_DEVICE);
+		mboxioc->numsgelements = 0;
+		break;
+	}
+
+	return scb;
+}
+
+static int
+megadev_close (struct inode *inode, struct file *filep)
+{
+#ifdef MODULE
+	MOD_DEC_USE_COUNT;
+#endif
+	return 0;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 static Scsi_Host_Template driver_template = MEGARAID;
+#include "scsi_module.c"
+#else
+#ifdef MODULE
+Scsi_Host_Template driver_template = MEGARAID;
 
 #include "scsi_module.c"
+#endif				/* MODULE */
+#endif				/* LINUX VERSION 2.4.XX  test */

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