Misc. changes for hardware support, from various sources.

---

 arch/i386/config.in             |   57 
 arch/i386/kernel/setup.c        |   71 
 drivers/ide/Config.in           |    1 
 drivers/ide/pci/Makefile        |    1 
 drivers/ide/pci/cs5535.c        |  452 ++++++
 drivers/ide/pci/cs5535.h        |   75 +
 drivers/isdn/hisax/config.c     |    8 
 drivers/isdn/hisax/gazel.c      |    6 
 drivers/isdn/isdn_common.c      |    4 
 drivers/isdn/isdn_net.c         |   11 
 drivers/isdn/isdn_ppp.c         |    3 
 drivers/scsi/aacraid/CHANGELOG  | 1606 +++++++++++++++++++++
 drivers/scsi/aacraid/Makefile   |  136 +
 drivers/scsi/aacraid/README     |   39 
 drivers/scsi/aacraid/TODO       |    5 
 drivers/scsi/aacraid/aachba.c   | 2989 +++++++++++++++++++++++++++++++---------
 drivers/scsi/aacraid/aacraid.h  | 1199 +++++++++++-----
 drivers/scsi/aacraid/commctrl.c |  602 ++++++--
 drivers/scsi/aacraid/comminit.c |  233 ++-
 drivers/scsi/aacraid/commsup.c  | 1611 +++++++++++++++++----
 drivers/scsi/aacraid/compat.h   |  256 +++
 drivers/scsi/aacraid/csmi.c     | 1686 ++++++++++++++++++++++
 drivers/scsi/aacraid/csmi.h     |  402 +++++
 drivers/scsi/aacraid/dpcsup.c   |  199 ++
 drivers/scsi/aacraid/fwdebug.c  |  343 ++++
 drivers/scsi/aacraid/fwdebug.h  |   51 
 drivers/scsi/aacraid/linit.c    | 2402 +++++++++++++++++++++++++-------
 drivers/scsi/aacraid/rkt.c      |  538 +++++++
 drivers/scsi/aacraid/rx.c       |  401 +++--
 drivers/scsi/aacraid/sa.c       |  243 +--
 include/asm-i386/msr.h          |    8 
 include/linux/pci_ids.h         |    2 
 32 files changed, 13385 insertions(+), 2255 deletions(-)

diff --git a/arch/i386/config.in b/arch/i386/config.in
index 6838057..8bc0034 100644
--- a/arch/i386/config.in
+++ b/arch/i386/config.in
@@ -42,6 +42,8 @@ choice 'Processor family' \
 	 Winchip-C6				CONFIG_MWINCHIPC6 \
 	 Winchip-2				CONFIG_MWINCHIP2 \
 	 Winchip-2A/Winchip-3			CONFIG_MWINCHIP3D \
+	 Geode-GX1/SC1200			CONFIG_GEODE_SC1200 \
+	 Geode-GX2/GX3				CONFIG_GEODE_GX2 \
 	 CyrixIII/VIA-C3			CONFIG_MCYRIXIII \
 	 VIA-C3-2				CONFIG_MVIAC3_2" Pentium-Pro
 #
@@ -139,9 +141,31 @@ if [ "$CONFIG_MK7" = "y" ]; then
    define_bool CONFIG_X86_GOOD_APIC y
    define_bool CONFIG_X86_USE_3DNOW y
    define_bool CONFIG_X86_PGE y
+   define_bool CONFIG_X86_USE_PPRO_CHECKSUM y 	
+   define_bool CONFIG_X86_F00F_WORKS_OK y
+fi
+
+if [ "$CONFIG_GEODE_SC1200" = "y" ]; then
+   define_int  CONFIG_X86_L1_CACHE_SHIFT 5
+   define_bool CONFIG_X86_USE_STRING_486 y
+   define_bool CONFIG_X86_ALIGNMENT_16 y
+   define_bool CONFIG_X86_HAS_TSC y
+   define_bool CONFIG_X86_PPRO_FENCE y
+   define_bool CONFIG_X86_F00F_WORKS_OK y
+fi
+
+if [ "$CONFIG_GEODE_GX2" = "y" ]; then
+   define_int  CONFIG_X86_L1_CACHE_SHIFT 5
+   define_bool CONFIG_X86_HAS_TSC y
+   define_bool CONFIG_MTRR n
+   define_bool CONFIG_X86_LOCAL_APIC n
+   define_bool CONFIG_X86_GOOD_APIC n
+   define_bool CONFIG_X86_PGE y
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
    define_bool CONFIG_X86_F00F_WORKS_OK y
+   define_bool CONFIG_X86_MCE n
 fi
+
 if [ "$CONFIG_MELAN" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 4
    define_bool CONFIG_X86_USE_STRING_486 y
@@ -192,7 +216,9 @@ if [ "$CONFIG_MWINCHIP3D" = "y" ]; then
    define_bool CONFIG_X86_F00F_WORKS_OK y
 fi
 
+if [ "$CONFIG_GEODE_GX2" != "y" ]; then
 bool 'Machine Check Exception' CONFIG_X86_MCE
+fi
 
 tristate 'Toshiba Laptop support' CONFIG_TOSHIBA
 tristate 'Dell laptop support' CONFIG_I8K
@@ -205,10 +231,19 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
    tristate 'BIOS Enhanced Disk Drive calls determine boot disk (EXPERIMENTAL)' CONFIG_EDD
 fi
 
-choice 'High Memory Support' \
+# GX2/3 does not have PAE support, so don't give em the option of 64G support
+
+if [ "$CONFIG_GEODE_GX2" != "y" ]; then
+	choice 'High Memory Support' \
 	"off    CONFIG_NOHIGHMEM \
 	 4GB    CONFIG_HIGHMEM4G \
 	 64GB   CONFIG_HIGHMEM64G" off
+else
+	choice 'High Memory Support' \
+	"off	CONFIG_NOHIGHMEM \
+	 4GB	CONFIG_HIGHMEM4G" off
+fi
+
 if [ "$CONFIG_HIGHMEM4G" = "y" -o "$CONFIG_HIGHMEM64G" = "y" ]; then
    define_bool CONFIG_HIGHMEM y
 else
@@ -223,16 +258,22 @@ if [ "$CONFIG_HIGHMEM" = "y" ]; then
 fi
 
 bool 'Math emulation' CONFIG_MATH_EMULATION
+
+if [ "$CONFIG_GEODE_GX2" != "y" ]; then
 bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR
+fi
+
 bool 'Symmetric multi-processing support' CONFIG_SMP
 if [ "$CONFIG_SMP" != "y" ]; then
-   bool 'Local APIC support on uniprocessors' CONFIG_X86_UP_APIC
-   dep_bool 'IO-APIC support on uniprocessors' CONFIG_X86_UP_IOAPIC $CONFIG_X86_UP_APIC
-   if [ "$CONFIG_X86_UP_APIC" = "y" ]; then
-      define_bool CONFIG_X86_LOCAL_APIC y
-   fi
-   if [ "$CONFIG_X86_UP_IOAPIC" = "y" ]; then
-      define_bool CONFIG_X86_IO_APIC y
+   if [ "$CONFIG_GEODE_GX2" != "y" ]; then
+   	bool 'Local APIC support on uniprocessors' CONFIG_X86_UP_APIC
+   	dep_bool 'IO-APIC support on uniprocessors' CONFIG_X86_UP_IOAPIC $CONFIG_X86_UP_APIC
+   	if [ "$CONFIG_X86_UP_APIC" = "y" ]; then
+      	define_bool CONFIG_X86_LOCAL_APIC y
+   	fi
+   	if [ "$CONFIG_X86_UP_IOAPIC" = "y" ]; then
+      	define_bool CONFIG_X86_IO_APIC y
+   	fi 
    fi
 else
    int  'Maximum number of CPUs (2-32)' CONFIG_NR_CPUS 32
diff --git a/include/asm-i386/msr.h b/include/asm-i386/msr.h
index ea2d626..2e87084 100644
--- a/include/asm-i386/msr.h
+++ b/include/asm-i386/msr.h
@@ -1,6 +1,8 @@
 #ifndef __ASM_MSR_H
 #define __ASM_MSR_H
 
+#include <linux/config.h>
+
 /*
  * Access to machine-specific registers (available on 586 and better only)
  * Note: the rd* operations modify the parameters directly (without using
@@ -17,8 +19,14 @@
 			  : /* no outputs */ \
 			  : "c" (msr), "a" (val1), "d" (val2))
 
+#ifdef CONFIG_GEODE_SC1200
+#define rdtsc(low,high) \
+     __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high)); \
+    if ((unsigned long) low > 0xFFFFFFFC) high--
+#else
 #define rdtsc(low,high) \
      __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
+#endif
 
 #define rdtscl(low) \
      __asm__ __volatile__("rdtsc" : "=a" (low) : : "edx")
diff --git a/drivers/scsi/aacraid/CHANGELOG b/drivers/scsi/aacraid/CHANGELOG
new file mode 100644
index 0000000..18d2d25
--- /dev/null
+++ b/drivers/scsi/aacraid/CHANGELOG
@@ -0,0 +1,1606 @@
+Version: 0.9.10
+
+Version: 1.1.2
+
+2003-05-15	Mark_Salyzyn@adaptec.com
+
+Differences between 2.4.21-rc2-ac2 kernel and our 1.1.2 versioned driver,
+changes as performed by Deanna Bonds, Bob Pasteur and Mark Salyzyn.
+
+aachba.c:
+	- If the state of a logical unit is hidden, then do not report. This
+	  state is typically entered when a device is being cleared.
+	- Added support for the Tallahassee project, where one channel is
+	  dedicated to SCSI, and the other channel is dedicated to RAID.
+	- Resolved some issues surrounding PAE support and IA64.
+	- If the driver is a not a boot disk driver, then set the Removable
+	  bit on the inquiry strings returned by the logical units to ensure
+	  that any changes in the arrays will be acquired when the device is
+	  re-attached.
+	- mask the SRB status with 0x3F to deal with misbehaving devices.
+	- Do not report DISKs to inquiry requests on the SCSI bus except if
+	  the channel is designated as a SCSI only bus.
+	- Propagate check conditions to the SCSI command result.
+	- Add support for programmable timeouts to propagate down toe the
+	  requests.
+	- If we have pae mode enabled, right after we get the adapter
+	  information and determine the pae mode capability, we enable the
+	  system to issue 64 bit requests.
+aacraid.h:
+	- Had to drop from 512 commands to 100 commands because some versions
+	  of the firmware would starve commands causing a timeout reaction
+	  which lead to lost commands.
+	- Added a global control variable for nondasd and paemode support.
+	- Dealt with some 64 bit / 32 bit issues in list_head structures and
+	  helper Macros, replacing them with our own more sensitive variants.
+	- Differentiated virtual and physical references to the shared fib
+	  allocations.
+	- information structure not synchronized to firmware, needed to add
+	  a clusterchannelmask.
+	- Added definitions in support of the new configuration information
+	  page bits in support of Tallahassee.
+	- Changed to an allocated fib pool, rather than an array in the hba
+	  structure as this affected the SCSI memory pool.
+	- Added some AIF definitions to permit us to sniff for container
+	  changes to permit a rescan to pick up new information or targets.
+commctrl.c:
+	- The fib reference was changed to a physical and a virtual address,
+	  absorb the name changes.
+	- The list_head structure handlers have been replaced with our own,
+	  absorb the name changes.
+	- The fib address reported in an AIF is a physical (32 bit) reference,
+	  and not a virtual (possibly 64 bit) reference.
+	- added the ioctl handling for sending a raw srb (FSACTL_SEND_RAW_SRB).
+comminit.c:
+	- Deal with IA64 issues.
+	- Change to using the physical address (32 bit) for the AIF references.
+	- The list_head structure handlers have been replaced with our own,
+	  absorb the name changes.
+	- Observed a memory leak, free up the queue resources should we fail
+	  to initialize the adapter.
+commsup.c:
+	- The fib reference was changed to a physical and a virtual address,
+	  absorb the name changes.
+	- Instead of panicking the kernel when a fib allocation was available,
+	  sleep until it is available.
+	- Submitted fib pointers are physical (32 bit) rather than virtual
+	  (possibly 64 bit) values.
+	- producer and consumer indexes should be converted over to local
+	  cpu endian before comparison.
+	- aac_handle_aif now sniffs AIF events and takes plug and play action
+	  for container changes.
+	- The aif thread is set up to be a kernel thread, and not a user
+	  thread. This permits us the ability to make plug and play calls
+	  without prejudice.
+	- Added instrumentation to the aif thread to confirm the plug and
+	  play activity and as an aid to several other debug sessions.
+	- Do not age an aif context based on the last received aif, but rather
+	  the last poll.
+dpcsup.c:
+	- The fib reference was changed to a physical and a virtual address,
+	  absorb the name changes.
+	- Submitted fib pointers are physical (32 bit) rather than virtual
+	  (possibly 64 bit) values.
+linit.c:
+	- Added paemode control.
+	- Added various upcoming board products, and documented better the
+	  existing board product ids. This includes SATA RAID products.
+	- needed to take the io_request_lock during portions of initialization.
+	- allocate the fib resource separately, rather than part of adapter
+	  structure to aid in the precious SCSI resources.
+	- cleanup of none dasd support options.
+	- Added more details about the build date of the driver to the proc
+	  information.
+	- dropped a change that permitted 64 bit DMA resources to be generated
+	  instead of through a 32 bit bounce buffer. (it was moved to aachba.c
+	  where it can be turned on after we determine the adapter's
+	  capabilities).
+	- max_id, max_lun and max_channel parameters are set after the
+	  adapter information has been picked up (the number of channels is
+	  based on the product id table now).
+sa.c:
+	- Context of timeout handling was incorrect, only noticed in IA64
+	  bit machines (due to lack of BIOS initialization).
+
+Differences that need further investigation and could be viewed as regressions
+and added after submission:
+
+rx.c:
+	- Dropped detection of failure to generate kernel command thread.
+sa.c:
+	- Dropped detection of failure to generate kernel command thread.
+
+Version: 1.1.3
+
+2003-07-01	Mark_Salyzyn@adaptec.com
+
+aachba.c:
+	- Added aac_get_container_name to permit override of array inquiry
+	  string with the set name.
+
+2003-07-08	Mark_Salyzyn@adaptec.com
+
+aachba.c:
+	- Return 0 (success) for unsupported commands, the check condition
+	  should perform the necessary action of error handling.
+
+2003-07-10	Mark_Salyzyn@adaptec.com
+
+aachba.c:
+	- The pass-through SCSI SCB command in PAE mode was getting the fib
+	  size count wrong, by using the 32 bit command, then doing an (n-1)
+	  times the size of the 64 bit scatter gather. Resolution was to
+	  subtract the 32 bit scatter gather, then do an n times the 64 scatter
+	  gather size.
+	- Only go into PAE mode if more than 4MB of memory in the system.
+
+2003-07-10	Mark_Salyzyn@adaptec.com
+
+linit.c:
+	- Added `Family' product codes and reordered the product discovery code
+	  to produce devices in PCI order rather than in product order.
+	  Dell, Legend and Adaptec Families were produced with the assumption
+	  of 2 available busses.
+
+2003-07-24	Mark_Salyzyn@adaptec.com
+
+linit.c:
+	- Added Bearcat (6 ch SATA) and a commented entry for Lancer where
+	  future workarounds may be necessary due to hardware constraints.
+	- Set highmem_io (for kernels of 2.4.18 and above).
+
+aachba.c:
+	- Set highmem_io (for kernels of 2.4.18 and above; and when the
+	  adapter is guaranteed to handle the possible address ranges it
+	  will be provided).
+
+Version: 1.1.4:
+
+2003-07-28	Mark_Salyzyn@adaptec.com
+
+aacraid.h+common/include/fsaioctl.h+aachba.c
+	- Added the FSACTL_REGISTER_FIB_SEND function to the ioctl. This ioctl
+	  is *not* a user accessible ioctl, meant only for driver use to permit
+	  stacking a filter driver just ahead of the hardware layer. The call
+	  to register is:
+
+		typedef void (*fib_callback)(void *ctxt, struct fib *fibctx);
+		typedef struct {
+			int (*fib_send)(u16 command,
+					struct fib * context,
+					unsigned long fib_size,
+					int priority,
+					int wait,
+					int reply
+					fib_callback callback,
+					void * ctxt);
+		} fib_send_t;
+		. . .
+		fib_send_t original;
+		int dummy_fib_send (u16 command,
+				    struct fib * context,
+				    unsigned long fib_size,
+				    int priority,
+				    int wait,
+				    int reply
+				    fib_callback callback,
+				    void * ctxt)
+		{
+			return (*original->fib_send)(command, context, fib_size, priority, wait, reply, callback, ctxt);
+		}
+		. . .
+		Scsi_Host_Template * host;
+		Scsi_Device * adapter;
+		original->fib_send = dummy_fib_send;
+		host->ioctl(adapter, FSACTL_REGISTER_FIB_SEND, &original);
+
+	  Return value from the ioctl include ENOTTY (not supported), EINVAL
+	  (invalid argument pointer) and EBUSY (another function already
+	  registered) and the original fib_send function is returned in the
+	  ioctl argument structure. A NULL value for the fib_send member of the
+	  structure deregisters the filter driver. The fib_callback function is
+	  issued at interrupt priority and should follow all the constraints of
+	  interrupt operation. It is the responsibility of the registered
+	  fib_send function to ensure that the original fib_callback function
+	  is called with the ctxt value when completing the command (this
+	  subtlety is lost in the above dummy function).
+
+2003-07-28	Mark_Salyzyn@adaptec.com
+
+linit.c:
+	- Added Kernel, Firmware and BIOS revision and build number to proc
+	  information.
+	- Added board serial number to proc information.
+
+aachba.c:
+	- Do not set removable bit in the inquiry command, the aif delivery
+	  of array status change will handle the reasons for the removable
+	  bit (capacity change and differences in the partition table). Some
+	  customers take issue with the fact our arrays appear as removable.
+
+commctrl.c:
+	- Reported driver version and build number instead of Firmware version
+	  and build number for the Miniport Version Check ioctl. ADPmp57715
+
+2003-08-06	Mark_Salyzyn@adaptec.com and a cast of thousands
+
+all files:
+	- Added appropriate ifdefs, or merged in additions, in support of the
+	  2.6.0-test2 kernels as follows:
+
+Makefile:
+	- Added ifdefs for 2.4 and 2.6 kernels so we can use a common Makefile
+	  for both kernel build environments.
+
+aachba.c:
+	- use linux/blkdev.h in 2.5+ kernels.
+	- define aac_spin_* macros to differentiate between lock requirements
+	  in 2.5+ and 2.4 kernels.
+	- Use the SCSI layers definitions of the SCSI commands, rather than
+	  our own internal SS_* manifests.
+	- Define SCSICMD_TO_* macros to acquire the SCSI target host, channel,
+	  id and lun.
+	- Use the 2.6 SAM_* status codes for return, the 2.4 system will
+	  redefine the SAM_* codes to 2.4 variants.
+	- Change to devname instead of devno when referencing devices to
+	  simplify conversions.
+	- MAXIMUM_NUM_CONTAINERS references were +/- 1 in comparisons, made
+	  this value a `number' rather than a mix of `number' and `limit'.
+	- Resolved `Cast of pointer from integer of different size' by
+	  (void *)(ulong)dma_addr_t.
+	- Change to `id' rather than `target' to match SCSI subsystem
+	  references name for consistency.
+
+aacraid.h:
+	- MAXIMUM_NUM_CONTAINERS references were +/- 1 in comparisons, made
+	  this value a `number' rather than a mix of `number' and `limit'.
+	- Removed AAC_MAX_TARGET, as it is no longer used.
+	- Added CONTAINER_TO_* macros to simplify references.
+	- Change to `id' rather than `target' to match SCSI subsystem
+	  references name for consistency.
+	- Change to devname instead of devno when referencing devices.
+	- Use cap_to_cyls inline to handle 64 bit calculation correctly.
+
+commctrl.c:
+	- use linux/blkdev.h in 2.5+ kernels.
+	- Change to `id' rather than `target' to match SCSI subsystem
+	  references name for consistency.
+
+comminit.c:
+	- use linux/blkdev.h in 2.5+ kernels.
+
+commsup.c:
+	- use linux/blkdev.h in 2.5+ kernels.
+	- Moved CONTAINER_TO_* macros to aacraid.h to simplify references.
+	- Device Discovery loops are different for 2.4 and 2.5+ kernels,
+	  use list_for_each_entry siblings instead of host_queue loop.
+	- daemonize adds the process name as a parameter, and requires
+	  SIGKILL to be enabled to permit kernel shutdown in 2.5+ kernels.
+
+dpcsup.c:
+	- use linux/blkdev.h in 2.5+ kernels.
+
+linit.c:
+	- use linux/blkdev.h in 2.5+ kernels.
+	- added aacids to provide a table hint for installers.
+	- changed over to utilize ANSI structure initialization.
+	- aac_biosparm and aac_procinfo change parameters in 2.5+ kernels.
+	- aac_slave_configure replaces aac_queuedepth in 2.5+ kernels.
+	- detect no longer needs to unlock io_request_lock to do it's duty
+	  in 2.5+ kernels.
+	- use SCSI_set_device in 2.5+ kernels rather than scsi_set_pci_device.
+	- Change to devname instead of devno when referencing devices to
+	  simplify conversions.
+	- Use MAXIMUM_NUM_CONTAINERS rather than AAC_MAX_TARGET
+	- Use cap_to_cyls inline to handle 64 bit calculation correctly in
+	  aac_biosparm.
+	- Use minor in 2.5+ kernels instead of MINOR macro.
+
+rx.c:
+	- use linux/blkdev.h in 2.5+ kernels.
+	- interrupts now return irqreturn_t.
+
+sa.c:
+	- use linux/blkdev.h in 2.5+ kernels.
+	- interrupts now return irqreturn_t.
+
+2003-08-15	Mark_Salyzyn@adaptec.com
+
+install.sh:
+	- increased range of kernel version reports in the magic file to 30.
+
+2003-08-19	Mark_Salyzyn@adaptec.com & ijohns@elipsan.com
+
+aachba.c:
+	- status_byte in the result is shifted down by one.
+	- set_sense spoof was not immediately followed by a copy of the check
+	  condition results into the SCSI command.
+
+2003-08-20	Mark_Salyzyn@adaptec.com, Scott_Long@adaptec.com & Alan Cox
+
+commctrl.c:
+	- The raw SCSI SCB ioctl command in PAE mode was getting the fib
+	  size count wrong, by using the 32 bit command, then doing an (n-1)
+	  times the size of the 64 bit scatter gather. Resolution was to
+	  subtract the 32 bit scatter gather, then do an n times the 64 scatter
+	  gather size.
+
+aacraid.h:
+	- Added definition of CT_FLUSH_CACHE command and structures.
+	- Added AAC_QUIRK_31BIT for ROMB based adapters.
+
+linit.c:
+	- Added AAC_QUIRK_31BIT for ROMB based adapters.
+	- Check return from scsi_register.
+
+aachba.c:
+	- Added support for issuing CT_FLUSH_CACHE command when the SCSI
+	  SYNCHRONIZE command is issued to a container.
+	- Restored mask after adding AAC_QUIRK_31BIT for ROMB based adapters.
+
+2003-08-21	Mark_Salyzyn@adaptec.com
+
+aachba.c:
+	- Changed aac_get_container_name to be a none-blocking function,
+	  completing the incoming scsicmd with the adapter response.
+
+2003-08-26	Mark_Salyzyn@adaptec.com
+
+commsup.c + aacraid.h:
+	- Altered handling of AIF messages from Firmware to differentiate
+	  events in a finer grained manner.
+
+2003-08-29	Mark_Salyzyn@adaptec.com
+
+aachba.c + aacraid.h
+	- Driver too noisy, undefined AAC_DETAILD_STATUS_INFO and incorporated
+	  check condition report into the AAC_DETAILED_STATUS_INFO ifdef.
+
+2003-09-03	Mark_Salyzyn@adaptec.com
+
+aachba.c:
+	- Check if the device is in use and report that as a locked device
+	  to both the FSACTL_QUERY_DISK and FSACTL_DELETE_ARRAY ioctls.
+	- unlock/lock around probe_container as this is a blocking function.
+	  This change addresses a deadlock issue that surfaced in SMP only
+	  environments.
+
+Version: 1.1.4-2172
+
+2003-09-04	Mark_Salyzyn@adaptec.com
+
+commsup.c:
+	- References to the Status Job update structure were at incorrect
+	  offsets causing incorrect operation during an Array Clear with
+	  regards to plug and play actions.
+
+Version: 1.1.4-2177
+
+2003-09-05	Mark_Salyzyn@adaptec.com
+
+aachba.c:
+	- Cleanup request from the SCSI list maintainers.
+	- Dropped use of SCSICMD_TO_CHANNEL & friends since
+	  scsicmd->device->channel is available in all versions of the
+	  operating system.
+	- Removed deprecated code and/or comments related to deprecation.
+	- include <linux/blkdev.h> works in all versions of the operating
+	  system.
+
+2003-09-09	Mark_Salyzyn@adaptec.com
+
+aacraid.h:
+	- NUM_FIBs should be 64 larger (AIFS) larger than the NUM_IO_FIBS.
+
+commsup.c:
+	- efficiency improved if we hold on to the aac_queue variable, aims
+	  towards better code compliance and consistency.
+
+2003-09-15	Mark_Salyzyn@adaptec.com
+
+rkt.c:
+	- Copy if rx.c with rx = rkt
+
+aacraid.h:
+	- Added definition for rkt interface structures, copy of rx, but a
+	  larger reserved region.
+
+linit.c:
+	- Added product code for ROC (Lancer/Rocket) U320 two channel, use rkt
+	  interface.
+
+2003-09-16	Mark_Salyzyn@adaptec.com
+
+linit.c:
+	- Show Adapter vendor and model in proc information.
+
+Version: 1.1.4-2185
+
+2003-09-16	Mark_Salyzyn@adaptec.com
+
+aacraid.h:
+	- Added definition of nblank() to assist us in determining if
+	  dprintk(x) is defined as a blank definition to enable us to ifdef
+	  debug code that ends up calling only dprintk functions.
+
+commsup.c:
+	- Ignore events that refer to containers > MAXIMUM_NUM_CONTAINERS
+	- include <linux/blkdev.h> works in all versions of the operating
+	  system.
+
+linit.c:
+	- print more details about outstanding commands when a SCSI hang
+	  occurs (first use of nblank() macro just defined in aacraid.h)
+
+2003-09-19	Mark_Salyzyn@adaptec.com & Mark Haverkamp <markh@osdi.org>
+
+commsup.c & aachba.c:
+	- valid flag has added support for a value of 2, which means target
+	  is still valid, but needs a probe_container.
+
+commsup.c:
+	- fib_alloc should not go to sleep, but return NULL if there are no
+	  available entries in the pool.
+
+dpcsup.c:
+	- print a message if the fib kmalloc fails when forwarding AIFs
+
+comminit.c:
+	- check fib_alloc return, and report -ENOMEM should the pool be
+	  empty.
+
+aachba.c:
+	- Check value of scsicmd->scsi_done in aac_io_done as we can get
+	  errant firmware which returns commands twice (no released firmware
+	  does this, this is a driver hardening issue only).
+	- When a fib_alloc fails, return -1 to SCSI layer. Formerly, we would
+	  send the command with DID_ERROR.
+
+Version: 1.1.4-2192
+
+2003-09-25	Mark_Salyzyn@adaptec.com
+
+linit.c:
+	- Moved debug variables into block to reduce impact on none-debug
+	  environments.
+
+dpcsup.c + commsup.c:
+	- Use the fib pool instead of a kmalloc to allocate a fib for the
+	  processing of an AIF.
+
+install.sh:
+	- Install driver into any forgotten /lib/modules directories.
+
+2003-09-26	Mark_Salyzyn@adaptec.com
+
+commctrl.c + aacraid.h:
+	- AMD-64 and IA-64 management applications will fail, need to change
+	  fibctx to a 32 bit unique value.
+
+Version: 1.1.4-2194
+
+2003-09-29	Mark_Salyzyn@adaptec.com & Mark Haverkamp <markh@osdi.org>
+
+aachba.c:
+	- use linux/blkdev.h for all variants on Linux.
+	- hold on to the host pointer in aac_io_done, because it's reference
+	  in the device and scsicmd can go away after scsi_done is called.
+	- check return value of pci_set_dma_mask.
+
+commctrl.c:
+	- use linux/blkdev.h for all variants on Linux.
+
+comminit.c:
+	- use linux/blkdev.h for all variants on Linux.
+
+commsup.c:
+	- use linux/blkdev.h for all variants on Linux.
+	- drop linux/smp_lock.h include as it was added in a debug test from
+	  some time ago.
+	- Added current 2.6 kernel support routines for rescanning.
+
+dpcsup.c:
+	- use linux/blkdev.h for all variants on Linux.
+
+linit.c:
+	- use linux/blkdev.h for all variants on Linux.
+	- check return value of pci_set_dma_mask.
+	- template->present is no longer relevant in 2.6 based kernels.
+
+rx.c:
+	- use linux/blkdev.h for all variants on Linux.
+
+sa.c:
+	- use linux/blkdev.h for all variants on Linux.
+
+rkt.c:
+	- use linux/blkdev.h for all variants on Linux.
+
+2003-10-01	Mark_Salyzyn@adaptec.com
+
+commsup.c:
+	- needed a fib_dealloc call ahead of the fib_free call added when
+	  we moved over to the fib pool to handle the AIFs.
+
+dpcsup.c:
+	- need to use the `local' fibctx so that the AIF command can be
+	  acknowledged.
+
+commctrl.c:
+	- return error status from the send_fib function in ioctl_send_fib.
+
+2003-10-07	Mark_Salyzyn@adaptec.com
+
+aachba.c + linit.c:
+	- serial number contains the cookie (fafa0001) that is at index 1
+	  of the serial number element. Only show the serial number which
+	  is at index 0.
+
+linit.c:
+	- Added registration to receive 32 bit ioctls.
+
+commsup.c + dpcsup.c + aacraid.h:
+	- Dropped code to acquire AIF's from the general FIB pool, it was a
+	  fool's errand. However, we kept the code that limits the AIF's
+	  received and allocated to the AdapterFibsSize / sizeof(hw_fib).
+	  The `last' AIF hw_fib is used to quickly acknowledge the entries,
+	  and drop the results on the floor.
+
+rx.c + rkt.c:
+	- Cache the OIMR data in dev->OIMR, it looks remarkably like irq_mask,
+	  which is really unused, but we can clean that up later.
+
+2003-10-08	Matthew Wilcox <willy@debian.org>
+
+aachba.c:
+	- Use SCp.dma_handle instead of SCp.ptr for holding on to the physical
+	  address of the allocated pci_map_single as part of the request.
+
+compat.h:
+	- define dma_handle to be ptr (in support of SCp.dma_handle change
+	  above) for kernels that do not define this member.
+
+2003-10-08	Christoph Hellwig <hch@infradead.org>
+
+aachba.c:
+	- drop use of scsi_to_pci_dma_dir() as it is a pass-through in all
+	  versions of the kernel.
+
+2003-10-09	Mark_Salyzyn@adaptec.com
+
+linit.c:
+	- When an Adapter Reset is requested, wait up to 60 seconds for all
+	  outstanding commands to complete and report SUCCESS.
+
+Version: 1.1.4-2221
+
+2003-10-09	Mark_Salyzyn@adaptec.com
+
+linit.c:
+	- Waited for *all* commands to complete for *all* devices on the
+	  controller when an Adapter Reset is requested.
+
+Version: 1.1.4-2222
+
+2003-10-10	Mark_Salyzyn@adaptec.com
+
+aacraid.h + rx.c + rkt.c + sa.c + linit.c:
+	- Added a aac_adapter_check_health, make sure the adapter is healthy
+	  when performing and Adapter Reset request, report error codes.
+
+aachba.c:
+	- revert to use of scsi_to_pci_dma_dir() as it is not a pass-through in
+	  all versions of the kernel.
+
+linit.c:
+	- SCSI_HAS_HOST_LOCK means that we should be working with releasing
+	  host->lock or host->host_lock instead of io_request_lock surrounding
+	  scsi_sleep.
+
+aacraid.h:
+	- Added definition for AAC_MAX_HOSTPHYSMEMPAGES
+
+comminit.c:
+	- Utilized AAC_MAX_HOSTPHYSMEMPAGES to limit the number of open DMA
+	  4096 byte PAGES of memory requested by the operating system.
+
+2003-10-16	Mark_Salyzyn@adaptec.com
+
+install.sh:
+	- Added support for x86_64 installs
+
+aachba.c:
+	- used SENSE KEYS from scsi.h rather than our own definitions.
+
+2003-10-20	Xose Vazquez Perez <xose@wanadoo.es>
+
+linit.c:
+	- Added pci_ids for 0x10110046/0x90050365
+
+Version: 1.1.4-2265
+
+2003-10-23	Mark_Salyzyn@adaptec.com
+
+linit.c:
+	- no need to set template->present as this is done by the SCSI layer.
+
+2003-10-24	Mark_Salyzyn@adaptec.com
+
+install.sh
+	- Added support for SuSE kernel determination for finer selection
+	  of modules
+	- If the kernel is compiled for athlon, use that instead of
+	  /proc/cpuinfo
+	- if /proc/cpuinfo is not present, don't show any errors during
+	  install
+
+2003-10-28	Mark_Salyzyn@adaptec.com
+
+install.sh
+	- The entire class of SuSE OS releases (sles7, sles8, suse7, suse8,
+	  suse8.1, suse8.2, ul1, ul1-sp2a) place the driver module results into
+	  /lib/modules/[kernel]/kernel/drivers/scsi/aacraid/aacraid.o. The
+	  package places updates in ...//scsi/aacraid.o (note, one directory
+	  up). The module selected for use in the mkinitrd is fed via a `find'
+	  command which reports files in raw directory order which in the
+	  reiser file system would be in the .../scsi directory, but for EXT2
+	  since the file was added later, would prefer the previously placed
+	  product in ../scsi/aacraid/aacraid.o. The fix is to have the driver
+	  disk post-install remove the older .../scsi/aacraid directory.
+
+2003-10-30	Mark_Salyzyn@adaptec.com
+
+install.sh
+	- For the installations to `extra' /lib/modules directories beyond
+	  the boot set, take the processor clue from the postscript (-athlon,
+	  -x86_64 or -ia64) rather than from /proc/cpuinfo.
+
+Version: 1.1.4-2282
+Version: 1.1.4-2292 (Debug)
+
+2003-10-31	Mark_Salyzyn@adaptec.com
+
+aacraid.h + aachba.c:
+	- Added a nested count to the fsa_scsi_dev structure since some kernels
+	  before 2.4.19 have troubles overflowing their stack when a device
+	  goes offline. The issue is that the SCSI done call nests into sending
+	  another queued command, which in turn spoofs a response back
+	  indicating failure which in turn calls SCSI done. We limit the
+	  nesting to 64 commands before we respond with a busy instead.
+
+Version: 1.1.4-2296 (Debug)
+
+linit.c & .version:
+	- Versioning is defined by the structure:
+	    struct {
+		unsigned char dash; // Dash version number
+		unsigned char type; // Type, 1=Devo, 2=Alpha, 3=Beta, 4=Release
+		unsigned char minor;// Minor version minor
+		unsigned char major;// Major version number
+	    }
+	  Adjusted version data to match this definition for generation and
+	  support.
+
+Version: 1.1.4-2299
+Version: 1.1.4-2301
+Version: 1.1.4-2302
+Version: 1.1.4-2303
+
+linit.c & aacraid.h:
+	- Allow 64 bit apps to call GET_NEXT_ADAPTER_FIB ioctl directly,
+	  promoting 32 bit apps when they call.
+
+aachba.c & aacraid.h:
+	- Set MAX_NESTED to 1, and improve code to reflect this simplicity.
+
+install.sh:
+	- Handle name change of products from *-athlon-athlon to *-athlon.
+	- Warn the user if the initrd shrinks too much
+
+Version: 1.1.4-2308
+
+install.sh:
+	- Add support for identifying 2.4.19-340 kernels.
+
+2003-12-12	Mark Haverkamp <markh@osdl.org>
+
+linit.c:
+	- updated aac_eh_reset to use __shost_for_each_device now that the
+	  device element is now private and we're supposed to use the helper
+	  function for access.
+
+Version: 1.1.4-2309
+Version: 1.1.4-2310 (debug)
+
+2003-12-18	Mark Salyzyn <Mark_Salyzyn@adaptec.com>
+
+linit.c:
+	- suppress unused variable warning in debug code.
+	- cast sys_ioctl when registering as it does not match prototype
+	  argument for ioctl32 registration.
+
+Version: 1.1.4-2311
+
+2003-12-22	Mark Haverkamp <markh@osdl.org>
+
+aachba.c:
+	- change from pae to dac as this is the more public understanding of
+	  the 64 bit support concepts.
+aacraid.h:
+	- Remove padding and SavedIrql
+commsup.c + aachba.c:
+	- use atomic_read when accessing access_count member of device
+	  structure.
+linit.c & aacraid.h
+	- iminor takes the inode, not the inode->i_rdev member.
+
+Version: 1.1.4-2313
+
+aachba.c + commsup.c:
+	- use device_busy, shost_status, in_recovery instead of just
+	  access_count. Adjust for each OS release variant.
+
+Version: 1.1.4-2314
+
+2003-12-22: Ken Beaty <ken@nova.org>
+
+aachba.c + commsup.c:
+	- Adjusted ifdefs for kernel version to make more sense.
+
+2004-01-24: Mark Salyzyn <Mark_Salyzyn@adaptec.com>
+
+install.sh:
+	- Altered script to discover prebuilt binaries from the classic
+	  Adaptec rpm package, the Red Hat install disk format, or the
+	  SuSE install disk format.
+
+2004-02-09: Christoph Hellwig <hch@lst.de>
+
+aachba.c:
+	- Remove fsa_dev structure since fsa_dev is always available.
+
+Version: 1.1.4-2324
+
+2004-02-10: Submit to scsi list for inclusion
+
+2004-02-17: Herve MORILLON <hmorillon@doremilabs.fr> + Mark_Salyzyn@adaptec.com
+
+rx.c + rkt.c:
+	- hit doorbell before processing host_command_normal
+
+aachba.c:
+	- Permit requests larger than 64KB
+
+aacraid.h:
+	- Permit 512 outstanding requests
+
+Version: 1.1.5-2326
+
+linit.c + build:
+	- Added support for vary_io, unfortunately the build system also needed
+	  to be adjusted to generate the SCSI_HAS_VARY_IO if the member is
+	  seen in the drivers/scsi/hosts.h file.
+
+build + install.sh:
+	- Added support for 2.4.19-189, 2.4.19-191 and 2.4.19-201 SuSE Kernels
+
+Version: 1.1.5-2327
+
+rkt.c + rx.c:
+	- Added support to issue the Temperature sync command. Since the
+	  cost of the sync command should not increase, the decision was
+	  made to support a `varargs' approach to dealing with the additional
+	  temperature elements *only* for this command.
+
+linit.c:
+	- Added a proc write that accepts the string "Temperature=[0-9.],..."
+	  to send the off-board temperature value to the Firmware so that it
+	  may be integrated into the Enclosure Data.
+	- Added SkyHawk SATA cards to device list. 2020S changes now to 
+	  2020ZCR, and we add 2020SA.
+
+aachba.c:
+	- PERCRAID RAID-5 is superfluous, changed to to PERC RAID-5.
+
+Version: 1.1.5-2328
+
+linit.c + aacraid.h:
+	- Migrate towards using CONFIG_COMPAT instead of __x86_64__
+
+rx.c + rkt.c:
+	- Added support to pick up an Adapter Blink code. ADPmp64499.
+
+linit.c:
+	- Report the Adapter Blink code to the console log. ADPmp64499.
+
+build:
+	- Correctly built the x86_64 SLES8 and ul1 driver disk. Side effects
+	  discovered also fix problems with ia32 SLES8 install. ADPmp64499.
+
+Version: 1.1.5-2329
+
+linit.c + aacraid.h:
+	- Report an AifExeFirmwarePanic AIF message to applications when the
+	  adapter is in a blinkled state.
+
+aachba.c + commsup.c: Brad House <brad@mainstreetsoftworks.com>
+	- use shost_for_each_device instead of list_for_each_entry.
+
+linit.c + aachba.c:
+	- xscale (arm) systems can not have highmem_io set as virtual/phys
+	  handling does not recognize the page/offset addressing.
+
+rkt.c + rx.c:
+	- The Mailbox[7] in none BBS systems is not active until shortly
+	  before the Firmware kernel is booted. The Outbound Message register
+	  is always active and contains the same bringup conditions. We must
+	  look at the OMR during the *_init wait.
+
+Version: 1.1.5-2330
+
+rkt.c + rx.c + sa.c:
+	- Set the time by using get_seconds (epoch January 1 1970) instead
+	  of jiffies/HZ (epoch machine startup). get_seconds is provided
+	  for kernels < 2.6.
+
+Version: 1.1.5-2331
+
+rkt.c:
+	- Mailbox[7] becomes momentarily inaccessible right after PATUWAIT
+	  on the Callisto, lets loop on OMR only. Do not know if this
+	  problem exists on other systems.
+
+Version: 1.1.5-2332
+
+aachba.c + linit.c:
+	- Issue CT_COMMIT_CONFIG before issuign the VM_NameServe. This is
+	  for systems that do not have a BIOS to perform this step.
+
+Version: 1.1.5-2333
+
+aacraid.h:
+	- SAS requires the ability to handle as many as 32 Adapters in a
+	  system, increased the manifest that limits the number of Adapters.
+	- Testing has shown that allowing 33MB I/O can starve a machine, so
+	  we are limiting the maximum I/O size to 4MB (to match other drivers
+	  that permit large I/O).
+
+linit.c:
+	- Make sure that the driver does not register more than
+	  AAC_MAXIMUM_ADAPTERS instances.
+	- Set the queue depth to each device as divided up from AAC_MAX_IO_FIB
+
+commctrl.c: Chris Wright <chrisw@osdl.org>
+	- aac_send_raw_srb added check for bounding of fibsize value.
+
+all: Mark Haverkamp <markh@osdl.org> & Mark Salyzyn <Mark_Salyzyn@adaptec.com>
+	- merge 2.6 driver changes into tree to synchronize.
+
+Version: 1.1.5-2334
+
+aacraid.h+linit.c+commctrl.c+comminit.c:
+	- Added sg_tablesize and max_fib_size to adapter structure and
+	  negotiate these plus Scsi_Host sg_tablesize, can_queue and
+	  max_sectors based on the adapter capabilities.
+
+aachba.c:
+	- Added aac_raw_io command
+	- Recognize that read_callback is identical to write_callback, which
+	  is in turn identical to raw_io's need for a callback. Renamed to
+	  one callback function io_callback.
+
+rx.c+rkt.c+sa.c:
+	- Moved initialization around to permit New Command Interface probes
+	- dropped irq_mask and associated functions.
+	- moved acknowledgement of F/W commands *before* processing so that
+	  we get re-interrupted if a new command is added to the produced
+	  index while we are processing.
+
+linit.c+aachba.c:
+	- Do not print `bad0' for the serial number
+
+linit.c:
+	- this_id = 32, because it gets in the way of Container 16 being
+	  processed.
+
+aachba.c:
+	- scsi_add_timer call issued just before completion routine called
+	  since error recovery handler is there *just* to detect card
+	  failure and not to affect command processing.
+
+build:
+	- Added 2.4.19.SuSE-343 kernel in support of ul1-sles8-ia32 install,
+	  which adds yet another installation floppy to the list.
+
+Version: 1.1.5-2335
+
+linit.c+all:
+	- Revert temporarily to 1.1.4-2177, Changed ASR-2020S to ASR-2020ZCR,
+	  and ASR-2020S Terminator to ASR-2025ZCR.
+
+Version: 1.1.4-2336
+
+linit.c+all:
+	- Revert temporarily to 1.1.4-2322, Changed ASR-2020S to ASR-2020ZCR,
+	  and ASR-2020S Terminator to ASR-2025ZCR.
+
+Version: 1.1.4-2337
+
+all:
+	- Revert back to 1.1.5 code base.
+
+commsup.c:
+	- Fix Irq Moderation code. A Misnomer, since this is really a PCI
+	  utilization moderation, interrupts are not recurring on F/W.
+
+comminit.c:
+	- Turn on Irq Moderation feature (Tentatively 30% reduction in Host
+	  CPU utilization)
+
+Version: 1.1.5-2337
+
+aacraid.h+commsup.c+dpcsup.c+comminit.c+rx.c:
+	- Added support for the new comm interface.
+
+linit.c:
+	- Added debug information to proc output
+
+Version: 1.1.5-2338
+
+commsup.c: Mark Haverkamp <markh@osdl.org>
+	- Added scsi/scsi_device.h, scsi/scsi_driver.h to include file set
+	- set removable to a value of 1, not to TRUE.
+
+aachba.c: Mark_Salyzyn@adaptec.com
+	- Switch to using max_fib_size rather than FIB_DATA_SIZE_IN_BYTES,
+	  this permits SAS management applications to send ioctl FIBs larger
+	  than 512 bytes in size to adapters that accept larger FIBs.
+	- Added support for SAI_READ_CAPACITY_16, READ_12, WRITE_12, READ_16
+	  and WRITE_16 commands.
+	- Played `tricks' with device_blocked and queue_depth fields in the
+	  scsi_device structure to meter the outstanding commands down when
+	  large sequential activity is detected.
+
+aacraid.h: Mark_Salyzyn@adaptec.com
+	- Remove unused definition of FIB_DATA_SIZE_IN_BYTES.
+
+linit.c:
+	- Setting the maximum number of I/O requests/device to a maximum of
+	  256 would act in the SCSI layer as only allocating to permit 1 I/O
+	  for each device.
+
+Version: 1.1.5-2339
+
+build: Mark_Salyzyn@adaptec.com
+	- Added support for 2.6.4-52 SuSE 9.1 Pro install
+	- Added support for multiple architectures for 2.4.21-15.EL RHEL3 QU2
+	  install.
+
+aacraid.h+aachba.c+linit.c: Mark Haverkamp <markh@osdl.org>
+	- Define 2131 as FSACTL_GET_CONTAINERS
+
+commctrl.c: Adam Manthei <amanthei@redhat.com>, Mark_Salyzyn@adaptec.com
+	- change all printk() to dprintk(()) as this is a user initiated
+	  call for aac_send_rw_srb & aac_get_pci_info.
+
+rx.c+rkt.c: Adam Manthei <amanthei@redhat.com>, Mark_Salyzyn@adaptec.com
+	- use pci_alloc_consistent/pci_free_consistent instead of an
+	  unchecked combination of kmalloc(,_GFP_DMA)/pci_map_single/
+	  pci_unmap_single/kfree.
+
+Version: 1.1.5-2340
+
+linit.c+commctrl.c: Mark Haverkamp <markh@osdl.org>
+	- adjust to reflect linux-scsi submission results
+
+aachba.c: Mark_Salyzyn@adaptec.com
+	- remove print for unhandled commands into a debug print. The
+	  unhandled commands are reported to the caller as unhandled, let
+	  the caller deal with this.
+
+rx.c+rkt.c+sa.c: maximilian attems <janitor@sternwelten.at>
+	- upon failure of the init routine, make sure that the registered
+	  interupt handler is deregistered.
+
+commsup.c:
+	- fib_adapter_complete is supposed to free the hw_fib and that is it,
+	  it tried to talk to hardware and caused a lockup.
+
+Version: 1.1.5-2341
+
+build:
+	- use aacraid.ko for 2.6 releases
+
+Version: 1.1.5-2342
+
+aachba.c: Mark_Salyzyn@adaptec.com
+	- added support for a module parameter 'commit=1' to enable COMMIT
+	  CONFIG to be issued to the adapter.
+	- added support for a module parameter 'coalescethreshold=16' which
+	  sets the maximum block size to consider for pushing back to the
+	  scsi_merge layer.
+	- added support for a module parameter 'acbsize=8192' which sets the
+	  suggested fib size to override the suggestion from Firmare.
+	- dropped call to scsi_add_timer, as it causes a panic. It was placed
+	  in the source to resolve a command completion race condition.
+
+Version: 1.1.5-2343
+
+install.sh: Mark_Salyzyn@adaptec.com
+	- globbing issue caused more whiny complaints about a missing
+	  installation into the initrd.
+	- fixed some issued surrounding using the script for SuSE module
+	  update.
+
+linit.c: Mark_Salyzyn@adaptec.com
+	- if the driver does not discover any targets, report failure.
+	- drop kernel_version hack to support build
+
+build: Mark_Salyzyn@adaptec.com
+	- Use vermagic instead of kernel_version to pick up matching kernel.
+	- when innoculating 2.6 tree builds, one needs a *full* compile in
+	  order to generate the struct_module member.
+	- use module.ko for 2.6 kernels.
+
+Version: 1.1.5-2344
+
+build: Mark_Salyzyn@adaptec.com
+	- floppy linux/suse/${ARCH}-${VERS}/modules/${PRODUCT}.o needs to be
+	  a ${PRODUCT}.ko in the 2.6 based installations.
+	- Placed module in both scsi and scsi/${PRODUCT} directories as it
+	  appears that the post-install is not functioning properly.
+
+aachba.c: Mark_Salyzyn@adaptec.com
+	- Checked if the lba exceeds 32 bit block address for systems that
+	  can not support it. raw_io_64 enables 64 bit block addresses.
+	- Redid math for u64 >> 32 as it appears the xscale 64 bit library
+	  is flawed.
+
+Version: 1.1.5-2345
+
+aachba.c: Mark_Salyzyn@adaptec.com
+	- Overrides to force 8KB fibs needs to be reverted to defaults.
+
+Version: 1.1.5-2346
+
+build: Mark_Salyzyn@adaptec.com
+	- Added 2.4.21-15.0.2.EL kernel
+	- Added 2.6.5-7.97 kernel to the build
+
+rx.c+rkt.c: Mark_Salyzyn@adaptec.com
+	- Mailbox7 continues to be a consternation regarding reliable
+	  adapter recovery scenarios; switched to using OMRx[0].
+
+Version: 1.1.5-2347
+
+aachba.c: Mark_Salyzyn@adaptec.com
+	- (u64)=((u8)<<24) does not give expected results, sign extension
+	  occurs. Replace with (u64)=((u64)(u8)<<24)
+
+Version: 1.1.5-2348
+
+install.sh: Mark_Salyzyn@adaptec.com
+	- initrd is blocked from incorporating our product if there is
+	  something in /lib/modules/${OS}-${CONFIG}/update/${PRODUCT}.o,
+	  so remove the file.
+
+Version: 1.1.5-2349
+
+aachba.c+aacraid.h:
+	- define commit_config FIB command
+	- define get_container_count FIB command.
+
+aachba.c+aacraid.h+commsup.c+linit.c
+	- fsa_dev becomes a dynamic structure to accommodate a variable
+	  maximum_num_containers.
+
+build:
+	- Added 2.4.21-231 kernel to build system.
+
+linit.c:
+	- Turned on debug printing of scsi timeouts for xscale only.
+
+Version: 1.1.5-2350
+
+rkt.c:
+	- Limit can_queue to 246 for rocket
+
+build:
+	- Added 2.4.19-306 kernel to build system.
+
+aachba.c:
+	- Removed an innocuous (obnoxious?) DEBUG printk
+
+2004-07-15: Mark Salyzyn <Mark_Salyzyn@adaptec.com>
+
+Version: 1.1.5-2351
+
+build:
+	- Added 2.4.9-31 to the build system
+
+modules.conf:
+	- Added 2.4.9-e.41, 2.4.9-e.43, 2.4.21-17.EL & 2.4.21-15.0.3.EL kernels
+
+build:
+	- Dropped 2.4.21-231 from build
+
+2004-07-16: Mark Salyzyn <Mark_Salyzyn@adaptec.com>
+
+Version: 1.1.5-2352
+
+build:
+	- Added 2.6.3-7mdk to the build system
+
+2004-07-20: Mark Salyzyn <Mark_Salyzyn@adaptec.com>
+
+Version: 1.1.5-2353 (Lantana Build w/o SLES9, SuSE9.1 & SuSE9 errata 231)
+Version: 1.1.5-2354 (Lantana Build w/o SLES9 & SuSE9 errata 231)
+Version: 1.1.5-2355 (BigQual refresh)
+
+install.sh:
+	- If missing, add a reference to the module to the kernel's module.dep
+	  file (affects drivers that are *not* shipped with the OS; HostRAID
+	  and some dpt_i2o)
+
+aachba.c:
+	- for __arm__ build, the default FIB size is selected by F/W and not
+	  overridden to 8192 bytes.
+
+Version: 1.1.5-2356 (Jupiter)
+
+aacraid.h+comminit.c+rkt.c+commsup.c+linit.c: Ken Sandars <Ken_Sandars@adaptec.com> + Mark Salyzyn
+	- Added AAC_NUM_MGT_FIB, and ensured can_queue represents the
+	  maximum number of io commands allowed and not be confused as the
+	  maximum number of FIB commands permitted into the Adapter. Thus
+	  host->can_queue is the maximum number of I/O commands, AAC_NUM_MGT_FIB
+	  is the maximum number of ioctl commands (set to 8 rather than legacy
+	  of 64) and init->MaxIoCommands sent back to the adapter is the total
+	  number of FIBs.
+
+Version: 1.1.5-2357 (Jupiter+BigQual)
+
+commctrl.c: Mark Salyzyn
+	- Added support for issuing FIBs that are larger than the negotiated
+	  size for the management interface.
+
+linit.c: Mark Salyzyn
+	- Added ASR-2240S, ASR-4005SAS, ASR-4000SAS, ASR-4800SAS, ASR-4805SAS
+	  and AAR-2610SA to the product list.
+
+install.sh: Mark Salyzyn
+	- Fixed problems with using the RH & SuSE modules disk as an update
+	  media, most of which was the selection of the extraction name from
+	  the modules.cgz file or acquiring the appropriate update.tar.gz file.
+
+build: Mark Salyzyn
+	- set 700 for update.sh in the modules disks to recognize at least
+	  that the RH modules disk works as an update media.
+
+aachba.c: Mark Salyzyn
+	- Dropped to 8K for the coalesce threshold for xscale builds.
+
+Version: 1.1.5-2358 (BigQual+Lantana)
+
+aachba.c+commctrl.c+aacraid.h+comminit.c+commsup.c+dpcsup.c+linit.c:
+	- Merged 2.6.8-rc2-bk9 differences into the driver (COSMETIC)
+
+compat.h
+	- Added definition for __user for kernels less than 2.5 (COSMETIC)
+
+linit.c:
+	- The aac_get_next_adapter_fib_ioctl for 64 bit implementations under
+	  2.6 maladdressed the transfer.
+
+Version: 1.1.5-2359 (BigQual+SPOCK+Lantana)
+
+commctrl.c:
+	- Added support for CODE_STREAM_IDENTIFIER, accessed via a new
+	  ioctl FSACTL_GET_VERSION_MATCHING
+	- Added support for FSACTL_SEND_LARGE_FIB
+
+aacraid.h:
+	- Added definition for struct VersionMatch
+	- Added definition for FSACTL_GET_VERSION_MATCHING
+	- Added definition for FSACTL_SEND_LARGE_FIB
+
+install.sh:
+	- if the modules.dep file does not exist, then ensure no complaints
+	  are made about mv not being able to access the file.
+	- If an entry is missing in modules.dep, construct it correctly.
+
+aachba.c:
+	- Remove any leading spaces from the Container Name. Ensure that
+	  if there is no container name remaining, to leave the existing
+	  one alone.
+
+build:
+	- Added support for 2.4.18-e.43
+	- Added support for 2.4.18-e.47
+	- Added support for 2.4.9-e.48
+	- Added support for 2.4.9-e.49 (RHAS 2.1 QU5)
+	- Added support for 2.4.21-15.0.4.EL
+
+rx.c+rkt.c:
+	- When responding to AIFs, use DoorBellAdapterNormRespReady instead of
+	  DoorBellAdapterNormCmdReady. The code appeared to work without
+	  undue side effects because Firmware would clear off the queues
+	  when new AIFs are delivered.
+
+commsup.c:
+	- If busy, defer scan action to next AIF. Half hearted attempt to
+	  improve the reliability of this unsupported feature.
+
+aacraid.h+linit.c+comminit.c+rx.c+rkt.c+sa.c:
+	- Remove references to Mailbox7 accesses for synchronous commands.
+
+aacraid.h+aachba.c:
+	- Turned on support for Compatibility ID testing. Only enabled if
+	  the build environment defines CODE_STREAM_IDENTIFIER.
+	- Fortify the adapter information to include supplemental information
+	  as well as the GetBusInfo in support of SAS programatic limits.
+
+linit.c+aachba.c:
+	- Use the newly acquired supplement information vendor and product
+	  fields to override the cardtype selection.
+
+Version: 1.1.5-2360
+Version: 1.1.5-2361 (Branch off 1.1.5-2340 in RHEL3 QU3 with aac_info fix in 1.1.5-2364)
+
+linit.c:
+	- register a reboot notifier to flush adapter
+	- faked AIF needs to call fib_init() later (ADPmp70525)
+
+commctrl.c:
+	- Since kfree has the possibility of switching in some esoteric
+	  variants of the kernel, and since the BKL is held during ioctl
+	  calls, we are unlocking the fib lock around these system calls.
+
+Version: 1.1.5-2362
+
+build:
+	- Added support for 2.4.21-17.EL (RHEL3 QU3 beta)
+	- Added support for 2.4.21-20.EL (RHEL3 QU3)
+	- Added support for 2.6.7-1.451.2.3 (RHEL4 alpha 4)
+
+linit.c:
+	- ASR4000 series entries were flawed in the indexes. Added an
+	  additional AvonPark entry.
+
+Version: 1.1.5-2363
+
+linit.c:
+	- aac_info is flawed and causes periodic panics in certain systems.
+
+build:
+	- Allow background builds
+	- em32t binaries did not show in the rpm
+
+Version: 1.1.5-2364 [BigQual, Pratt, Jupiter Dual & Lantana]
+
+linit.c:
+	- AAR-2610SA has had a subproduct change from 0x103C/0x0295 to
+	  0x103C/0x3227.
+	- Some adapters have internal limits of 34 SG elements as a result
+	  of a bug of not splitting requests up when cache is disabled when
+	  sending them to the CHIM. Created a quirk for the adapters that
+	  have this limit.
+
+Version: 1.1.5-2365
+
+aachba.c:
+	- Neglected to add maximum_num_physical check to the srb handler.
+	- leading space on inquiry code was flawed as a result ot a typographic
+	  error (replace ! with *)
+
+linit.c:
+	- ASR-4005SAS for IBM is designated as an 8i (ADPmp71521)
+	- Added check for late completion of command during timeout
+	- called aac_get_fw_debug_buffer() after init
+
+fwdebug.c+fwdebug.h
+	- Added firmware debug print handlers
+
+build:
+	- RH floppy disk was limited to 864KB, let it open up to 1.4MB. The
+	  risk is that 864KB was about all the ramdisk could handle when
+	  extracting, so we will no longer get a report of disk overrun as
+	  a warning to existing OS releases. We do not know what will overload
+	  the ramdisk during install. (ADPmp72476)
+	- Product ID list for aacraid is broken in the build due to changes
+	  resulting from incorporating the 2.6 tree.
+	- em32t binaries did not show in the rpm fix broke SuSE releases that
+	  utilize the 2.4.19 kernel (ADPmp73104)
+
+commsup.c:
+	- Added support for sending the time every 30 minutes.
+
+Version: 1.1.5-2366
+
+commctrl.c:
+	- Fixed 64 bit version of the SCB ioctl call as it was not translating
+	  the 32 bit scatter-gather correctly for scatter gather elements
+	  beyond the first one. Do not believe this issue presented a problem
+	  for any Adaptec management products due to their needs as they
+	  limited their SG to only one entry.
+
+build:
+	- Added 2.4.19-238
+	- Added 2.4.19-241
+	- Added 2.4.19-248
+	- Added 2.4.19-251
+
+Version: 1.1.5-2367
+
+linit.c:
+	- Added Themisto discovery to driver
+	- Added AAC_QUIRK_MASTER and AAC_QUIRK_SLAVE to deal with controller
+	  pairs.
+	- Changed Prowler "ESD SO-DIMM PCI-X SATA ZCR" to "ASR-2026ZCR".
+	- Return FAILED when hba_reset completed, the ten second bus settling
+	  delay is counter productive.
+
+aacraid.h+linit.c: Christoph Hellwig <hch@lst.de>
+	- drop casting surrounding iomap and ioremap and use the __iomem
+	  type enhancement.
+
+csmi.c+csmi.h:
+	- Added CSMI ioctl support.
+
+install.sh:
+	- log both successful and failed installations and limit complaints
+	  about installation to a minimum by not repeating similar failure
+	  messages.
+
+aachba.c:
+	- vtune reports that 2% of the time dealing with read calls was
+	  devoted to get_sd_devname(). Optimized codepath.
+
+Version: 1.1.5-2368
+
+build:
+	- Added 2.4.27 debian smp kernel to build
+	- Added 2.6.7-1.451.2.3 RHEL4 alpha 4 to the build
+	- Added 2.6.8-1.602 RHEL4 beta 1 to the build
+	- Added 2.6.5-7.109.5 SuSE 9.1 errata to the build
+
+csmi.h:
+	- Changed from CSMI_8_BYTE_ALLIGNED to CSMI_8_BYTE_ALIGNED
+
+csmi.c:
+	- failure on return from copy_to_user is ignored, but (void) is
+	  not the way to ignore it based on compiler warnings.
+	- scb size is set to 16 always.
+	- scb flags is set to 0 always.
+
+linit.c+compat.h:
+	- scsi_sleep() renamed to ssleep() in 2.6.9 kernel
+
+commctrl.c:
+	- 32 bit application issuing a raw srb in a 64 bit address space
+	  is not handled correctly for the fibsize calculation.
+	- Limit the number of scatter gather entries to 32, and zero
+	  out the references to those sg entries.
+
+Version: 1.1.5-2369
+
+compat.h:
+	- 2.6.8-1.602 RHEL4 beta 1 kernel looks more like 2.6.9, so needed to
+	  define scsi_sleep for kernels 2.6.8 and up rather than 2.6.9 and up.
+
+linit.c: Chris Trown <ctrown@uoregon.edu>
+	- Added an include for linux/delay.h to pick up the definition of
+	  ssleep().
+	- Added `other' Themisto ID to list.
+
+csmi.h:
+	- bumped to 0.83 version
+
+csmi.c:
+	- Acquired slot number from Supplementary Adapter Info SlotNumber
+	  field
+	- Added support to determine the actual bus type (SAS, SATA, Other).
+
+build:
+	- Added support for 2.4.21-22.EL (RHEL3 errata)
+	- Added support for 2.6.5-7.111 (SLES9 NLD)
+	- Added support for 2.4.21-243 (SuSE 9.x errata)
+
+aachba.c:
+	- valid must clear if VM_Nameserve fails on scan
+	- setinqstr has the possibility of overflowing the inquiry structure,
+	  the results are a damaged stack.
+
+commsup.c:
+	- do a probe_container before issuing scan as the adapter can take
+	  some time to write DDF data (not SCSI).
+
+aacraid.h:
+	- added definition of probe_container.
+
+Version: 1.1.5-2370
+
+aacraid.h+commsup.c+aachba.c+commctrl.c+comminit.c+linit.c+sa.c: Adrian Bunk <bunk@stusta.de>
+	- Make some needlessly global code static
+
+linit.c:
+	- Added Intruder (AAR-2420SA, AAR-2620SA & AAR-2820SA)
+
+aachba.c+commsup.c:
+	- Enable a 50 second timeout on the first asynchronous command to
+	  permit the driver to error out and report the hardware failure.
+
+linit.c:
+	- Fixed a comment completion problem for Intruder additions.
+
+build:
+	- Added support for 2.6.8-24 (SuSE 9.2)
+
+Version: 1.1.5-2371
+
+aachba.c: Jens Axboe
+	- Use a busy status return with scsi_done rather than -1 to
+	  signal OS to try again later for aac_read and aac_write to
+	  meet with acceptable coding standards.
+
+aachba.c+linit.c: Mark Salyzyn & Christoph Hellwig <hch@infradead.org>
+	- Moved AAC_EXTENDED_TIMEOUT to set sdev->timeout instead of
+	  inline for every command in the 2.6 variant.
+
+linit.c:
+	- There is a subsystem device id clash between SATAHAWK and INTRUDER
+	  and is giving the BIOS group some grief. Therefore the subsystem
+	  device ID for intruder is changed to 029B, 029C and 029D for 8, 6,
+	  and 4 port versions respectively.
+	- Added FSACTL_GET_VERSION_MATCHING and FSACTL_SEND_LARGE_FIB ioctls to
+	  list of supported 32 bit ioctl calls.
+
+build:
+	- enhanced README.txt to also provide a brief description of the
+	  binary file.
+	- Added support for a RHEL3 i686 ISO image as well.
+	- Added support for 2.6.5-7.109.12 (SLES9/SuSE9.1 SP1 B2 i386)
+	- Added support for 2.6.5-7.109.13 (SLES9/SuSE9.1 SP1 B2 x86_64)
+	- Added support for 2.6.5-7.115 (SLES9/SuSE9.1 SP1 B3)
+	- Added support for 2.6.5-1.358 (RH FC2)
+	- Added support for 2.6.9-1.667 (RH FC3)
+	- Added support for 2.4.21-260 (SuSE 9 errata)
+	- Added support for 2.4.21-261 (SuSE 8 errata)
+
+csmi.c:
+	- return code for CSMIGetSATASignature is under the control of the
+	  firmware and should not be blindly set to SUCCESS if the command
+	  succeeded.
+
+
+Version: 1.1.5-2372
+
+build:
+	- Added support for 2.6.9-1.648_EL (RHEL4 beta 2)
+
+linit.c:
+	- trim space from Model
+
+install.sh:
+	- Add /etc/modprobe.conf as another modules configuration file.
+	- If the module in the initrd does not match, but has the same
+	  `size' values, then report a `possibly stripped' warning message.
+
+Version: 1.1.5-2373
+
+build:
+	- Use "Avon Park SIT" for this build for the version identifier
+
+commsup.c:
+	- enable scsi-scan-single (ADPmp75534 & ADPmp69336)
+
+Version: 1.1.5-2374
+
+build:
+	- Added support for 2.6.5-7.111.5 (SLES9 NLD errata)
+	- Added support for 2.6.5-7.128 (SLES9 SP1 B4)
+	- Added support for 2.6.5-7.134 (SLES9 SP1 RC)
+	- Added support for 2.6.9-1.906_EL (RHEL4 RC)
+
+commsup.c:
+	- disable scsi-scan-single for 2.6 kernels, proc_scsi no longer
+	  exported
+
+install.sh
+	- Missed a double quote in the scripting to reduce size sensitivity.
+
+Version: 1.1.5-2375 (Avon Park SIT)
+
+csmi.c:
+	- Paramters.uFlags is a bit field, not a state.
+	- cdbLength needs to be hard coded to 14 from 16 (beware, 2TB warning).
+	- Set the srbFlags based on data direction or if there is any data to
+	  send at all (HOST_FLAGS_DATA_IN/DATA_OUT/NO_DATA_TRANSFER).
+
+csmi.h:
+	- Added definition for HOST_FLAGS_DATA_IN/DATA_OUT/NO_DATA_TRANSFER.
+
+Version: 1.1.5-2376 (This is a code stream identifier)
+
+linit.c:
+	- Added ICP Lancer products ICP9024R0 and ICP9014R0.
+	- Added include of asm/ioctl32.h
+	- Report ServeRAID for driver name if IBM 8i.
+
+aacraid.h
+	- Added definition for IOP_RESET synchronous command
+
+rkt.c+rx.c+linit.c+aacraid.h+commsup.c+aachba.c+csmi.c+comminit.c+commctrl.c+compat.h
+	- Merged code and style changes in 2.6.10-rc3-bk14 into codebase.
+
+aachba.c:
+	- set the scsi device as removeable during the Read Capacity call.
+	  (ADPmp76369)
+
+pci.ids:
+	- Submitted patch to pci-ids@ucw.cz to update the vital product list
+	  to match the products in the linit.c file (ADPmp77082)
+
+build:
+	- Added support for 2.4.21-20.0.1.EL (RHEL3 errata)
+	- Added support for 2.4.21-27.EL (RHEL3 QU4)
+	- Added support for 2.4.21-27.0.1.EL (RHEL3 errata)
+
+Version: 1.1.5-2377 (Avon Park SIT)
+
+linit.c:
+	- Dropped the maximum number of commands down to 16 per target if on
+	  an x86_64 machine with more than 4GB of memory when built in the
+	  2.4.* environment.
+
+Version: 1.1.5-2378 (CERC Test)
+
+linit.c:
+	- Dropped the maximum number of commands down to 10 per target for
+	  this test.
+
+Version: 1.1.5-2379 (CERC Test)
+
+build:
+	- Added support for 2.6.9-5.EL (RHEL4 RC)
+	- Added support for 2.6.5-7.139 (SLES9 SP1)
+	- Added support for 2.4.9-e.57 (RHAS QU6)
+	- Added support for 2.4.9-e.59 (RHAS QU6 errata 59)
+
+commsup.c:
+	- Added kernel ifdef's to handle scsi_add_target and
+	  scsi_remove_target calls.
+
+aachba.c+aacraid.h:
+	- Added AAC_DEBUG_INSTRUMENT_DAC_CERC to disable 64 bit scatter gather
+	  for only the CERC SR2 product.
+
+Version: 1.1.5-2380 (This is a code stream identifier)
+
+aachba.c+comminit.c:
+	- Added numacb insmod parameter.
+
+aachba.c+aacraid.h
+	- Remove AAC_DEBUG_INSTRUMENT_DAC_CERC code.
+
+build:
+	- Error in incorporating the RHAS2.1 QU6 kernel (2.4.9-e.57) on to the
+	  driver disk (ADPmp78010)
+	- Same problem with RHEL4 RC (2.6.9-5.EL) (ADPmp69861)
+
+Version: 1.1.5-2381 (This is a code stream identifier)
+
+build:
+	- Added support for 2.4.21-273 (SLES 8 errata 273)
+	- Added support for 2.6.5-7.111.30 (SLES 9 errata 30)
+	- Added support for 2.6.8-24.11 (SuSE 9.2 errata 11)
+	- Added support for 2.4.19.SuSE-256 (SLES8 x86_64 errata 256)
+	- Added support for 2.4.21-9.EL (RHEL3 QU1)
+	- Added support for 2.6.8.1-12mdk (Mandrake 10.1)
+	- Added support for 2.6.9-1.11_FC2 (FC2)
+	- Added support for 2.6.10-1.9_FC2 (FC2)
+
+commsup.c+aacraid.h
+	- Changed Plug-n-Play state machine to be per-array rather than
+	  per-adapter (ADPmp77096)
+
+Version: 1.1.5-2382 (This is a code stream identifier)
diff --git a/drivers/scsi/aacraid/Makefile b/drivers/scsi/aacraid/Makefile
index 1bea28d..a945219 100644
--- a/drivers/scsi/aacraid/Makefile
+++ b/drivers/scsi/aacraid/Makefile
@@ -1,10 +1,142 @@
+# Adaptec aacraid
+AAC_FLAGS := $(shell if [ ! -d ${TOPDIR}/drivers/scsi/aacraid ] ; then \
+	echo --error_Please_build_this_driver_in_the_Linux_Kernel_tree ; \
+fi)
+AAC_FLAGS += $(shell if [ -s ${TOPDIR}/include/linux/pci.h ] ; then \
+	if grep shutdown ${TOPDIR}/include/linux/pci.h >/dev/null 2>/dev/null ; then \
+		echo -DPCI_HAS_SHUTDOWN ; \
+	fi ; \
+fi)
+AAC_FLAGS += $(shell if [ -s ${TOPDIR}/drivers/scsi/hosts.h ] ; then \
+	if grep vary_io ${TOPDIR}/drivers/scsi/hosts.h >/dev/null 2>/dev/null ; then \
+		echo -DSCSI_HAS_VARY_IO ; \
+	fi ; \
+fi)
+AAC_FLAGS += $(shell if [ -s ${TOPDIR}/drivers/scsi/hosts.c ] ; then \
+	if grep scsi_in_detection ${TOPDIR}/drivers/scsi/hosts.c >/dev/null 2>/dev/null ; then \
+		echo -DSCSI_HAS_SCSI_IN_DETECTION ; \
+	fi ; \
+fi)
+AAC_FLAGS += $(shell if [ -s ${TOPDIR}/drivers/scsi/scsi_syms.c ] ; then \
+	if grep scsi_in_detection ${TOPDIR}/drivers/scsi/scsi_syms.c >/dev/null 2>/dev/null ; then \
+		echo -DSCSI_HAS_SCSI_SCAN_HOST ; \
+	fi ; \
+fi)
+AAC_FLAGS += $(shell if [ -s ${TOPDIR}/include/linux/delay.h ] ; then \
+	if grep ssleep ${TOPDIR}/include/linux/delay.h >/dev/null 2>/dev/null ; then \
+		echo -DSCSI_HAS_SSLEEP ; \
+	fi ; \
+fi)
+AAC_FLAGS += $(shell if [ -s ${TOPDIR}/include/scsi/scsi_device.h ] ; then \
+	if grep scsi_device_online ${TOPDIR}/include/scsi/scsi_device.h >/dev/null 2>/dev/null ; then \
+		echo -DSCSI_HAS_SCSI_DEVICE_ONLINE ; \
+	fi ; \
+fi)
+AAC_FLAGS += $(shell if [ -s ${TOPDIR}/include/scsi/scsi_host.h ] ; then \
+	if grep dump_poll ${TOPDIR}/include/scsi/scsi_host.h >/dev/null 2>/dev/null ; then \
+		echo -DSCSI_HAS_DUMP ; \
+	fi ; \
+fi)
+AAC_FLAGS += $(shell if [ -s ${TOPDIR}/include/scsi/scsi_host.h ] ; then \
+	if grep dump_sanity_check ${TOPDIR}/include/scsi/scsi_host.h >/dev/null 2>/dev/null ; then \
+		echo -DSCSI_HAS_DUMP_SANITY_CHECK ; \
+	fi ; \
+fi)
+AAC_FLAGS += $(shell if [ -s ${TOPDIR}/drivers/scsi/scsi_dump.h ] ; then \
+	echo -DSCSI_HAS_DUMP -DSCSI_HAS_DUMP_SANITY_CHECK ; \
+fi)
+AAC_FLAGS += $(shell if [ -s ${TOPDIR}/include/linux/types.h ] ; then \
+	if grep __bitwise ${TOPDIR}/include/linux/types.h >/dev/null 2>/dev/null ; then \
+		echo -DHAS_BITWISE_TYPE ; \
+	fi ; \
+fi)
+AAC_FLAGS += $(shell if [ -s ${TOPDIR}/include/linux/delay.h.h ] ; then \
+	if grep msleep ${TOPDIR}/include/linux/delay.h >/dev/null 2>/dev/null ; then \
+		echo -DHAS_MSLEEP ; \
+	fi ; \
+fi)
+ifeq (${VERSION},2) # 2.x.x
+ifeq (${PATCHLEVEL},2) # 2.2.x
 
-EXTRA_CFLAGS	+= -I$(TOPDIR)/drivers/scsi
+ifeq ($(shell grep AAC_DRIVER_BRANCH.*dkms ${dkms_tree}/${PACKAGE_NAME}/${PACKAGE_VERSION}/build/aacraid.h >/dev/null 2>/dev/null ; echo $?),0)
+CONFIG_SCSI_AACRAID := m
+endif
+
+CFILES_DRIVER=linit.c aachba.c commctrl.c comminit.c commsup.c \
+	dpcsup.c rx.c sa.c rkt.c fwdebug.c csmi.c
+
+IFILES_DRIVER=aacraid.h compat.h
+
+ALL_SOURCE=${CFILES_DRIVER} ${IFILES_DRIVER} 
+
+TARGET_OFILES=${CFILES_DRIVER:.c=.o}
+
+ifndef GCCVERSION
+GCCVERSION=2.96
+endif
+
+GCCMACHINE:=$(shell ls -d /usr/lib/gcc-lib/*/${GCCVERSION} | sed -n 1s@/${GCCVERSION}@@p)
+
+INCS=-I. -I.. -I../../../include -I/usr/src/linux/include -I/usr/src/linux/drivers/scsi 
+INCS=-nostdinc -I${GCCMACHINE}/${GCCVERSION}/include -I. -I..
+
+WARNINGS= -w -Wall -Wno-unused -Wno-switch -Wno-missing-prototypes -Wno-implicit
+
+COMMON_FLAGS=\
+	-D__KERNEL__=1 -DUNIX -DCVLOCK_USE_SPINLOCK -DLINUX \
+	-Wall -Wstrict-prototypes \
+	${INCS} \
+	${WARNINGS} \
+	-O2 -fomit-frame-pointer
+
+AACFLAGS=${COMMON_FLAGS} ${CFLAGS} ${EXTRA_FLAGS} ${AAC_FLAGS}
+COMPILE.c=${CC} ${AACFLAGS} ${TARGET_ARCH} -c
+
+.SUFFIXES:
+.SUFFIXES: .c .o .h .a
+
+all: source ${TARGET_OFILES} aacraid.o
+
+modules: all
+
+source: ${ALL_SOURCE}
+
+clean:
+	rm *.o
+
+aacraid.o: source ${TARGET_OFILES}
+	ld -r -o $@ $(TARGET_OFILES)
+	cp -r aacraid.o ../
+
+endif # 2.2.x
+ifeq (${PATCHLEVEL},4) # 2.4.x
+
+EXTRA_CFLAGS	+= -I$(TOPDIR)/drivers/scsi ${EXTRA_FLAGS} ${AAC_FLAGS}
 
 O_TARGET	:= aacraid.o
 obj-m		:= $(O_TARGET)
 
 obj-y		:= linit.o aachba.o commctrl.o comminit.o commsup.o \
-		   dpcsup.o rx.o sa.o
+		   dpcsup.o rx.o sa.o rkt.o fwdebug.o csmi.o
+
+ifeq ($(shell grep AAC_DRIVER_BRANCH.*dkms ${dkms_tree}/${PACKAGE_NAME}/${PACKAGE_VERSION}/build/aacraid.h >/dev/null 2>/dev/null ; echo $?),0)
+CONFIG_SCSI_AACRAID := m
+endif
 
 include $(TOPDIR)/Rules.make
+
+endif # 2.4.x
+ifeq (${PATCHLEVEL},6) # 2.6.x
+
+ifeq ($(shell grep AAC_DRIVER_BRANCH.*dkms ${dkms_tree}/${PACKAGE_NAME}/${PACKAGE_VERSION}/build/aacraid.h >/dev/null 2>/dev/null ; echo $?),0)
+obj-m := aacraid.o
+else
+obj-$(CONFIG_SCSI_AACRAID) := aacraid.o
+endif
+
+aacraid-objs	:= linit.o aachba.o commctrl.o comminit.o commsup.o \
+		   dpcsup.o rx.o sa.o rkt.o fwdebug.o csmi.o
+
+EXTRA_CFLAGS	:= -Idrivers/scsi ${EXTRA_FLAGS} ${AAC_FLAGS}
+endif # 2.6.x
+endif # 2.x.x
diff --git a/drivers/scsi/aacraid/README b/drivers/scsi/aacraid/README
index eba70ef..fdb0f45 100644
--- a/drivers/scsi/aacraid/README
+++ b/drivers/scsi/aacraid/README
@@ -10,25 +10,37 @@ the original).
 
 Supported Cards/Chipsets
 -------------------------
-	Dell Computer Corporation PERC 2 Quad Channel
-	Dell Computer Corporation PERC 2/Si
-	Dell Computer Corporation PERC 3/Si
-	Dell Computer Corporation PERC 3/Di
+	Adaptec 2020S
+	Adaptec 2025S
+	Adaptec 2120S
+	Adaptec 2200S
+	Adaptec 2230S
+	Adaptec 2240S
+	Adaptec 2410SA
+	Adaptec 2610SA
+	Adaptec 2810SA
+	Adaptec 21610SA
+	Adaptec 3230S
+	Adaptec 3240S
+	Adaptec 4000SAS
+	Adaptec 4005SAS
+	Adaptec 4800SAS
+	Adaptec 4805SAS
+	Adaptec 5400S
+	Dell PERC 2 Quad Channel
+	Dell PERC 2/Si
+	Dell PERC 3/Si
+	Dell PERC 3/Di
+	Dell CERC 2
 	HP NetRAID-4M
-	ADAPTEC 2120S
-	ADAPTEC 2200S
-	ADAPTEC 5400S
 	Legend S220
 	Legend S230
-	Adaptec 3230S
-	Adaptec 3240S
-	ASR-2020S PCI-X
-	AAR-2410SA SATA
 
 People
 -------------------------
 Alan Cox <alan@redhat.com>
-Christoph Hellwig <hch@infradead.org>	(small cleanups/fixes)
+Christoph Hellwig <hch@infradead.org>	(updates for new-style PCI probing and SCSI host registration,
+					 small cleanups/fixes)
 Matt Domsch <matt_domsch@dell.com>	(revision ioctl, adapter messages)
 Deanna Bonds                            (non-DASD support, PAE fibs and 64 bit, added new adaptec controllers
 					 added new ioctls, changed scsi interface to use new error handler,
@@ -45,8 +57,7 @@ Adaptec Unix OEM Product Group
 
 Mailing List
 -------------------------
-linux-aacraid-devel@dell.com (Interested parties troll here)
-http://mbserver.adaptec.com/ (Currently more Community Support than Devel Support)
+linux-scsi@vger.kernel.org (Interested parties troll here)
 Also note this is very different to Brian's original driver
 so don't expect him to support it.
 Adaptec does support this driver.  Contact either tech support or Mark Salyzyn.
diff --git a/drivers/scsi/aacraid/TODO b/drivers/scsi/aacraid/TODO
index f9ac6ac..1ebef3c 100644
--- a/drivers/scsi/aacraid/TODO
+++ b/drivers/scsi/aacraid/TODO
@@ -1,5 +1,4 @@
 o	Testing
 o	More testing
-o	Feature request: display the firmware/bios/etc revisions in the
-	/proc info
-o	2.5.0 and beyond.
+o	I/O size increase
+o	add sysfs interface
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
index 4d21996..2e14356 100644
--- a/drivers/scsi/aacraid/aachba.c
+++ b/drivers/scsi/aacraid/aachba.c
@@ -4,6 +4,7 @@
  *
  * based on the old aacraid driver that is..
  * Adaptec aacraid device driver for Linux.
+ *
  * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
  *
  * This program is free software; you can redistribute it and/or modify
@@ -22,8 +23,6 @@
  *
  */
 
-#include <linux/config.h>
-#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/types.h>
@@ -32,74 +31,46 @@
 #include <linux/spinlock.h>
 #include <linux/slab.h>
 #include <linux/completion.h>
+#include <linux/blkdev.h>
+#include <linux/version.h> /* For the following test */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+#include <linux/dma-mapping.h>
+#endif
 #include <asm/semaphore.h>
 #include <asm/uaccess.h>
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+#include <linux/module.h>
 #define MAJOR_NR SCSI_DISK0_MAJOR	/* For DEVICE_NR() */
-#include <linux/blk.h>
+#include <linux/blk.h>	/* for DEVICE_NR & io_request_lock definition */
 #include "scsi.h"
 #include "hosts.h"
 #include "sd.h"
+#else
+#include <linux/moduleparam.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)) && !defined(BLIST_NO_ULD_ATTACH))
+#include <scsi/scsi_devinfo.h>	/* Pick up BLIST_NO_ULD_ATTACH? */
+#endif
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_tcq.h>
+#endif
 
 #include "aacraid.h"
 
-/*	SCSI Commands */
-/*	TODO:  dmb - use the ones defined in include/scsi/scsi.h */
-
-#define	SS_TEST			0x00	/* Test unit ready */
-#define SS_REZERO		0x01	/* Rezero unit */
-#define	SS_REQSEN		0x03	/* Request Sense */
-#define SS_REASGN		0x07	/* Reassign blocks */
-#define	SS_READ			0x08	/* Read 6   */
-#define	SS_WRITE		0x0A	/* Write 6  */
-#define	SS_INQUIR		0x12	/* inquiry */
-#define	SS_ST_SP		0x1B	/* Start/Stop unit */
-#define	SS_LOCK			0x1E	/* prevent/allow medium removal */
-#define SS_RESERV		0x16	/* Reserve */
-#define SS_RELES		0x17	/* Release */
-#define SS_MODESEN		0x1A	/* Mode Sense 6 */
-#define	SS_RDCAP		0x25	/* Read Capacity */
-#define	SM_READ			0x28	/* Read 10  */
-#define	SM_WRITE		0x2A	/* Write 10 */
-#define SS_SEEK			0x2B	/* Seek */
-
 /* values for inqd_pdt: Peripheral device type in plain English */
-#define	INQD_PDT_DA	0x00		/* Direct-access (DISK) device */
-#define	INQD_PDT_PROC	0x03		/* Processor device */
-#define	INQD_PDT_CHNGR	0x08		/* Changer (jukebox, scsi2) */
-#define	INQD_PDT_COMM	0x09		/* Communication device (scsi2) */
-#define	INQD_PDT_NOLUN2 0x1f		/* Unknown Device (scsi2) */
-#define	INQD_PDT_NOLUN	0x7f		/* Logical Unit Not Present */
+#define	INQD_PDT_DA	0x00	/* Direct-access (DISK) device */
+#define	INQD_PDT_PROC	0x03	/* Processor device */
+#define	INQD_PDT_CHNGR	0x08	/* Changer (jukebox, scsi2) */
+#define	INQD_PDT_COMM	0x09	/* Communication device (scsi2) */
+#define	INQD_PDT_NOLUN2 0x1f	/* Unknown Device (scsi2) */
+#define	INQD_PDT_NOLUN	0x7f	/* Logical Unit Not Present */
 
-#define	INQD_PDT_DMASK	0x1F		/* Peripheral Device Type Mask */
-#define	INQD_PDT_QMASK	0xE0		/* Peripheral Device Qualifer Mask */
-
-#define	TARGET_LUN_TO_CONTAINER(target, lun)	(target)
-#define CONTAINER_TO_TARGET(cont)		((cont))
-#define CONTAINER_TO_LUN(cont)			(0)
-
-#define MAX_FIB_DATA (sizeof(struct hw_fib) - sizeof(FIB_HEADER))
-
-#define MAX_DRIVER_SG_SEGMENT_COUNT 17
-
-/*
- *	Sense keys
- */
-#define SENKEY_NO_SENSE      			0x00	
-#define SENKEY_UNDEFINED     			0x01	
-#define SENKEY_NOT_READY     			0x02	
-#define SENKEY_MEDIUM_ERR    			0x03	
-#define SENKEY_HW_ERR        			0x04	
-#define SENKEY_ILLEGAL       			0x05	
-#define SENKEY_ATTENTION     			0x06	
-#define SENKEY_PROTECTED     			0x07	
-#define SENKEY_BLANK         			0x08	
-#define SENKEY_V_UNIQUE      			0x09	
-#define SENKEY_CPY_ABORT     			0x0A	
-#define SENKEY_ABORT         			0x0B	
-#define SENKEY_EQUAL         			0x0C	
-#define SENKEY_VOL_OVERFLOW  			0x0D	
-#define SENKEY_MISCOMP       			0x0E	
-#define SENKEY_RESERVED      			0x0F	
+#define	INQD_PDT_DMASK	0x1F	/* Peripheral Device Type Mask */
+#define	INQD_PDT_QMASK	0xE0	/* Peripheral Device Qualifer Mask */
 
 /*
  *	Sense codes
@@ -109,6 +80,7 @@
 #define SENCODE_END_OF_DATA                     0x00
 #define SENCODE_BECOMING_READY                  0x04
 #define SENCODE_INIT_CMD_REQUIRED               0x04
+#define SENCODE_DATA_PROTECT			0x0E
 #define SENCODE_PARAM_LIST_LENGTH_ERROR         0x1A
 #define SENCODE_INVALID_COMMAND                 0x20
 #define SENCODE_LBA_OUT_OF_RANGE                0x21
@@ -158,82 +130,274 @@
 #define BYTE2(x) (unsigned char)((x) >> 16)
 #define BYTE3(x) (unsigned char)((x) >> 24)
 
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+/* compatibility */
+#ifndef SAM_STAT_CHECK_CONDITION
+# define SAM_STAT_CHECK_CONDITION	(CHECK_CONDITION << 1)
+#endif
+#ifndef SAM_STAT_GOOD
+# define SAM_STAT_GOOD			(GOOD << 1)
+#endif
+#ifndef SAM_STAT_TASK_SET_FULL
+# define SAM_STAT_TASK_SET_FULL		(QUEUE_FULL << 1)
+#endif
+
+#endif
 /*------------------------------------------------------------------------------
  *              S T R U C T S / T Y P E D E F S
  *----------------------------------------------------------------------------*/
 /* SCSI inquiry data */
 struct inquiry_data {
-	u8 inqd_pdt;		/* Peripheral qualifier | Peripheral Device Type  */
-	u8 inqd_dtq;		/* RMB | Device Type Qualifier  */
-	u8 inqd_ver;		/* ISO version | ECMA version | ANSI-approved version */
-	u8 inqd_rdf;		/* AENC | TrmIOP | Response data format */
-	u8 inqd_len;		/* Additional length (n-4) */
-	u8 inqd_pad1[2];	/* Reserved - must be zero */
-	u8 inqd_pad2;		/* RelAdr | WBus32 | WBus16 |  Sync  | Linked |Reserved| CmdQue | SftRe */
-	u8 inqd_vid[8];		/* Vendor ID */
-	u8 inqd_pid[16];	/* Product ID */
-	u8 inqd_prl[4];		/* Product Revision Level */
-};
-
-struct sense_data {
-	u8 error_code;		/* 70h (current errors), 71h(deferred errors) */
-	u8 valid:1;		/* A valid bit of one indicates that the information  */
-	/* field contains valid information as defined in the
-	 * SCSI-2 Standard.
-	 */
-	u8 segment_number;	/* Only used for COPY, COMPARE, or COPY AND VERIFY Commands */
-	u8 sense_key:4;		/* Sense Key */
-	u8 reserved:1;
-	u8 ILI:1;		/* Incorrect Length Indicator */
-	u8 EOM:1;		/* End Of Medium - reserved for random access devices */
-	u8 filemark:1;		/* Filemark - reserved for random access devices */
-
-	u8 information[4];	/* for direct-access devices, contains the unsigned 
-				 * logical block address or residue associated with 
-				 * the sense key 
-				 */
-	u8 add_sense_len;	/* number of additional sense bytes to follow this field */
-	u8 cmnd_info[4];	/* not used */
-	u8 ASC;			/* Additional Sense Code */
-	u8 ASCQ;		/* Additional Sense Code Qualifier */
-	u8 FRUC;		/* Field Replaceable Unit Code - not used */
-	u8 bit_ptr:3;		/* indicates which byte of the CDB or parameter data
-				 * was in error
-				 */
-	u8 BPV:1;		/* bit pointer valid (BPV): 1- indicates that 
-				 * the bit_ptr field has valid value
-				 */
-	u8 reserved2:2;
-	u8 CD:1;		/* command data bit: 1- illegal parameter in CDB.
-				 * 0- illegal parameter in data.
-				 */
-	u8 SKSV:1;
-	u8 field_ptr[2];	/* byte of the CDB or parameter data in error */
+	u8 inqd_pdt;	/* Peripheral qualifier | Peripheral Device Type  */
+	u8 inqd_dtq;	/* RMB | Device Type Qualifier  */
+	u8 inqd_ver;	/* ISO version | ECMA version | ANSI-approved version */
+	u8 inqd_rdf;	/* AENC | TrmIOP | Response data format */
+	u8 inqd_len;	/* Additional length (n-4) */
+	u8 inqd_pad1[2];/* Reserved - must be zero */
+	u8 inqd_pad2;	/* RelAdr | WBus32 | WBus16 |  Sync  | Linked |Reserved| CmdQue | SftRe */
+	u8 inqd_vid[8];	/* Vendor ID */
+	u8 inqd_pid[16];/* Product ID */
+	u8 inqd_prl[4];	/* Product Revision Level */
 };
 
 /*
  *              M O D U L E   G L O B A L S
  */
  
-static struct fsa_scsi_hba *fsa_dev[MAXIMUM_NUM_ADAPTERS];	/*  SCSI Device Instance Pointers */
-static struct sense_data sense_data[MAXIMUM_NUM_CONTAINERS];
-static void get_sd_devname(int disknum, char *buffer);
-static unsigned long aac_build_sg(Scsi_Cmnd* scsicmd, struct sgmap* sgmap);
-static unsigned long aac_build_sg64(Scsi_Cmnd* scsicmd, struct sgmap64* psg);
-static int aac_send_srb_fib(Scsi_Cmnd* scsicmd);
+static unsigned long aac_build_sg(struct scsi_cmnd* scsicmd, struct sgmap* sgmap);
+static unsigned long aac_build_sg64(struct scsi_cmnd* scsicmd, struct sgmap64* psg);
+static unsigned long aac_build_sgraw(struct scsi_cmnd* scsicmd, struct sgmapraw* psg);
+static int aac_send_srb_fib(struct scsi_cmnd* scsicmd);
+#ifdef AAC_DETAILED_STATUS_INFO
 static char *aac_get_status_string(u32 status);
+#endif
 
 /*
  *	Non dasd selection is handled entirely in aachba now
  */	
  
+static int nondasd = -1;
+static int dacmode = -1;
+
+#if (defined(__arm__) || defined(CONFIG_EXTERNAL))
+static int commit = 1;
+#else
+static int commit = -1;
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+module_param(nondasd, int, S_IRUGO|S_IWUSR);
+#else
 MODULE_PARM(nondasd, "i");
+#endif
 MODULE_PARM_DESC(nondasd, "Control scanning of hba for nondasd devices. 0=off, 1=on");
-MODULE_PARM(paemode, "i");
-MODULE_PARM_DESC(paemode, "Control whether dma addressing is using PAE. 0=off, 1=on");
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+module_param(dacmode, int, S_IRUGO|S_IWUSR);
+#else
+MODULE_PARM(dacmode, "i");
+#endif
+MODULE_PARM_DESC(dacmode, "Control whether dma addressing is using 64 bit DAC. 0=off, 1=on");
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+module_param(commit, int, S_IRUGO|S_IWUSR);
+#else
+MODULE_PARM(commit, "i");
+#endif
+MODULE_PARM_DESC(commit, "Control whether a COMMIT_CONFIG is issued to the adapter for foreign arrays.\nThis is typically needed in systems that do not have a BIOS. 0=off, 1=on");
+
+#if (defined(__arm__) || defined(CONFIG_EXTERNAL) || (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) || defined(__VMKERNEL_MODULE__))
+static int coalescethreshold = 0;
+#else
+static int coalescethreshold = 16; /* 8KB coalesce knee */
+#endif
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+module_param(coalescethreshold, int, S_IRUGO|S_IWUSR);
+#else
+MODULE_PARM(coalescethreshold, "i");
+#endif
+MODULE_PARM_DESC(coalescethreshold, "Control the maximum block size of sequential requests that are fed back to the scsi_merge layer for coalescing. 0=off, 16 block (8KB) default.");
+
+int numacb = -1;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+module_param(numacb, int, S_IRUGO|S_IWUSR);
+#else
+MODULE_PARM(numacb, "i");
+#endif
+MODULE_PARM_DESC(numacb, "Request a limit to the number of adapter control blocks (FIB) allocated. Valid values are 512 and down. Default is to use suggestion from Firmware.");
+
+int acbsize = -1;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+module_param(acbsize, int, S_IRUGO|S_IWUSR);
+#else
+MODULE_PARM(acbsize, "i");
+#endif
+MODULE_PARM_DESC(acbsize, "Request a specific adapter control block (FIB) size. Valid values are 512, 2048, 4096 and 8192. Default is to use suggestion from Firmware.");
+
+int update_interval = 30 * 60;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+module_param(update_interval, int, S_IRUGO|S_IWUSR);
+#else
+MODULE_PARM(update_interval, "i");
+#endif
+MODULE_PARM_DESC(update_interval, "Interval in seconds between time sync updates issued to adapter.");
+
+int check_interval = 24 * 60 * 60;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+module_param(check_interval, int, S_IRUGO|S_IWUSR);
+#else
+MODULE_PARM(check_interval, "i");
+#endif
+MODULE_PARM_DESC(check_interval, "Interval in seconds between adapter health checks.");
+
+int check_reset = 1;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+module_param(check_reset, int, S_IRUGO|S_IWUSR);
+#else
+MODULE_PARM(check_reset, "i");
+#endif
+MODULE_PARM_DESC(check_reset, "If adapter fails health check, reset the adapter.");
+#if (defined(AAC_EXTENDED_TIMEOUT))
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+int extendedtimeout = -1;
+module_param(extendedtimeout, int, S_IRUGO|S_IWUSR);
+#else
+static int extendedtimeout = -1;
+MODULE_PARM(extendedtimeout, "i");
+#endif
+MODULE_PARM_DESC(extendedtimeout, "Request a specific timeout to override I/O requests issed to the adapter.");
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+static char aacraid[256];
+module_param_string(aacraid, aacraid, sizeof(aacraid), 0);
+#else
+static char * aacraid = NULL;
+MODULE_PARM(aacraid, "s");
+#endif
+MODULE_PARM_DESC(aacraid, "set the various published parameters of the aacraid driver with a syntax of aacraid=parm:value[,parm:value]...");
+
+static int aacraid_setup(char *str)
+{
+	int i;
+	char *key;
+	char *value;
+	struct {
+		char * option_name;
+		int * option_flag;
+		int option_value;
+	} options[] = {
+		{ "nondasd", &nondasd, 1 },
+		{ "dacmode", &dacmode, 1 },
+		{ "commit", &commit, 1 },
+		{ "coalescethreshold", &coalescethreshold, 16 },
+		{ "acbsize", &acbsize, 8192 },
+		{ "update_interval", &update_interval, 30 * 60 },
+		{ "check_interval", &check_interval, -1 },
+		{ "check_reset", &check_reset, 1 },
+#if (defined(AAC_EXTENDED_TIMEOUT))
+		{ "extendedtimeout", &extendedtimeout, AAC_EXTENDED_TIMEOUT },
+#endif
+	};
+
+#if (defined(AAC_DEBUG_INSTRUMENT_SETUP))
+printk (KERN_INFO "aacraid_setup(\"%s\")\n", (str) ? str : "<null>");
+#endif
+	if (str) while ((key = strsep(&str, ",."))) {
+		if (!*key)
+			continue;
+		value = strchr(key, ':');
+		if (value)
+			*value++ = '\0';
+		for (i = 0; i < (sizeof (options) / sizeof (options[0])); i++) {
+			if (strnicmp (key, options[i].option_name,
+			     strlen(options[i].option_name)) == 0) {
+				*options[i].option_flag
+				  = (value)
+				    ? simple_strtoul(value, NULL, 0)
+				    : options[i].option_value;
+				break;
+			}
+		}
+	}
 
-static int nondasd = -1;
-static int paemode = -1;
+	return (1);
+}
+
+__setup("aacraid=", aacraid_setup);
+
+/**
+ *	aac_get_config_status	-	check the adapter configuration
+ *	@common: adapter to query
+ *
+ *	Query config status, and commit the configuration if needed.
+ */
+int aac_get_config_status(struct aac_dev *dev)
+{
+	int status = 0;
+	struct fib * fibptr;
+
+	if (!(fibptr = fib_alloc(dev)))
+		return -ENOMEM;
+
+	fib_init(fibptr);
+	{
+		struct aac_get_config_status *dinfo;
+		dinfo = (struct aac_get_config_status *) fib_data(fibptr);
+
+		dinfo->command = cpu_to_le32(VM_ContainerConfig);
+		dinfo->type = cpu_to_le32(CT_GET_CONFIG_STATUS);
+		dinfo->count = cpu_to_le32(sizeof(((struct aac_get_config_status_resp *)NULL)->data));
+	}
+
+	status = fib_send(ContainerCommand,
+			    fibptr,
+			    sizeof (struct aac_get_config_status),
+			    FsaNormal,
+			    1, 1,
+			    NULL, NULL);
+	if (status < 0 ) {
+		printk(KERN_WARNING "aac_get_config_status: SendFIB failed.\n");
+	} else {
+		struct aac_get_config_status_resp *reply
+		  = (struct aac_get_config_status_resp *) fib_data(fibptr);
+		dprintk((KERN_WARNING
+		  "aac_get_config_status: response=%d status=%d action=%d\n",
+		  le32_to_cpu(reply->response),
+		  le32_to_cpu(reply->status),
+		  le32_to_cpu(reply->data.action)));
+		if ((le32_to_cpu(reply->response) != ST_OK) ||
+		     (le32_to_cpu(reply->status) != CT_OK) ||
+		     (le32_to_cpu(reply->data.action) > CFACT_PAUSE)) {
+			printk(KERN_WARNING "aac_get_config_status: Will not issue the Commit Configuration\n");
+			status = -EINVAL;
+		}
+	}
+	fib_complete(fibptr);
+	/* Send a CT_COMMIT_CONFIG to enable discovery of devices */
+	if (status >= 0) {
+		if (commit == 1) {
+			struct aac_commit_config * dinfo;
+			fib_init(fibptr);
+			dinfo = (struct aac_commit_config *) fib_data(fibptr);
+	
+			dinfo->command = cpu_to_le32(VM_ContainerConfig);
+			dinfo->type = cpu_to_le32(CT_COMMIT_CONFIG);
+	
+			status = fib_send(ContainerCommand,
+				    fibptr,
+				    sizeof (struct aac_commit_config),
+				    FsaNormal,
+				    1, 1,
+				    NULL, NULL);
+			fib_complete(fibptr);
+		} else if (commit == 0) {
+			printk(KERN_WARNING
+			  "aac_get_config_status: Foreign device configurations are being ignored\n");
+		}
+	}
+	fib_free(fibptr);
+	return status;
+}
 
 /**
  *	aac_get_containers	-	list containers
@@ -243,21 +407,56 @@ static int paemode = -1;
  */
 int aac_get_containers(struct aac_dev *dev)
 {
-	struct fsa_scsi_hba *fsa_dev_ptr;
-	u32 index;
+	struct fsa_dev_info *fsa_dev_ptr;
+	u32 index; 
 	int status = 0;
-	struct aac_query_mount *dinfo;
-	struct aac_mount *dresp;
 	struct fib * fibptr;
 	unsigned instance;
+	struct aac_get_container_count *dinfo;
+	struct aac_get_container_count_resp *dresp;
+	int maximum_num_containers = MAXIMUM_NUM_CONTAINERS;
 
-	fsa_dev_ptr = &(dev->fsa_dev);
 	instance = dev->scsi_host_ptr->unique_id;
 
 	if (!(fibptr = fib_alloc(dev)))
 		return -ENOMEM;
 
-	for (index = 0; index < MAXIMUM_NUM_CONTAINERS; index++) {
+	fib_init(fibptr);
+	dinfo = (struct aac_get_container_count *) fib_data(fibptr);
+	dinfo->command = cpu_to_le32(VM_ContainerConfig);
+	dinfo->type = cpu_to_le32(CT_GET_CONTAINER_COUNT);
+
+	status = fib_send(ContainerCommand,
+		    fibptr,
+		    sizeof (struct aac_get_container_count),
+		    FsaNormal,
+		    1, 1,
+		    NULL, NULL);
+	if (status >= 0) {
+		dresp = (struct aac_get_container_count_resp *)fib_data(fibptr);
+		maximum_num_containers = le32_to_cpu(dresp->ContainerSwitchEntries);
+		fib_complete(fibptr);
+	}
+
+	if (maximum_num_containers < MAXIMUM_NUM_CONTAINERS)
+		maximum_num_containers = MAXIMUM_NUM_CONTAINERS;
+	fsa_dev_ptr = (struct fsa_dev_info *) kmalloc(
+	  sizeof(*fsa_dev_ptr) * maximum_num_containers, GFP_KERNEL);
+	if (!fsa_dev_ptr) {
+		fib_free(fibptr);
+		return -ENOMEM;
+	}
+	memset(fsa_dev_ptr, 0, sizeof(*fsa_dev_ptr) * maximum_num_containers);
+
+	dev->fsa_dev = fsa_dev_ptr;
+	dev->maximum_num_containers = maximum_num_containers;
+
+	for (index = 0; index < dev->maximum_num_containers; index++) {
+		struct aac_query_mount *dinfo;
+		struct aac_mount *dresp;
+
+		fsa_dev_ptr[index].devname[0] = '\0';
+
 		fib_init(fibptr);
 		dinfo = (struct aac_query_mount *) fib_data(fibptr);
 
@@ -277,83 +476,276 @@ int aac_get_containers(struct aac_dev *dev)
 		}
 		dresp = (struct aac_mount *)fib_data(fibptr);
 
+#if (defined(AAC_DEBUG_INSTRUMENT_2TB))
+		printk(KERN_INFO "dresp->mnt[0].vol=%d "
+		  "dresp->mnt[0].capacity=%u"
+		  "={%02x %02x %02x %02x}\n",
+		  le32_to_cpu(dresp->mnt[0].vol),
+		  le32_to_cpu(dresp->mnt[0].capacity),
+		  ((u8 *)&dresp->mnt[0].capacity)[0],
+		  ((u8 *)&dresp->mnt[0].capacity)[1],
+		  ((u8 *)&dresp->mnt[0].capacity)[2],
+		  ((u8 *)&dresp->mnt[0].capacity)[3]);
+#endif
+		if ((le32_to_cpu(dresp->status) == ST_OK) &&
+		    (le32_to_cpu(dresp->mnt[0].vol) == CT_NONE)) {
+			dinfo->command = cpu_to_le32(VM_NameServe64);
+			dinfo->count = cpu_to_le32(index);
+			dinfo->type = cpu_to_le32(FT_FILESYS);
+
+			if (fib_send(ContainerCommand,
+				    fibptr,
+				    sizeof(struct aac_query_mount),
+				    FsaNormal,
+				    1, 1,
+				    NULL, NULL) < 0)
+				continue;
+#if (defined(AAC_DEBUG_INSTRUMENT_2TB))
+			printk(KERN_INFO "dresp->mnt[0].capacity64=%llu"
+			  "={%02x %02x %02x %02x %02x %02x %02x %02x}\n",
+			  ((u64)le32_to_cpu(dresp->mnt[0].capacity)) +
+			    (((u64)le32_to_cpu(dresp->mnt[0].capacityhigh)) << 32),
+			  ((u8 *)&dresp->mnt[0].capacity)[0],
+			  ((u8 *)&dresp->mnt[0].capacity)[1],
+			  ((u8 *)&dresp->mnt[0].capacity)[2],
+			  ((u8 *)&dresp->mnt[0].capacity)[3],
+			  ((u8 *)&dresp->mnt[0].capacityhigh)[0],
+			  ((u8 *)&dresp->mnt[0].capacityhigh)[1],
+			  ((u8 *)&dresp->mnt[0].capacityhigh)[2],
+			  ((u8 *)&dresp->mnt[0].capacityhigh)[3]);
+#endif
+		} else
+			dresp->mnt[0].capacityhigh = 0;
+
+		dprintk ((KERN_DEBUG
+		  "VM_NameServe cid=%d status=%d vol=%d state=%d cap=%llu\n",
+		  (int)index, (int)le32_to_cpu(dresp->status),
+		  (int)le32_to_cpu(dresp->mnt[0].vol),
+		  (int)le32_to_cpu(dresp->mnt[0].state),
+		  ((u64)le32_to_cpu(dresp->mnt[0].capacity)) +
+		    (((u64)le32_to_cpu(dresp->mnt[0].capacityhigh)) << 32)));
 		if ((le32_to_cpu(dresp->status) == ST_OK) &&
 		    (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE) &&
 		    (le32_to_cpu(dresp->mnt[0].state) != FSCS_HIDDEN)) {
-			fsa_dev_ptr->valid[index] = 1;
-			fsa_dev_ptr->type[index] = le32_to_cpu(dresp->mnt[0].vol);
-			fsa_dev_ptr->size[index] = le32_to_cpu(dresp->mnt[0].capacity);
+			fsa_dev_ptr[index].valid = 1;
+			fsa_dev_ptr[index].type = le32_to_cpu(dresp->mnt[0].vol);
+			fsa_dev_ptr[index].size
+			  = ((u64)le32_to_cpu(dresp->mnt[0].capacity)) +
+			    (((u64)le32_to_cpu(dresp->mnt[0].capacityhigh)) << 32);
 			if (le32_to_cpu(dresp->mnt[0].state) & FSCS_READONLY)
-				    fsa_dev_ptr->ro[index] = 1;
+				    fsa_dev_ptr[index].ro = 1;
+#if (defined(AAC_DEBUG_INSTRUMENT_2TB))
+			printk(KERN_INFO "Valid type=%u size=%llu ro=%d\n",
+			  fsa_dev_ptr[index].type, fsa_dev_ptr[index].size,
+			  fsa_dev_ptr[index].ro);
+#endif
 		}
 		fib_complete(fibptr);
 		/*
 		 *	If there are no more containers, then stop asking.
 		 */
-		if ((index + 1) >= le32_to_cpu(dresp->count))
+		if ((index + 1) >= le32_to_cpu(dresp->count)){
 			break;
+		}
 	}
 	fib_free(fibptr);
-	fsa_dev[instance] = fsa_dev_ptr;
 	return status;
 }
 
+static void aac_io_done(struct scsi_cmnd * scsicmd)
+{
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) /* suppress unused variable warning */
+	unsigned long cpu_flags;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) /* suppress unused variable warning */
+	struct Scsi_Host *host = scsicmd->device->host;
+#endif
+#endif
+
+	if (scsicmd->scsi_done == (void (*)(struct scsi_cmnd*))NULL) {
+		printk(KERN_WARNING "aac_io_done: scsi_done NULL\n");
+		return;
+	}
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
+	spin_lock_irqsave(&io_request_lock, cpu_flags);
+#endif
+	scsicmd->scsi_done(scsicmd);
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
+	spin_unlock_irqrestore(&io_request_lock, cpu_flags);
+#endif
+#if (defined(AAC_DEBUG_INSTRUMENT_TIMING))
+	{
+		u64 lba;
+		u32 count = 0;
+		struct timeval now;
+		do_gettimeofday(&now);
+		if ((scsicmd->cmnd[0] == WRITE_6) ||	/* 6 byte command */
+		    (scsicmd->cmnd[0] == READ_6)) {
+			lba = ((scsicmd->cmnd[1] & 0x1F) << 16) |
+			    (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
+			count = scsicmd->cmnd[4];
+			if (count == 0)
+				count = 256;
+#if (defined(WRITE_16))
+		} else if ((scsicmd->cmnd[0] == WRITE_16) || /* 16 byte command */
+		    (scsicmd->cmnd[0] == READ_16)) {
+			lba = ((u64)scsicmd->cmnd[2] << 56)
+			    | ((u64)scsicmd->cmnd[3] << 48)
+			    | ((u64)scsicmd->cmnd[4] << 40)
+			    | ((u64)scsicmd->cmnd[9] << 32)
+			    | ((u64)scsicmd->cmnd[6] << 24)
+			    | (scsicmd->cmnd[7] << 16)
+			    | (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
+			count = (scsicmd->cmnd[10] << 24)
+			      | (scsicmd->cmnd[11] << 16)
+			      | (scsicmd->cmnd[12] << 8) | scsicmd->cmnd[13];
+#endif
+		} else if ((scsicmd->cmnd[0] == WRITE_12) /* 12 byte command */
+		 || (scsicmd->cmnd[0] == READ_12)) {
+			lba = ((u64)scsicmd->cmnd[2] << 24)
+			    | (scsicmd->cmnd[3] << 16)
+			    | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
+			count = (scsicmd->cmnd[6] << 24)
+			      | (scsicmd->cmnd[7] << 16)
+			      | (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
+		} else if ((scsicmd->cmnd[0] == WRITE_10) /* 10 byte command */
+		 || (scsicmd->cmnd[0] == READ_10)) {
+			lba = ((u64)scsicmd->cmnd[2] << 24)
+			    | (scsicmd->cmnd[3] << 16)
+			    | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
+			count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
+		} else
+			lba = (u64)(long)scsicmd;
+		printk(((count)
+		  ? KERN_DEBUG "%lu.%06lu d%lu %llu[%u]\n"
+		  : KERN_DEBUG "%lu.%06lu d%lu 0x%llx\n"),
+		  now.tv_sec % 100, now.tv_usec,
+		  ((struct aac_dev *)scsicmd->device->host->hostdata)->queues->queue[AdapNormCmdQueue].numpending,
+		  lba, count);
+	}
+#endif
+}
+#if (defined(AAC_DEBUG_INSTRUMENT_TIMING))
+
+static inline void __aac_io_done(struct scsi_cmnd * scsicmd)
+{
+	struct timeval now;
+	scsicmd->scsi_done(scsicmd);
+	do_gettimeofday(&now);
+	printk(KERN_DEBUG "%lu.%06lu d%lu %p\n",
+	  now.tv_sec % 100, now.tv_usec,
+	  ((struct aac_dev *)scsicmd->device->host->hostdata)->queues->queue[AdapNormCmdQueue].numpending,
+	  scsicmd);
+}
+#endif
+
+static void aac_internal_transfer(struct scsi_cmnd *scsicmd, void *data, unsigned int offset, unsigned int len)
+{
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+	void *buf;
+	unsigned int transfer_len;
+	struct scatterlist *sg = scsicmd->request_buffer;
+
+	if (scsicmd->use_sg) {
+		buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
+		transfer_len = min(sg->length, len + offset);
+	} else {
+		buf = scsicmd->request_buffer;
+		transfer_len = min(scsicmd->request_bufflen, len + offset);
+	}
+
+	memcpy(buf + offset, data, transfer_len - offset);
+
+	if (scsicmd->use_sg) 
+		kunmap_atomic(buf - sg->offset, KM_IRQ0);
+
+#else
+	memcpy(scsicmd->request_buffer + offset, data,
+	  min(scsicmd->request_bufflen, len + offset) - offset);
+#endif
+}
+
+static void get_container_name_callback(void *context, struct fib * fibptr)
+{
+	struct aac_get_name_resp * get_name_reply;
+	struct scsi_cmnd * scsicmd;
+
+	scsicmd = (struct scsi_cmnd *) context;
+	scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL;
+
+	dprintk((KERN_DEBUG "get_container_name_callback[cpu %d]: t = %ld.\n", smp_processor_id(), jiffies));
+	if (fibptr == NULL)
+		BUG();
+
+	get_name_reply = (struct aac_get_name_resp *) fib_data(fibptr);
+	/* Failure is irrelevant, using default value instead */
+	if ((le32_to_cpu(get_name_reply->status) == CT_OK)
+	 && (get_name_reply->data[0] != '\0')) {
+		char *sp = get_name_reply->data;
+		sp[sizeof(((struct aac_get_name_resp *)NULL)->data)-1] = '\0';
+		while (*sp == ' ')
+			++sp;
+		if (*sp) {
+			char d[sizeof(((struct inquiry_data *)NULL)->inqd_pid)];
+			int count = sizeof(d);
+			char *dp = d;
+			do {
+				*dp++ = (*sp) ? *sp++ : ' ';
+			} while (--count > 0);
+			aac_internal_transfer(scsicmd, d, 
+			  offsetof(struct inquiry_data, inqd_pid), sizeof(d));
+		}
+	}
+
+	scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+
+	fib_complete(fibptr);
+	fib_free(fibptr);
+	aac_io_done(scsicmd);
+}
+
 /**
- *	aac_get_container_name	-	get container name
+ *	aac_get_container_name	-	get container name, none blocking.
  */
-static int aac_get_container_name(struct aac_dev *dev, int cid, char * pid)
+static int aac_get_container_name(struct scsi_cmnd * scsicmd, int cid)
 {
-	struct fsa_scsi_hba *fsa_dev_ptr;
-	int status = 0;
+	int status;
 	struct aac_get_name *dinfo;
-	struct aac_get_name_resp *dresp;
-	struct fib * fibptr;
-	unsigned instance;
+	struct fib * cmd_fibcontext;
+	struct aac_dev * dev;
 
-	fsa_dev_ptr = &(dev->fsa_dev);
-	instance = dev->scsi_host_ptr->unique_id;
+	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
 
-	if (!(fibptr = fib_alloc(dev)))
+	if (!(cmd_fibcontext = fib_alloc(dev)))
 		return -ENOMEM;
 
-	fib_init(fibptr);
-	dinfo = (struct aac_get_name *) fib_data(fibptr);
+	fib_init(cmd_fibcontext);
+	dinfo = (struct aac_get_name *) fib_data(cmd_fibcontext);
 
 	dinfo->command = cpu_to_le32(VM_ContainerConfig);
 	dinfo->type = cpu_to_le32(CT_READ_NAME);
 	dinfo->cid = cpu_to_le32(cid);
 	dinfo->count = cpu_to_le32(sizeof(((struct aac_get_name_resp *)NULL)->data));
 
-	status = fib_send(ContainerCommand,
-			    fibptr,
-			    sizeof (struct aac_get_name),
-			    FsaNormal,
-			    1, 1,
-			    NULL, NULL);
-	if (status < 0 ) {
-		printk(KERN_WARNING "aac_get_container_name: SendFIB failed.\n");
-	} else {
-		dresp = (struct aac_get_name_resp *)fib_data(fibptr);
-
-		status = (le32_to_cpu(dresp->status) != CT_OK)
-		      || (dresp->data[0] == '\0');
-		if (status == 0) {
-			char * sp = dresp->data;
-			char * dp = pid;
-			do {
-				if ((*sp == '\0')
-				 || ((dp - pid) >= sizeof(((struct aac_get_name_resp *)NULL)->data))) {
-					*dp = ' ';
-				} else {
-					*dp = *sp++;
-				}
-			} while (++dp < &pid[sizeof(((struct inquiry_data *)NULL)->inqd_pid)]);
-		}
+	status = fib_send(ContainerCommand, 
+		  cmd_fibcontext, 
+		  sizeof (struct aac_get_name),
+		  FsaNormal, 
+		  0, 1, 
+		  (fib_callback) get_container_name_callback, 
+		  (void *) scsicmd);
+	
+	/*
+	 *	Check that the command queued to the controller
+	 */
+	if (status == -EINPROGRESS) {
+		scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
+		return 0;
 	}
-	fib_complete(fibptr);
-	fib_free(fibptr);
-	fsa_dev[instance] = fsa_dev_ptr;
-	return status;
+		
+	printk(KERN_WARNING "aac_get_container_name: fib_send failed with status: %d.\n", status);
+	fib_complete(cmd_fibcontext);
+	fib_free(cmd_fibcontext);
+	return -1;
 }
 
 /**
@@ -362,19 +754,24 @@ static int aac_get_container_name(struct aac_dev *dev, int cid, char * pid)
  *	@cid: container identifier
  *
  *	Queries the controller about the given volume. The volume information
- *	is updated in the struct fsa_scsi_hba structure rather than returned.
+ *	is updated in the struct fsa_dev_info structure rather than returned.
  */
  
-static int probe_container(struct aac_dev *dev, int cid)
+int probe_container(struct aac_dev *dev, int cid)
 {
-	struct fsa_scsi_hba *fsa_dev_ptr;
+	struct fsa_dev_info *fsa_dev_ptr;
 	int status;
 	struct aac_query_mount *dinfo;
 	struct aac_mount *dresp;
 	struct fib * fibptr;
 	unsigned instance;
+#if (defined(AAC_DEBUG_INSTRUMENT_VM_NAMESERVE))
+	unsigned long tag;
+#endif
 
-	fsa_dev_ptr = &(dev->fsa_dev);
+	fsa_dev_ptr = dev->fsa_dev;
+	if (!fsa_dev_ptr)
+		return -ENOMEM;
 	instance = dev->scsi_host_ptr->unique_id;
 
 	if (!(fibptr = fib_alloc(dev)))
@@ -388,27 +785,61 @@ static int probe_container(struct aac_dev *dev, int cid)
 	dinfo->count = cpu_to_le32(cid);
 	dinfo->type = cpu_to_le32(FT_FILESYS);
 
+#if (defined(AAC_DEBUG_INSTRUMENT_VM_NAMESERVE))
+	tag = jiffies;
+#endif
 	status = fib_send(ContainerCommand,
 			    fibptr,
 			    sizeof(struct aac_query_mount),
 			    FsaNormal,
 			    1, 1,
 			    NULL, NULL);
+#if (defined(AAC_DEBUG_INSTRUMENT_VM_NAMESERVE))
+	tag = jiffies - tag;
+	printk(KERN_INFO "VM_Nameserve: %lu.%03lus\n",
+	  tag / HZ, ((tag % HZ) * 1000) / HZ);
+#endif
 	if (status < 0) {
-		printk(KERN_WARNING "aacraid: probe_containers query failed.\n");
+		printk(KERN_WARNING "aacraid: probe_container query failed.\n");
 		goto error;
 	}
 
 	dresp = (struct aac_mount *) fib_data(fibptr);
 
 	if ((le32_to_cpu(dresp->status) == ST_OK) &&
+	    (le32_to_cpu(dresp->mnt[0].vol) == CT_NONE)) {
+		dinfo->command = cpu_to_le32(VM_NameServe64);
+		dinfo->count = cpu_to_le32(cid);
+		dinfo->type = cpu_to_le32(FT_FILESYS);
+
+#if (defined(AAC_DEBUG_INSTRUMENT_VM_NAMESERVE))
+		tag = jiffies;
+#endif
+		if (fib_send(ContainerCommand,
+			    fibptr,
+			    sizeof(struct aac_query_mount),
+			    FsaNormal,
+			    1, 1,
+			    NULL, NULL) < 0)
+			goto error;
+#if (defined(AAC_DEBUG_INSTRUMENT_VM_NAMESERVE))
+		tag = jiffies - tag;
+		printk(KERN_INFO "VM_Nameserve64: %lu.%03lus\n",
+		  tag / HZ, ((tag % HZ) * 1000) / HZ);
+#endif
+	} else
+		dresp->mnt[0].capacityhigh = 0;
+
+	if ((le32_to_cpu(dresp->status) == ST_OK) &&
 	    (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE) &&
 	    (le32_to_cpu(dresp->mnt[0].state) != FSCS_HIDDEN)) {
-		fsa_dev_ptr->valid[cid] = 1;
-		fsa_dev_ptr->type[cid] = le32_to_cpu(dresp->mnt[0].vol);
-		fsa_dev_ptr->size[cid] = le32_to_cpu(dresp->mnt[0].capacity);
+		fsa_dev_ptr[cid].valid = 1;
+		fsa_dev_ptr[cid].type = le32_to_cpu(dresp->mnt[0].vol);
+		fsa_dev_ptr[cid].size
+		  = ((u64)le32_to_cpu(dresp->mnt[0].capacity)) +
+		    (((u64)le32_to_cpu(dresp->mnt[0].capacityhigh)) << 32);
 		if (le32_to_cpu(dresp->mnt[0].state) & FSCS_READONLY)
-			fsa_dev_ptr->ro[cid] = 1;
+			fsa_dev_ptr[cid].ro = 1;
 	}
 
 error:
@@ -457,6 +888,11 @@ static char *container_types[] = {
         "V-MIRRORS",          
         "PSEUDO R4",          
 	"RAID50",
+	"RAID5D",
+	"RAID5D0",
+	"RAID1E",
+	"RAID6",
+	"RAID60",
         "Unknown"
 };
 
@@ -471,40 +907,68 @@ static char *container_types[] = {
  * files instead of in OS dependant driver source.
  */
 
-static void setinqstr(int devtype, void *data, int tindex)
+static void setinqstr(struct aac_dev *dev, void *data, int tindex)
 {
 	struct scsi_inq *str;
-	char *findit;
-	struct aac_driver_ident *mp;
 
-	mp = aac_get_driver_ident(devtype);
-   
 	str = (struct scsi_inq *)(data); /* cast data to scsi inq block */
+	memset(str, ' ', sizeof(*str));
+
+	if (dev->supplement_adapter_info.AdapterTypeText[0]) {
+		char * cp = dev->supplement_adapter_info.AdapterTypeText;
+		int c = sizeof(str->vid);
+		while (*cp && *cp != ' ' && --c)
+			++cp;
+		c = *cp;
+		*cp = '\0';
+		inqstrcpy (dev->supplement_adapter_info.AdapterTypeText,
+		  str->vid); 
+		*cp = c;
+		while (*cp && *cp != ' ')
+			++cp;
+		while (*cp == ' ')
+			++cp;
+		/* last six chars reserved for vol type */
+		c = 0;
+		if (strlen(cp) > sizeof(str->pid)) {
+			c = cp[sizeof(str->pid)];
+			cp[sizeof(str->pid)] = '\0';
+		}
+		inqstrcpy (cp, str->pid);
+		if (c)
+			cp[sizeof(str->pid)] = c;
+	} else {
+		struct aac_driver_ident *mp = aac_get_driver_ident(dev->cardtype);
+   
+		inqstrcpy (mp->vname, str->vid); 
+		/* last six chars reserved for vol type */
+		inqstrcpy (mp->model, str->pid);
+	}
 
-	inqstrcpy (mp->vname, str->vid); 
-	inqstrcpy (mp->model, str->pid); /* last six chars reserved for vol type */
-
-	findit = str->pid;
-
-	for ( ; *findit != ' '; findit++); /* walk till we find a space then incr by 1 */
-		findit++;
-	
 	if (tindex < (sizeof(container_types)/sizeof(char *))){
-		inqstrcpy (container_types[tindex], findit);
+		char *findit = str->pid;
+
+		for ( ; *findit != ' '; findit++); /* walk till we find a space */
+		/* RAID is superfluous in the context of a RAID device */
+		if (memcmp(findit-4, "RAID", 4) == 0)
+			*(findit -= 4) = ' ';
+		if (((findit - str->pid) + strlen(container_types[tindex]))
+		 < (sizeof(str->pid) + sizeof(str->prl)))
+			inqstrcpy (container_types[tindex], findit + 1);
 	}
 	inqstrcpy ("V1.0", str->prl);
 }
 
-void set_sense(u8 *sense_buf, u8 sense_key, u8 sense_code,
-		    u8 a_sense_code, u8 incorrect_length,
-		    u8 bit_pointer, u16 field_pointer,
-		    u32 residue)
+static void set_sense(u8 *sense_buf, u8 sense_key, u8 sense_code,
+		      u8 a_sense_code, u8 incorrect_length,
+		      u8 bit_pointer, u16 field_pointer,
+		      u32 residue)
 {
 	sense_buf[0] = 0xF0;	/* Sense data valid, err code 70h (current error) */
 	sense_buf[1] = 0;	/* Segment number, always zero */
 
 	if (incorrect_length) {
-		sense_buf[2] = sense_key | 0x20;	/* Set ILI bit | sense key */
+		sense_buf[2] = sense_key | 0x20;/* Set ILI bit | sense key */
 		sense_buf[3] = BYTE3(residue);
 		sense_buf[4] = BYTE2(residue);
 		sense_buf[5] = BYTE1(residue);
@@ -512,22 +976,22 @@ void set_sense(u8 *sense_buf, u8 sense_key, u8 sense_code,
 	} else
 		sense_buf[2] = sense_key;	/* Sense key */
 
-	if (sense_key == SENKEY_ILLEGAL)
+	if (sense_key == ILLEGAL_REQUEST)
 		sense_buf[7] = 10;	/* Additional sense length */
 	else
 		sense_buf[7] = 6;	/* Additional sense length */
 
 	sense_buf[12] = sense_code;	/* Additional sense code */
 	sense_buf[13] = a_sense_code;	/* Additional sense code qualifier */
-	if (sense_key == SENKEY_ILLEGAL) {
+	if (sense_key == ILLEGAL_REQUEST) {
 		sense_buf[15] = 0;
 
 		if (sense_code == SENCODE_INVALID_PARAM_FIELD)
-			sense_buf[15] = 0x80;	/* Std sense key specific field */
+			sense_buf[15] = 0x80;/* Std sense key specific field */
 		/* Illegal parameter is in the parameter block */
 
 		if (sense_code == SENCODE_INVALID_CDB_FIELD)
-			sense_buf[15] = 0xc0;	/* Std sense key specific field */
+			sense_buf[15] = 0xc0;/* Std sense key specific field */
 		/* Illegal parameter is in the CDB block */
 		sense_buf[15] |= bit_pointer;
 		sense_buf[16] = field_pointer >> 8;	/* MSB */
@@ -535,62 +999,178 @@ void set_sense(u8 *sense_buf, u8 sense_key, u8 sense_code,
 	}
 }
 
-static void aac_io_done(Scsi_Cmnd * scsicmd)
-{
-	unsigned long cpu_flags;
-	spin_lock_irqsave(&io_request_lock, cpu_flags);
-	scsicmd->scsi_done(scsicmd);
-	spin_unlock_irqrestore(&io_request_lock, cpu_flags);
-}
-
-static void __aac_io_done(Scsi_Cmnd * scsicmd)
-{
-	scsicmd->scsi_done(scsicmd);
-}
-
 int aac_get_adapter_info(struct aac_dev* dev)
 {
 	struct fib* fibptr;
-	struct aac_adapter_info* info;
 	int rcode;
 	u32 tmp;
+	struct aac_adapter_info *info;
+	struct aac_bus_info *command;
+	struct aac_bus_info_response *bus_info;
+
 	if (!(fibptr = fib_alloc(dev)))
 		return -ENOMEM;
 
 	fib_init(fibptr);
-	info = (struct aac_adapter_info*) fib_data(fibptr);
-
-	memset(info,0,sizeof(struct aac_adapter_info));
+	info = (struct aac_adapter_info *) fib_data(fibptr);
+	memset(info,0,sizeof(*info));
 
 	rcode = fib_send(RequestAdapterInfo,
-			fibptr, 
-			sizeof(struct aac_adapter_info),
-			FsaNormal, 
-			1, 1, 
-			NULL, 
+			 fibptr, 
+			 sizeof(*info),
+			 FsaNormal, 
+			 -1, 1, /* First `interrupt' command uses special wait */
+			 NULL, 
+			 NULL);
+
+	if (rcode < 0) {
+		fib_complete(fibptr);
+		fib_free(fibptr);
+		return rcode;
+	}
+	memcpy(&dev->adapter_info, info, sizeof(*info));
+
+	if (dev->adapter_info.options & AAC_OPT_SUPPLEMENT_ADAPTER_INFO) {
+		struct aac_supplement_adapter_info * info;
+
+		fib_init(fibptr);
+
+		info = (struct aac_supplement_adapter_info *) fib_data(fibptr);
+
+		memset(info,0,sizeof(*info));
+
+		rcode = fib_send(RequestSupplementAdapterInfo,
+				 fibptr,
+				 sizeof(*info),
+				 FsaNormal,
+				 1, 1,
+				 NULL,
+				 NULL);
+
+		if (rcode >= 0)
+			memcpy(&dev->supplement_adapter_info, info, sizeof(*info));
+		if ((dev->supplement_adapter_info.Version
+		      < AAC_SIS_VERSION_V3) ||
+		    (dev->supplement_adapter_info.SlotNumber
+		      == AAC_SIS_SLOT_UNKNOWN))
+			(void)aac_adapter_sync_cmd(dev, SEND_SLOT_NUMBER,
+			  dev->supplement_adapter_info.SlotNumber
+			    = PCI_SLOT(dev->pdev->devfn),
+			  0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL);
+	}
+
+#if (defined(CODE_STREAM_IDENTIFIER))
+	if (dev->supplement_adapter_info.FeatureBits & le32_to_cpu(AAC_FEATURE_FALCON)) {
+		char * info;
+
+		fib_init(fibptr);
+
+		info = (char *) fib_data(fibptr);
+
+		memset(info,0,MAX_CODE_STREAM_IDENTIFIER_LENGTH);
+
+		rcode = fib_send(RequestCompatibilityId,
+			fibptr,
+			MAX_CODE_STREAM_IDENTIFIER_LENGTH,
+			FsaNormal,
+			1, 1,
+			NULL,
 			NULL);
 
-	memcpy(&dev->adapter_info, info, sizeof(struct aac_adapter_info));
+		if (rcode >= 0)
+			memcpy(dev->code_stream_identifier, info,
+			  MAX_CODE_STREAM_IDENTIFIER_LENGTH);
+
+		if (dev->code_stream_identifier[0]
+		 && strncmp(CODE_STREAM_IDENTIFIER,
+		  dev->code_stream_identifier,
+		  MAX_CODE_STREAM_IDENTIFIER_LENGTH)) {
+			extern char aac_driver_version[];
+			printk(KERN_INFO
+			  "%s%d: Warning ! ! ! Compatibility Mismatch\n",
+			  dev->name, dev->id);
+			tmp = le32_to_cpu(dev->adapter_info.kernelrev);
+			printk(KERN_INFO
+			  "%s%d: Firmware=%d.%d-%d[%d], Device Driver=%s\n",
+			  dev->name, dev->id,
+			  tmp>>24,(tmp>>16)&0xff,tmp&0xff,
+			  le32_to_cpu(dev->adapter_info.kernelbuild),
+			  aac_driver_version);
+			printk(KERN_INFO
+			  "%s%d: These should be a tested set to avoid possible compatibility problems.\n",
+			  dev->name, dev->id);
+		}
+	}
+#endif
 
-	tmp = dev->adapter_info.kernelrev;
-	printk(KERN_INFO "%s%d: kernel %d.%d.%d build %d\n", 
-			dev->name, dev->id,
-			tmp>>24,(tmp>>16)&0xff,(tmp>>8)&0xff,
-			dev->adapter_info.kernelbuild);
-	tmp = dev->adapter_info.monitorrev;
-	printk(KERN_INFO "%s%d: monitor %d.%d.%d build %d\n", 
-			dev->name, dev->id,
-			tmp>>24,(tmp>>16)&0xff,(tmp>>8)&0xff,
-			dev->adapter_info.monitorbuild);
-	tmp = dev->adapter_info.biosrev;
-	printk(KERN_INFO "%s%d: bios %d.%d.%d build %d\n", 
+	/* 
+	 * GetBusInfo 
+	 */
+
+	fib_init(fibptr);
+
+	bus_info = (struct aac_bus_info_response *) fib_data(fibptr);
+
+	memset(bus_info, 0, sizeof(*bus_info));
+
+	command = (struct aac_bus_info *)bus_info;
+
+	command->Command = cpu_to_le32(VM_Ioctl);
+	command->ObjType = cpu_to_le32(FT_DRIVE);
+	command->MethodId = cpu_to_le32(1);
+	command->CtlCmd = cpu_to_le32(GetBusInfo);
+
+	rcode = fib_send(ContainerCommand,
+			 fibptr,
+			 sizeof (*bus_info),
+			 FsaNormal,
+			 1, 1,
+			 NULL, NULL);
+
+	if (rcode >= 0 && le32_to_cpu(bus_info->Status) == ST_OK) {
+		dev->maximum_num_physicals = le32_to_cpu(bus_info->TargetsPerBus);
+		dev->maximum_num_channels = le32_to_cpu(bus_info->BusCount);
+	}
+
+	if (!dev->in_reset) {
+		tmp = le32_to_cpu(dev->adapter_info.kernelrev);
+		printk(KERN_INFO "%s%d: kernel %d.%d-%d[%d] %.*s\n", 
+			dev->name, 
+			dev->id,
+			tmp>>24,
+			(tmp>>16)&0xff,
+			tmp&0xff,
+			le32_to_cpu(dev->adapter_info.kernelbuild),
+			(int)sizeof(dev->supplement_adapter_info.BuildDate),
+			dev->supplement_adapter_info.BuildDate);
+		tmp = le32_to_cpu(dev->adapter_info.monitorrev);
+		printk(KERN_INFO "%s%d: monitor %d.%d-%d[%d]\n", 
 			dev->name, dev->id,
-			tmp>>24,(tmp>>16)&0xff,(tmp>>8)&0xff,
-			dev->adapter_info.biosbuild);
-	printk(KERN_INFO "%s%d: serial %x%x\n",
+			tmp>>24,(tmp>>16)&0xff,tmp&0xff,
+			le32_to_cpu(dev->adapter_info.monitorbuild));
+		tmp = le32_to_cpu(dev->adapter_info.biosrev);
+		printk(KERN_INFO "%s%d: bios %d.%d-%d[%d]\n", 
 			dev->name, dev->id,
-			dev->adapter_info.serial[0],
-			dev->adapter_info.serial[1]);
+			tmp>>24,(tmp>>16)&0xff,tmp&0xff,
+			le32_to_cpu(dev->adapter_info.biosbuild));
+		if (le32_to_cpu(dev->adapter_info.serial[0]) != 0xBAD0)
+			printk(KERN_INFO "%s%d: serial %x\n",
+				dev->name, dev->id,
+				le32_to_cpu(dev->adapter_info.serial[0]));
+	}
+	aacraid_setup(aacraid);
+#if (defined(AAC_DEBUG_INSTRUMENT_SETUP))
+#if (defined(AAC_EXTENDED_TIMEOUT))
+	printk(KERN_INFO "nondasd=%d dacmode=%d commit=%d "
+	  "coalescethreshold=%d acbsize=%d extendedtimeout=%d\n",
+	  nondasd, dacmode, commit, coalescethreshold, acbsize,
+	  extendedtimeout);
+#else
+	printk(KERN_INFO "nondasd=%d dacmode=%d commit=%d "
+	  "coalescethreshold=%d acbsize=%d\n",
+	  nondasd, dacmode, commit, coalescethreshold, acbsize);
+#endif
+#endif
 
 	dev->nondasd_support = 0;
 	dev->raid_scsi_mode = 0;
@@ -609,33 +1189,92 @@ int aac_get_adapter_info(struct aac_dev* dev)
 	 * function aac_detect will have to be modified where it sets up the
 	 * max number of channels based on the aac->nondasd_support flag only.
 	 */
-	if ((dev->adapter_info.options & AAC_OPT_SCSI_MANAGED)
-		&& (dev->adapter_info.options & AAC_OPT_RAID_SCSI_MODE))
-	{
+	if ((dev->adapter_info.options & AAC_OPT_SCSI_MANAGED) &&
+	    (dev->adapter_info.options & AAC_OPT_RAID_SCSI_MODE)) {
 		dev->nondasd_support = 1;
 		dev->raid_scsi_mode = 1;
 	}
 	if (dev->raid_scsi_mode != 0)
-		printk(KERN_INFO "%s%d: ROMB RAID/SCSI mode enabled\n",dev->name, dev->id);
+		printk(KERN_INFO "%s%d: ROMB RAID/SCSI mode enabled\n",
+				dev->name, dev->id);
 		
-	if (nondasd != -1)
+	if(nondasd != -1) {  
 		dev->nondasd_support = (nondasd!=0);
-
-	if(dev->nondasd_support != 0)
-		printk(KERN_INFO "%s%d: Non-DASD support enabled\n",dev->name, dev->id);
-
-	dev->pae_support = 0;
-	if( (sizeof(dma_addr_t) > 4) && (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64)){
-		dev->pae_support = 1;
+	}
+	if(dev->nondasd_support != 0){
+		printk(KERN_INFO "%s%d: Non-DASD support enabled.\n",dev->name, dev->id);
 	}
 
-	if(paemode != -1)
-		dev->pae_support = (paemode != 0);
+	dev->dac_support = 0;
+	/*
+	 *	Only enable DAC mode if the dma_addr_t is larger than 32
+	 * bit addressing, and we have more than 32 bit addressing worth of
+	 * memory and if the controller supports 64 bit scatter gather elements.
+	 */
+	if( (sizeof(dma_addr_t) > 4) && (num_physpages > (0xFFFFFFFFULL >> PAGE_SHIFT)) && (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64)){
+		dev->dac_support = 1;
+	}
 
-	if(dev->pae_support != 0) 
-	{
-		printk(KERN_INFO "%s%d: 64 Bit PAE enabled\n", dev->name, dev->id);
-		pci_set_dma_mask(dev->pdev, (dma_addr_t)0xFFFFFFFFFFFFFFFFULL);
+	if(dacmode != -1) {
+		dev->dac_support = (dacmode!=0);
+	}
+	if(dev->dac_support != 0) {
+		if (!pci_set_dma_mask(dev->pdev, DMA_64BIT_MASK) &&
+			!pci_set_consistent_dma_mask(dev->pdev, DMA_64BIT_MASK)) {
+			printk(KERN_INFO"%s%d: 64 Bit DAC enabled\n",
+				dev->name, dev->id);
+		} else if (!pci_set_dma_mask(dev->pdev, DMA_32BIT_MASK) &&
+			!pci_set_consistent_dma_mask(dev->pdev, DMA_32BIT_MASK)) {
+			printk(KERN_INFO"%s%d: DMA mask set failed, 64 Bit DAC disabled\n",
+				dev->name, dev->id);
+			dev->dac_support = 0;
+		} else {
+			printk(KERN_WARNING"%s%d: No suitable DMA available.\n",
+				dev->name, dev->id);
+			rcode = -ENOMEM;
+		}
+	}
+	/* 
+	 * 57 scatter gather elements 
+	 */
+	if (!(dev->raw_io_interface)) {
+		dev->scsi_host_ptr->sg_tablesize = (dev->max_fib_size -
+			sizeof(struct aac_fibhdr) -
+			sizeof(struct aac_write) + sizeof(struct sgentry)) /
+				sizeof(struct sgentry);
+		if( (sizeof(dma_addr_t) > 4) && (num_physpages >= (0xFFFFFFFFULL >> PAGE_SHIFT)) && (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64) && (dev->dac_support) ){
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,18)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)) && (!defined(__arm__)) && defined(CONFIG_HIGHMEM) && ((LINUX_VERSION_CODE != KERNEL_VERSION(2,4,19)) || defined(CONFIG_HIGHIO))
+			dev->scsi_host_ptr->highmem_io = 1;
+#endif
+			/* 
+			 * 38 scatter gather elements 
+			 */
+			dev->scsi_host_ptr->sg_tablesize =
+				(dev->max_fib_size -
+				sizeof(struct aac_fibhdr) -
+				sizeof(struct aac_write64) +
+				sizeof(struct sgentry64)) /
+					sizeof(struct sgentry64);
+		}
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,18)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)) && (!defined(__arm__)) && defined(CONFIG_HIGHMEM) && ((LINUX_VERSION_CODE != KERNEL_VERSION(2,4,19)) || defined(CONFIG_HIGHIO))
+		else {
+			dev->scsi_host_ptr->highmem_io = 0;
+		}
+#endif
+		dev->scsi_host_ptr->max_sectors = AAC_MAX_32BIT_SGBCOUNT;
+		if(!(dev->adapter_info.options & AAC_OPT_NEW_COMM)) {
+			/*
+			 * Worst case size that could cause sg overflow when
+			 * we break up SG elements that are larger than 64KB.
+			 * Would be nice if we could tell the SCSI layer what
+			 * the maximum SG element size can be. Worst case is
+			 * (sg_tablesize-1) 4KB elements with one 64KB
+			 * element.
+			 *	32bit -> 468 or 238KB	64bit -> 424 or 212KB
+			 */
+			dev->scsi_host_ptr->max_sectors =
+			  (dev->scsi_host_ptr->sg_tablesize * 8) + 112;
+		}
 	}
 
 	fib_complete(fibptr);
@@ -645,21 +1284,49 @@ int aac_get_adapter_info(struct aac_dev* dev)
 }
 
 
-static void read_callback(void *context, struct fib * fibptr)
+static void io_callback(void *context, struct fib * fibptr)
 {
 	struct aac_dev *dev;
 	struct aac_read_reply *readreply;
-	Scsi_Cmnd *scsicmd;
-	u32 lba;
+	struct scsi_cmnd *scsicmd;
 	u32 cid;
 
-	scsicmd = (Scsi_Cmnd *) context;
-
-	dev = (struct aac_dev *)scsicmd->host->hostdata;
-	cid =TARGET_LUN_TO_CONTAINER(scsicmd->target, scsicmd->lun);
-
-	lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
-	dprintk((KERN_DEBUG "read_callback[cpu %d]: lba = %u, t = %ld.\n", smp_processor_id(), lba, jiffies));
+	scsicmd = (struct scsi_cmnd *) context;
+	scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL;
+
+	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
+	cid = ID_LUN_TO_CONTAINER(scsicmd->device->id, scsicmd->device->lun);
+
+	if (nblank(dprintk(x))) {
+		u64 lba;
+		if ((scsicmd->cmnd[0] == WRITE_6) ||	/* 6 byte command */
+		    (scsicmd->cmnd[0] == READ_6))
+			lba = ((scsicmd->cmnd[1] & 0x1F) << 16) |
+			    (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
+#if (defined(WRITE_16))
+		else if ((scsicmd->cmnd[0] == WRITE_16)	|| /* 16 byte command */
+		  	 (scsicmd->cmnd[0] == READ_16))
+			lba = ((u64)scsicmd->cmnd[2] << 56) |
+			      ((u64)scsicmd->cmnd[3] << 48) |
+			      ((u64)scsicmd->cmnd[4] << 40) |
+			      ((u64)scsicmd->cmnd[9] << 32) |
+			      ((u64)scsicmd->cmnd[6] << 24) |
+			      (scsicmd->cmnd[7] << 16) |
+			      (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
+#endif
+		else if ((scsicmd->cmnd[0] == WRITE_12)	|| /* 12 byte command */
+		 	 (scsicmd->cmnd[0] == READ_12))
+			lba = ((u64)scsicmd->cmnd[2] << 24) |
+			      (scsicmd->cmnd[3] << 16) |
+			      (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
+		else
+			lba = ((u64)scsicmd->cmnd[2] << 24) |
+			       (scsicmd->cmnd[3] << 16) |
+			       (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
+		printk(KERN_DEBUG
+		  "io_callback[cpu %d]: lba = %llu, t = %ld.\n",
+		  smp_processor_id(), (unsigned long long)lba, jiffies);
+	}
 
 	if (fibptr == NULL)
 		BUG();
@@ -668,77 +1335,108 @@ static void read_callback(void *context, struct fib * fibptr)
 		pci_unmap_sg(dev->pdev, 
 			(struct scatterlist *)scsicmd->buffer,
 			scsicmd->use_sg,
-			scsi_to_pci_dma_dir(scsicmd->sc_data_direction));
+			scsicmd->sc_data_direction);
 	else if(scsicmd->request_bufflen)
-		pci_unmap_single(dev->pdev, (dma_addr_t)(unsigned long)scsicmd->SCp.ptr,
+		pci_unmap_single(dev->pdev, scsicmd->SCp.dma_handle,
 				 scsicmd->request_bufflen,
-				 scsi_to_pci_dma_dir(scsicmd->sc_data_direction));
+				 scsicmd->sc_data_direction);
 	readreply = (struct aac_read_reply *)fib_data(fibptr);
 	if (le32_to_cpu(readreply->status) == ST_OK)
-		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
+		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
 	else {
-		printk(KERN_WARNING "read_callback: read failed, status = %d\n", readreply->status);
-		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION;
-		set_sense((u8 *) &sense_data[cid],
-				    SENKEY_HW_ERR,
+#ifdef AAC_DETAILED_STATUS_INFO
+		printk(KERN_WARNING "io_callback: io failed, status = %d\n",
+		  le32_to_cpu(readreply->status));
+#endif
+		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
+		set_sense((u8 *) &dev->fsa_dev[cid].sense_data,
+				    HARDWARE_ERROR,
 				    SENCODE_INTERNAL_TARGET_FAILURE,
 				    ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
 				    0, 0);
+		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
+		  (sizeof(dev->fsa_dev[cid].sense_data) > sizeof(scsicmd->sense_buffer))
+		    ? sizeof(scsicmd->sense_buffer)
+		    : sizeof(dev->fsa_dev[cid].sense_data));
 	}
 	fib_complete(fibptr);
 	fib_free(fibptr);
 
 	aac_io_done(scsicmd);
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+	if (scsicmd->device->device_blocked) {
+		struct scsi_cmnd * cmd;
+		cid = 0;
+
+		for (cmd = scsicmd->device->device_queue; cmd; cmd = cmd->next)
+			if (cmd->serial_number)
+				++cid;
+		if (cid < scsicmd->device->queue_depth)
+			scsicmd->device->device_blocked = 0;
+	}
+#endif
 }
 
-static void write_callback(void *context, struct fib * fibptr)
+static inline void aac_select_queue_depth(
+	struct scsi_cmnd * scsicmd,
+	int cid,
+	u64 lba,
+	u32 count)
 {
+	struct scsi_device *device = scsicmd->device;
 	struct aac_dev *dev;
-	struct aac_write_reply *writereply;
-	Scsi_Cmnd *scsicmd;
-	u32 lba;
-	u32 cid;
+	unsigned depth;
 
-	scsicmd = (Scsi_Cmnd *) context;
-	dev = (struct aac_dev *)scsicmd->host->hostdata;
-	cid = TARGET_LUN_TO_CONTAINER(scsicmd->target, scsicmd->lun);
-
-	lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
-	dprintk((KERN_DEBUG "write_callback[cpu %d]: lba = %u, t = %ld.\n", smp_processor_id(), lba, jiffies));
-	if (fibptr == NULL)
-		BUG();
-
-	if(scsicmd->use_sg)
-		pci_unmap_sg(dev->pdev, 
-			(struct scatterlist *)scsicmd->buffer,
-			scsicmd->use_sg,
-			scsi_to_pci_dma_dir(scsicmd->sc_data_direction));
-	else if(scsicmd->request_bufflen)
-		pci_unmap_single(dev->pdev, (dma_addr_t)(unsigned long)scsicmd->SCp.ptr,
-				 scsicmd->request_bufflen,
-				 scsi_to_pci_dma_dir(scsicmd->sc_data_direction));
-
-	writereply = (struct aac_write_reply *) fib_data(fibptr);
-	if (le32_to_cpu(writereply->status) == ST_OK)
-		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
-	else {
-		printk(KERN_WARNING "write_callback: write failed, status = %d\n", writereply->status);
-		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION;
-		set_sense((u8 *) &sense_data[cid],
-				    SENKEY_HW_ERR,
-				    SENCODE_INTERNAL_TARGET_FAILURE,
-				    ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
-				    0, 0);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+	if (!device->tagged_supported)
+		return;
+#endif
+	dev = (struct aac_dev *)device->host->hostdata;
+	if (dev->fsa_dev[cid].queue_depth <= 2)
+		dev->fsa_dev[cid].queue_depth = device->queue_depth;
+	if (lba == dev->fsa_dev[cid].last) {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+		struct scsi_cmnd * cmd;
+#endif
+		/*
+		 * If larger than coalescethreshold in size, coalescing has
+		 * less effect on overall performance.  Also, if we are
+		 * coalescing right now, leave it alone if above the threshold.
+		 */
+		if (count > coalescethreshold)
+			return;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+		depth = 0;
+
+		for (cmd = device->device_queue; cmd; cmd = cmd->next)
+			if ((cmd->serial_number)
+			 && (cmd != scsicmd)
+			 && (++depth > 1)) {
+				device->device_blocked = 1;
+				break;
+			}
+#endif
+		depth = 2;
+	} else {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+		device->device_blocked = 0;
+#endif
+		depth = dev->fsa_dev[cid].queue_depth;
 	}
-
-	fib_complete(fibptr);
-	fib_free(fibptr);
-	aac_io_done(scsicmd);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+	scsi_adjust_queue_depth(device, MSG_ORDERED_TAG, depth);
+#else
+	device->queue_depth = depth;
+#endif
+	dprintk((KERN_DEBUG "l=%llu %llu[%u] q=%u %lu\n",
+	  dev->fsa_dev[cid].last, lba, count, device->queue_depth,
+	  dev->queues->queue[AdapNormCmdQueue].numpending));
+	dev->fsa_dev[cid].last = lba + count;
 }
 
-int aac_read(Scsi_Cmnd * scsicmd, int cid)
+static int aac_read(struct scsi_cmnd * scsicmd, int cid)
 {
-	u32 lba;
+	u64 lba;
 	u32 count;
 	int status;
 
@@ -746,51 +1444,132 @@ int aac_read(Scsi_Cmnd * scsicmd, int cid)
 	struct aac_dev *dev;
 	struct fib * cmd_fibcontext;
 
-	dev = (struct aac_dev *)scsicmd->host->hostdata;
+	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
 	/*
 	 *	Get block address and transfer length
 	 */
-	if (scsicmd->cmnd[0] == SS_READ)	/* 6 byte command */
+#if (defined(AAC_DEBUG_INSTRUMENT_IO))
+	printk(KERN_DEBUG "aac_read: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+	  scsicmd->cmnd[0],  scsicmd->cmnd[1],  scsicmd->cmnd[2],
+	  scsicmd->cmnd[3],  scsicmd->cmnd[4],  scsicmd->cmnd[5],
+	  scsicmd->cmnd[6],  scsicmd->cmnd[7],  scsicmd->cmnd[8],
+	  scsicmd->cmnd[9],  scsicmd->cmnd[10], scsicmd->cmnd[11],
+	  scsicmd->cmnd[12], scsicmd->cmnd[13], scsicmd->cmnd[14],
+	  scsicmd->cmnd[15]);
+#endif
+	if (scsicmd->cmnd[0] == READ_6)	/* 6 byte command */
 	{
-		dprintk((KERN_DEBUG "aachba: received a read(6) command on target %d.\n", cid));
+		dprintk((KERN_DEBUG "aachba: received a read(6) command on id %d.\n", cid));
 
 		lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
 		count = scsicmd->cmnd[4];
 
 		if (count == 0)
 			count = 256;
+#if (defined(READ_16))
+	} else if (scsicmd->cmnd[0] == READ_16) { /* 16 byte command */
+		dprintk((KERN_DEBUG "aachba: received a read(16) command on id %d.\n", cid));
+
+		lba = 	((u64)scsicmd->cmnd[2] << 56) |
+		 	((u64)scsicmd->cmnd[3] << 48) |
+			((u64)scsicmd->cmnd[4] << 40) |
+			((u64)scsicmd->cmnd[9] << 32) |
+			((u64)scsicmd->cmnd[6] << 24) | 
+			(scsicmd->cmnd[7] << 16) |
+			(scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
+		count = (scsicmd->cmnd[10] << 24) | (scsicmd->cmnd[11] << 16) |
+			(scsicmd->cmnd[12] << 8) | scsicmd->cmnd[13];
+#endif
+	} else if (scsicmd->cmnd[0] == READ_12) { /* 12 byte command */
+		dprintk((KERN_DEBUG "aachba: received a read(12) command on id %d.\n", cid));
+
+		lba = ((u64)scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16)
+		    | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
+		count = (scsicmd->cmnd[6] << 24) | (scsicmd->cmnd[7] << 16)
+		      | (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
 	} else {
-		dprintk((KERN_DEBUG "aachba: received a read(10) command on target %d.\n", cid));
+		dprintk((KERN_DEBUG "aachba: received a read(10) command on id %d.\n", cid));
 
-		lba = (scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
+		lba = ((u64)scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
 		count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
 	}
-	dprintk((KERN_DEBUG "aac_read[cpu %d]: lba = %u, t = %ld.\n", smp_processor_id(), lba, jiffies));
+	dprintk((KERN_DEBUG "aac_read[cpu %d]: lba = %llu, t = %ld.\n",
+	  smp_processor_id(), (unsigned long long)lba, jiffies));
+	if ((!(dev->raw_io_interface) || !(dev->raw_io_64)) &&
+		(lba & 0xffffffff00000000LL)) {
+		dprintk((KERN_DEBUG "aac_read: Illegal lba\n"));
+		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | 
+			SAM_STAT_CHECK_CONDITION;
+		set_sense((u8 *) &dev->fsa_dev[cid].sense_data,
+			    HARDWARE_ERROR,
+			    SENCODE_INTERNAL_TARGET_FAILURE,
+			    ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
+			    0, 0);
+		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
+		  (sizeof(dev->fsa_dev[cid].sense_data) > sizeof(scsicmd->sense_buffer))
+		    ? sizeof(scsicmd->sense_buffer)
+		    : sizeof(dev->fsa_dev[cid].sense_data));
+#if (defined(AAC_DEBUG_INSTRUMENT_TIMING))
+		__aac_io_done(scsicmd);
+#else
+		scsicmd->scsi_done(scsicmd);
+#endif
+		return 0;
+	}
+	/*
+	 *	Are we in a sequential mode?
+	 */
+	aac_select_queue_depth(scsicmd, cid, lba, count);
 	/*
 	 *	Alocate and initialize a Fib
 	 */
 	if (!(cmd_fibcontext = fib_alloc(dev))) {
-		scsicmd->result = DID_ERROR << 16;
-		aac_io_done(scsicmd);
-		return (-1);
+		return -1;
 	}
 
 	fib_init(cmd_fibcontext);
 
-	if(dev->pae_support == 1){
+	if (dev->raw_io_interface) {
+		struct aac_raw_io *readcmd;
+		readcmd = (struct aac_raw_io *) fib_data(cmd_fibcontext);
+		readcmd->block[0] = cpu_to_le32((u32)(lba&0xffffffff));
+		readcmd->block[1] = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32));
+		readcmd->count = cpu_to_le32(count<<9);
+		readcmd->cid = cpu_to_le16(cid);
+		readcmd->flags = cpu_to_le16(1);
+		readcmd->bpTotal = 0;
+		readcmd->bpComplete = 0;
+		
+		aac_build_sgraw(scsicmd, &readcmd->sg);
+		fibsize = sizeof(struct aac_raw_io) + ((le32_to_cpu(readcmd->sg.count) - 1) * sizeof (struct sgentryraw));
+		if (fibsize > (dev->max_fib_size - sizeof(struct aac_fibhdr)))
+			BUG();
+		/*
+		 *	Now send the Fib to the adapter
+		 */
+		status = fib_send(ContainerRawIo,
+			  cmd_fibcontext, 
+			  fibsize, 
+			  FsaNormal, 
+			  0, 1, 
+			  (fib_callback) io_callback, 
+			  (void *) scsicmd);
+	} else if (dev->dac_support == 1) {
 		struct aac_read64 *readcmd;
 		readcmd = (struct aac_read64 *) fib_data(cmd_fibcontext);
 		readcmd->command = cpu_to_le32(VM_CtHostRead64);
 		readcmd->cid = cpu_to_le16(cid);
 		readcmd->sector_count = cpu_to_le16(count);
-		readcmd->block = cpu_to_le32(lba);
-		readcmd->pad   = cpu_to_le16(0);
-		readcmd->flags = cpu_to_le16(0); 
-		
+		readcmd->block = cpu_to_le32((u32)(lba&0xffffffff));
+		readcmd->pad   = 0;
+		readcmd->flags = 0; 
+
 		aac_build_sg64(scsicmd, &readcmd->sg);
-		if(readcmd->sg.count > MAX_DRIVER_SG_SEGMENT_COUNT)
-			BUG();
-		fibsize = sizeof(struct aac_read64) + ((readcmd->sg.count - 1) * sizeof (struct sgentry64));
+		fibsize = sizeof(struct aac_read64) + 
+			((le32_to_cpu(readcmd->sg.count) - 1) * 
+			 sizeof (struct sgentry64));
+		BUG_ON (fibsize > (dev->max_fib_size - 
+					sizeof(struct aac_fibhdr)));
 		/*
 		 *	Now send the Fib to the adapter
 		 */
@@ -799,23 +1578,22 @@ int aac_read(Scsi_Cmnd * scsicmd, int cid)
 			  fibsize, 
 			  FsaNormal, 
 			  0, 1, 
-			  (fib_callback) read_callback, 
+			  (fib_callback) io_callback, 
 			  (void *) scsicmd);
 	} else {
 		struct aac_read *readcmd;
 		readcmd = (struct aac_read *) fib_data(cmd_fibcontext);
 		readcmd->command = cpu_to_le32(VM_CtBlockRead);
 		readcmd->cid = cpu_to_le32(cid);
-		readcmd->block = cpu_to_le32(lba);
+		readcmd->block = cpu_to_le32((u32)(lba&0xffffffff));
 		readcmd->count = cpu_to_le32(count * 512);
 
-		if (count * 512 > (64 * 1024))
-			BUG();
-
 		aac_build_sg(scsicmd, &readcmd->sg);
-		if(readcmd->sg.count > MAX_DRIVER_SG_SEGMENT_COUNT)
-			BUG();
-		fibsize = sizeof(struct aac_read) + ((readcmd->sg.count - 1) * sizeof (struct sgentry));
+		fibsize = sizeof(struct aac_read) + 
+			((le32_to_cpu(readcmd->sg.count) - 1) * 
+			 sizeof (struct sgentry));
+		BUG_ON (fibsize > (dev->max_fib_size -
+					sizeof(struct aac_fibhdr)));
 		/*
 		 *	Now send the Fib to the adapter
 		 */
@@ -824,78 +1602,162 @@ int aac_read(Scsi_Cmnd * scsicmd, int cid)
 			  fibsize, 
 			  FsaNormal, 
 			  0, 1, 
-			  (fib_callback) read_callback, 
+			  (fib_callback) io_callback, 
 			  (void *) scsicmd);
 	}
+
 	
-	
+
 	/*
 	 *	Check that the command queued to the controller
 	 */
-	if (status == -EINPROGRESS) 
+	if (status == -EINPROGRESS) {
+		scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
 		return 0;
+	}
 		
 	printk(KERN_WARNING "aac_read: fib_send failed with status: %d.\n", status);
 	/*
 	 *	For some reason, the Fib didn't queue, return QUEUE_FULL
 	 */
-	scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | QUEUE_FULL;
+	scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_TASK_SET_FULL;
 	aac_io_done(scsicmd);
 	fib_complete(cmd_fibcontext);
 	fib_free(cmd_fibcontext);
-	return -1;
+	return 0;
 }
 
-static int aac_write(Scsi_Cmnd * scsicmd, int cid)
+static int aac_write(struct scsi_cmnd * scsicmd, int cid)
 {
-	u32 lba;
+	u64 lba;
 	u32 count;
 	int status;
 	u16 fibsize;
 	struct aac_dev *dev;
 	struct fib * cmd_fibcontext;
 
-	dev = (struct aac_dev *)scsicmd->host->hostdata;
+	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
 	/*
 	 *	Get block address and transfer length
 	 */
-	if (scsicmd->cmnd[0] == SS_WRITE)	/* 6 byte command */
+#if (defined(AAC_DEBUG_INSTRUMENT_IO))
+	printk(KERN_DEBUG "aac_write: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+	  scsicmd->cmnd[0],  scsicmd->cmnd[1],  scsicmd->cmnd[2],
+	  scsicmd->cmnd[3],  scsicmd->cmnd[4],  scsicmd->cmnd[5],
+	  scsicmd->cmnd[6],  scsicmd->cmnd[7],  scsicmd->cmnd[8],
+	  scsicmd->cmnd[9],  scsicmd->cmnd[10], scsicmd->cmnd[11],
+	  scsicmd->cmnd[12], scsicmd->cmnd[13], scsicmd->cmnd[14],
+	  scsicmd->cmnd[15]);
+#endif
+	if (scsicmd->cmnd[0] == WRITE_6)	/* 6 byte command */
 	{
 		lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
 		count = scsicmd->cmnd[4];
 		if (count == 0)
 			count = 256;
+#if (defined(WRITE_16))
+	} else if (scsicmd->cmnd[0] == WRITE_16) { /* 16 byte command */
+		dprintk((KERN_DEBUG "aachba: received a write(16) command on id %d.\n", cid));
+
+		lba = 	((u64)scsicmd->cmnd[2] << 56) |
+			((u64)scsicmd->cmnd[3] << 48) |
+			((u64)scsicmd->cmnd[4] << 40) |
+			((u64)scsicmd->cmnd[9] << 32) |
+			((u64)scsicmd->cmnd[6] << 24) | 
+			(scsicmd->cmnd[7] << 16) |
+			(scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
+		count = (scsicmd->cmnd[10] << 24) | (scsicmd->cmnd[11] << 16) |
+			(scsicmd->cmnd[12] << 8) | scsicmd->cmnd[13];
+#endif
+	} else if (scsicmd->cmnd[0] == WRITE_12) { /* 12 byte command */
+		dprintk((KERN_DEBUG "aachba: received a write(12) command on id %d.\n", cid));
+
+		lba = ((u64)scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16)
+		    | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
+		count = (scsicmd->cmnd[6] << 24) | (scsicmd->cmnd[7] << 16)
+		      | (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
 	} else {
-		dprintk((KERN_DEBUG "aachba: received a write(10) command on target %d.\n", cid));
-		lba = (scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
+		dprintk((KERN_DEBUG "aachba: received a write(10) command on id %d.\n", cid));
+		lba = ((u64)scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
 		count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
 	}
-	dprintk((KERN_DEBUG "aac_write[cpu %d]: lba = %u, t = %ld.\n", smp_processor_id(), lba, jiffies));
+	dprintk((KERN_DEBUG "aac_write[cpu %d]: lba = %llu, t = %ld.\n",
+	  smp_processor_id(), (unsigned long long)lba, jiffies));
+	if ((!(dev->raw_io_interface) || !(dev->raw_io_64))
+	 && (lba & 0xffffffff00000000LL)) {
+		dprintk((KERN_DEBUG "aac_write: Illegal lba\n"));
+		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
+		set_sense((u8 *) &dev->fsa_dev[cid].sense_data,
+			    HARDWARE_ERROR,
+			    SENCODE_INTERNAL_TARGET_FAILURE,
+			    ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
+			    0, 0);
+		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
+		  (sizeof(dev->fsa_dev[cid].sense_data) > sizeof(scsicmd->sense_buffer))
+		    ? sizeof(scsicmd->sense_buffer)
+		    : sizeof(dev->fsa_dev[cid].sense_data));
+#if (defined(AAC_DEBUG_INSTRUMENT_TIMING))
+		__aac_io_done(scsicmd);
+#else
+		scsicmd->scsi_done(scsicmd);
+#endif
+		return 0;
+	}
+	/*
+	 *	Are we in a sequential mode?
+	 */
+	aac_select_queue_depth(scsicmd, cid, lba, count);
 	/*
 	 *	Allocate and initialize a Fib then setup a BlockWrite command
 	 */
 	if (!(cmd_fibcontext = fib_alloc(dev))) {
 		scsicmd->result = DID_ERROR << 16;
 		aac_io_done(scsicmd);
-		return -1;
+		return 0;
 	}
 	fib_init(cmd_fibcontext);
 
-	if(dev->pae_support == 1)
-	{
+	if (dev->raw_io_interface) {
+		struct aac_raw_io *writecmd;
+		writecmd = (struct aac_raw_io *) fib_data(cmd_fibcontext);
+		writecmd->block[0] = cpu_to_le32((u32)(lba&0xffffffff));
+		writecmd->block[1] = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32));
+		writecmd->count = cpu_to_le32(count<<9);
+		writecmd->cid = cpu_to_le16(cid);
+		writecmd->flags = 0; 
+		writecmd->bpTotal = 0;
+		writecmd->bpComplete = 0;
+		
+		aac_build_sgraw(scsicmd, &writecmd->sg);
+		fibsize = sizeof(struct aac_raw_io) + ((le32_to_cpu(writecmd->sg.count) - 1) * sizeof (struct sgentryraw));
+		if (fibsize > (dev->max_fib_size - sizeof(struct aac_fibhdr)))
+			BUG();
+		/*
+		 *	Now send the Fib to the adapter
+		 */
+		status = fib_send(ContainerRawIo,
+			  cmd_fibcontext, 
+			  fibsize, 
+			  FsaNormal, 
+			  0, 1, 
+			  (fib_callback) io_callback, 
+			  (void *) scsicmd);
+	} else if (dev->dac_support == 1) {
 		struct aac_write64 *writecmd;
 		writecmd = (struct aac_write64 *) fib_data(cmd_fibcontext);
 		writecmd->command = cpu_to_le32(VM_CtHostWrite64);
 		writecmd->cid = cpu_to_le16(cid);
 		writecmd->sector_count = cpu_to_le16(count); 
-		writecmd->block = cpu_to_le32(lba);
-		writecmd->pad	= cpu_to_le16(0);
-		writecmd->flags	= cpu_to_le16(0);
+		writecmd->block = cpu_to_le32((u32)(lba&0xffffffff));
+		writecmd->pad	= 0;
+		writecmd->flags	= 0;
 
 		aac_build_sg64(scsicmd, &writecmd->sg);
-		if(writecmd->sg.count > MAX_DRIVER_SG_SEGMENT_COUNT)
-			BUG();
-		fibsize = sizeof(struct aac_write64) + ((writecmd->sg.count - 1) * sizeof (struct sgentry64));
+		fibsize = sizeof(struct aac_write64) + 
+			((le32_to_cpu(writecmd->sg.count) - 1) * 
+			 sizeof (struct sgentry64));
+		BUG_ON (fibsize > (dev->max_fib_size -
+					sizeof(struct aac_fibhdr)));
 		/*
 		 *	Now send the Fib to the adapter
 		 */
@@ -904,26 +1766,24 @@ static int aac_write(Scsi_Cmnd * scsicmd, int cid)
 			  fibsize, 
 			  FsaNormal, 
 			  0, 1, 
-			  (fib_callback) write_callback, 
+			  (fib_callback) io_callback, 
 			  (void *) scsicmd);
-	}
-	else 
-	{
+	} else {
 		struct aac_write *writecmd;
 		writecmd = (struct aac_write *) fib_data(cmd_fibcontext);
 		writecmd->command = cpu_to_le32(VM_CtBlockWrite);
 		writecmd->cid = cpu_to_le32(cid);
-		writecmd->block = cpu_to_le32(lba);
+		writecmd->block = cpu_to_le32((u32)(lba&0xffffffff));
 		writecmd->count = cpu_to_le32(count * 512);
 		writecmd->sg.count = cpu_to_le32(1);
 		/* ->stable is not used - it did mean which type of write */
 
-		if (count * 512 > (64 * 1024))
-			BUG();
 		aac_build_sg(scsicmd, &writecmd->sg);
-		if(writecmd->sg.count > MAX_DRIVER_SG_SEGMENT_COUNT)
-			BUG();
-		fibsize = sizeof(struct aac_write) + ((writecmd->sg.count - 1) * sizeof (struct sgentry));
+		fibsize = sizeof(struct aac_write) + 
+			((le32_to_cpu(writecmd->sg.count) - 1) * 
+			 sizeof (struct sgentry));
+		BUG_ON (fibsize > (dev->max_fib_size -
+					sizeof(struct aac_fibhdr)));
 		/*
 		 *	Now send the Fib to the adapter
 		 */
@@ -932,100 +1792,417 @@ static int aac_write(Scsi_Cmnd * scsicmd, int cid)
 			  fibsize, 
 			  FsaNormal, 
 			  0, 1, 
-			  (fib_callback) write_callback, 
+			  (fib_callback) io_callback, 
 			  (void *) scsicmd);
 	}
 
 	/*
 	 *	Check that the command queued to the controller
 	 */
-	if (status == -EINPROGRESS)
+	if (status == -EINPROGRESS) {
+		scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
 		return 0;
+	}
 
 	printk(KERN_WARNING "aac_write: fib_send failed with status: %d\n", status);
 	/*
 	 *	For some reason, the Fib didn't queue, return QUEUE_FULL
 	 */
-	scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | QUEUE_FULL;
+	scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_TASK_SET_FULL;
 	aac_io_done(scsicmd);
 
 	fib_complete(cmd_fibcontext);
 	fib_free(cmd_fibcontext);
-	return -1;
+	return 0;
+}
+
+static void synchronize_callback(void *context, struct fib *fibptr)
+{
+	struct aac_synchronize_reply *synchronizereply;
+	struct scsi_cmnd *cmd;
+
+	cmd = context;
+	cmd->SCp.phase = AAC_OWNER_MIDLEVEL;
+
+	dprintk((KERN_DEBUG "synchronize_callback[cpu %d]: t = %ld.\n", 
+				smp_processor_id(), jiffies));
+	BUG_ON(fibptr == NULL);
+
+
+	synchronizereply = fib_data(fibptr);
+	if (le32_to_cpu(synchronizereply->status) == CT_OK)
+		cmd->result = DID_OK << 16 | 
+			COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+	else {
+		struct scsi_device *sdev = cmd->device;
+		struct aac_dev *dev = (struct aac_dev *)sdev->host->hostdata;
+		u32 cid = ID_LUN_TO_CONTAINER(sdev->id, sdev->lun);
+		printk(KERN_WARNING 
+		     "synchronize_callback: synchronize failed, status = %d\n",
+		     le32_to_cpu(synchronizereply->status));
+		cmd->result = DID_OK << 16 | 
+			COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
+		set_sense((u8 *)&dev->fsa_dev[cid].sense_data,
+				    HARDWARE_ERROR,
+				    SENCODE_INTERNAL_TARGET_FAILURE,
+				    ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
+				    0, 0);
+		memcpy(cmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
+		  min(sizeof(dev->fsa_dev[cid].sense_data), 
+			  sizeof(cmd->sense_buffer)));
+	}
+
+	fib_complete(fibptr);
+	fib_free(fibptr);
+	aac_io_done(cmd);
 }
 
+static int aac_synchronize(struct scsi_cmnd *scsicmd, int cid)
+{
+	int status;
+	struct fib *cmd_fibcontext;
+	struct aac_synchronize *synchronizecmd;
+	struct scsi_cmnd *cmd;
+	struct scsi_device *sdev = scsicmd->device;
+	int active = 0;
+	struct aac_dev *aac;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+	unsigned long flags;
+
+	/*
+	 * Wait for all outstanding queued commands to complete to this
+	 * specific target (block).
+	 */
+	spin_lock_irqsave(&sdev->list_lock, flags);
+	list_for_each_entry(cmd, &sdev->cmd_list, list)
+		if (cmd != scsicmd && cmd->SCp.phase == AAC_OWNER_FIRMWARE) {
+			++active;
+			break;
+		}
+
+	spin_unlock_irqrestore(&sdev->list_lock, flags);
+#else
+
+	/*
+	 * Wait for all commands to complete to this specific
+	 * target (block).
+	 */
+	for(cmd = sdev->device_queue; cmd; cmd = cmd->next)
+		if (cmd != scsicmd && cmd->SCp.phase == AAC_OWNER_FIRMWARE) {
+			++active;
+			break;
+		}
+#endif
+
+	/*
+	 *	Yield the processor (requeue for later)
+	 */
+	if (active)
+		return SCSI_MLQUEUE_DEVICE_BUSY;
+
+	aac = (struct aac_dev *)scsicmd->device->host->hostdata;
+	if (aac->in_reset)
+		return SCSI_MLQUEUE_HOST_BUSY;
+
+#if (defined(AAC_DEBUG_INSTRUMENT_IO))
+	printk(KERN_DEBUG "aac_synchronize[cpu %d]: t = %ld.\n",
+	  smp_processor_id(), jiffies);
+#endif
+	/*
+	 *	Allocate and initialize a Fib
+	 */
+	if (!(cmd_fibcontext = fib_alloc(aac)))
+		return SCSI_MLQUEUE_HOST_BUSY;
+
+	fib_init(cmd_fibcontext);
+
+	synchronizecmd = fib_data(cmd_fibcontext);
+	synchronizecmd->command = cpu_to_le32(VM_ContainerConfig);
+	synchronizecmd->type = cpu_to_le32(CT_FLUSH_CACHE);
+	synchronizecmd->cid = cpu_to_le32(cid);
+	synchronizecmd->count = 
+	     cpu_to_le32(sizeof(((struct aac_synchronize_reply *)NULL)->data));
+
+	/*
+	 *	Now send the Fib to the adapter
+	 */
+	status = fib_send(ContainerCommand,
+		  cmd_fibcontext,
+		  sizeof(struct aac_synchronize),
+		  FsaNormal,
+		  0, 1,
+		  (fib_callback)synchronize_callback,
+		  (void *)scsicmd);
+
+	/*
+	 *	Check that the command queued to the controller
+	 */
+	if (status == -EINPROGRESS) {
+		scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
+		return 0;
+	}
+
+	printk(KERN_WARNING 
+		"aac_synchronize: fib_send failed with status: %d.\n", status);
+	fib_complete(cmd_fibcontext);
+	fib_free(cmd_fibcontext);
+	return SCSI_MLQUEUE_HOST_BUSY;
+}
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+
+static inline void get_sd_devname(int disknum, char *buffer)
+{
+	if (disknum < 0) {
+		buffer[0] = '\0';
+		return;
+	}
+
+	buffer[0] = 's';
+	buffer[1] = 'd';
+	if (disknum < 26) {
+		buffer[2] = 'a' + disknum;
+		buffer[3] = '\0';
+	} else {
+		/*
+		 * For larger numbers of disks, we need to go to a new
+		 * naming scheme.
+		 */
+		buffer[2] = 'a' - 1 + (disknum / 26);
+		buffer[3] = 'a' + (disknum % 26);
+		buffer[4] = '\0';
+	}
+}
+
+# define strlcpy(s1,s2,n) strncpy(s1,s2,n);s1[n-1]='\0'
+# ifndef min
+#  define min(a,b) (((a)<(b))?(a):(b))
+# endif
+#endif
 
 /**
  *	aac_scsi_cmd()		-	Process SCSI command
  *	@scsicmd:		SCSI command block
- *	@wait:			1 if the user wants to await completion
  *
  *	Emulate a SCSI command and queue the required request for the
  *	aacraid firmware.
  */
  
-int aac_scsi_cmd(Scsi_Cmnd * scsicmd)
+int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
 {
 	u32 cid = 0;
-	struct fsa_scsi_hba *fsa_dev_ptr;
-	int cardtype;
-	int ret;
-	struct aac_dev *dev = (struct aac_dev *)scsicmd->host->hostdata;
+	struct Scsi_Host *host = scsicmd->device->host;
+	struct aac_dev *dev = (struct aac_dev *)host->hostdata;
+	struct fsa_dev_info *fsa_dev_ptr = dev->fsa_dev;
 	
-	cardtype = dev->cardtype;
-
-	fsa_dev_ptr = fsa_dev[scsicmd->host->unique_id];
-
+	if (fsa_dev_ptr == NULL)
+		return -1;
+#	if (defined(AAC_DEBUG_INSTRUMENT_2TB))
+		printk(KERN_NOTICE "scsicmd->cmnd={%02x %02x %02x %02x %02x "
+		  "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x}\n",
+		  scsicmd->cmnd[0], scsicmd->cmnd[1], scsicmd->cmnd[2],
+		  scsicmd->cmnd[3], scsicmd->cmnd[4], scsicmd->cmnd[5],
+		  scsicmd->cmnd[6], scsicmd->cmnd[7], scsicmd->cmnd[8],
+		  scsicmd->cmnd[9], scsicmd->cmnd[10], scsicmd->cmnd[11],
+		  scsicmd->cmnd[12], scsicmd->cmnd[13], scsicmd->cmnd[14],
+		  scsicmd->cmnd[15]);
+#	endif
 	/*
-	 *	If the bus, target or lun is out of range, return fail
+	 *	If the bus, id or lun is out of range, return fail
 	 *	Test does not apply to ID 16, the pseudo id for the controller
 	 *	itself.
 	 */
-	if (scsicmd->target != scsicmd->host->this_id) {
-		if ((scsicmd->channel == 0) ){
-			if( (scsicmd->target >= AAC_MAX_TARGET) || (scsicmd->lun != 0)){ 
+	if (scsicmd->device->id != host->this_id) {
+		if ((scsicmd->device->channel == 0) ){
+			if( (scsicmd->device->id >= dev->maximum_num_containers) || (scsicmd->device->lun != 0)){ 
+#				if (defined(AAC_DEBUG_INSTRUMENT_2TB))
+					printk(KERN_INFO
+					  "scsicmd(0:%d:%d:0) No Connect\n",
+					  scsicmd->device->channel,
+					  scsicmd->device->id);
+#				endif
 				scsicmd->result = DID_NO_CONNECT << 16;
+#if (defined(AAC_DEBUG_INSTRUMENT_TIMING))
 				__aac_io_done(scsicmd);
+#else
+				scsicmd->scsi_done(scsicmd);
+#endif
 				return 0;
 			}
-			cid = TARGET_LUN_TO_CONTAINER(scsicmd->target, scsicmd->lun);
+			cid = ID_LUN_TO_CONTAINER(scsicmd->device->id, scsicmd->device->lun);
 
 			/*
 			 *	If the target container doesn't exist, it may have
 			 *	been newly created
 			 */
-			if (fsa_dev_ptr->valid[cid] == 0) {
+#if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) && defined(CONFIG_TIMESYS))
+			if ((fsa_dev_ptr[cid].valid & 1) == 0)
+				fsa_dev_ptr[cid].valid = 0;
+#else
+#if (!defined(__arm__) && !defined(CONFIG_EXTERNAL))
+			if ((fsa_dev_ptr[cid].valid & 1) == 0) {
+#endif
 				switch (scsicmd->cmnd[0]) {
-				case SS_INQUIR:
-				case SS_RDCAP:
-				case SS_TEST:
+#if (defined(SERVICE_ACTION_IN))
+				case SERVICE_ACTION_IN:
+					if (!(dev->raw_io_interface) ||
+					    !(dev->raw_io_64) ||
+					    ((scsicmd->cmnd[1] & 0x1f) != SAI_READ_CAPACITY_16))
+						break;
+#endif
+				case INQUIRY:
+				case READ_CAPACITY:
+				case TEST_UNIT_READY:
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19))
+# if (MAX_NESTED == 1)
+					if (fsa_dev_ptr[cid].nested)
+						return -1;
+					fsa_dev_ptr[cid].nested = 1;
+# else
+					if (fsa_dev_ptr[cid].nested >= MAX_NESTED)
+						return -1;
+					++(fsa_dev_ptr[cid].nested);
+# endif
+#endif
+					if (dev->in_reset)
+						return -1;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+					spin_unlock_irq(host->host_lock);
+#else
 					spin_unlock_irq(&io_request_lock);
+#endif
 					probe_container(dev, cid);
+					if ((fsa_dev_ptr[cid].valid & 1) == 0)
+						fsa_dev_ptr[cid].valid = 0;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+					spin_lock_irq(host->host_lock);
+#else
 					spin_lock_irq(&io_request_lock);
-					if (fsa_dev_ptr->valid[cid] == 0) {
+#endif
+					if (fsa_dev_ptr[cid].valid == 0) {
+#						if (defined(AAC_DEBUG_INSTRUMENT_2TB))
+							printk(KERN_INFO
+							  "scsicmd(0:%d:%d:0) "
+							  "Invalid\n",
+							  scsicmd->device->channel,
+							  scsicmd->device->id);
+#						endif
 						scsicmd->result = DID_NO_CONNECT << 16;
+#if (defined(AAC_DEBUG_INSTRUMENT_TIMING))
 						__aac_io_done(scsicmd);
+#else
+						scsicmd->scsi_done(scsicmd);
+#endif
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19))
+# if (MAX_NESTED == 1)
+						fsa_dev_ptr[cid].nested = 0;
+# else
+						if (fsa_dev_ptr[cid].nested != 0)
+							--(fsa_dev_ptr[cid].nested);
+# endif
+#endif
 						return 0;
 					}
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19))
+# if (MAX_NESTED == 1)
+					fsa_dev_ptr[cid].nested = 0;
+# else
+					if (fsa_dev_ptr[cid].nested != 0)
+						--(fsa_dev_ptr[cid].nested);
+# endif
+#endif
 				default:
 					break;
 				}
+#if (!defined(__arm__) && !defined(CONFIG_EXTERNAL))
 			}
+#endif
+#endif
 			/*
 			 *	If the target container still doesn't exist, 
 			 *	return failure
 			 */
-			if (fsa_dev_ptr->valid[cid] == 0) {
+			if (fsa_dev_ptr[cid].valid == 0) {
+#				if (defined(AAC_DEBUG_INSTRUMENT_2TB))
+					printk(KERN_INFO
+					  "scsicmd(0:%d:%d:0) Does not exist\n",
+					  scsicmd->device->channel,
+					  scsicmd->device->id);
+#				endif
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19))
+# if (MAX_NESTED == 1)
+				if (fsa_dev_ptr[cid].nested)
+					return -1;
+				fsa_dev_ptr[cid].nested = 1;
+# else
+				if (fsa_dev_ptr[cid].nested >= MAX_NESTED)
+					return -1;
+				++(fsa_dev_ptr[cid].nested);
+# endif
+#endif
 				scsicmd->result = DID_BAD_TARGET << 16;
+#if (defined(AAC_DEBUG_INSTRUMENT_TIMING))
 				__aac_io_done(scsicmd);
-				return -1;
+#else
+				scsicmd->scsi_done(scsicmd);
+#endif
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19))
+# if (MAX_NESTED == 1)
+				fsa_dev_ptr[cid].nested = 0;
+# else
+				if (fsa_dev_ptr[cid].nested != 0)
+					--(fsa_dev_ptr[cid].nested);
+# endif
+#endif
+				return 0;
 			}
 		} else {  /* check for physical non-dasd devices */
+#			if (defined(AAC_DEBUG_INSTRUMENT_2TB))
+				printk(KERN_INFO "scsicmd(0:%d:%d:0) Phys\n",
+				  scsicmd->device->channel,
+				  scsicmd->device->id);
+#			endif
 			if(dev->nondasd_support == 1){
+#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)) || defined(BLIST_NO_ULD_ATTACH))
+				if (scsicmd->device->no_uld_attach)
+				switch (scsicmd->cmnd[0]) {
+				/* Filter Format? SMART Verify/Fix? */
+				case WRITE_6:
+				case WRITE_10:
+				case WRITE_12:
+#if (defined(WRITE_16))
+				case WRITE_16:
+#endif
+					scsicmd->result = DID_OK << 16
+					  | COMMAND_COMPLETE << 8
+					  | SAM_STAT_CHECK_CONDITION;
+					set_sense((u8 *)
+					  &dev->fsa_dev[cid].sense_data,
+					  DATA_PROTECT, SENCODE_DATA_PROTECT,
+					  ASENCODE_END_OF_DATA, 0, 0, 0, 0);
+					memcpy(scsicmd->sense_buffer,
+					  &dev->fsa_dev[cid].sense_data,
+					  (sizeof(dev->fsa_dev[cid].sense_data)
+					      > sizeof(scsicmd->sense_buffer))
+					    ? sizeof(scsicmd->sense_buffer)
+					    : sizeof(dev->fsa_dev[cid].sense_data));
+#if (defined(AAC_DEBUG_INSTRUMENT_TIMING))
+					__aac_io_done(scsicmd);
+#else
+					scsicmd->scsi_done(scsicmd);
+#endif
+					return 0;
+				}
+#endif
+				if (dev->in_reset)
+					return -1;
 				return aac_send_srb_fib(scsicmd);
 			} else {
 				scsicmd->result = DID_NO_CONNECT << 16;
+#if (defined(AAC_DEBUG_INSTRUMENT_TIMING))
 				__aac_io_done(scsicmd);
+#else
+				scsicmd->scsi_done(scsicmd);
+#endif
 				return 0;
 			}
 		}
@@ -1033,59 +2210,141 @@ int aac_scsi_cmd(Scsi_Cmnd * scsicmd)
 	/*
 	 * else Command for the controller itself
 	 */
-	else if ((scsicmd->cmnd[0] != SS_INQUIR) &&	/* only INQUIRY & TUR cmnd supported for controller */
-		(scsicmd->cmnd[0] != SS_TEST)) 
+	else if ((scsicmd->cmnd[0] != INQUIRY) &&	/* only INQUIRY & TUR cmnd supported for controller */
+		(scsicmd->cmnd[0] != TEST_UNIT_READY)) 
 	{
 		dprintk((KERN_WARNING "Only INQUIRY & TUR command supported for controller, rcvd = 0x%x.\n", scsicmd->cmnd[0]));
-		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION;
-		set_sense((u8 *) &sense_data[cid],
-			    SENKEY_ILLEGAL,
+		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
+		set_sense((u8 *) &dev->fsa_dev[cid].sense_data,
+			    ILLEGAL_REQUEST,
 			    SENCODE_INVALID_COMMAND,
 			    ASENCODE_INVALID_COMMAND, 0, 0, 0, 0);
+		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
+		  (sizeof(dev->fsa_dev[cid].sense_data) > sizeof(scsicmd->sense_buffer))
+		    ? sizeof(scsicmd->sense_buffer)
+		    : sizeof(dev->fsa_dev[cid].sense_data));
+#if (defined(AAC_DEBUG_INSTRUMENT_TIMING))
 		__aac_io_done(scsicmd);
-		return -1;
+#else
+		scsicmd->scsi_done(scsicmd);
+#endif
+		return 0;
 	}
 
 
 	/* Handle commands here that don't really require going out to the adapter */
+#	if (defined(AAC_DEBUG_INSTRUMENT_2TB))
+		printk(KERN_NOTICE "cmnd[0]=%02x\n", scsicmd->cmnd[0]);
+#	endif
 	switch (scsicmd->cmnd[0]) {
-	case SS_INQUIR:
+	case INQUIRY:
 	{
-		struct inquiry_data *inq_data_ptr;
+		struct inquiry_data inq_data;
 
-		dprintk((KERN_DEBUG "INQUIRY command, ID: %d.\n", scsicmd->target));
-		inq_data_ptr = (struct inquiry_data *)scsicmd->request_buffer;
-		memset(inq_data_ptr, 0, sizeof (struct inquiry_data));
+		dprintk((KERN_DEBUG "INQUIRY command, ID: %d.\n", scsicmd->device->id));
+		memset(&inq_data, 0, sizeof (struct inquiry_data));
 
-		inq_data_ptr->inqd_ver = 2;	/* claim compliance to SCSI-2 */
-		inq_data_ptr->inqd_rdf = 2;	/* A response data format value of two indicates that the data shall be in the format specified in SCSI-2 */
-		inq_data_ptr->inqd_len = 31;
+		inq_data.inqd_ver = 2;	/* claim compliance to SCSI-2 */
+		inq_data.inqd_rdf = 2;	/* A response data format value of two indicates that the data shall be in the format specified in SCSI-2 */
+		inq_data.inqd_len = 31;
 		/*Format for "pad2" is  RelAdr | WBus32 | WBus16 |  Sync  | Linked |Reserved| CmdQue | SftRe */
-		inq_data_ptr->inqd_pad2= 0x32 ;	 /*WBus16|Sync|CmdQue */
+		inq_data.inqd_pad2= 0x32 ;	 /*WBus16|Sync|CmdQue */
 		/*
 		 *	Set the Vendor, Product, and Revision Level
 		 *	see: <vendor>.c i.e. aac.c
 		 */
-		if (scsicmd->target == scsicmd->host->this_id) {
-			setinqstr(cardtype, (void *) (inq_data_ptr->inqd_vid), (sizeof(container_types)/sizeof(char *)));
-			inq_data_ptr->inqd_pdt = INQD_PDT_PROC;	/* Processor device */
-		} else {
-			setinqstr(cardtype, (void *) (inq_data_ptr->inqd_vid), fsa_dev_ptr->type[cid]);
-			aac_get_container_name(dev, cid, inq_data_ptr->inqd_pid);
-			inq_data_ptr->inqd_pdt = INQD_PDT_DA;	/* Direct/random access device */
+		if (scsicmd->device->id == host->this_id) {
+			setinqstr(dev, (void *) (inq_data.inqd_vid), (sizeof(container_types)/sizeof(char *)));
+			inq_data.inqd_pdt = INQD_PDT_PROC;	/* Processor device */
+			aac_internal_transfer(scsicmd, &inq_data, 0, sizeof(inq_data));
+			scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+#if (defined(AAC_DEBUG_INSTRUMENT_TIMING))
+			__aac_io_done(scsicmd);
+#else
+			scsicmd->scsi_done(scsicmd);
+#endif
+			return 0;
+		}
+		if (dev->in_reset)
+			return -1;
+		setinqstr(dev, (void *) (inq_data.inqd_vid), fsa_dev_ptr[cid].type);
+		inq_data.inqd_pdt = INQD_PDT_DA;	/* Direct/random access device */
+		aac_internal_transfer(scsicmd, &inq_data, 0, sizeof(inq_data));
+		return aac_get_container_name(scsicmd, cid);
+	}
+#if (defined(SERVICE_ACTION_IN))
+	case SERVICE_ACTION_IN:
+#if (defined(AAC_DEBUG_INSTRUMENT_2TB))
+		printk(KERN_NOTICE
+		  "SERVICE_ACTION_IN, raw_io_interface=%d raw_io_64=%d\n",
+		  dev->raw_io_interface, dev->raw_io_64);
+#endif
+		if (!(dev->raw_io_interface) ||
+		    !(dev->raw_io_64) ||
+		    ((scsicmd->cmnd[1] & 0x1f) != SAI_READ_CAPACITY_16))
+			break;
+	{
+		u64 capacity;
+		char cp[12];
+		unsigned int offset = 0;
+
+		dprintk((KERN_DEBUG "READ CAPACITY_16 command.\n"));
+		capacity = fsa_dev_ptr[cid].size - 1;
+		if (scsicmd->cmnd[13] > 12) {
+			offset = scsicmd->cmnd[13] - 12;
+			if (offset > sizeof(cp))
+				break;
+			memset(cp, 0, offset);
+			aac_internal_transfer(scsicmd, cp, 0, offset);
 		}
-		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
+		cp[0] = (capacity >> 56) & 0xff;
+		cp[1] = (capacity >> 48) & 0xff;
+		cp[2] = (capacity >> 40) & 0xff;
+		cp[3] = (capacity >> 32) & 0xff;
+		cp[4] = (capacity >> 24) & 0xff;
+		cp[5] = (capacity >> 16) & 0xff;
+		cp[6] = (capacity >> 8) & 0xff;
+		cp[7] = (capacity >> 0) & 0xff;
+		cp[8] = 0;
+		cp[9] = 0;
+		cp[10] = 2;
+		cp[11] = 0;
+#if (defined(AAC_DEBUG_INSTRUMENT_2TB))
+		printk(KERN_INFO "SAI_READ_CAPACITY_16(%d): "
+		  "%02x %02x %02x %02x %02x %02x %02x %02x "
+		  "%02x %02x %02x %02x\n",
+		  scsicmd->cmnd[13],
+		  cp[0] & 0xff, cp[1] & 0xff, cp[2] & 0xff, cp[3] & 0xff,
+		  cp[4] & 0xff, cp[5] & 0xff, cp[6] & 0xff, cp[7] & 0xff,
+		  cp[8] & 0xff, cp[9] & 0xff, cp[10] & 0xff, cp[11] & 0xff);
+#endif
+		aac_internal_transfer(scsicmd, cp, offset, sizeof(cp));
+
+		/* Do not cache partition table for arrays */
+		scsicmd->device->removable = 1;
+
+		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+#if (defined(AAC_DEBUG_INSTRUMENT_TIMING))
 		__aac_io_done(scsicmd);
+#else
+		scsicmd->scsi_done(scsicmd);
+#endif
+
 		return 0;
 	}
-	case SS_RDCAP:
+
+#endif
+	case READ_CAPACITY:
 	{
-		int capacity;
-		char *cp;
+		u32 capacity;
+		char cp[8];
 
 		dprintk((KERN_DEBUG "READ CAPACITY command.\n"));
-		capacity = fsa_dev_ptr->size[cid] - 1;
-		cp = scsicmd->request_buffer;
+		if (fsa_dev_ptr[cid].size <= 0x100000000ULL)
+			capacity = fsa_dev_ptr[cid].size - 1;
+		else
+			capacity = (u32)-1;
+
 		cp[0] = (capacity >> 24) & 0xff;
 		cp[1] = (capacity >> 16) & 0xff;
 		cp[2] = (capacity >> 8) & 0xff;
@@ -1094,19 +2353,51 @@ int aac_scsi_cmd(Scsi_Cmnd * scsicmd)
 		cp[5] = 0;
 		cp[6] = 2;
 		cp[7] = 0;
-
-		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
+#if (defined(AAC_DEBUG_INSTRUMENT_2TB))
+		printk(KERN_INFO "READ_CAPACITY: "
+		  "%02x %02x %02x %02x %02x %02x %02x %02x\n",
+		  cp[0] & 0xff, cp[1] & 0xff, cp[2] & 0xff, cp[3] & 0xff,
+		  cp[4] & 0xff, cp[5] & 0xff, cp[6] & 0xff, cp[7] & 0xff);
+#endif
+		aac_internal_transfer(scsicmd, cp, 0, sizeof(cp));
+		/* Do not cache partition table for arrays */
+		scsicmd->device->removable = 1;
+
+		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+#if (defined(AAC_DEBUG_INSTRUMENT_TIMING))
 		__aac_io_done(scsicmd);
+#else
+		scsicmd->scsi_done(scsicmd);
+#endif
 
 		return 0;
 	}
 
-	case SS_MODESEN:
+	case MODE_SENSE:
 	{
-		char *mode_buf;
+		char mode_buf[4];
 
 		dprintk((KERN_DEBUG "MODE SENSE command.\n"));
-		mode_buf = scsicmd->request_buffer;
+		mode_buf[0] = 3;	/* Mode data length */
+		mode_buf[1] = 0;	/* Medium type - default */
+		mode_buf[2] = 0;	/* Device-specific param, bit 8: 0/1 = write enabled/protected */
+		mode_buf[3] = 0;	/* Block descriptor length */
+
+		aac_internal_transfer(scsicmd, mode_buf, 0, sizeof(mode_buf));
+		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+#if (defined(AAC_DEBUG_INSTRUMENT_TIMING))
+		__aac_io_done(scsicmd);
+#else
+		scsicmd->scsi_done(scsicmd);
+#endif
+
+		return 0;
+	}
+	case MODE_SENSE_10:
+	{
+		char mode_buf[8];
+
+		dprintk((KERN_DEBUG "MODE SENSE 10 byte command.\n"));
 		mode_buf[0] = 0;	/* Mode data length (MSB) */
 		mode_buf[1] = 6;	/* Mode data length (LSB) */
 		mode_buf[2] = 0;	/* Medium type - default */
@@ -1115,202 +2406,352 @@ int aac_scsi_cmd(Scsi_Cmnd * scsicmd)
 		mode_buf[5] = 0;	/* reserved */
 		mode_buf[6] = 0;	/* Block descriptor length (MSB) */
 		mode_buf[7] = 0;	/* Block descriptor length (LSB) */
+		aac_internal_transfer(scsicmd, mode_buf, 0, sizeof(mode_buf));
 
-		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
+		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+#if (defined(AAC_DEBUG_INSTRUMENT_TIMING))
 		__aac_io_done(scsicmd);
+#else
+		scsicmd->scsi_done(scsicmd);
+#endif
 
 		return 0;
 	}
-	case SS_REQSEN:
+	case REQUEST_SENSE:
 		dprintk((KERN_DEBUG "REQUEST SENSE command.\n"));
-		memcpy(scsicmd->sense_buffer, &sense_data[cid], sizeof (struct sense_data));
-		memset(&sense_data[cid], 0, sizeof (struct sense_data));
-		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
+		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, sizeof (struct sense_data));
+		memset(&dev->fsa_dev[cid].sense_data, 0, sizeof (struct sense_data));
+		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+#if (defined(AAC_DEBUG_INSTRUMENT_TIMING))
 		__aac_io_done(scsicmd);
-		return (0);
+#else
+		scsicmd->scsi_done(scsicmd);
+#endif
+		return 0;
 
-	case SS_LOCK:
+	case ALLOW_MEDIUM_REMOVAL:
 		dprintk((KERN_DEBUG "LOCK command.\n"));
 		if (scsicmd->cmnd[4])
-			fsa_dev_ptr->locked[cid] = 1;
+			fsa_dev_ptr[cid].locked = 1;
 		else
-			fsa_dev_ptr->locked[cid] = 0;
+			fsa_dev_ptr[cid].locked = 0;
 
-		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
+		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+#if (defined(AAC_DEBUG_INSTRUMENT_TIMING))
 		__aac_io_done(scsicmd);
+#else
+		scsicmd->scsi_done(scsicmd);
+#endif
 		return 0;
 	/*
 	 *	These commands are all No-Ops
 	 */
-	case SS_TEST:
-	case SS_RESERV:
-	case SS_RELES:
-	case SS_REZERO:
-	case SS_REASGN:
-	case SS_SEEK:
-	case SS_ST_SP:
-		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
+	case TEST_UNIT_READY:
+	case RESERVE:
+	case RELEASE:
+	case REZERO_UNIT:
+	case REASSIGN_BLOCKS:
+	case SEEK_10:
+	case START_STOP:
+		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+#if (defined(AAC_DEBUG_INSTRUMENT_TIMING))
 		__aac_io_done(scsicmd);
-		return (0);
+#else
+		scsicmd->scsi_done(scsicmd);
+#endif
+		return 0;
 	}
 
 	switch (scsicmd->cmnd[0]) 
 	{
-		case SS_READ:
-		case SM_READ:
+		case READ_6:
+		case READ_10:
+		case READ_12:
+#if (defined(READ_16))
+		case READ_16:
+#endif
+			if (dev->in_reset)
+				return -1;
 			/*
 			 *	Hack to keep track of ordinal number of the device that
 			 *	corresponds to a container. Needed to convert
 			 *	containers to /dev/sd device names
 			 */
+#if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) && defined(AAC_EXTENDED_TIMEOUT))
+			if ((scsicmd->eh_state != SCSI_STATE_QUEUED)
+			 && (extendedtimeout > 0)) {
+				mod_timer(&scsicmd->eh_timeout, jiffies + (extendedtimeout * HZ));
+			}
+#endif
 			 
-			spin_unlock_irq(&io_request_lock);
-			fsa_dev_ptr->devno[cid] = DEVICE_NR(scsicmd->request.rq_dev);
-			ret = aac_read(scsicmd, cid);
-			spin_lock_irq(&io_request_lock);
-			return ret;
-
-		case SS_WRITE:
-		case SM_WRITE:
-			spin_unlock_irq(&io_request_lock);
-			ret = aac_write(scsicmd, cid);
-			spin_lock_irq(&io_request_lock);
-			return ret;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+#if (defined(AAC_DEBUG_INSTRUMENT_IOCTL))
+			if(fsa_dev_ptr[cid].devname[0]=='\0') {
+				printk(KERN_INFO
+				  "rq_disk=%p disk_name=\"%s\"\n",
+				  scsicmd->request->rq_disk,
+				  scsicmd->request->rq_disk
+				    ? scsicmd->request->rq_disk->disk_name
+				    : "Aiiiii");
+			}
+#endif
+			if (scsicmd->request->rq_disk)
+				strlcpy(fsa_dev_ptr[cid].devname,
+				scsicmd->request->rq_disk->disk_name,
+				min(sizeof(fsa_dev_ptr[cid].devname),
+				  sizeof(scsicmd->request->rq_disk->disk_name) + 1));
+#else
+			get_sd_devname(DEVICE_NR(scsicmd->request.rq_dev), fsa_dev_ptr[cid].devname);
+#endif
+
+			return aac_read(scsicmd, cid);
+
+		case WRITE_6:
+		case WRITE_10:
+		case WRITE_12:
+#if (defined(WRITE_16))
+		case WRITE_16:
+#endif
+			if (dev->in_reset)
+				return -1;
+#if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) && defined(AAC_EXTENDED_TIMEOUT))
+			if ((scsicmd->eh_state != SCSI_STATE_QUEUED)
+			 && (extendedtimeout > 0)) {
+				mod_timer(&scsicmd->eh_timeout, jiffies + (extendedtimeout * HZ));
+			}
+#endif
+			return aac_write(scsicmd, cid);
+
+		case SYNCHRONIZE_CACHE:
+			/* Issue FIB to tell Firmware to flush it's cache */
+			return aac_synchronize(scsicmd, cid);
+			
 		default:
 			/*
 			 *	Unhandled commands
 			 */
-			printk(KERN_WARNING "Unhandled SCSI Command: 0x%x.\n", scsicmd->cmnd[0]);
-			scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION;
-			set_sense((u8 *) &sense_data[cid],
-				SENKEY_ILLEGAL, SENCODE_INVALID_COMMAND,
-			ASENCODE_INVALID_COMMAND, 0, 0, 0, 0);
+			dprintk((KERN_WARNING "Unhandled SCSI Command: 0x%x.\n", scsicmd->cmnd[0]));
+			scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
+			set_sense((u8 *) &dev->fsa_dev[cid].sense_data,
+				ILLEGAL_REQUEST, SENCODE_INVALID_COMMAND,
+				ASENCODE_INVALID_COMMAND, 0, 0, 0, 0);
+			memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
+			  (sizeof(dev->fsa_dev[cid].sense_data) > sizeof(scsicmd->sense_buffer))
+			    ? sizeof(scsicmd->sense_buffer)
+			    : sizeof(dev->fsa_dev[cid].sense_data));
+#if (defined(AAC_DEBUG_INSTRUMENT_TIMING))
 			__aac_io_done(scsicmd);
+#else
+			scsicmd->scsi_done(scsicmd);
+#endif
 			return 0;
 	}
 }
 
-static int query_disk(struct aac_dev *dev, void *arg)
+static int busy_disk(struct aac_dev * dev, int cid)
+{
+	if ((dev != (struct aac_dev *)NULL)
+	 && (dev->scsi_host_ptr != (struct Scsi_Host *)NULL)) {
+		struct scsi_device *device;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
+		shost_for_each_device(device, dev->scsi_host_ptr)
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+		list_for_each_entry(device, &dev->scsi_host_ptr->my_devices, siblings)
+#else
+		for (device = dev->scsi_host_ptr->host_queue;
+		  device != (struct scsi_device *)NULL;
+		  device = device->next)
+#endif
+		{
+			if ((device->channel == CONTAINER_TO_CHANNEL(cid))
+			 && (device->id == CONTAINER_TO_ID(cid))
+			 && (device->lun == CONTAINER_TO_LUN(cid))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
+			 && (atomic_read(&device->access_count)
+			  || test_bit(SHOST_RECOVERY, &dev->scsi_host_ptr->shost_state))) {
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
+			&& (device->device_busy
+			  || test_bit(SHOST_RECOVERY, &dev->scsi_host_ptr->shost_state))) {
+#else
+			&& (device->access_count
+			  || dev->scsi_host_ptr->in_recovery)) {
+#endif
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
+				scsi_device_put(device);
+#endif
+				return 1;
+			}
+		}
+	}
+	return 0;
+}
+
+static int query_disk(struct aac_dev *dev, void __user *arg)
 {
 	struct aac_query_disk qd;
-	struct fsa_scsi_hba *fsa_dev_ptr;
+	struct fsa_dev_info *fsa_dev_ptr;
 
-	fsa_dev_ptr = &(dev->fsa_dev);
+	fsa_dev_ptr = dev->fsa_dev;
+	if (!fsa_dev_ptr)
+		return -ENODEV;
 	if (copy_from_user(&qd, arg, sizeof (struct aac_query_disk)))
 		return -EFAULT;
 	if (qd.cnum == -1)
-		qd.cnum = TARGET_LUN_TO_CONTAINER(qd.target, qd.lun);
-	else if ((qd.bus == -1) && (qd.target == -1) && (qd.lun == -1)) 
+		qd.cnum = ID_LUN_TO_CONTAINER(qd.id, qd.lun);
+	else if ((qd.bus == -1) && (qd.id == -1) && (qd.lun == -1)) 
 	{
-		if (qd.cnum < 0 || qd.cnum > MAXIMUM_NUM_CONTAINERS)
+		if (qd.cnum < 0 || qd.cnum >= dev->maximum_num_containers)
 			return -EINVAL;
 		qd.instance = dev->scsi_host_ptr->host_no;
 		qd.bus = 0;
-		qd.target = CONTAINER_TO_TARGET(qd.cnum);
+		qd.id = CONTAINER_TO_ID(qd.cnum);
 		qd.lun = CONTAINER_TO_LUN(qd.cnum);
 	}
 	else return -EINVAL;
 
-	qd.valid = fsa_dev_ptr->valid[qd.cnum];
-	qd.locked = fsa_dev_ptr->locked[qd.cnum];
-	qd.deleted = fsa_dev_ptr->deleted[qd.cnum];
+	qd.valid = fsa_dev_ptr[qd.cnum].valid != 0;
+	qd.locked = fsa_dev_ptr[qd.cnum].locked || busy_disk(dev, qd.cnum);
+	qd.deleted = fsa_dev_ptr[qd.cnum].deleted;
 
-	if (fsa_dev_ptr->devno[qd.cnum] == -1)
+	if (fsa_dev_ptr[qd.cnum].devname[0] == '\0')
 		qd.unmapped = 1;
 	else
 		qd.unmapped = 0;
 
-	get_sd_devname(fsa_dev_ptr->devno[qd.cnum], qd.name);
+	strlcpy(qd.name, fsa_dev_ptr[qd.cnum].devname,
+	  min(sizeof(qd.name), sizeof(fsa_dev_ptr[qd.cnum].devname) + 1));
 
 	if (copy_to_user(arg, &qd, sizeof (struct aac_query_disk)))
 		return -EFAULT;
 	return 0;
 }
 
-static void get_sd_devname(int disknum, char *buffer)
-{
-	if (disknum < 0) {
-		sprintf(buffer, "%s", "");
-		return;
-	}
-
-	if (disknum < 26)
-		sprintf(buffer, "sd%c", 'a' + disknum);
-	else {
-		unsigned int min1;
-		unsigned int min2;
-		/*
-		 * For larger numbers of disks, we need to go to a new
-		 * naming scheme.
-		 */
-		min1 = disknum / 26;
-		min2 = disknum % 26;
-		sprintf(buffer, "sd%c%c", 'a' + min1 - 1, 'a' + min2);
-	}
-}
-
-static int force_delete_disk(struct aac_dev *dev, void *arg)
+static int force_delete_disk(struct aac_dev *dev, void __user *arg)
 {
 	struct aac_delete_disk dd;
-	struct fsa_scsi_hba *fsa_dev_ptr;
+	struct fsa_dev_info *fsa_dev_ptr;
 
-	fsa_dev_ptr = &(dev->fsa_dev);
+	fsa_dev_ptr = dev->fsa_dev;
+	if (!fsa_dev_ptr)
+		return -ENODEV;
 
 	if (copy_from_user(&dd, arg, sizeof (struct aac_delete_disk)))
 		return -EFAULT;
 
-	if (dd.cnum > MAXIMUM_NUM_CONTAINERS)
+	if (dd.cnum >= dev->maximum_num_containers)
 		return -EINVAL;
 	/*
 	 *	Mark this container as being deleted.
 	 */
-	fsa_dev_ptr->deleted[dd.cnum] = 1;
+	fsa_dev_ptr[dd.cnum].deleted = 1;
 	/*
 	 *	Mark the container as no longer valid
 	 */
-	fsa_dev_ptr->valid[dd.cnum] = 0;
+	fsa_dev_ptr[dd.cnum].valid = 0;
 	return 0;
 }
 
-static int delete_disk(struct aac_dev *dev, void *arg)
+static int delete_disk(struct aac_dev *dev, void __user *arg)
 {
 	struct aac_delete_disk dd;
-	struct fsa_scsi_hba *fsa_dev_ptr;
+	struct fsa_dev_info *fsa_dev_ptr;
 
-	fsa_dev_ptr = &(dev->fsa_dev);
+	fsa_dev_ptr = dev->fsa_dev;
+	if (!fsa_dev_ptr)
+		return -ENODEV;
 
 	if (copy_from_user(&dd, arg, sizeof (struct aac_delete_disk)))
 		return -EFAULT;
 
-	if (dd.cnum > MAXIMUM_NUM_CONTAINERS)
+	if (dd.cnum >= dev->maximum_num_containers)
 		return -EINVAL;
 	/*
 	 *	If the container is locked, it can not be deleted by the API.
 	 */
-	if (fsa_dev_ptr->locked[dd.cnum])
+	if (fsa_dev_ptr[dd.cnum].locked || busy_disk(dev, dd.cnum))
 		return -EBUSY;
 	else {
 		/*
 		 *	Mark the container as no longer being valid.
 		 */
-		fsa_dev_ptr->valid[dd.cnum] = 0;
-		fsa_dev_ptr->devno[dd.cnum] = -1;
+		fsa_dev_ptr[dd.cnum].valid = 0;
+		fsa_dev_ptr[dd.cnum].devname[0] = '\0';
 		return 0;
 	}
 }
 
-int aac_dev_ioctl(struct aac_dev *dev, int cmd, void *arg)
+#if (defined(FSACTL_REGISTER_FIB_SEND))
+static int aac_register_fib_send(struct aac_dev *dev, void *arg)
 {
+	fib_send_t callback;
+
+	if (arg == NULL) {
+		return -EINVAL;
+	}
+	callback = *((fib_send_t *)arg);
+	*((fib_send_t *)arg) = aac_fib_send;
+	if (callback == (fib_send_t)NULL) {
+		fib_send = aac_fib_send;
+		return 0;
+	}
+	if (fib_send != aac_fib_send) {
+		return -EBUSY;
+	}
+	fib_send = callback;
+	return 0;
+}
+
+#endif
+int aac_dev_ioctl(struct aac_dev *dev, int cmd, void __user *arg)
+{
+#if (defined(AAC_DEBUG_INSTRUMENT_IOCTL))
+	int retval;
+	if (cmd != FSACTL_GET_NEXT_ADAPTER_FIB)
+		printk("aac_dev_ioctl(%p,%x,%p)\n", dev, cmd, arg);
+#endif
 	switch (cmd) {
 	case FSACTL_QUERY_DISK:
+#if (defined(AAC_DEBUG_INSTRUMENT_IOCTL))
+		retval = query_disk(dev, arg);
+		printk("aac_dev_ioctl returns %d\n", retval);
+		return retval;
+#endif
 		return query_disk(dev, arg);
 	case FSACTL_DELETE_DISK:
+#if (defined(AAC_DEBUG_INSTRUMENT_IOCTL))
+		retval = delete_disk(dev, arg);
+		printk("aac_dev_ioctl returns %d\n", retval);
+		return retval;
+#endif
 		return delete_disk(dev, arg);
 	case FSACTL_FORCE_DELETE_DISK:
+#if (defined(AAC_DEBUG_INSTRUMENT_IOCTL))
+		retval = force_delete_disk(dev, arg);
+		printk("aac_dev_ioctl returns %d\n", retval);
+		return retval;
+#endif
 		return force_delete_disk(dev, arg);
-	case 2131:
+	case FSACTL_GET_CONTAINERS:
+#if (defined(AAC_DEBUG_INSTRUMENT_IOCTL))
+		retval = aac_get_containers(dev);
+		printk("aac_dev_ioctl returns %d\n", retval);
+		return retval;
+#endif
 		return aac_get_containers(dev);
+#if (defined(FSACTL_REGISTER_FIB_SEND))
+	case FSACTL_REGISTER_FIB_SEND:
+#if (defined(AAC_DEBUG_INSTRUMENT_IOCTL))
+		retval = aac_register_fib_send(dev, arg);
+		printk("aac_dev_ioctl returns %d\n", retval);
+		return retval;
+#endif
+		return aac_register_fib_send(dev, arg);
+#endif
 	default:
+#if (defined(AAC_DEBUG_INSTRUMENT_IOCTL))
+		printk("aac_dev_ioctl returns -ENOTTY\n");
+	case FSACTL_GET_NEXT_ADAPTER_FIB:
+#endif
 		return -ENOTTY;
 	}
 }
@@ -1329,28 +2770,33 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
 {
 	struct aac_dev *dev;
 	struct aac_srb_reply *srbreply;
-	Scsi_Cmnd *scsicmd;
+	struct scsi_cmnd *scsicmd;
 
-	scsicmd = (Scsi_Cmnd *) context;
-	dev = (struct aac_dev *)scsicmd->host->hostdata;
+	scsicmd = (struct scsi_cmnd *) context;
+	scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL;
+	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
 
 	if (fibptr == NULL)
 		BUG();
 
 	srbreply = (struct aac_srb_reply *) fib_data(fibptr);
 
-	scsicmd->sense_buffer[0] = '\0';  // initialize sense valid flag to false
-	// calculate resid for sg 
-	scsicmd->resid = scsicmd->request_bufflen - srbreply->data_xfer_length;
+	scsicmd->sense_buffer[0] = '\0';  /* Initialize sense valid flag to false */
+	/*
+	 *	Calculate resid for sg 
+	 */
+	 
+	scsicmd->resid = scsicmd->request_bufflen - 
+		le32_to_cpu(srbreply->data_xfer_length);
 
 	if(scsicmd->use_sg)
 		pci_unmap_sg(dev->pdev, 
 			(struct scatterlist *)scsicmd->buffer,
 			scsicmd->use_sg,
-			scsi_to_pci_dma_dir(scsicmd->sc_data_direction));
+			scsicmd->sc_data_direction);
 	else if(scsicmd->request_bufflen)
-		pci_unmap_single(dev->pdev, (ulong)scsicmd->SCp.ptr, scsicmd->request_bufflen,
-			scsi_to_pci_dma_dir(scsicmd->sc_data_direction));
+		pci_unmap_single(dev->pdev, scsicmd->SCp.dma_handle, scsicmd->request_bufflen,
+			scsicmd->sc_data_direction);
 
 	/*
 	 * First check the fib status
@@ -1359,9 +2805,11 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
 	if (le32_to_cpu(srbreply->status) != ST_OK){
 		int len;
 		printk(KERN_WARNING "aac_srb_callback: srb failed, status = %d\n", le32_to_cpu(srbreply->status));
-		len = (srbreply->sense_data_size > sizeof(scsicmd->sense_buffer))?
-				sizeof(scsicmd->sense_buffer):srbreply->sense_data_size;
-		scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION;
+		len = (le32_to_cpu(srbreply->sense_data_size) > 
+				sizeof(scsicmd->sense_buffer)) ?
+				sizeof(scsicmd->sense_buffer) : 
+				le32_to_cpu(srbreply->sense_data_size);
+		scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
 		memcpy(scsicmd->sense_buffer, srbreply->sense_data, len);
 	}
 
@@ -1372,6 +2820,9 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
 	case SRB_STATUS_ERROR_RECOVERY:
 	case SRB_STATUS_PENDING:
 	case SRB_STATUS_SUCCESS:
+#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)) || defined(BLIST_NO_ULD_ATTACH))
+		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
+#else
 		if(scsicmd->cmnd[0] == INQUIRY ){
 			u8 b;
 			u8 b1;
@@ -1388,14 +2839,18 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
 			 * We will allow disk devices if in RAID/SCSI mode and
 			 * the channel is 2
 			 */
-			} else if((dev->raid_scsi_mode)&&(scsicmd->channel == 2)){
-				scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
+			} else if ((dev->raid_scsi_mode) &&
+					(scsicmd->device->channel == 2)) {
+				scsicmd->result = DID_OK << 16 | 
+						COMMAND_COMPLETE << 8;
 			} else {
-				scsicmd->result = DID_NO_CONNECT << 16 | COMMAND_COMPLETE << 8;
+				scsicmd->result = DID_NO_CONNECT << 16 | 
+						COMMAND_COMPLETE << 8;
 			}
 		} else {
 			scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
 		}
+#endif
 		break;
 	case SRB_STATUS_DATA_OVERRUN:
 		switch(scsicmd->cmnd[0]){
@@ -1405,6 +2860,12 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
 		case  WRITE_10:
 		case  READ_12:
 		case  WRITE_12:
+#if (defined(READ_16))
+		case  READ_16:
+#endif
+#if (defined(WRITE_16))
+		case  WRITE_16:
+#endif
 			if(le32_to_cpu(srbreply->data_xfer_length) < scsicmd->underflow ) {
 				printk(KERN_WARNING"aacraid: SCSI CMD underflow\n");
 			} else {
@@ -1413,6 +2874,9 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
 			scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8;
 			break;
 		case INQUIRY: {
+#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)) || defined(BLIST_NO_ULD_ATTACH))
+			scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
+#else
 			u8 b;
 			u8 b1;
 			/* We can't expose disk devices because we can't tell whether they
@@ -1427,11 +2891,15 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
 			 * We will allow disk devices if in RAID/SCSI mode and
 			 * the channel is 2
 			 */
-			} else if((dev->raid_scsi_mode)&&(scsicmd->channel == 2)){
-				scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
+			} else if ((dev->raid_scsi_mode) &&
+					(scsicmd->device->channel == 2)) {
+				scsicmd->result = DID_OK << 16 | 
+						COMMAND_COMPLETE << 8;
 			} else {
-				scsicmd->result = DID_NO_CONNECT << 16 | COMMAND_COMPLETE << 8;
+				scsicmd->result = DID_NO_CONNECT << 16 | 
+						COMMAND_COMPLETE << 8;
 			}
+#endif
 			break;
 		}
 		default:
@@ -1488,17 +2956,30 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
 	case SRB_STATUS_FORCE_ABORT:
 	case SRB_STATUS_DOMAIN_VALIDATION_FAIL:
 	default:
-		printk("aacraid: SRB ERROR(%u) %s scsi cmd 0x%x - scsi status 0x%x\n",le32_to_cpu(srbreply->srb_status&0x3f),aac_get_status_string(le32_to_cpu(srbreply->srb_status)), scsicmd->cmnd[0], le32_to_cpu(srbreply->scsi_status) );
+#ifdef AAC_DETAILED_STATUS_INFO
+		printk("aacraid: SRB ERROR(%u) %s scsi cmd 0x%x - scsi status 0x%x\n",
+			le32_to_cpu(srbreply->srb_status) & 0x3F,
+			aac_get_status_string(
+				le32_to_cpu(srbreply->srb_status) & 0x3F), 
+			scsicmd->cmnd[0], 
+			le32_to_cpu(srbreply->scsi_status));
+#endif
 		scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8;
 		break;
 	}
 	if (le32_to_cpu(srbreply->scsi_status) == 0x02 ){  // Check Condition
 		int len;
-		scsicmd->result |= CHECK_CONDITION;
-		len = (srbreply->sense_data_size > sizeof(scsicmd->sense_buffer))?
-				sizeof(scsicmd->sense_buffer):srbreply->sense_data_size;
-		printk(KERN_WARNING "aac_srb_callback: check condition, status = %d len=%d\n", le32_to_cpu(srbreply->status), len);
+		scsicmd->result |= SAM_STAT_CHECK_CONDITION;
+		len = (le32_to_cpu(srbreply->sense_data_size) > 
+				sizeof(scsicmd->sense_buffer)) ?
+				sizeof(scsicmd->sense_buffer) :
+				le32_to_cpu(srbreply->sense_data_size);
+#ifdef AAC_DETAILED_STATUS_INFO
+		printk(KERN_WARNING "aac_srb_callback: check condition, status = %d len=%d\n",
+					le32_to_cpu(srbreply->status), len);
+#endif
 		memcpy(scsicmd->sense_buffer, srbreply->sense_data, len);
+		
 	}
 	/*
 	 * OR in the scsi status (already shifted up a bit)
@@ -1519,7 +3000,7 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
  * scsicmd passed in.
  */
 
-static int aac_send_srb_fib(Scsi_Cmnd* scsicmd)
+static int aac_send_srb_fib(struct scsi_cmnd* scsicmd)
 {
 	struct fib* cmd_fibcontext;
 	struct aac_dev* dev;
@@ -1529,25 +3010,30 @@ static int aac_send_srb_fib(Scsi_Cmnd* scsicmd)
 	u32 flag;
 	u32 timeout;
 
-	if( scsicmd->target > 15 || scsicmd->lun > 7) {
+	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
+	if (scsicmd->device->id >= dev->maximum_num_physicals || 
+			scsicmd->device->lun > 7) {
 		scsicmd->result = DID_NO_CONNECT << 16;
+#if (defined(AAC_DEBUG_INSTRUMENT_TIMING))
 		__aac_io_done(scsicmd);
+#else
+		scsicmd->scsi_done(scsicmd);
+#endif
 		return 0;
 	}
 
-	dev = (struct aac_dev *)scsicmd->host->hostdata;
 	switch(scsicmd->sc_data_direction){
-	case SCSI_DATA_WRITE:
+	case DMA_TO_DEVICE:
 		flag = SRB_DataOut;
 		break;
-	case SCSI_DATA_UNKNOWN:  
+	case DMA_BIDIRECTIONAL:
 		flag = SRB_DataIn | SRB_DataOut;
 		break;
-	case SCSI_DATA_READ:
+	case DMA_FROM_DEVICE:
 		flag = SRB_DataIn;
 		break;
-	case SCSI_DATA_NONE: 
-	default:
+	case DMA_NONE:
+	default:	/* shuts up some versions of gcc */
 		flag = SRB_NoDataXfer;
 		break;
 	}
@@ -1557,27 +3043,25 @@ static int aac_send_srb_fib(Scsi_Cmnd* scsicmd)
 	 *	Allocate and initialize a Fib then setup a BlockWrite command
 	 */
 	if (!(cmd_fibcontext = fib_alloc(dev))) {
-		scsicmd->result = DID_ERROR << 16;
-		__aac_io_done(scsicmd);
 		return -1;
 	}
 	fib_init(cmd_fibcontext);
 
 	srbcmd = (struct aac_srb*) fib_data(cmd_fibcontext);
 	srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi);
-	srbcmd->channel  = cpu_to_le32(aac_logical_to_phys(scsicmd->channel));
-	srbcmd->target   = cpu_to_le32(scsicmd->target);
-	srbcmd->lun      = cpu_to_le32(scsicmd->lun);
+	srbcmd->channel  = cpu_to_le32(aac_logical_to_phys(scsicmd->device->channel));
+	srbcmd->id   = cpu_to_le32(scsicmd->device->id);
+	srbcmd->lun      = cpu_to_le32(scsicmd->device->lun);
 	srbcmd->flags    = cpu_to_le32(flag);
-	timeout = (scsicmd->timeout-jiffies)/HZ;
+	timeout = scsicmd->timeout_per_command/HZ;
 	if(timeout == 0){
 		timeout = 1;
 	}
 	srbcmd->timeout  = cpu_to_le32(timeout);  // timeout in seconds
-	srbcmd->retry_limit =cpu_to_le32(0); // Obsolete parameter
+	srbcmd->retry_limit = 0; /* Obsolete parameter */
 	srbcmd->cdb_size = cpu_to_le32(scsicmd->cmd_len);
 	
-	if( dev->pae_support ==1 ) {
+	if( dev->dac_support == 1 ) {
 		aac_build_sg64(scsicmd, (struct sgmap64*) &srbcmd->sg);
 		srbcmd->count = cpu_to_le32(scsicmd->request_bufflen);
 
@@ -1586,13 +3070,19 @@ static int aac_send_srb_fib(Scsi_Cmnd* scsicmd)
 		/*
 		 *	Build Scatter/Gather list
 		 */
-		fibsize = sizeof (struct aac_srb) - sizeof (struct sgentry) + ((srbcmd->sg.count & 0xff) * sizeof (struct sgentry64));
+		fibsize = sizeof (struct aac_srb) - sizeof (struct sgentry) +
+			((le32_to_cpu(srbcmd->sg.count) & 0xff) * 
+			 sizeof (struct sgentry64));
+		BUG_ON (fibsize > (dev->max_fib_size -
+					sizeof(struct aac_fibhdr)));
 
 		/*
 		 *	Now send the Fib to the adapter
 		 */
-		status = fib_send(ScsiPortCommand64, cmd_fibcontext, fibsize, FsaNormal, 0, 1,
-				  (fib_callback) aac_srb_callback, (void *) scsicmd);
+		status = fib_send(ScsiPortCommand64, cmd_fibcontext, 
+				fibsize, FsaNormal, 0, 1,
+				  (fib_callback) aac_srb_callback, 
+				  (void *) scsicmd);
 	} else {
 		aac_build_sg(scsicmd, (struct sgmap*)&srbcmd->sg);
 		srbcmd->count = cpu_to_le32(scsicmd->request_bufflen);
@@ -1602,7 +3092,11 @@ static int aac_send_srb_fib(Scsi_Cmnd* scsicmd)
 		/*
 		 *	Build Scatter/Gather list
 		 */
-		fibsize = sizeof (struct aac_srb) + (((srbcmd->sg.count & 0xff) - 1) * sizeof (struct sgentry));
+		fibsize = sizeof (struct aac_srb) + 
+			(((le32_to_cpu(srbcmd->sg.count) & 0xff) - 1) * 
+			 sizeof (struct sgentry));
+		BUG_ON (fibsize > (dev->max_fib_size -
+					sizeof(struct aac_fibhdr)));
 
 		/*
 		 *	Now send the Fib to the adapter
@@ -1613,54 +3107,89 @@ static int aac_send_srb_fib(Scsi_Cmnd* scsicmd)
 	/*
 	 *	Check that the command queued to the controller
 	 */
-	if (status == -EINPROGRESS){
+	if (status == -EINPROGRESS) {
+		scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
 		return 0;
 	}
 
 	printk(KERN_WARNING "aac_srb: fib_send failed with status: %d\n", status);
-	/*
-	 *	For some reason, the Fib didn't queue, return QUEUE_FULL
-	 */
-	scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | QUEUE_FULL;
-	__aac_io_done(scsicmd);
-
 	fib_complete(cmd_fibcontext);
 	fib_free(cmd_fibcontext);
 
 	return -1;
 }
 
-static unsigned long aac_build_sg(Scsi_Cmnd* scsicmd, struct sgmap* psg)
+static unsigned long aac_build_sg(struct scsi_cmnd* scsicmd, struct sgmap* psg)
 {
-	struct aac_dev *dev;
+	struct Scsi_Host *host = scsicmd->device->host;
+	struct aac_dev *dev = (struct aac_dev *)host->hostdata;
 	unsigned long byte_count = 0;
 
-	dev = (struct aac_dev *)scsicmd->host->hostdata;
 	// Get rid of old data
-	psg->count = cpu_to_le32(0);
-	psg->sg[0].addr = cpu_to_le32(NULL);
-	psg->sg[0].count = cpu_to_le32(0);  
+	psg->count = 0;
+	psg->sg[0].addr = 0;
+	psg->sg[0].count = 0;  
 	if (scsicmd->use_sg) {
 		struct scatterlist *sg;
 		int i;
 		int sg_count;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+		int sg_count_hold;
+#endif
 		sg = (struct scatterlist *) scsicmd->request_buffer;
 
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+		sg_count_hold =
+#endif
 		sg_count = pci_map_sg(dev->pdev, sg, scsicmd->use_sg,
-			scsi_to_pci_dma_dir(scsicmd->sc_data_direction));
-		psg->count = cpu_to_le32(sg_count);
-
-		byte_count = 0;
+			scsicmd->sc_data_direction);
 
 		for (i = 0; i < sg_count; i++) {
-			psg->sg[i].addr = cpu_to_le32(sg_dma_address(sg));
-			psg->sg[i].count = cpu_to_le32(sg_dma_len(sg));
-			byte_count += sg_dma_len(sg);
+			int count = sg_dma_len(sg);
+			u32 addr = sg_dma_address(sg);
+#if (defined(AAC_DEBUG_INSTRUMENT_SG_PROBE))
+			char c = ((char *)sg->page + sg->offset)[0];
+			c = ((char *)sg->page + sg->offset)[count-1];
+#endif
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+			if (!(dev->adapter_info.options & AAC_OPT_NEW_COMM))
+			while (count > 65536) {
+				psg->sg[i].addr = cpu_to_le32(addr);
+				psg->sg[i].count = cpu_to_le32(65536);
+				++i;
+				if (++sg_count > host->sg_tablesize) {
+#if (defined(AAC_DEBUG_INSTRUMENT_SG))
+					printk(KERN_INFO
+					  "SG List[%d] too large based on original[%d]:\n",
+					  sg_count, sg_count_hold);
+					sg = (struct scatterlist *) scsicmd->request_buffer;
+					for (i = 0; i < sg_count_hold; i++) {
+						printk(KERN_INFO "0x%llx[%d] ",
+						  (u64)(sg_dma_address(sg)),
+						  (int)(sg_dma_len(sg)));
+						++sg;
+					}
+					printk(KERN_INFO "...\n");
+#endif
+					BUG();
+				}
+				byte_count += 65536;
+				addr += 65536;
+				count -= 65536;
+			}
+#endif
+
+			psg->sg[i].addr = cpu_to_le32(addr);
+			psg->sg[i].count = cpu_to_le32(count);
+			byte_count += count;
 			sg++;
 		}
+		psg->count = cpu_to_le32(sg_count);
 		/* hba wants the size to be exact */
 		if(byte_count > scsicmd->request_bufflen){
-			psg->sg[i-1].count -= (byte_count - scsicmd->request_bufflen);
+			u32 temp = le32_to_cpu(psg->sg[i-1].count) - 
+				(byte_count - scsicmd->request_bufflen);
+			psg->sg[i-1].count = cpu_to_le32(temp);
 			byte_count = scsicmd->request_bufflen;
 		}
 		/* Check for command underflow */
@@ -1670,57 +3199,265 @@ static unsigned long aac_build_sg(Scsi_Cmnd* scsicmd, struct sgmap* psg)
 		}
 	}
 	else if(scsicmd->request_bufflen) {
-		dma_addr_t addr; 
-		addr = pci_map_single(dev->pdev,
+		int i, count;
+		u32 addr;
+#if (defined(AAC_DEBUG_INSTRUMENT_SG_PROBE))
+		char c = ((char *)scsicmd->request_buffer)[0];
+		c = ((char *)scsicmd->request_buffer)[scsicmd->request_bufflen-1];
+#endif
+		scsicmd->SCp.dma_handle = pci_map_single(dev->pdev,
 				scsicmd->request_buffer,
 				scsicmd->request_bufflen,
-				scsi_to_pci_dma_dir(scsicmd->sc_data_direction));
-		psg->count = cpu_to_le32(1);
-		psg->sg[0].addr = cpu_to_le32(addr);
-		psg->sg[0].count = cpu_to_le32(scsicmd->request_bufflen);  
-		/* Cast to pointer from integer of different size */
-		scsicmd->SCp.ptr = (void *)addr;
+				scsicmd->sc_data_direction);
+		addr = scsicmd->SCp.dma_handle;
+		count = scsicmd->request_bufflen;  
+		i = 0;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+		if (!(dev->adapter_info.options & AAC_OPT_NEW_COMM))
+		while (count > 65536) {
+			psg->sg[i].addr = cpu_to_le32(addr);
+			psg->sg[i].count = cpu_to_le32(65536);
+			if (++i >= host->sg_tablesize) {
+#if (defined(AAC_DEBUG_INSTRUMENT_SG))
+				printk(KERN_INFO
+				  "SG List[%d] too large based on original single element %d in size\n",
+				  i, scsicmd->request_bufflen);
+#endif
+				BUG();
+			}
+			addr += 65536;
+			count -= 65536;
+		}
+#endif
+		psg->count = cpu_to_le32(1+i);
+		psg->sg[i].addr = cpu_to_le32(addr);
+		psg->sg[i].count = cpu_to_le32(count);
 		byte_count = scsicmd->request_bufflen;
 	}
+#if (defined(AAC_DEBUG_INSTRUMENT_SG))
+{
+	int i, sg_count = le32_to_cpu(psg->count);
+	printk("aac_build_sg:");
+	for (i = 0; i < sg_count; i++) {
+		int count = le32_to_cpu(psg->sg[i].count);
+		u32 addr = le32_to_cpu(psg->sg[i].addr);
+		printk(" %x[%d]", addr, count);
+	}
+	printk ("\n");
+}
+#endif
+#if (defined(AAC_DEBUG_INSTRUMENT_AAC_CONFIG))
+	if (le32_to_cpu(psg->count) > aac_config.peak_sg) {
+		aac_config.peak_sg = le32_to_cpu(psg->count);
+		printk ("peak_sg=%u\n", aac_config.peak_sg);
+	}
+	if (byte_count > aac_config.peak_size) {
+		aac_config.peak_size = byte_count;
+		printk ("peak_size=%u\n", aac_config.peak_size);
+	}
+#endif
 	return byte_count;
 }
 
 
-static unsigned long aac_build_sg64(Scsi_Cmnd* scsicmd, struct sgmap64* psg)
+static unsigned long aac_build_sg64(struct scsi_cmnd* scsicmd, struct sgmap64* psg)
 {
-	struct aac_dev *dev;
+	struct Scsi_Host *host = scsicmd->device->host;
+	struct aac_dev *dev = (struct aac_dev *)host->hostdata;
 	unsigned long byte_count = 0;
-	u64 le_addr;
 
-	dev = (struct aac_dev *)scsicmd->host->hostdata;
 	// Get rid of old data
-	psg->count = cpu_to_le32(0);
-	psg->sg[0].addr[0] = cpu_to_le32(NULL);
-	psg->sg[0].addr[1] = cpu_to_le32(NULL);
-	psg->sg[0].count = cpu_to_le32(0);  
+	psg->count = 0;
+	psg->sg[0].addr[0] = 0;
+	psg->sg[0].addr[1] = 0;
+	psg->sg[0].count = 0;
 	if (scsicmd->use_sg) {
 		struct scatterlist *sg;
 		int i;
 		int sg_count;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+		int sg_count_hold;
+#endif
 		sg = (struct scatterlist *) scsicmd->request_buffer;
 
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+		sg_count_hold =
+#endif
 		sg_count = pci_map_sg(dev->pdev, sg, scsicmd->use_sg,
-			scsi_to_pci_dma_dir(scsicmd->sc_data_direction));
+			scsicmd->sc_data_direction);
+
+		for (i = 0; i < sg_count; i++) {
+			int count = sg_dma_len(sg);
+			u64 addr = sg_dma_address(sg);
+#if (defined(AAC_DEBUG_INSTRUMENT_SG_PROBE))
+			char c = ((char *)sg->page + sg->offset)[0];
+			c = ((char *)sg->page + sg->offset)[count-1];
+#endif
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+			if (!(dev->adapter_info.options & AAC_OPT_NEW_COMM))
+			while (count > 65536) {
+				psg->sg[i].addr[1] = cpu_to_le32((u32)(addr>>32));
+				psg->sg[i].addr[0] = cpu_to_le32((u32)(addr & 0xffffffff));
+				psg->sg[i].count = cpu_to_le32(65536);
+				++i;
+				if (++sg_count > host->sg_tablesize) {
+#if (defined(AAC_DEBUG_INSTRUMENT_SG))
+					printk(KERN_INFO
+					  "SG List[%d] too large based on original[%d]:\n",
+					  sg_count, sg_count_hold);
+					sg = (struct scatterlist *) scsicmd->request_buffer;
+					for (i = 0; i < sg_count_hold; i++) {
+						printk(KERN_INFO "0x%llx[%d] ",
+						  (u64)sg_dma_address(sg),
+						  (int)sg_dma_len(sg));
+						++sg;
+					}
+					printk(KERN_INFO "...\n");
+#endif
+					BUG();
+				}
+				byte_count += 65536;
+				addr += 65536;
+				count -= 65536;
+			}
+#endif
+			psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff);
+			psg->sg[i].addr[1] = cpu_to_le32(addr>>32);
+			psg->sg[i].count = cpu_to_le32(count);
+			byte_count += count;
+			sg++;
+		}
 		psg->count = cpu_to_le32(sg_count);
+		/* hba wants the size to be exact */
+		if(byte_count > scsicmd->request_bufflen){
+			u32 temp = le32_to_cpu(psg->sg[i-1].count) - 
+				(byte_count - scsicmd->request_bufflen);
+			psg->sg[i-1].count = cpu_to_le32(temp);
+			byte_count = scsicmd->request_bufflen;
+		}
+		/* Check for command underflow */
+		if(scsicmd->underflow && (byte_count < scsicmd->underflow)){
+			printk(KERN_WARNING"aacraid: cmd len %08lX cmd underflow %08X\n",
+					byte_count, scsicmd->underflow);
+		}
+	}
+	else if(scsicmd->request_bufflen) {
+		int i, count;
+		u64 addr;
+#if (defined(AAC_DEBUG_INSTRUMENT_SG_PROBE))
+		char c = ((char *)scsicmd->request_buffer)[0];
+		c = ((char *)scsicmd->request_buffer)[scsicmd->request_bufflen-1];
+#endif
+		scsicmd->SCp.dma_handle = pci_map_single(dev->pdev,
+				scsicmd->request_buffer,
+				scsicmd->request_bufflen,
+				scsicmd->sc_data_direction);
+		addr = scsicmd->SCp.dma_handle;
+		count = scsicmd->request_bufflen;  
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+		i = 0;
+		if (!(dev->adapter_info.options & AAC_OPT_NEW_COMM))
+		while (count > 65536) {
+			psg->sg[i].addr[1] = cpu_to_le32((u32)(addr>>32));
+			psg->sg[i].addr[0] = cpu_to_le32((u32)(addr & 0xffffffff));
+			psg->sg[i].count = cpu_to_le32(65536);
+			if (++i >= host->sg_tablesize) {
+#if (defined(AAC_DEBUG_INSTRUMENT_SG))
+				printk(KERN_INFO
+				  "SG List[%d] too large based on original single element %d in size\n",
+				  i, scsicmd->request_bufflen);
+#endif
+				BUG();
+			}
+			addr += 65536;
+			count -= 65536;
+		}
+		psg->count = cpu_to_le32(1+i);
+		psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff);
+		psg->sg[i].addr[1] = cpu_to_le32(addr>>32);
+		psg->sg[i].count = cpu_to_le32(count);
+#else
+		psg->count = cpu_to_le32(1);
+		psg->sg[0].addr[0] = cpu_to_le32(addr & 0xffffffff);
+		psg->sg[0].addr[1] = cpu_to_le32(addr>>32);
+		psg->sg[0].count = cpu_to_le32(count);
+#endif
+		byte_count = scsicmd->request_bufflen;
+	}
+#if (defined(AAC_DEBUG_INSTRUMENT_SG))
+{
+	int i, sg_count = le32_to_cpu(psg->count);
+	printk("aac_build_sg64:");
+	for (i = 0; i < sg_count; i++) {
+		int count = le32_to_cpu(psg->sg[i].count);
+		u32 addr0 = le32_to_cpu(psg->sg[i].addr[0]);
+		u32 addr1 = le32_to_cpu(psg->sg[i].addr[1]);
+		if (addr1 == 0)
+			printk(" %x[%d]", addr0, count);
+		else
+			printk(" %x%08x[%d]", addr1, addr0, count);
+	}
+	printk ("\n");
+}
+#endif
+#if (defined(AAC_DEBUG_INSTRUMENT_AAC_CONFIG))
+	if (le32_to_cpu(psg->count) > aac_config.peak_sg) {
+		aac_config.peak_sg = le32_to_cpu(psg->count);
+		printk ("peak_sg=%u\n", aac_config.peak_sg);
+	}
+	if (byte_count > aac_config.peak_size) {
+		aac_config.peak_size = byte_count;
+		printk ("peak_size=%u\n", aac_config.peak_size);
+	}
+#endif
+	return byte_count;
+}
+
+static unsigned long aac_build_sgraw(struct scsi_cmnd* scsicmd, struct sgmapraw* psg)
+{
+	struct Scsi_Host *host = scsicmd->device->host;
+	struct aac_dev *dev = (struct aac_dev *)host->hostdata;
+	unsigned long byte_count = 0;
+
+	// Get rid of old data
+	psg->count = 0;
+	psg->sg[0].next = 0;
+	psg->sg[0].prev = 0;
+	psg->sg[0].addr[0] = 0;
+	psg->sg[0].addr[1] = 0;
+	psg->sg[0].count = 0;
+	psg->sg[0].flags = 0;
+	if (scsicmd->use_sg) {
+		struct scatterlist *sg;
+		int i;
+		int sg_count;
+		sg = (struct scatterlist *) scsicmd->request_buffer;
 
-		byte_count = 0;
+		sg_count = pci_map_sg(dev->pdev, sg, scsicmd->use_sg,
+			scsicmd->sc_data_direction);
 
 		for (i = 0; i < sg_count; i++) {
-			le_addr = cpu_to_le64(sg_dma_address(sg));
-			psg->sg[i].addr[1] = (u32)(le_addr>>32);
-			psg->sg[i].addr[0] = (u32)(le_addr & 0xffffffff);
-			psg->sg[i].count = cpu_to_le32(sg_dma_len(sg));
-			byte_count += sg_dma_len(sg);
+			int count = sg_dma_len(sg);
+			u64 addr = sg_dma_address(sg);
+#if (defined(AAC_DEBUG_INSTRUMENT_SG_PROBE))
+			char c = ((char *)sg->page + sg->offset)[0];
+			c = ((char *)sg->page + sg->offset)[count-1];
+#endif
+			psg->sg[i].next = 0;
+			psg->sg[i].prev = 0;
+			psg->sg[i].addr[1] = cpu_to_le32((u32)(addr>>32));
+			psg->sg[i].addr[0] = cpu_to_le32((u32)(addr & 0xffffffff));
+			psg->sg[i].count = cpu_to_le32(count);
+			psg->sg[i].flags = 0;
+			byte_count += count;
 			sg++;
 		}
+		psg->count = cpu_to_le32(sg_count);
 		/* hba wants the size to be exact */
 		if(byte_count > scsicmd->request_bufflen){
-			psg->sg[i-1].count -= (byte_count - scsicmd->request_bufflen);
+			u32 temp = le32_to_cpu(psg->sg[i-1].count) - 
+				(byte_count - scsicmd->request_bufflen);
+			psg->sg[i-1].count = cpu_to_le32(temp);
 			byte_count = scsicmd->request_bufflen;
 		}
 		/* Check for command underflow */
@@ -1730,23 +3467,42 @@ static unsigned long aac_build_sg64(Scsi_Cmnd* scsicmd, struct sgmap64* psg)
 		}
 	}
 	else if(scsicmd->request_bufflen) {
-		dma_addr_t addr; 
-		addr = pci_map_single(dev->pdev,
+		int count;
+		u64 addr;
+#if (defined(AAC_DEBUG_INSTRUMENT_SG_PROBE))
+		char c = ((char *)scsicmd->request_buffer)[0];
+		c = ((char *)scsicmd->request_buffer)[scsicmd->request_bufflen-1];
+#endif
+		scsicmd->SCp.dma_handle = pci_map_single(dev->pdev,
 				scsicmd->request_buffer,
 				scsicmd->request_bufflen,
-				scsi_to_pci_dma_dir(scsicmd->sc_data_direction));
+				scsicmd->sc_data_direction);
+		addr = scsicmd->SCp.dma_handle;
+		count = scsicmd->request_bufflen;
 		psg->count = cpu_to_le32(1);
-		le_addr = cpu_to_le64(addr);
-		psg->sg[0].addr[1] = (u32)(le_addr>>32);
-		psg->sg[0].addr[0] = (u32)(le_addr & 0xffffffff);
-		psg->sg[0].count = cpu_to_le32(scsicmd->request_bufflen);  
-		/* Cast to pointer from integer of different size */
-		scsicmd->SCp.ptr = (void *)addr;
+		psg->sg[0].next = 0;
+		psg->sg[0].prev = 0;
+		psg->sg[0].addr[1] = cpu_to_le32((u32)(addr>>32));
+		psg->sg[0].addr[0] = cpu_to_le32((u32)(addr & 0xffffffff));
+		psg->sg[0].count = cpu_to_le32(count);
+		psg->sg[0].flags = 0;
 		byte_count = scsicmd->request_bufflen;
 	}
+#if (defined(AAC_DEBUG_INSTRUMENT_AAC_CONFIG))
+	if (le32_to_cpu(psg->count) > aac_config.peak_sg) {
+		aac_config.peak_sg = le32_to_cpu(psg->count);
+		printk ("peak_sg=%u\n", aac_config.peak_sg);
+	}
+	if (byte_count > aac_config.peak_size) {
+		aac_config.peak_size = byte_count;
+		printk ("peak_size=%u\n", aac_config.peak_size);
+	}
+#endif
 	return byte_count;
 }
 
+#ifdef AAC_DETAILED_STATUS_INFO
+
 struct aac_srb_status_info {
 	u32	status;
 	char	*str;
@@ -1801,3 +3557,4 @@ char *aac_get_status_string(u32 status)
 	return "Bad Status Code";
 }
 
+#endif
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
index 31fb452..1eb73f2 100644
--- a/drivers/scsi/aacraid/aacraid.h
+++ b/drivers/scsi/aacraid/aacraid.h
@@ -1,34 +1,87 @@
-#define AAC_DRIVER_VERSION		0x01010300
-#define AAC_DRIVER_BUILD_DATE		__DATE__ " " __TIME__
-
 //#define dprintk(x) printk x
 #if (!defined(dprintk))
 # define dprintk(x)
 #endif
+//#define fwprintf(x) aac_fw_printf x
+#if (!defined(fwprintf))
+# define fwprintf(x)
+#endif
+//#define AAC_DETAILED_STATUS_INFO
+//#define AAC_DEBUG_INSTRUMENT_TIMING
+//#define AAC_DEBUG_INSTRUMENT_AIF
+//#define AAC_DEBUG_INSTRUMENT_IOCTL
+//#define AAC_DEBUG_INSTRUMENT_AAC_CONFIG
+//#define AAC_DEBUG_INSTRUMENT_RESET
+//#define AAC_DEBUG_INSTRUMENT_FIB
+//#define AAC_DEBUG_INSTRUMENT_2TB
+//#define AAC_DEBUG_INSTRUMENT_SENDFIB
+//#define AAC_DEBUG_INSTRUMENT_IO
+//#define AAC_DEBUG_INSTRUMENT_PENDING
+//#define AAC_DEBUG_INSTRUMENT_SG
+//#define AAC_DEBUG_INSTRUMENT_SG_PROBE
+//#define AAC_DEBUG_INSTRUMENT_VM_NAMESERVE
+
+/* eg: if (nblank(dprintk(x))) */
+#define _nblank(x) #x
+#define nblank(x) _nblank(x)[0]
+
+#include "compat.h"
+#if (defined(SCSI_HAS_DUMP))
+#include <linux/interrupt.h>
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,23))
+#if (!defined(IRQ_NONE))
+  typedef void irqreturn_t;
+# define IRQ_HANDLED
+# define IRQ_NONE
+#endif
+#endif
+#endif
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,9))
+#define AAC_CSMI
+#endif
 
 /*------------------------------------------------------------------------------
  *              D E F I N E S
  *----------------------------------------------------------------------------*/
 
-#define MAXIMUM_NUM_CONTAINERS	31
-#define MAXIMUM_NUM_ADAPTERS	8
+//#define AAC_EXTENDED_TIMEOUT	120
+
+#ifndef AAC_DRIVER_BUILD
+# define AAC_DRIVER_BUILD 9999
+#endif
+#define MAXIMUM_NUM_CONTAINERS	32
 
-#define AAC_NUM_FIB		578
-//#define AAC_NUM_IO_FIB	512
-#define AAC_NUM_IO_FIB		100
+#define AAC_NUM_MGT_FIB         8
+#define AAC_NUM_IO_FIB		(512 - AAC_NUM_MGT_FIB)
+#define AAC_NUM_FIB		(AAC_NUM_IO_FIB + AAC_NUM_MGT_FIB)
 
-#define AAC_MAX_TARGET		(MAXIMUM_NUM_CONTAINERS+1)
-//#define AAC_MAX_TARGET 	(16)
 #define AAC_MAX_LUN		(8)
 
+#define AAC_MAX_HOSTPHYSMEMPAGES (0xfffff)
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+/*
+ *  max_sectors is an unsigned short, otherwise limit is 0x100000000 / 512
+ * Linux has starvation problems if we permit larger than 4MB I/O ...
+ */
+#endif
+#define AAC_MAX_32BIT_SGBCOUNT	((unsigned short)512)
+
 /*
  * These macros convert from physical channels to virtual channels
  */
-#define CONTAINER_CHANNEL	(0)
+#define CONTAINER_CHANNEL		(0)
+#define ID_LUN_TO_CONTAINER(id, lun)	(id)
+#define CONTAINER_TO_CHANNEL(cont)	(CONTAINER_CHANNEL)
+#define CONTAINER_TO_ID(cont)		(cont)
+#define CONTAINER_TO_LUN(cont)		(0)
+
 #define aac_phys_to_logical(x)  (x+1)
 #define aac_logical_to_phys(x)  (x?x-1:0)
 
-#define AAC_DETAILED_STATUS_INFO
+/* #define AAC_DETAILED_STATUS_INFO */
+#if (defined(__arm__))
+#define AAC_LM_SENSOR
+#endif
 
 struct diskparm
 {
@@ -57,6 +110,7 @@ struct diskparm
 #define		CT_VOLUME_OF_MIRRORS	12	/* volume of mirror */
 #define		CT_PSEUDO_RAID		13	/* really raid4 */
 #define		CT_LAST_VOLUME_TYPE	14
+#define 	CT_OK        		218
 
 /*
  *	Types of objects addressable in some fashion by the client.
@@ -73,7 +127,7 @@ struct diskparm
 #define		FT_SOCK		6	/* socket */
 #define		FT_FIFO		7	/* fifo */
 #define		FT_FILESYS	8	/* ADAPTEC's "FSA"(tm) filesystem */
-#define		FT_DRIVE	9	/* physical disk - addressable in scsi by bus/target/lun */
+#define		FT_DRIVE	9	/* physical disk - addressable in scsi by bus/id/lun */
 #define		FT_SLICE	10	/* virtual disk - raw volume - slice */
 #define		FT_PARTITION	11	/* FSA partition - carved out of a slice - building block for containers */
 #define		FT_VOLUME	12	/* Container - Volume Set */
@@ -85,19 +139,45 @@ struct diskparm
 /*
  *	Host side memory scatter gather list
  *	Used by the adapter for read, write, and readdirplus operations
- *	We have seperate 32 and 64 bit version because even
+ *	We have separate 32 and 64 bit version because even
  *	on 64 bit systems not all cards support the 64 bit version
  */
 struct sgentry {
+	__le32	addr;	/* 32-bit address. */
+	__le32	count;	/* Length. */
+};
+
+struct user_sgentry {
 	u32	addr;	/* 32-bit address. */
 	u32	count;	/* Length. */
 };
 
 struct sgentry64 {
+	__le32	addr[2];	/* 64-bit addr. 2 pieces for data alignment */
+	__le32	count;	/* Length. */
+};
+
+struct user_sgentry64 {
 	u32	addr[2];	/* 64-bit addr. 2 pieces for data alignment */
 	u32	count;	/* Length. */
 };
 
+struct sgentryraw {
+	__le32		next;	/* reserved for F/W use */
+	__le32		prev;	/* reserved for F/W use */
+	__le32		addr[2];
+	__le32		count;
+	__le32		flags;	/* reserved for F/W use */
+};
+
+struct user_sgentryraw {
+	u32		next;	/* reserved for F/W use */
+	u32		prev;	/* reserved for F/W use */
+	u32		addr[2];
+	u32		count;
+	u32		flags;	/* reserved for F/W use */
+};
+
 /*
  *	SGMAP
  *
@@ -106,15 +186,35 @@ struct sgentry64 {
  */
 
 struct sgmap {
-	u32		count;
+	__le32		count;
 	struct sgentry	sg[1]; 
 };
 
-struct sgmap64 {
+struct user_sgmap {
 	u32		count;
+	struct user_sgentry	sg[1]; 
+};
+
+struct sgmap64 {
+	__le32		count;
 	struct sgentry64 sg[1];
 };
 
+struct user_sgmap64 {
+	u32		count;
+	struct user_sgentry64 sg[1];
+};
+
+struct sgmapraw {
+	__le32		  count;
+	struct sgentryraw sg[1];
+};
+
+struct user_sgmapraw {
+	u32		  count;
+	struct user_sgentryraw sg[1];
+};
+
 struct creation_info
 {
 	u8 		buildnum;		/* e.g., 588 */
@@ -123,14 +223,14 @@ struct creation_info
 						 * 	 2 = API
 						 */
 	u8	 	year;		 	/* e.g., 1997 = 97 */
-	u32		date;			/*
+	__le32		date;			/*
 						 * unsigned 	Month		:4;	// 1 - 12
 						 * unsigned 	Day		:6;	// 1 - 32
 						 * unsigned 	Hour		:6;	// 0 - 23
 						 * unsigned 	Minute		:6;	// 0 - 60
 						 * unsigned 	Second		:6;	// 0 - 60
 						 */
-	u32		serial[2];			/* e.g., 0x1DEADB0BFAFAF001 */
+	__le32		serial[2];			/* e.g., 0x1DEADB0BFAFAF001 */
 };
 
 
@@ -175,8 +275,8 @@ struct creation_info
  */
 
 struct aac_entry {
-	u32 size;          /* Size in bytes of Fib which this QE points to */
-	u32 addr; /* Receiver address of the FIB */
+	__le32 size; /* Size in bytes of Fib which this QE points to */
+	__le32 addr; /* Receiver address of the FIB */
 };
 
 /*
@@ -185,9 +285,10 @@ struct aac_entry {
  */
  
 struct aac_qhdr {
-	u64 header_addr;		/* Address to hand the adapter to access to this queue head */
-	u32 *producer;			/* The producer index for this queue (host address) */
-	u32 *consumer;			/* The consumer index for this queue (host address) */
+	__le64 header_addr;/* Address to hand the adapter to access 
+			      to this queue head */
+	__le32 *producer; /* The producer index for this queue (host address) */
+	__le32 *consumer; /* The consumer index for this queue (host address) */
 };
 
 /*
@@ -261,32 +362,30 @@ enum aac_queue_types {
  */
 
 struct aac_fibhdr {
-	u32 XferState;			// Current transfer state for this CCB
-	u16 Command;			// Routing information for the destination
-	u8 StructType;			// Type FIB
-	u8 Flags;			// Flags for FIB
-	u16 Size;			// Size of this FIB in bytes
-	u16 SenderSize;			// Size of the FIB in the sender (for response sizing)
-	u32 SenderFibAddress;		// Host defined data in the FIB
-	u32 ReceiverFibAddress;		// Logical address of this FIB for the adapter
-	u32 SenderData;			// Place holder for the sender to store data
+	__le32 XferState;	/* Current transfer state for this CCB */
+	__le16 Command;		/* Routing information for the destination */
+	u8 StructType;		/* Type FIB */
+	u8 Flags;		/* Flags for FIB */
+	__le16 Size;		/* Size of this FIB in bytes */
+	__le16 SenderSize;	/* Size of the FIB in the sender 
+				   (for response sizing) */
+	__le32 SenderFibAddress;  /* Host defined data in the FIB */
+	__le32 ReceiverFibAddress;/* Logical address of this FIB for 
+				     the adapter */
+	u32 SenderData;		/* Place holder for the sender to store data */
 	union {
 		struct {
-		    u32 _ReceiverTimeStart; 	// Timestamp for receipt of fib
-		    u32 _ReceiverTimeDone;	// Timestamp for completion of fib
+		    __le32 _ReceiverTimeStart; 	/* Timestamp for 
+						   receipt of fib */
+		    __le32 _ReceiverTimeDone;	/* Timestamp for 
+						   completion of fib */
 		} _s;
-//		struct aac_list_head _FibLinks;	// Used to link Adapter Initiated Fibs on the host
 	} _u;
 };
 
-//#define FibLinks			_u._FibLinks
-
-#define FIB_DATA_SIZE_IN_BYTES (512 - sizeof(struct aac_fibhdr))
-
-
 struct hw_fib {
 	struct aac_fibhdr header;
-	u8 data[FIB_DATA_SIZE_IN_BYTES];		// Command specific data
+	u8 data[512-sizeof(struct aac_fibhdr)];	// Command specific data
 };
 
 /*
@@ -330,6 +429,7 @@ struct hw_fib {
  */
 #define		ContainerCommand		500
 #define		ContainerCommand64		501
+#define		ContainerRawIo			502
 /*
  *	Cluster Commands
  */
@@ -348,11 +448,14 @@ struct hw_fib {
 #define		RequestAdapterInfo		703
 #define		IsAdapterPaused			704
 #define		SendHostTime			705
-#define		LastMiscCommand			706
+#define		RequestSupplementAdapterInfo	706
+#define		LastMiscCommand			707
 
-//
-// Commands that will target the failover level on the FSA adapter
-//
+#define		RequestCompatibilityId		802
+
+/*
+ * Commands that will target the failover level on the FSA adapter
+ */
 
 enum fib_xfer_state {
 	HostOwned 			= (1<<0),
@@ -385,48 +488,63 @@ enum fib_xfer_state {
  */
 
 #define ADAPTER_INIT_STRUCT_REVISION		3
+#define ADAPTER_INIT_STRUCT_REVISION_4		4 // rocket science
 
 struct aac_init
 {
-	u32	InitStructRevision;
-	u32	MiniPortRevision;
-	u32	fsrev;
-	u32	CommHeaderAddress;
-	u32	FastIoCommAreaAddress;
-	u32	AdapterFibsPhysicalAddress;
-	u32	AdapterFibsVirtualAddress;
-	u32	AdapterFibsSize;
-	u32	AdapterFibAlign;
-	u32	printfbuf;
-	u32	printfbufsiz;
-	u32	HostPhysMemPages;		// number of 4k pages of host physical memory
-	u32	HostElapsedSeconds;		// number of seconds since 1970.
+	__le32	InitStructRevision;
+	__le32	MiniPortRevision;
+	__le32	fsrev;
+	__le32	CommHeaderAddress;
+	__le32	FastIoCommAreaAddress;
+	__le32	AdapterFibsPhysicalAddress;
+	__le32	AdapterFibsVirtualAddress;
+	__le32	AdapterFibsSize;
+	__le32	AdapterFibAlign;
+	__le32	printfbuf;
+	__le32	printfbufsiz;
+	__le32	HostPhysMemPages;   /* number of 4k pages of host 
+				       physical memory */
+	__le32	HostElapsedSeconds; /* number of seconds since 1970. */
+	/*
+	 * ADAPTER_INIT_STRUCT_REVISION_4 begins here
+	 */
+	__le32	InitFlags;	/* flags for supported features */
+#define INITFLAGS_NEW_COMM_SUPPORTED	0x00000001
+	__le32	MaxIoCommands;	/* max outstanding commands */
+	__le32	MaxIoSize;	/* largest I/O command */
+	__le32	MaxFibSize;	/* largest FIB to adapter */
 };
 
 enum aac_log_level {
-	LOG_INIT			= 10,
-	LOG_INFORMATIONAL		= 20,
-	LOG_WARNING			= 30,
-	LOG_LOW_ERROR			= 40,
-	LOG_MEDIUM_ERROR		= 50,
-	LOG_HIGH_ERROR			= 60,
-	LOG_PANIC			= 70,
-	LOG_DEBUG			= 80,
-	LOG_WINDBG_PRINT		= 90
+	LOG_AAC_INIT			= 10,
+	LOG_AAC_INFORMATIONAL		= 20,
+	LOG_AAC_WARNING			= 30,
+	LOG_AAC_LOW_ERROR		= 40,
+	LOG_AAC_MEDIUM_ERROR		= 50,
+	LOG_AAC_HIGH_ERROR		= 60,
+	LOG_AAC_PANIC			= 70,
+	LOG_AAC_DEBUG			= 80,
+	LOG_AAC_WINDBG_PRINT		= 90
 };
 
 #define FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT	0x030b
 #define FSAFS_NTC_FIB_CONTEXT			0x030c
 
 struct aac_dev;
+struct fib;
 
 struct adapter_ops
 {
 	void (*adapter_interrupt)(struct aac_dev *dev);
 	void (*adapter_notify)(struct aac_dev *dev, u32 event);
-	void (*adapter_enable_int)(struct aac_dev *dev, u32 event);
-	void (*adapter_disable_int)(struct aac_dev *dev, u32 event);
-	int  (*adapter_sync_cmd)(struct aac_dev *dev, u32 command, u32 p1, u32 *status);
+	void (*adapter_disable_int)(struct aac_dev *dev);
+	int  (*adapter_sync_cmd)(struct aac_dev *dev, u32 command, u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6, u32 *status, u32 *r1, u32 *r2, u32 *r3, u32 *r4);
+	int  (*adapter_check_health)(struct aac_dev *dev);
+	int  (*adapter_send)(struct fib * fib);
+#if (defined(SCSI_HAS_DUMP))
+	irqreturn_t (*adapter_intr)(int irq, void *dev_id, struct pt_regs *regs);
+#endif
 };
 
 /*
@@ -435,23 +553,42 @@ struct adapter_ops
 
 struct aac_driver_ident
 {
-	u16	vendor;
-	u16	device;
-	u16	subsystem_vendor;
-	u16	subsystem_device;
-	int 	(*init)(struct aac_dev *dev, unsigned long num);
+	int 	(*init)(struct aac_dev *dev);
 	char *	name;
 	char *	vname;
 	char *	model;
 	u16	channels;
 	int	quirks;
-#define AAC_QUIRK_31BIT			1
 };
+/*
+ * Some adapter firmware needs communication memory 
+ * below 2gig. This tells the init function to set the
+ * dma mask such that fib memory will be allocated where the
+ * adapter firmware can get to it.
+ */
+#define AAC_QUIRK_31BIT	0x0001
+
+/*
+ * Some adapter firmware, when the raid card's cache is turned off, can not
+ * split up scatter gathers in order to deal with the limits of the
+ * underlying CHIM. This limit is 34 scatter gather elements.
+ */
+#define AAC_QUIRK_34SG	0x0002
+
+/*
+ * This adapter is a slave (no Firmware)
+ */
+#define AAC_QUIRK_SLAVE 0x0004
+
+/*
+ * This adapter is a master.
+ */
+#define AAC_QUIRK_MASTER 0x0008
 
 /*
  *	The adapter interface specs all queues to be located in the same
  *	physically contigous block. The host structure that defines the
- *	commuication queues will assume they are each a seperate physically
+ *	commuication queues will assume they are each a separate physically
  *	contigous memory region that will support them all being one big
  *	contigous block. 
  *	There is a command and response queue for each level and direction of
@@ -459,22 +596,20 @@ struct aac_driver_ident
  */
  
 struct aac_queue {
-	u64		 	logical;		/* This is the address we give the adapter */
-	struct aac_entry	*base;		   	/* This is the system virtual address */
-	struct aac_qhdr 	headers;       		/* A pointer to the producer and consumer queue headers for this queue */
-	u32	 		entries;	   	/* Number of queue entries on this queue */
-	wait_queue_head_t	qfull;		      	/* Event to wait on if the queue is full */
-	wait_queue_head_t	cmdready;	  	/* Indicates there is a Command ready from the adapter on this queue. */
-                                        		/* This is only valid for adapter to host command queues. */                      
-	spinlock_t	 	*lock;		     	/* Spinlock for this queue must take this lock before accessing the lock */
-	spinlock_t		lockdata;		/* Actual lock (used only on one side of the lock) */
-	unsigned long		SavedIrql;      	/* Previous IRQL when the spin lock is taken */
-	u32			padding;		/* Padding - FIXME - can remove I believe */
-	struct list_head 	cmdq;		   	/* A queue of FIBs which need to be prcessed by the FS thread. This is */
-                                		        /* only valid for command queues which receive entries from the adapter. */
-	struct list_head	pendingq;		/* A queue of outstanding fib's to the adapter. */
-	unsigned long		numpending;		/* Number of entries on outstanding queue. */
-	struct aac_dev *	dev;			/* Back pointer to adapter structure */
+	u64		 	logical;	/*address we give the adapter */
+	struct aac_entry	*base;		/*system virtual address */
+	struct aac_qhdr 	headers;       	/*producer,consumer q headers*/
+	u32	 		entries;	/*Number of queue entries */
+	wait_queue_head_t	qfull;		/*Event to wait on if q full */
+	wait_queue_head_t	cmdready;	/*Cmd ready from the adapter */
+                  /* This is only valid for adapter to host command queues. */ 
+	spinlock_t	 	*lock;		/* Spinlock for this queue must take this lock before accessing the lock */
+	spinlock_t		lockdata;	/* Actual lock (used only on one side of the lock) */
+	struct list_head 	cmdq;	   	/* A queue of FIBs which need to be prcessed by the FS thread. This is */
+                                		/* only valid for command queues which receive entries from the adapter. */
+	struct list_head	pendingq;	/* A queue of outstanding fib's to the adapter. */
+	u32			numpending;	/* Number of entries on outstanding queue. */
+	struct aac_dev *	dev;		/* Back pointer to adapter structure */
 };
 
 /*
@@ -492,40 +627,32 @@ struct aac_queue_block
  */
  
 struct sa_drawbridge_CSR {
-						//	 Offset |	Name
-	u32	reserved[10];			//	00h-27h |   Reserved
-	u8	LUT_Offset;			//	28h	|	Looup Table Offset
-	u8	reserved1[3];			// 	29h-2bh	|	Reserved
-	u32	LUT_Data;			//	2ch	|	Looup Table Data	
-	u32	reserved2[26];			//	30h-97h	|	Reserved
-	u16	PRICLEARIRQ;			//	98h	|	Primary Clear Irq
-	u16	SECCLEARIRQ;			//	9ah	|	Secondary Clear Irq
-	u16	PRISETIRQ;			//	9ch	|	Primary Set Irq
-	u16	SECSETIRQ;			//	9eh	|	Secondary Set Irq
-	u16	PRICLEARIRQMASK;		//	a0h	|	Primary Clear Irq Mask
-	u16	SECCLEARIRQMASK;		//	a2h	|	Secondary Clear Irq Mask
-	u16	PRISETIRQMASK;			//	a4h	|	Primary Set Irq Mask
-	u16	SECSETIRQMASK;			//	a6h	|	Secondary Set Irq Mask
-	u32	MAILBOX0;			//	a8h	|	Scratchpad 0
-	u32	MAILBOX1;			//	ach	|	Scratchpad 1
-	u32	MAILBOX2;			//	b0h	|	Scratchpad 2
-	u32	MAILBOX3;			//	b4h	|	Scratchpad 3
-	u32	MAILBOX4;			//	b8h	|	Scratchpad 4
-	u32	MAILBOX5;			//	bch	|	Scratchpad 5
-	u32	MAILBOX6;			//	c0h	|	Scratchpad 6
-	u32	MAILBOX7;			//	c4h	|	Scratchpad 7
-
-	u32	ROM_Setup_Data;			//	c8h | 	Rom Setup and Data
-	u32	ROM_Control_Addr;		//	cch | 	Rom Control and Address
-
-	u32	reserved3[12];			//	d0h-ffh	| 	reserved
-	u32	LUT[64];			// 100h-1ffh|	Lookup Table Entries
-
-	//
-	//  TO DO
-	//	need to add DMA, I2O, UART, etc registers form 80h to 364h
-	//
-
+				/*	Offset 	|  Name */
+	__le32	reserved[10];	/*	00h-27h |  Reserved */
+	u8	LUT_Offset;	/*	28h	|  Lookup Table Offset */
+	u8	reserved1[3];	/* 	29h-2bh	|  Reserved */
+	__le32	LUT_Data;	/*	2ch	|  Looup Table Data */
+	__le32	reserved2[26];	/*	30h-97h	|  Reserved */
+	__le16	PRICLEARIRQ;	/*	98h	|  Primary Clear Irq */
+	__le16	SECCLEARIRQ;	/*	9ah	|  Secondary Clear Irq */
+	__le16	PRISETIRQ;	/*	9ch	|  Primary Set Irq */
+	__le16	SECSETIRQ;	/*	9eh	|  Secondary Set Irq */
+	__le16	PRICLEARIRQMASK;/*	a0h	|  Primary Clear Irq Mask */
+	__le16	SECCLEARIRQMASK;/*	a2h	|  Secondary Clear Irq Mask */
+	__le16	PRISETIRQMASK;	/*	a4h	|  Primary Set Irq Mask */
+	__le16	SECSETIRQMASK;	/*	a6h	|  Secondary Set Irq Mask */
+	__le32	MAILBOX0;	/*	a8h	|  Scratchpad 0 */
+	__le32	MAILBOX1;	/*	ach	|  Scratchpad 1 */
+	__le32	MAILBOX2;	/*	b0h	|  Scratchpad 2 */
+	__le32	MAILBOX3;	/*	b4h	|  Scratchpad 3 */
+	__le32	MAILBOX4;	/*	b8h	|  Scratchpad 4 */
+	__le32	MAILBOX5;	/*	bch	|  Scratchpad 5 */
+	__le32	MAILBOX6;	/*	c0h	|  Scratchpad 6 */
+	__le32	MAILBOX7;	/*	c4h	|  Scratchpad 7 */
+	__le32	ROM_Setup_Data;	/*	c8h 	|  Rom Setup and Data */
+	__le32	ROM_Control_Addr;/*	cch 	|  Rom Control and Address */
+	__le32	reserved3[12];	/*	d0h-ffh	|  reserved */
+	__le32	LUT[64];	/*    100h-1ffh	|  Lookup Table Entries */
 };
 
 #define Mailbox0	SaDbCSR.MAILBOX0
@@ -534,6 +661,7 @@ struct sa_drawbridge_CSR {
 #define Mailbox3	SaDbCSR.MAILBOX3
 #define Mailbox4	SaDbCSR.MAILBOX4
 #define Mailbox5	SaDbCSR.MAILBOX5
+#define Mailbox6	SaDbCSR.MAILBOX6
 #define Mailbox7	SaDbCSR.MAILBOX7
 	
 #define DoorbellReg_p SaDbCSR.PRISETIRQ
@@ -541,13 +669,13 @@ struct sa_drawbridge_CSR {
 #define DoorbellClrReg_p SaDbCSR.PRICLEARIRQ
 
 
-#define	DOORBELL_0	cpu_to_le16(0x0001)
-#define DOORBELL_1	cpu_to_le16(0x0002)
-#define DOORBELL_2	cpu_to_le16(0x0004)
-#define DOORBELL_3	cpu_to_le16(0x0008)
-#define DOORBELL_4	cpu_to_le16(0x0010)
-#define DOORBELL_5	cpu_to_le16(0x0020)
-#define DOORBELL_6	cpu_to_le16(0x0040)
+#define	DOORBELL_0	0x0001
+#define DOORBELL_1	0x0002
+#define DOORBELL_2	0x0004
+#define DOORBELL_3	0x0008
+#define DOORBELL_4	0x0010
+#define DOORBELL_5	0x0020
+#define DOORBELL_6	0x0040
 
 	
 #define PrintfReady	DOORBELL_5
@@ -570,25 +698,33 @@ struct sa_registers {
  */
 
 struct rx_mu_registers {
-						//	 Local	|   PCI*	|	Name
-						//			|		|
-	u32	ARSR;				//	1300h	|	00h	|	APIC Register Select Register
-	u32	reserved0;			//	1304h	|	04h	|	Reserved
-	u32	AWR;				//	1308h	|	08h	|	APIC Window Register
-	u32	reserved1;			//	130Ch	|	0Ch	|	Reserved
-	u32	IMRx[2];			//	1310h	|	10h	|	Inbound Message Registers
-	u32	OMRx[2];			//	1318h	|	18h	|	Outbound Message Registers
-	u32	IDR;				//	1320h	|	20h	|	Inbound Doorbell Register
-	u32	IISR;				//	1324h	|	24h	|	Inbound Interrupt Status Register
-	u32	IIMR;				//	1328h	|	28h	|	Inbound Interrupt Mask Register
-	u32	ODR;				//	132Ch	|	2Ch	|	Outbound Doorbell Register
-	u32	OISR;				//	1330h	|	30h	|	Outbound Interrupt Status Register
-	u32	OIMR;				//	1334h	|	34h	|	Outbound Interrupt Mask Register
-						// * Must access through ATU Inbound Translation Window
+			    /*	Local  | PCI*| Name */
+	__le32	ARSR;	    /*	1300h  | 00h | APIC Register Select Register */
+	__le32	reserved0;  /*	1304h  | 04h | Reserved */
+	__le32	AWR;	    /*	1308h  | 08h | APIC Window Register */
+	__le32	reserved1;  /*	130Ch  | 0Ch | Reserved */
+	__le32	IMRx[2];    /*	1310h  | 10h | Inbound Message Registers */
+	__le32	OMRx[2];    /*	1318h  | 18h | Outbound Message Registers */
+	__le32	IDR;	    /*	1320h  | 20h | Inbound Doorbell Register */
+	__le32	IISR;	    /*	1324h  | 24h | Inbound Interrupt 
+						Status Register */
+	__le32	IIMR;	    /*	1328h  | 28h | Inbound Interrupt 
+					 	Mask Register */
+	__le32	ODR;	    /*	132Ch  | 2Ch | Outbound Doorbell Register */
+	__le32	OISR;	    /*	1330h  | 30h | Outbound Interrupt 
+						Status Register */
+	__le32	OIMR;	    /*	1334h  | 34h | Outbound Interrupt 
+						Mask Register */
+	__le32	reserved2;  /*	1338h  | 38h | Reserved */
+	__le32	reserved3;  /*	133Ch  | 3Ch | Reserved */
+	__le32	InboundQueue;/*	1340h  | 40h | Inbound Queue Port relative to firmware */
+	__le32	OutboundQueue;/*1344h  | 44h | Outbound Queue Port relative to firmware */
+			    /* * Must access through ATU Inbound 
+			     	 Translation Window */
 };
 
 struct rx_inbound {
-	u32	Mailbox[8];
+	__le32	Mailbox[8];
 };
 
 #define	InboundMailbox0		IndexRegs.Mailbox[0]
@@ -596,27 +732,29 @@ struct rx_inbound {
 #define	InboundMailbox2		IndexRegs.Mailbox[2]
 #define	InboundMailbox3		IndexRegs.Mailbox[3]
 #define	InboundMailbox4		IndexRegs.Mailbox[4]
-
-#define	INBOUNDDOORBELL_0	cpu_to_le32(0x00000001)
-#define INBOUNDDOORBELL_1	cpu_to_le32(0x00000002)
-#define INBOUNDDOORBELL_2	cpu_to_le32(0x00000004)
-#define INBOUNDDOORBELL_3	cpu_to_le32(0x00000008)
-#define INBOUNDDOORBELL_4	cpu_to_le32(0x00000010)
-#define INBOUNDDOORBELL_5	cpu_to_le32(0x00000020)
-#define INBOUNDDOORBELL_6	cpu_to_le32(0x00000040)
-
-#define	OUTBOUNDDOORBELL_0	cpu_to_le32(0x00000001)
-#define OUTBOUNDDOORBELL_1	cpu_to_le32(0x00000002)
-#define OUTBOUNDDOORBELL_2	cpu_to_le32(0x00000004)
-#define OUTBOUNDDOORBELL_3	cpu_to_le32(0x00000008)
-#define OUTBOUNDDOORBELL_4	cpu_to_le32(0x00000010)
+#define	InboundMailbox5		IndexRegs.Mailbox[5]
+#define	InboundMailbox6		IndexRegs.Mailbox[6]
+
+#define	INBOUNDDOORBELL_0	0x00000001
+#define INBOUNDDOORBELL_1	0x00000002
+#define INBOUNDDOORBELL_2	0x00000004
+#define INBOUNDDOORBELL_3	0x00000008
+#define INBOUNDDOORBELL_4	0x00000010
+#define INBOUNDDOORBELL_5	0x00000020
+#define INBOUNDDOORBELL_6	0x00000040
+
+#define	OUTBOUNDDOORBELL_0	0x00000001
+#define OUTBOUNDDOORBELL_1	0x00000002
+#define OUTBOUNDDOORBELL_2	0x00000004
+#define OUTBOUNDDOORBELL_3	0x00000008
+#define OUTBOUNDDOORBELL_4	0x00000010
 
 #define InboundDoorbellReg	MUnit.IDR
 #define OutboundDoorbellReg	MUnit.ODR
 
 struct rx_registers {
-	struct rx_mu_registers		MUnit;		// 1300h - 1334h
-	u32				reserved1[6];	// 1338h - 134ch
+	struct rx_mu_registers		MUnit;		/* 1300h - 1344h */
+	__le32				reserved1[2];	/* 1348h - 134ch */
 	struct rx_inbound		IndexRegs;
 };
 
@@ -625,29 +763,97 @@ struct rx_registers {
 #define rx_writeb(AEP, CSR, value)	writeb(value, &((AEP)->regs.rx->CSR))
 #define rx_writel(AEP, CSR, value)	writel(value, &((AEP)->regs.rx->CSR))
 
-struct fib;
+/*
+ *	Rkt Message Unit Registers (same as Rx, except a larger reserve region)
+ */
+
+#define rkt_mu_registers rx_mu_registers
+#define rkt_inbound rx_inbound
+
+struct rkt_registers {
+	struct rkt_mu_registers		MUnit;		 /* 1300h - 1344h */
+	__le32				reserved1[1006]; /* 1348h - 22fch */
+	struct rkt_inbound		IndexRegs;	 /* 2300h - */
+};
+
+#define rkt_readb(AEP, CSR)		readb(&((AEP)->regs.rkt->CSR))
+#define rkt_readl(AEP, CSR)		readl(&((AEP)->regs.rkt->CSR))
+#define rkt_writeb(AEP, CSR, value)	writeb(value, &((AEP)->regs.rkt->CSR))
+#define rkt_writel(AEP, CSR, value)	writel(value, &((AEP)->regs.rkt->CSR))
 
 typedef void (*fib_callback)(void *ctxt, struct fib *fibctx);
 
 struct aac_fib_context {
 	s16	 		type;		// used for verification of structure	
 	s16	 		size;
+	u32			unique;		// unique value representing this context
 	ulong			jiffies;	// used for cleanup - dmb changed to ulong
 	struct list_head	next;		// used to link context's into a linked list
 	struct semaphore 	wait_sem;	// this is used to wait for the next fib to arrive.
 	int			wait;		// Set to true when thread is in WaitForSingleObject
 	unsigned long		count;		// total number of FIBs on FibList
-	struct list_head	fib_list;	// this holds fibs which should be 32 bit addresses
+	struct list_head	fib_list;	// this holds fibs and their attachd hw_fibs
 };
 
-struct fsa_scsi_hba {
-	u32		size[MAXIMUM_NUM_CONTAINERS];
-	u32		type[MAXIMUM_NUM_CONTAINERS];
-	u8		valid[MAXIMUM_NUM_CONTAINERS];
-	u8		ro[MAXIMUM_NUM_CONTAINERS];
-	u8		locked[MAXIMUM_NUM_CONTAINERS];
-	u8		deleted[MAXIMUM_NUM_CONTAINERS];
-	s32		devno[MAXIMUM_NUM_CONTAINERS];
+struct sense_data {
+	u8 error_code;		/* 70h (current errors), 71h(deferred errors) */
+	u8 valid:1;		/* A valid bit of one indicates that the information  */
+				/* field contains valid information as defined in the
+				 * SCSI-2 Standard.
+				 */
+	u8 segment_number;	/* Only used for COPY, COMPARE, or COPY AND VERIFY Commands */
+	u8 sense_key:4;		/* Sense Key */
+	u8 reserved:1;
+	u8 ILI:1;		/* Incorrect Length Indicator */
+	u8 EOM:1;		/* End Of Medium - reserved for random access devices */
+	u8 filemark:1;		/* Filemark - reserved for random access devices */
+
+	u8 information[4];	/* for direct-access devices, contains the unsigned 
+				 * logical block address or residue associated with 
+				 * the sense key 
+				 */
+	u8 add_sense_len;	/* number of additional sense bytes to follow this field */
+	u8 cmnd_info[4];	/* not used */
+	u8 ASC;			/* Additional Sense Code */
+	u8 ASCQ;		/* Additional Sense Code Qualifier */
+	u8 FRUC;		/* Field Replaceable Unit Code - not used */
+	u8 bit_ptr:3;		/* indicates which byte of the CDB or parameter data
+				 * was in error
+				 */
+	u8 BPV:1;		/* bit pointer valid (BPV): 1- indicates that 
+				 * the bit_ptr field has valid value
+				 */
+	u8 reserved2:2;
+	u8 CD:1;		/* command data bit: 1- illegal parameter in CDB.
+				 * 0- illegal parameter in data.
+				 */
+	u8 SKSV:1;
+	u8 field_ptr[2];	/* byte of the CDB or parameter data in error */
+};
+
+struct fsa_dev_info {
+	u64		last;
+	u64		size;
+	u32		type;
+	u32		config_waiting_on;
+	u16		queue_depth;
+	u8		config_needed;
+	u8		valid;
+	u8		ro;
+	u8		locked;
+	u8		deleted;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19))
+#	define MAX_NESTED AAC_NUM_MGT_FIB
+//#	undef MAX_NESTED
+//#	define MAX_NESTED 1
+#	if (MAX_NESTED >= 256)
+		u16	nested;
+#	else
+		u8	nested;
+#	endif
+#endif
+	char		devname[8];
+	struct sense_data sense_data;
 };
 
 struct fib {
@@ -682,6 +888,12 @@ struct fib {
 	void 			*data;
 	struct hw_fib		*hw_fib;		/* Actual shared object */
 	dma_addr_t		hw_fib_pa;		/* physical address of hw_fib*/
+#if (defined(AAC_DEBUG_INSTRUMENT_TIMING))
+	unsigned long		DriverTimeStartS;
+	unsigned long		DriverTimeStartuS;
+	unsigned long		DriverTimeDoneS;
+	unsigned long		DriverTimeDoneuS;
+#endif
 };
 
 /*
@@ -692,27 +904,68 @@ struct fib {
  
 struct aac_adapter_info
 {
-	u32	platform;
-	u32	cpu;
-	u32	subcpu;
-	u32	clock;
-	u32	execmem;
-	u32	buffermem;
-	u32	totalmem;
-	u32	kernelrev;
-	u32	kernelbuild;
-	u32	monitorrev;
-	u32	monitorbuild;
-	u32	hwrev;
-	u32	hwbuild;
-	u32	biosrev;
-	u32	biosbuild;
-	u32	cluster;
-	u32	clusterchannelmask; 
-	u32	serial[2];
-	u32	battery;
-	u32	options;
-	u32	OEM;
+	__le32	platform;
+	__le32	cpu;
+	__le32	subcpu;
+	__le32	clock;
+	__le32	execmem;
+	__le32	buffermem;
+	__le32	totalmem;
+	__le32	kernelrev;
+	__le32	kernelbuild;
+	__le32	monitorrev;
+	__le32	monitorbuild;
+	__le32	hwrev;
+	__le32	hwbuild;
+	__le32	biosrev;
+	__le32	biosbuild;
+	__le32	cluster;
+	__le32	clusterchannelmask; 
+	__le32	serial[2];
+	__le32	battery;
+	__le32	options;
+	__le32	OEM;
+};
+
+struct aac_supplement_adapter_info
+{
+	u8	AdapterTypeText[17+1];
+	u8	Pad[2];
+	__le32	FlashMemoryByteSize;
+	__le32	FlashImageId;
+	__le32	MaxNumberPorts;
+	__le32	Version;
+	__le32	FeatureBits;
+	u8	SlotNumber;
+	u8	ReservedPad0[0];
+	u8	BuildDate[12];
+	__le32	CurrentNumberPorts;
+	__le32	ReservedGrowth[24];
+};
+#define AAC_FEATURE_FALCON	0x00000010
+#define AAC_SIS_VERSION_V3	3
+#define AAC_SIS_SLOT_UNKNOWN	0xFF
+
+#define GetBusInfo 0x00000009
+struct aac_bus_info {
+	__le32	Command;	/* VM_Ioctl */
+	__le32	ObjType;	/* FT_DRIVE */
+	__le32	MethodId;	/* 1 = SCSI Layer */
+	__le32	ObjectId;	/* Handle */
+	__le32	CtlCmd;		/* GetBusInfo */
+};
+
+struct aac_bus_info_response {
+	__le32	Status;		/* ST_OK */
+	__le32	ObjType;
+	__le32	MethodId;	/* unused */
+	__le32	ObjectId;	/* unused */
+	__le32	CtlCmd;		/* unused */
+	__le32	ProbeComplete;
+	__le32	BusCount;
+	__le32	TargetsPerBus;
+	u8	InitiatorBusId[10];
+	u8	BusValid[10];
 };
 
 /*
@@ -740,23 +993,30 @@ struct aac_adapter_info
 #define AAC_OPT_HOST_TIME_FIB		cpu_to_le32(1<<4)
 #define AAC_OPT_RAID50			cpu_to_le32(1<<5)
 #define AAC_OPT_4GB_WINDOW		cpu_to_le32(1<<6)
-#define AAC_OPT_SCSI_UPGRADEABLE	cpu_to_le32(1<<7)
+#define AAC_OPT_SCSI_UPGRADEABLE 	cpu_to_le32(1<<7)
 #define AAC_OPT_SOFT_ERR_REPORT		cpu_to_le32(1<<8)
-#define AAC_OPT_SUPPORTED_RECONDITION	cpu_to_le32(1<<9)
+#define AAC_OPT_SUPPORTED_RECONDITION 	cpu_to_le32(1<<9)
 #define AAC_OPT_SGMAP_HOST64		cpu_to_le32(1<<10)
 #define AAC_OPT_ALARM			cpu_to_le32(1<<11)
 #define AAC_OPT_NONDASD			cpu_to_le32(1<<12)
 #define AAC_OPT_SCSI_MANAGED    	cpu_to_le32(1<<13)
 #define AAC_OPT_RAID_SCSI_MODE		cpu_to_le32(1<<14)
-#define AAC_OPT_SUPPLEMENT_ADAPTER_INFO	cpu_to_le32(1<<15)
+#define AAC_OPT_SUPPLEMENT_ADAPTER_INFO	cpu_to_le32(1<<16)
+#define AAC_OPT_NEW_COMM		cpu_to_le32(1<<17)
+#define AAC_OPT_NEW_COMM_64		cpu_to_le32(1<<18)
 
 struct aac_dev
 {
-	struct aac_dev		*next;
+	struct list_head	entry;
 	const char		*name;
 	int			id;
 
-	u16			irq_mask;
+	/*
+	 *	negotiated FIB settings
+	 */
+	unsigned		max_fib_size;
+	unsigned		sg_tablesize;
+
 	/*
 	 *	Map for 128 fib objects (64k)
 	 */	
@@ -785,62 +1045,95 @@ struct aac_dev
 	struct adapter_ops	a_ops;
 	unsigned long		fsrev;		/* Main driver's revision number */
 	
+	unsigned		base_size;	/* Size of mapped in region */
 	struct aac_init		*init;		/* Holds initialization info to communicate with adapter */
 	dma_addr_t		init_pa; 	/* Holds physical address of the init struct */
 	
 	struct pci_dev		*pdev;		/* Our PCI interface */
 	void *			printfbuf;	/* pointer to buffer used for printf's from the adapter */
+	u32			DebugFlags;	/* Debug print flags bitmap */
+	u8 *			FwDebugBuffer_P;/* Addr FW Debug Buffer */
+	u32 *			FwDebugFlags_P;	/* Addr FW Debug Flags */
+	u32			FwDebugFlags;	/* FW Debug Flags */
+	u32 *			FwDebugStrLength_P;/* Addr FW Debug String Length */
+	u8 *			FwDebugBLEDflag_P;/* Addr FW Debug BLED */
+	u8 *			FwDebugBLEDvalue_P;/* Addr FW Debug BLED */
+	u32			FwDebugBufferSize;/* FW Debug Buffer Size in Bytes */
 	void *			comm_addr;	/* Base address of Comm area */
 	dma_addr_t		comm_phys;	/* Physical Address of Comm area */
 	size_t			comm_size;
 
 	struct Scsi_Host	*scsi_host_ptr;
-	struct fsa_scsi_hba	fsa_dev;
+	int			maximum_num_containers;
+	int			maximum_num_physicals;
+	int			maximum_num_channels;
+	struct fsa_dev_info	*fsa_dev;
 	pid_t			thread_pid;
 	int			cardtype;
 	
 	/*
 	 *	The following is the device specific extension.
 	 */
+#if (!defined(AAC_MIN_FOOTPRINT_SIZE))
+#	define AAC_MIN_FOOTPRINT_SIZE 8192
+#endif
 	union
 	{
-		struct sa_registers *sa;
-		struct rx_registers *rx;
+		struct sa_registers __iomem *sa;
+		struct rx_registers __iomem *rx;
+		struct rkt_registers __iomem *rkt;
 	} regs;
+	u32			OIMR; /* Mask Register Cache */
 	/*
-	 *	The following is the number of the individual adapter
+	 *	AIF thread states
 	 */
-	u32			devnum;
 	u32			aif_thread;
 	struct completion	aif_completion;
 	struct aac_adapter_info adapter_info;
+	struct aac_supplement_adapter_info supplement_adapter_info;
+#if (defined(CODE_STREAM_IDENTIFIER))
+# if (!defined(MAX_CODE_STREAM_IDENTIFIER_LENGTH))
+#  define MAX_CODE_STREAM_IDENTIFIER_LENGTH 64
+# endif
+	char			code_stream_identifier[MAX_CODE_STREAM_IDENTIFIER_LENGTH];
+#endif
 	/* These are in adapter info but they are in the io flow so
 	 * lets break them out so we don't have to do an AND to check them
 	 */
 	u8			nondasd_support; 
-	u8			pae_support;
+	u8			dac_support;
 	u8			raid_scsi_mode;
+	u8			new_comm_interface;
+	/* macro side-effects BEWARE */
+#	define			raw_io_interface \
+	  init->InitStructRevision==cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION_4)
+	u8			raw_io_64;
+	u8			printf_enabled;
+	u8			in_reset;
 };
 
-#define AllocateAndMapFibSpace(dev, MapFibContext) \
-	dev->a_ops.AllocateAndMapFibSpace(dev, MapFibContext)
-
-#define UnmapAndFreeFibSpace(dev, MapFibContext) \
-	dev->a_ops.UnmapAndFreeFibSpace(dev, MapFibContext)
-
 #define aac_adapter_interrupt(dev) \
-	dev->a_ops.adapter_interrupt(dev)
+	(dev)->a_ops.adapter_interrupt(dev)
 
 #define aac_adapter_notify(dev, event) \
-	dev->a_ops.adapter_notify(dev, event)
+	(dev)->a_ops.adapter_notify(dev, event)
 
-#define aac_adapter_enable_int(dev, event) \
-	dev->a_ops.adapter_enable_int(dev, event)
+#define aac_adapter_disable_int(dev) \
+	(dev)->a_ops.adapter_disable_int(dev)
 
-#define aac_adapter_disable_int(dev, event) \
-	dev->a_ops.adapter_disable_int(dev, event)
+#define aac_adapter_sync_cmd(dev, command, p1, p2, p3, p4, p5, p6, status, r1, r2, r3, r4) \
+	(dev)->a_ops.adapter_sync_cmd(dev, command, p1, p2, p3, p4, p5, p6, status, r1, r2, r3, r4)
 
+#define aac_adapter_check_health(dev) \
+	(dev)->a_ops.adapter_check_health(dev)
 
+#define aac_adapter_send(fib) \
+	((fib)->dev)->a_ops.adapter_send(fib)
+#if (defined(SCSI_HAS_DUMP))
+
+#define aac_adapter_intr(dev) \
+	(dev)->a_ops.adapter_intr(dev->scsi_host_ptr->irq, (void *)dev, (struct pt_regs *)NULL)
+#endif
 
 #define FIB_CONTEXT_FLAG_TIMED_OUT		(0x00000001)
 
@@ -950,62 +1243,129 @@ struct aac_dev
 
 struct aac_read
 {
-	u32	 	command;
-	u32 		cid;
-	u32 		block;
-	u32 		count;
+	__le32	 	command;
+	__le32 		cid;
+	__le32 		block;
+	__le32 		count;
 	struct sgmap	sg;	// Must be last in struct because it is variable
 };
 
 struct aac_read64
 {
-	u32	 	command;
-	u16 		cid;
-	u16 		sector_count;
-	u32 		block;
-	u16		pad;
-	u16		flags;
+	__le32	 	command;
+	__le16 		cid;
+	__le16 		sector_count;
+	__le32 		block;
+	__le16		pad;
+	__le16		flags;
 	struct sgmap64	sg;	// Must be last in struct because it is variable
 };
 
 struct aac_read_reply
 {
-	u32	 	status;
-	u32 		count;
+	__le32	 	status;
+	__le32 		count;
 };
 
 struct aac_write
 {
-	u32		command;
-	u32 		cid;
-	u32 		block;
-	u32 		count;
-	u32	 	stable;	// Not used
+	__le32		command;
+	__le32 		cid;
+	__le32 		block;
+	__le32 		count;
+	__le32	 	stable;	// Not used
 	struct sgmap	sg;	// Must be last in struct because it is variable
 };
 
 struct aac_write64
 {
-	u32	 	command;
-	u16 		cid;
-	u16 		sector_count;
-	u32 		block;
-	u16		pad;
-	u16		flags;
+	__le32	 	command;
+	__le16 		cid;
+	__le16 		sector_count;
+	__le32 		block;
+	__le16		pad;
+	__le16		flags;
 	struct sgmap64	sg;	// Must be last in struct because it is variable
 };
 struct aac_write_reply
 {
-	u32		status;
-	u32 		count;
-	u32		committed;
+	__le32		status;
+	__le32 		count;
+	__le32		committed;
+};
+
+struct aac_raw_io
+{
+	__le32		block[2];
+	__le32		count;
+	__le16		cid;
+	__le16		flags;		/* 00 W, 01 R */
+	__le16		bpTotal;	/* reserved for F/W use */
+	__le16		bpComplete;	/* reserved for F/W use */
+	struct sgmapraw	sg;
+};
+
+#define CT_FLUSH_CACHE 129
+struct aac_synchronize {
+	__le32		command;	/* VM_ContainerConfig */
+	__le32		type;		/* CT_FLUSH_CACHE */
+	__le32		cid;
+	__le32		parm1;
+	__le32		parm2;
+	__le32		parm3;
+	__le32		parm4;
+	__le32		count;	/* sizeof(((struct aac_synchronize_reply *)NULL)->data) */
+};
+
+struct aac_synchronize_reply {
+	__le32		dummy0;
+	__le32		dummy1;
+	__le32		status;	/* CT_OK */
+	__le32		parm1;
+	__le32		parm2;
+	__le32		parm3;
+	__le32		parm4;
+	__le32		parm5;
+	u8		data[16];
+};
+
+#define CT_PAUSE_IO    65
+#define CT_RELEASE_IO  66
+struct aac_pause {
+	__le32		command;	/* VM_ContainerConfig */
+	__le32		type;		/* CT_PAUSE_IO */
+	__le32		timeout;	/* 10ms ticks */
+	__le32		min;
+	__le32		noRescan;
+	__le32		parm3;
+	__le32		parm4;
+	__le32		count;	/* sizeof(((struct aac_pause_reply *)NULL)->data) */
 };
 
 struct aac_srb
 {
+	__le32		function;
+	__le32		channel;
+	__le32		id;
+	__le32		lun;
+	__le32		timeout;
+	__le32		flags;
+	__le32		count;		// Data xfer size
+	__le32		retry_limit;
+	__le32		cdb_size;
+	u8		cdb[16];
+	struct	sgmap	sg;
+};
+
+/*
+ * This and associated data structs are used by the
+ * ioctl caller and are in cpu order.
+ */
+struct user_aac_srb
+{
 	u32		function;
 	u32		channel;
-	u32		target;
+	u32		id;
 	u32		lun;
 	u32		timeout;
 	u32		flags;
@@ -1013,20 +1373,18 @@ struct aac_srb
 	u32		retry_limit;
 	u32		cdb_size;
 	u8		cdb[16];
-	struct	sgmap	sg;
+	struct	user_sgmap	sg;
 };
 
-
-
 #define		AAC_SENSE_BUFFERSIZE	 30
 
 struct aac_srb_reply
 {
-	u32		status;
-	u32		srb_status;
-	u32		scsi_status;
-	u32		data_xfer_length;
-	u32		sense_data_size;
+	__le32		status;
+	__le32		srb_status;
+	__le32		scsi_status;
+	__le32		data_xfer_length;
+	__le32		sense_data_size;
 	u8		sense_data[AAC_SENSE_BUFFERSIZE]; // Can this be SCSI_SENSE_BUFFERSIZE
 };
 /*
@@ -1121,8 +1479,10 @@ struct aac_srb_reply
 #define		VM_CtBlockVerify64	18
 #define		VM_CtHostRead64		19
 #define		VM_CtHostWrite64	20
+#define		VM_DrvErrTblLog		21
+#define		VM_NameServe64		22
 
-#define		MAX_VMCOMMAND_NUM	21	/* used for sizing stats array - leave last */
+#define		MAX_VMCOMMAND_NUM	23	/* used for sizing stats array - leave last */
 
 /*
  *	Descriptive information (eg, vital stats)
@@ -1133,14 +1493,14 @@ struct aac_srb_reply
  */
 
 struct aac_fsinfo {
-	u32  fsTotalSize;	/* Consumed by fs, incl. metadata */
-	u32  fsBlockSize;
-	u32  fsFragSize;
-	u32  fsMaxExtendSize;
-	u32  fsSpaceUnits;
-	u32  fsMaxNumFiles;
-	u32  fsNumFreeFiles;
-	u32  fsInodeDensity;
+	__le32  fsTotalSize;	/* Consumed by fs, incl. metadata */
+	__le32  fsBlockSize;
+	__le32  fsFragSize;
+	__le32  fsMaxExtendSize;
+	__le32  fsSpaceUnits;
+	__le32  fsMaxNumFiles;
+	__le32  fsNumFreeFiles;
+	__le32  fsInodeDensity;
 };	/* valid iff ObjType == FT_FILESYS && !(ContentState & FSCS_NOTCLEAN) */
 
 union aac_contentinfo {
@@ -1148,61 +1508,130 @@ union aac_contentinfo {
 };
 
 /*
+ *	Query for Container Configuration Status
+ */
+
+#define CT_GET_CONFIG_STATUS 147
+struct aac_get_config_status {
+	__le32		command;	/* VM_ContainerConfig */
+	__le32		type;		/* CT_GET_CONFIG_STATUS */
+	__le32		parm1;
+	__le32		parm2;
+	__le32		parm3;
+	__le32		parm4;
+	__le32		parm5;
+	__le32		count;	/* sizeof(((struct aac_get_config_status_resp *)NULL)->data) */
+};
+
+#define CFACT_CONTINUE 0
+#define CFACT_PAUSE    1
+#define CFACT_ABORT    2
+struct aac_get_config_status_resp {
+	__le32		response; /* ST_OK */
+	__le32		dummy0;
+	__le32		status;	/* CT_OK */
+	__le32		parm1;
+	__le32		parm2;
+	__le32		parm3;
+	__le32		parm4;
+	__le32		parm5;
+	struct {
+		__le32	action; /* CFACT_CONTINUE, CFACT_PAUSE or CFACT_ABORT */
+		__le16	flags;
+		__le16	count;
+	}		data;
+};
+
+/*
+ *	Accept the configuration as-is
+ */
+
+#define CT_COMMIT_CONFIG 152
+
+struct aac_commit_config {
+	__le32		command;	/* VM_ContainerConfig */
+	__le32		type;		/* CT_COMMIT_CONFIG */
+};
+
+/*
+ *	Query for Container Configuration Status
+ */
+
+#define CT_GET_CONTAINER_COUNT 4
+struct aac_get_container_count {
+	__le32		command;	/* VM_ContainerConfig */
+	__le32		type;		/* CT_GET_CONTAINER_COUNT */
+};
+
+struct aac_get_container_count_resp {
+	__le32		response; /* ST_OK */
+	__le32		dummy0;
+	__le32		MaxContainers;
+	__le32		ContainerSwitchEntries;
+	__le32		MaxPartitions;
+};
+
+
+/*
  *	Query for "mountable" objects, ie, objects that are typically
  *	associated with a drive letter on the client (host) side.
  */
 
 struct aac_mntent {
-	u32    			oid;
-	u8			name[16];	// if applicable
-	struct creation_info	create_info;	// if applicable
-	u32			capacity;
-	u32			vol;    	// substrate structure
-	u32			obj;	        // FT_FILESYS, FT_DATABASE, etc.
-	u32			state;		// unready for mounting, readonly, etc.
-	union aac_contentinfo	fileinfo;	// Info specific to content manager (eg, filesystem)
-	u32			altoid;		// != oid <==> snapshot or broken mirror exists
+	__le32    		oid;
+	u8			name[16];	/* if applicable */
+	struct creation_info	create_info;	/* if applicable */
+	__le32			capacity;
+	__le32			vol;    	/* substrate structure */
+	__le32			obj;	        /* FT_FILESYS, 
+						   FT_DATABASE, etc. */
+	__le32			state;		/* unready for mounting, 
+						   readonly, etc. */
+	union aac_contentinfo	fileinfo;	/* Info specific to content 
+						   manager (eg, filesystem) */
+	__le32			altoid;		/* != oid <==> snapshot or 
+						   broken mirror exists */
+	__le32			capacityhigh;
 };
 
-#define FSCS_NOTCLEAN	0x0001  	/* fsck is neccessary before mounting */
-#define FSCS_READONLY	0x0002		/* possible result of broken mirror */
-#define FSCS_HIDDEN	0x0004		/* should be ignored - set during a clear */
+#define FSCS_NOTCLEAN	0x0001  /* fsck is neccessary before mounting */
+#define FSCS_READONLY	0x0002	/* possible result of broken mirror */
+#define FSCS_HIDDEN	0x0004	/* should be ignored - set during a clear */
 
 struct aac_query_mount {
-	u32		command;
-	u32		type;
-	u32		count;
+	__le32		command;
+	__le32		type;
+	__le32		count;
 };
 
 struct aac_mount {
-	u32		status;
-	u32	   	type;           /* should be same as that requested */
-	u32		count;
+	__le32		status;
+	__le32	   	type;           /* should be same as that requested */
+	__le32		count;
 	struct aac_mntent mnt[1];
 };
 
 #define CT_READ_NAME 130
 struct aac_get_name {
-	u32		command;
-	u32		type;	// CT_READ_NAME
-	u32		cid;
-	u32		parm1;
-	u32		parm2;
-	u32		parm3;
-	u32		parm4;
-	u32		count;	// sizeof(((struct aac_get_name_resp *)NULL)->data)
+	__le32		command;	/* VM_ContainerConfig */
+	__le32		type;		/* CT_READ_NAME */
+	__le32		cid;
+	__le32		parm1;
+	__le32		parm2;
+	__le32		parm3;
+	__le32		parm4;
+	__le32		count;	/* sizeof(((struct aac_get_name_resp *)NULL)->data) */
 };
 
-#define CT_OK        218
 struct aac_get_name_resp {
-	u32		dummy0;
-	u32		dummy1;
-	u32		status;	// CT_OK
-	u32		parm1;
-	u32		parm2;
-	u32		parm3;
-	u32		parm4;
-	u32		parm5;
+	__le32		dummy0;
+	__le32		dummy1;
+	__le32		status;	/* CT_OK */
+	__le32		parm1;
+	__le32		parm2;
+	__le32		parm3;
+	__le32		parm4;
+	__le32		parm5;
 	u8		data[16];
 };
 
@@ -1211,15 +1640,15 @@ struct aac_get_name_resp {
  */
 
 struct aac_close {
-	u32	command;
-	u32	cid;
+	__le32	command;
+	__le32	cid;
 };
 
 struct aac_query_disk
 {
 	s32	cnum;
 	s32	bus;
-	s32	target;
+	s32	id;
 	s32	lun;
 	u32	valid;
 	u32	locked;
@@ -1233,21 +1662,33 @@ struct aac_delete_disk {
 	u32	disknum;
 	u32	cnum;
 };
-
+ 
 struct fib_ioctl
 {
-	char	*fibctx;
-	int	wait;
-	char	*fib;
+	u32	fibctx;
+	s32	wait;
+	char	__user *fib;
 };
 
 struct revision
 {
 	u32 compat;
-	u32 version;
-	u32 build;
+	__le32 version;
+	__le32 build;
+};
+
+#if (defined(CODE_STREAM_IDENTIFIER))
+#define VERSION_MATCH_SUCCESS		1
+#define VERSION_MATCH_FAILED		2
+#define VERSION_MATCH_UNSUPPORTED	3
+struct VersionMatch {
+	u32 status;
+	char driver[MAX_CODE_STREAM_IDENTIFIER_LENGTH];
+	char firmware[MAX_CODE_STREAM_IDENTIFIER_LENGTH];
 };
+#endif
 	
+
 /*
  * 	Ugly - non Linux like ioctl coding for back compat.
  */
@@ -1278,6 +1719,10 @@ struct revision
 #define FSACTL_MINIPORT_REV_CHECK               CTL_CODE(2107, METHOD_BUFFERED)
 #define FSACTL_GET_PCI_INFO               	CTL_CODE(2119, METHOD_BUFFERED)
 #define FSACTL_FORCE_DELETE_DISK		CTL_CODE(2120, METHOD_NEITHER)
+#define FSACTL_REGISTER_FIB_SEND		CTL_CODE(2136, METHOD_BUFFERED)
+#define FSACTL_GET_CONTAINERS			2131
+#define FSACTL_GET_VERSION_MATCHING		CTL_CODE(2137, METHOD_BUFFERED)
+#define FSACTL_SEND_LARGE_FIB			CTL_CODE(2138, METHOD_BUFFERED)
 
 
 struct aac_common
@@ -1290,6 +1735,13 @@ struct aac_common
 	u32 peak_fibs;
 	u32 zero_fibs;
 	u32 fib_timeouts;
+#if (defined(AAC_DEBUG_INSTRUMENT_AAC_CONFIG))
+	u32 peak_size;
+	u32 peak_sg;
+#endif
+#if (defined(AAC_DEBUG_INSTRUMENT_TIMING))
+	u32 peak_duration;
+#endif
 	/*
 	 *	Statistical counters in debug mode
 	 */
@@ -1313,7 +1765,7 @@ extern struct aac_common aac_config;
  *	only used for debugging.
  */
  
-#if DBG
+#ifdef DBG
 #define	FIB_COUNTER_INCREMENT(counter)		(counter)++
 #else
 #define	FIB_COUNTER_INCREMENT(counter)		
@@ -1324,14 +1776,20 @@ extern struct aac_common aac_config;
  *	Monitor/Kernel API
  */
 
-#define	BREAKPOINT_REQUEST		cpu_to_le32(0x00000004)
-#define	INIT_STRUCT_BASE_ADDRESS	cpu_to_le32(0x00000005)
-#define READ_PERMANENT_PARAMETERS	cpu_to_le32(0x0000000a)
-#define WRITE_PERMANENT_PARAMETERS	cpu_to_le32(0x0000000b)
-#define HOST_CRASHING			cpu_to_le32(0x0000000d)
-#define	SEND_SYNCHRONOUS_FIB		cpu_to_le32(0x0000000c)
-#define GET_ADAPTER_PROPERTIES		cpu_to_le32(0x00000019)
-#define RE_INIT_ADAPTER			cpu_to_le32(0x000000ee)
+#define	BREAKPOINT_REQUEST		0x00000004
+#define	INIT_STRUCT_BASE_ADDRESS	0x00000005
+#define READ_PERMANENT_PARAMETERS	0x0000000a
+#define WRITE_PERMANENT_PARAMETERS	0x0000000b
+#define HOST_CRASHING			0x0000000d
+#define	SEND_SYNCHRONOUS_FIB		0x0000000c
+#define COMMAND_POST_RESULTS		0x00000014
+#define GET_ADAPTER_PROPERTIES		0x00000019
+#define GET_DRIVER_BUFFER_PROPERTIES	0x00000023
+#define SEND_SLOT_NUMBER		0x00000024
+#define RCV_TEMP_READINGS		0x00000025
+#define GET_COMM_PREFERRED_SETTINGS	0x00000026
+#define IOP_RESET			0x00001000
+#define RE_INIT_ADAPTER			0x000000ee
 
 /*
  *	Adapter Status Register
@@ -1354,20 +1812,22 @@ extern struct aac_common aac_config;
  *	Phases are bit oriented.  It is NOT valid  to have multiple bits set						
  */					
 
-#define	SELF_TEST_FAILED		cpu_to_le32(0x00000004)
-#define	KERNEL_UP_AND_RUNNING		cpu_to_le32(0x00000080)
-#define	KERNEL_PANIC			cpu_to_le32(0x00000100)
+#define	SELF_TEST_FAILED		0x00000004
+#define	MONITOR_PANIC			0x00000020
+#define	KERNEL_UP_AND_RUNNING		0x00000080
+#define	KERNEL_PANIC			0x00000100
 
 /*
  *	Doorbell bit defines
  */
 
-#define DoorBellPrintfDone		cpu_to_le32(1<<5)	// Host -> Adapter
-#define DoorBellAdapterNormCmdReady	cpu_to_le32(1<<1)	// Adapter -> Host
-#define DoorBellAdapterNormRespReady	cpu_to_le32(1<<2)	// Adapter -> Host
-#define DoorBellAdapterNormCmdNotFull	cpu_to_le32(1<<3)	// Adapter -> Host
-#define DoorBellAdapterNormRespNotFull	cpu_to_le32(1<<4)	// Adapter -> Host
-#define DoorBellPrintfReady		cpu_to_le32(1<<5)	// Adapter -> Host
+#define DoorBellSyncCmdAvailable	(1<<0)	/* Host -> Adapter */
+#define DoorBellPrintfDone		(1<<5)	/* Host -> Adapter */
+#define DoorBellAdapterNormCmdReady	(1<<1)	/* Adapter -> Host */
+#define DoorBellAdapterNormRespReady	(1<<2)	/* Adapter -> Host */
+#define DoorBellAdapterNormCmdNotFull	(1<<3)	/* Adapter -> Host */
+#define DoorBellAdapterNormRespNotFull	(1<<4)	/* Adapter -> Host */
+#define DoorBellPrintfReady		(1<<5)	/* Adapter -> Host */
 
 /*
  *	For FIB communication, we need all of the following things
@@ -1375,12 +1835,23 @@ extern struct aac_common aac_config;
  */
  
 #define 	AifCmdEventNotify	1	/* Notify of event */
-#define		AifEnContainerChange	4	/* Container configuration change */
+#define			AifEnConfigChange	3	/* Adapter configuration change */
+#define			AifEnContainerChange	4	/* Container configuration change */
+#define			AifEnDeviceFailure	5	/* SCSI device failed */
+#define			AifEnAddContainer	15	/* A new array was created */
+#define			AifEnDeleteContainer	16	/* A container was deleted */
+#define			AifEnExpEvent		23	/* Firmware Event Log */
+#define			AifExeFirmwarePanic	3	/* Firmware Event Panic */
+#define			AifHighPriority		3	/* Highest Priority Event */
+
 #define		AifCmdJobProgress	2	/* Progress report */
+#define			AifJobCtrZero	101	/* Array Zero progress */
+#define			AifJobStsSuccess 1	/* Job completes */
+#define			AifJobStsRunning 102	/* Job running */
 #define		AifCmdAPIReport		3	/* Report from other user of API */
 #define		AifCmdDriverNotify	4	/* Notify host driver of event */
-#define		AifDenMorphComplete	200	/* A morph operation completed */
-#define		AifDenVolumeExtendComplete 201  /* A volume expand operation completed */
+#define			AifDenMorphComplete 200	/* A morph operation completed */
+#define			AifDenVolumeExtendComplete 201 /* A volume extend completed */
 #define		AifReqJobList		100	/* Gets back complete job list */
 #define		AifReqJobsForCtr	101	/* Gets back jobs for specific container */
 #define		AifReqJobsForScsi	102	/* Gets back jobs for specific SCSI device */ 
@@ -1400,37 +1871,85 @@ extern struct aac_common aac_config;
  */
 
 struct aac_aifcmd {
-	u32 command;		/* Tell host what type of notify this is */
-	u32 seqnum;		/* To allow ordering of reports (if necessary) */
+	__le32 command;		/* Tell host what type of notify this is */
+	__le32 seqnum;		/* To allow ordering of reports (if necessary) */
 	u8 data[1];		/* Undefined length (from kernel viewpoint) */
 };
 
+/**
+ * 	Convert capacity to cylinders
+ *  	accounting for the fact capacity could be a 64 bit value
+ *
+ */
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+typedef unsigned long sector_t;
+
+#endif
+static inline u32 cap_to_cyls(sector_t capacity, u32 divisor)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+	sector_div(capacity, divisor);
+#else
+	capacity /= divisor;
+#endif
+	return (u32)capacity;
+}
+
+struct scsi_cmnd;
+/* SCp.phase values */
+#define AAC_OWNER_MIDLEVEL	0x101
+#define AAC_OWNER_LOWLEVEL	0x102
+#define AAC_OWNER_ERROR_HANDLER	0x103
+#define AAC_OWNER_FIRMWARE	0x106
+
 const char *aac_driverinfo(struct Scsi_Host *);
 struct fib *fib_alloc(struct aac_dev *dev);
 int fib_setup(struct aac_dev *dev);
 void fib_map_free(struct aac_dev *dev);
 void fib_free(struct fib * context);
 void fib_init(struct fib * context);
-void fib_dealloc(struct fib * context);
 void aac_printf(struct aac_dev *dev, u32 val);
-int fib_send(u16 command, struct fib * context, unsigned long size, int priority, int wait, int reply, fib_callback callback, void *ctxt);
+#if (defined(FSACTL_REGISTER_FIB_SEND))
+typedef int (*fib_send_t)(u16 command, struct fib * context, unsigned long size, int priority, int wait, int reply, fib_callback callback, void *ctxt);
+extern fib_send_t fib_send;
+#else
+#define aac_fib_send fib_send
+#endif
+int aac_fib_send(u16 command, struct fib * context, unsigned long size, int priority, int wait, int reply, fib_callback callback, void *ctxt);
 int aac_consumer_get(struct aac_dev * dev, struct aac_queue * q, struct aac_entry **entry);
-int aac_consumer_avail(struct aac_dev * dev, struct aac_queue * q);
 void aac_consumer_free(struct aac_dev * dev, struct aac_queue * q, u32 qnum);
 int fib_complete(struct fib * context);
 #define fib_data(fibctx) ((void *)(fibctx)->hw_fib->data)
-int aac_detach(struct aac_dev *dev);
 struct aac_dev *aac_init_adapter(struct aac_dev *dev);
+int aac_get_config_status(struct aac_dev *dev);
 int aac_get_containers(struct aac_dev *dev);
-int aac_scsi_cmd(Scsi_Cmnd *scsi_cmnd_ptr);
-int aac_dev_ioctl(struct aac_dev *dev, int cmd, void *arg);
-int aac_do_ioctl(struct aac_dev * dev, int cmd, void *arg);
-int aac_rx_init(struct aac_dev *dev, unsigned long devNumber);
-int aac_sa_init(struct aac_dev *dev, unsigned long devNumber);
+int aac_scsi_cmd(struct scsi_cmnd *cmd);
+int aac_dev_ioctl(struct aac_dev *dev, int cmd, void __user *arg);
+#if (defined(AAC_CSMI))
+int aac_csmi_ioctl(struct aac_dev *dev, int cmd, void __user *arg);
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11))
+#if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) ? defined(__x86_64__) : defined(CONFIG_COMPAT))
+void aac_csmi_register_ioctl32_conversion(void);
+void aac_csmi_unregister_ioctl32_conversion(void);
+#endif
+#endif
+#endif
+int aac_do_ioctl(struct aac_dev * dev, int cmd, void __user *arg);
+int aac_rx_init(struct aac_dev *dev);
+int aac_rkt_init(struct aac_dev *dev);
+int aac_sa_init(struct aac_dev *dev);
 unsigned int aac_response_normal(struct aac_queue * q);
 unsigned int aac_command_normal(struct aac_queue * q);
+unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index);
+int aac_reset_adapter(struct aac_dev * dev);
+int aac_check_health(struct aac_dev * dev);
 int aac_command_thread(struct aac_dev * dev);
 int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context *fibctx);
 int fib_adapter_complete(struct fib * fibptr, unsigned short size);
 struct aac_driver_ident* aac_get_driver_ident(int devtype);
 int aac_get_adapter_info(struct aac_dev* dev);
+int aac_send_shutdown(struct aac_dev *dev);
+int probe_container(struct aac_dev *dev, int cid);
+extern int numacb;
+extern int acbsize;
+extern char aac_driver_version[];
diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c
index 1c58c0e..f83b24b 100644
--- a/drivers/scsi/aacraid/commctrl.c
+++ b/drivers/scsi/aacraid/commctrl.c
@@ -28,7 +28,6 @@
  *
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/types.h>
@@ -37,13 +36,23 @@
 #include <linux/spinlock.h>
 #include <linux/slab.h>
 #include <linux/completion.h>
-#include <linux/blk.h>
+#include <linux/version.h> /* for the following test */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+#include <linux/dma-mapping.h>
+#endif
+#include <linux/blkdev.h>
 #include <asm/semaphore.h>
 #include <asm/uaccess.h>
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0))
+#include <scsi/scsi.h>
+#else
 #include "scsi.h"
-#include "hosts.h"
+#endif
 
 #include "aacraid.h"
+#if (defined(AAC_CSMI))
+# include "csmi.h"
+#endif
 
 /**
  *	ioctl_send_fib	-	send a FIB from userspace
@@ -53,15 +62,45 @@
  *	This routine sends a fib to the adapter on behalf of a user level
  *	program.
  */
+#if (defined(AAC_DEBUG_INSTRUMENT_IOCTL_SENDFIB))
+static char * aac_debug_timestamp(void)
+{
+	unsigned long seconds = get_seconds();
+	static char buffer[80];
+	sprintf(buffer, "%02u:%02u:%02u: ",
+	  (int)((seconds / 3600) % 24),
+	  (int)((seconds / 60) % 60),
+	  (int)(seconds % 60));
+	return buffer;
+}
+# define AAC_DEBUG_PREAMBLE	"%s"
+# define AAC_DEBUG_POSTAMBLE	,aac_debug_timestamp()
+#else
+# define AAC_DEBUG_PREAMBLE	KERN_INFO
+# define AAC_DEBUG_POSTAMBLE
+#endif
  
-static int ioctl_send_fib(struct aac_dev * dev, void *arg)
+static int ioctl_send_fib(struct aac_dev * dev, void __user *arg)
 {
 	struct hw_fib * kfib;
 	struct fib *fibptr;
-
+	struct hw_fib * hw_fib = (struct hw_fib *)0;
+	dma_addr_t hw_fib_pa = (dma_addr_t)0LL;
+	unsigned size;
+	int retval;
+
+#if (defined(AAC_DEBUG_INSTRUMENT_IOCTL) || defined(AAC_DEBUG_INSTRUMENT_IOCTL_SENDFIB))
+	printk(AAC_DEBUG_PREAMBLE "ioctl_send_fib(%p,%p)\n" AAC_DEBUG_POSTAMBLE,
+	  dev, arg);
+#endif
 	fibptr = fib_alloc(dev);
-	if(fibptr == NULL)
+	if(fibptr == NULL) {
+#if (defined(AAC_DEBUG_INSTRUMENT_IOCTL) || defined(AAC_DEBUG_INSTRUMENT_IOCTL_SENDFIB))
+		printk(AAC_DEBUG_PREAMBLE "ioctl_send_fib returns -ENOMEM\n"
+		  AAC_DEBUG_POSTAMBLE);
+#endif
 		return -ENOMEM;
+	}
 		
 	kfib = fibptr->hw_fib;
 	/*
@@ -69,6 +108,10 @@ static int ioctl_send_fib(struct aac_dev * dev, void *arg)
 	 */
 	if (copy_from_user((void *)kfib, arg, sizeof(struct aac_fibhdr))) {
 		fib_free(fibptr);
+#if (defined(AAC_DEBUG_INSTRUMENT_IOCTL) || defined(AAC_DEBUG_INSTRUMENT_IOCTL_SENDFIB))
+		printk(AAC_DEBUG_PREAMBLE "ioctl_send_fib returns -EFAULT\n"
+		  AAC_DEBUG_POSTAMBLE);
+#endif
 		return -EFAULT;
 	}
 	/*
@@ -76,17 +119,28 @@ static int ioctl_send_fib(struct aac_dev * dev, void *arg)
 	 *	will not overrun the buffer when we copy the memory. Return
 	 *	an error if we would.
 	 */
-	if(le32_to_cpu(kfib->header.Size) > sizeof(struct hw_fib) - sizeof(struct aac_fibhdr)) {
-		fib_free(fibptr);
-		return -EINVAL;
+	size = le16_to_cpu(kfib->header.Size) + sizeof(struct aac_fibhdr);
+	if (size < le16_to_cpu(kfib->header.SenderSize))
+		size = le16_to_cpu(kfib->header.SenderSize);
+	if (size > dev->max_fib_size) {
+		if (size > 2048) {
+			retval = -EINVAL;
+			goto cleanup;
+		}
+		/* Highjack the hw_fib */
+		hw_fib = fibptr->hw_fib;
+		hw_fib_pa = fibptr->hw_fib_pa;
+		fibptr->hw_fib = kfib = pci_alloc_consistent(dev->pdev, size, &fibptr->hw_fib_pa);
+		memset(((char *)kfib) + dev->max_fib_size, 0, size - dev->max_fib_size);
+		memcpy(kfib, hw_fib, dev->max_fib_size);
 	}
 
-	if (copy_from_user((void *) kfib, arg, le32_to_cpu(kfib->header.Size) + sizeof(struct aac_fibhdr))) {
-		fib_free(fibptr);
-		return -EFAULT;
+	if (copy_from_user(kfib, arg, size)) {
+		retval = -EFAULT;
+		goto cleanup;
 	}
 
-	if (kfib->header.Command == cpu_to_le32(TakeABreakPt)) {
+	if (kfib->header.Command == cpu_to_le16(TakeABreakPt)) {
 		aac_adapter_interrupt(dev);
 		/*
 		 * Since we didn't really send a fib, zero out the state to allow 
@@ -94,15 +148,44 @@ static int ioctl_send_fib(struct aac_dev * dev, void *arg)
 		 */
 		kfib->header.XferState = 0;
 	} else {
-		if (fib_send(kfib->header.Command, fibptr, le32_to_cpu(kfib->header.Size) , FsaNormal,
-			1, 1, NULL, NULL) != 0) 
-		{
-			fib_free(fibptr);
-			return -EINVAL;
+#		if (defined(AAC_DEBUG_INSTRUMENT_IOCTL) || defined(AAC_DEBUG_INSTRUMENT_IOCTL_SENDFIB))
+			{
+				u8 * fib = (u8 *)kfib;
+				unsigned len = le16_to_cpu(kfib->header.Size);
+				char buffer[80];
+				char * cp = buffer;
+
+				strcpy(cp, "FIB=");
+				cp += 4;
+				while (len > 0) {
+					if (cp >= &buffer[sizeof(buffer)-4]) {
+						printk (AAC_DEBUG_PREAMBLE
+						  "%s\n" AAC_DEBUG_POSTAMBLE,
+						  buffer);
+						strcpy(cp = buffer, "    ");
+						cp += 4;
+					}
+					sprintf (cp, "%02x ", *(fib++));
+					cp += strlen(cp);
+					--len;
+				}
+				if (cp > &buffer[4])
+					printk (AAC_DEBUG_PREAMBLE "%s\n"
+					  AAC_DEBUG_POSTAMBLE, buffer);
+			}
+			printk(AAC_DEBUG_PREAMBLE "fib_send(%x,,%d,...)\n"
+			  AAC_DEBUG_POSTAMBLE, kfib->header.Command,
+			  le16_to_cpu(kfib->header.Size));
+#		endif
+		retval = fib_send(le16_to_cpu(kfib->header.Command), fibptr,
+				le16_to_cpu(kfib->header.Size) , FsaNormal,
+				1, 1, NULL, NULL);
+		if (retval) {
+			goto cleanup;
 		}
 		if (fib_complete(fibptr) != 0) {
-			fib_free(fibptr);
-			return -EINVAL;
+			retval = -EINVAL;
+			goto cleanup;
 		}
 	}
 	/*
@@ -113,12 +196,21 @@ static int ioctl_send_fib(struct aac_dev * dev, void *arg)
 	 *	was already included by the adapter.)
 	 */
 
-	if (copy_to_user(arg, (void *)kfib, kfib->header.Size)) {
-		fib_free(fibptr);
-		return -EFAULT;
+	retval = 0;
+	if (copy_to_user(arg, (void *)kfib, size))
+		retval = -EFAULT;
+cleanup:
+	if (hw_fib) {
+		pci_free_consistent(dev->pdev, size, kfib, fibptr->hw_fib_pa);
+		fibptr->hw_fib_pa = hw_fib_pa;
+		fibptr->hw_fib = hw_fib;
 	}
 	fib_free(fibptr);
-	return 0;
+#if (defined(AAC_DEBUG_INSTRUMENT_IOCTL) || defined(AAC_DEBUG_INSTRUMENT_IOCTL_SENDFIB))
+	printk(AAC_DEBUG_PREAMBLE "ioctl_send_fib returns %d\n"
+	  AAC_DEBUG_POSTAMBLE, retval);
+#endif
+	return retval;
 }
 
 /**
@@ -128,18 +220,28 @@ static int ioctl_send_fib(struct aac_dev * dev, void *arg)
  *	passed in from the user.
  */
 
-static int open_getadapter_fib(struct aac_dev * dev, void *arg)
+static int open_getadapter_fib(struct aac_dev * dev, void __user *arg)
 {
 	struct aac_fib_context * fibctx;
 	int status;
-	unsigned long flags;
 
 	fibctx = kmalloc(sizeof(struct aac_fib_context), GFP_KERNEL);
 	if (fibctx == NULL) {
 		status = -ENOMEM;
 	} else {
+		unsigned long flags;
+		struct list_head * entry;
+		struct aac_fib_context * context;
+
 		fibctx->type = FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT;
 		fibctx->size = sizeof(struct aac_fib_context);
+ 		/*
+		 *	Yes yes, I know this could be an index, but we have a
+		 * better guarantee of uniqueness for the locked loop below.
+		 * Without the aid of a persistent history, this also helps
+		 * reduce the chance that the opaque context would be reused.
+		 */
+		fibctx->unique = (u32)((ulong)fibctx & 0xFFFFFFFF);
 		/*
 		 *	Initialize the mutex used to wait for the next AIF.
 		 */
@@ -157,9 +259,22 @@ static int open_getadapter_fib(struct aac_dev * dev, void *arg)
 		 *	AdapterFibContext list.
 		 */
 		spin_lock_irqsave(&dev->fib_lock, flags);
+		/* Ensure that we have a unique identifier */
+		entry = dev->fib_list.next;
+		while (entry != &dev->fib_list) {
+			context = list_entry(entry, struct aac_fib_context, next);
+			if (context->unique == fibctx->unique) {
+				/* Not unique (32 bits) */
+				fibctx->unique++;
+				entry = dev->fib_list.next;
+			} else {
+				entry = entry->next;
+			}
+		}
 		list_add_tail(&fibctx->next, &dev->fib_list);
 		spin_unlock_irqrestore(&dev->fib_lock, flags);
-		if (copy_to_user(arg,  &fibctx, sizeof(struct aac_fib_context *))) {
+		if (copy_to_user(arg,  &fibctx->unique, 
+						sizeof(fibctx->unique))) {
 			status = -EFAULT;
 		} else {
 			status = 0;
@@ -177,42 +292,39 @@ static int open_getadapter_fib(struct aac_dev * dev, void *arg)
  *	passed in from the user.
  */
 
-static int next_getadapter_fib(struct aac_dev * dev, void *arg)
+static int next_getadapter_fib(struct aac_dev * dev, void __user *arg)
 {
 	struct fib_ioctl f;
-	struct aac_fib_context *fibctx, *aifcp;
-	struct fib * fib;
+	struct fib *fib;
+	struct aac_fib_context *fibctx;
 	int status;
 	struct list_head * entry;
-	int found;
 	unsigned long flags;
 	
 	if(copy_from_user((void *)&f, arg, sizeof(struct fib_ioctl)))
 		return -EFAULT;
 	/*
-	 *	Extract the AdapterFibContext from the Input parameters.
-	 */
-	fibctx = (struct aac_fib_context *) f.fibctx;
-
-	/*
 	 *	Verify that the HANDLE passed in was a valid AdapterFibContext
 	 *
 	 *	Search the list of AdapterFibContext addresses on the adapter
 	 *	to be sure this is a valid address
 	 */
-	found = 0;
 	entry = dev->fib_list.next;
+	fibctx = NULL;
 
-	while(entry != &dev->fib_list) {
-		aifcp = list_entry(entry, struct aac_fib_context, next);
-		if(fibctx == aifcp) {   /* We found a winner */
-			found = 1;
+	while (entry != &dev->fib_list) {
+		fibctx = list_entry(entry, struct aac_fib_context, next);
+		/*
+		 *	Extract the AdapterFibContext from the Input parameters.
+		 */
+		if (fibctx->unique == f.fibctx) {   /* We found a winner */
 			break;
 		}
 		entry = entry->next;
+		fibctx = NULL;
 	}
-	if (found == 0) {
-		dprintk ((KERN_INFO "Fib not found\n"));
+	if (!fibctx) {
+		dprintk ((KERN_INFO "Fib Context not found\n"));
 		return -EINVAL;
 	}
 
@@ -313,18 +425,12 @@ int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context * fibctx)
  *	This routine will close down the fibctx passed in from the user.
  */
  
-static int close_getadapter_fib(struct aac_dev * dev, void *arg)
+static int close_getadapter_fib(struct aac_dev * dev, void __user *arg)
 {
-	struct aac_fib_context *fibctx, *aifcp;
+	struct aac_fib_context *fibctx;
 	int status;
 	unsigned long flags;
 	struct list_head * entry;
-	int found;
-
-	/*
-	 *	Extract the fibctx from the input parameters
-	 */
-	fibctx = arg;
 
 	/*
 	 *	Verify that the HANDLE passed in was a valid AdapterFibContext
@@ -333,19 +439,23 @@ static int close_getadapter_fib(struct aac_dev * dev, void *arg)
 	 *	to be sure this is a valid address
 	 */
 
-	found = 0;
 	entry = dev->fib_list.next;
+	fibctx = NULL;
 
 	while(entry != &dev->fib_list) {
-		aifcp = list_entry(entry, struct aac_fib_context, next);
-		if(fibctx == aifcp) {   /* We found a winner */
-			found = 1;
+		fibctx = list_entry(entry, struct aac_fib_context, next);
+		/*
+		 *	Extract the fibctx from the input parameters
+		 */
+		if (fibctx->unique == (u32)(unsigned long)arg) {   
+			/* We found a winner */
 			break;
 		}
 		entry = entry->next;
+		fibctx = NULL;
 	}
 
-	if(found == 0)
+	if (!fibctx)
 		return 0; /* Already gone */
 
 	if((fibctx->type != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) ||
@@ -363,42 +473,86 @@ static int close_getadapter_fib(struct aac_dev * dev, void *arg)
  *	@arg: ioctl arguments
  *
  *	This routine returns the driver version.
- *      Under Linux, there have been no version incompatibilities, so this is simple!
+ *      Under Linux, there have been no version incompatibilities, so this is 
+ *      simple!
  */
 
-static int check_revision(struct aac_dev *dev, void *arg)
+static int check_revision(struct aac_dev *dev, void __user *arg)
 {
 	struct revision response;
+	char *driver_version = aac_driver_version;
+	u32 version;
 
 	response.compat = 1;
-	response.version = AAC_DRIVER_VERSION;
-	response.build = 9999;
+	version = (simple_strtol(driver_version, 
+				&driver_version, 10) << 24) | 0x00000400;
+	version += simple_strtol(driver_version + 1, &driver_version, 10) << 16;
+	version += simple_strtol(driver_version + 1, NULL, 10);
+	response.version = cpu_to_le32(version);
+#	if (defined(AAC_DRIVER_BUILD))
+		response.build = cpu_to_le32(AAC_DRIVER_BUILD);
+#	else
+		response.build = cpu_to_le32(9999);
+#	endif
 
 	if (copy_to_user(arg, &response, sizeof(response)))
 		return -EFAULT;
 	return 0;
 }
 
+#if (defined(CODE_STREAM_IDENTIFIER))
+/**
+ *	check_code_stream	-	close down user fib context
+ *	@dev: adapter
+ *	@arg: ioctl arguments
+ *
+ *	This routine returns the driver code stream identifier
+ */
+
+static int check_code_stream_identifier(struct aac_dev *dev, void __user *arg)
+{
+	struct VersionMatch response;
+
+	memset (&response, 0, sizeof(response));
+	strncpy (response.driver, CODE_STREAM_IDENTIFIER,
+	  MAX_CODE_STREAM_IDENTIFIER_LENGTH);
+	strncpy (response.firmware, dev->code_stream_identifier,
+	  MAX_CODE_STREAM_IDENTIFIER_LENGTH);
+	if (response.firmware[0] == '\0')
+		response.status = VERSION_MATCH_UNSUPPORTED;
+	else if (strncmp(response.driver, response.firmware,
+	  MAX_CODE_STREAM_IDENTIFIER_LENGTH))
+		response.status = VERSION_MATCH_FAILED;
+	else
+		response.status = VERSION_MATCH_SUCCESS;
+
+	if (copy_to_user(arg, &response, sizeof(response)))
+		return -EFAULT;
+	return 0;
+}
+#endif
+
 /**
  *
  * aac_send_raw_scb
  *
  */
 
-int aac_send_raw_srb(struct aac_dev* dev, void* arg)
+static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
 {
 	struct fib* srbfib;
 	int status;
-	struct aac_srb *srbcmd;
-	struct aac_srb *user_srb = arg;
-	struct aac_srb_reply* user_reply;
+	struct aac_srb *srbcmd = NULL;
+	struct user_aac_srb *user_srbcmd = NULL;
+	struct user_aac_srb __user *user_srb = arg;
+	struct aac_srb_reply __user *user_reply;
 	struct aac_srb_reply* reply;
 	u32 fibsize = 0;
 	u32 flags = 0;
 	s32 rcode = 0;
 	u32 data_dir;
-	ulong sg_user[32];
-	ulong sg_list[32];
+	void __user *sg_user[32];
+	void *sg_list[32];
 	u32   sg_indx = 0;
 	u32 byte_count = 0;
 	u32 actual_fibsize = 0;
@@ -406,164 +560,294 @@ int aac_send_raw_srb(struct aac_dev* dev, void* arg)
 
 
 	if (!capable(CAP_SYS_ADMIN)){
-		printk(KERN_DEBUG"aacraid: No permission to send raw srb\n"); 
+		dprintk((KERN_DEBUG"aacraid: No permission to send raw srb\n")); 
 		return -EPERM;
 	}
 	/*
 	 *	Allocate and initialize a Fib then setup a BlockWrite command
 	 */
 	if (!(srbfib = fib_alloc(dev))) {
-		return -1;
+		return -ENOMEM;
 	}
 	fib_init(srbfib);
 
 	srbcmd = (struct aac_srb*) fib_data(srbfib);
 
-	if(copy_from_user((void*)&fibsize, (void*)&user_srb->count,sizeof(u32))){
-		printk(KERN_DEBUG"aacraid: Could not copy data size from user\n"); 
+	memset(sg_list, 0, sizeof(sg_list)); /* cleanup may take issue */
+	if(copy_from_user(&fibsize, &user_srb->count,sizeof(u32))){
+		dprintk((KERN_DEBUG"aacraid: Could not copy data size from user\n")); 
 		rcode = -EFAULT;
 		goto cleanup;
 	}
 
-	if(copy_from_user(srbcmd, user_srb,fibsize)){
-		printk(KERN_DEBUG"aacraid: Could not copy srb from user\n"); 
+	if (fibsize > (dev->max_fib_size - sizeof(struct aac_fibhdr))) {
+		rcode = -EINVAL;
+		goto cleanup;
+	}
+
+	user_srbcmd = kmalloc(fibsize, GFP_KERNEL);
+	if (!user_srbcmd) {
+		dprintk((KERN_DEBUG"aacraid: Could not make a copy of the srb\n"));
+		rcode = -ENOMEM;
+		goto cleanup;
+	}
+	if(copy_from_user(user_srbcmd, user_srb,fibsize)){
+		dprintk((KERN_DEBUG"aacraid: Could not copy srb from user\n")); 
 		rcode = -EFAULT;
 		goto cleanup;
 	}
+#	if (defined(AAC_DEBUG_INSTRUMENT_IOCTL))
+		{
+			u8 * srb = (u8 *)user_srbcmd;
+			unsigned len = fibsize;
+			char buffer[80];
+			char * cp = buffer;
+
+			strcpy(cp, "SRB=");
+			cp += 4;
+			while (len > 0) {
+				if (cp >= &buffer[sizeof(buffer)-4]) {
+					printk (KERN_INFO "%s\n", buffer);
+					strcpy(cp = buffer, "    ");
+					cp += 4;
+				}
+				sprintf (cp, "%02x ", *(srb++));
+				cp += strlen(cp);
+				--len;
+			}
+			if (cp > &buffer[4])
+				printk (KERN_INFO "%s\n", buffer);
+		}
+#	endif
 
 	user_reply = arg+fibsize;
 
-	flags = srbcmd->flags;
+	flags = user_srbcmd->flags; /* from user in cpu order */
 	// Fix up srb for endian and force some values
+
 	srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi);	// Force this
-	srbcmd->channel  = cpu_to_le32(srbcmd->channel);
-	srbcmd->target   = cpu_to_le32(srbcmd->target);
-	srbcmd->lun      = cpu_to_le32(srbcmd->lun);
-	srbcmd->flags    = cpu_to_le32(srbcmd->flags);
-	srbcmd->timeout  = cpu_to_le32(srbcmd->timeout);
-	srbcmd->retry_limit =cpu_to_le32(0); // Obsolete parameter
-	srbcmd->cdb_size = cpu_to_le32(srbcmd->cdb_size);
-
-	switch(srbcmd->flags & (SRB_DataIn | SRB_DataOut)){
+	srbcmd->channel  = cpu_to_le32(user_srbcmd->channel);
+	srbcmd->id	 = cpu_to_le32(user_srbcmd->id);
+	srbcmd->lun      = cpu_to_le32(user_srbcmd->lun);
+	srbcmd->timeout  = cpu_to_le32(user_srbcmd->timeout);
+	srbcmd->flags    = cpu_to_le32(flags);
+	srbcmd->retry_limit = 0; // Obsolete parameter
+	srbcmd->cdb_size = cpu_to_le32(user_srbcmd->cdb_size);
+	memcpy(srbcmd->cdb, user_srbcmd->cdb, sizeof(srbcmd->cdb));
+	
+	switch (flags & (SRB_DataIn | SRB_DataOut)) {
 	case SRB_DataOut:
-		data_dir = SCSI_DATA_WRITE;
+		data_dir = DMA_TO_DEVICE;
 		break;
 	case (SRB_DataIn | SRB_DataOut):
-		data_dir = SCSI_DATA_UNKNOWN;  
+		data_dir = DMA_BIDIRECTIONAL;
 		break;
 	case SRB_DataIn:
-		data_dir = SCSI_DATA_READ;
+		data_dir = DMA_FROM_DEVICE;
 		break;
 	default:
-		data_dir = SCSI_DATA_NONE;
+		data_dir = DMA_NONE;
 	}
-	
-	if( dev->pae_support ==1 ) {
+	if (user_srbcmd->sg.count > (sizeof(sg_list)/sizeof(sg_list[0]))) {
+		dprintk((KERN_DEBUG"aacraid: too many sg entries %d\n",
+		  le32_to_cpu(srbcmd->sg.count)));
+		rcode = -EINVAL;
+		goto cleanup;
+	}
+	if (dev->dac_support == 1) {
+		struct user_sgmap64* upsg = (struct user_sgmap64*)&user_srbcmd->sg;
 		struct sgmap64* psg = (struct sgmap64*)&srbcmd->sg;
+		struct user_sgmap* usg;
 		byte_count = 0;
 
-		// This should also catch if user used the 32 bit sgmap
-		actual_fibsize = sizeof (struct aac_srb) + (((srbcmd->sg.count & 0xff) - 1) * sizeof (struct sgentry64));
+		/*
+		 * This should also catch if user used the 32 bit sgmap
+		 */
+		actual_fibsize = sizeof(struct aac_srb) - 
+			sizeof(struct sgentry) +
+			((upsg->count & 0xff) * 
+		 	sizeof(struct sgentry));
 		if(actual_fibsize != fibsize){ // User made a mistake - should not continue
-			printk(KERN_DEBUG"aacraid: Bad Size specified in Raw SRB command\n");
+			dprintk((KERN_DEBUG"aacraid: Bad Size specified in Raw SRB command\n"));
 			rcode = -EINVAL;
 			goto cleanup;
 		}
-		if ((data_dir == SCSI_DATA_NONE) && psg->count) { // Dogs and cats sleeping with eachother - should not continue
-			printk(KERN_DEBUG"aacraid: SG with no direction specified in Raw SRB command\n");
+		usg = kmalloc(actual_fibsize - sizeof(struct aac_srb)
+		  + sizeof(struct sgmap), GFP_KERNEL);
+		if (!usg) {
+			dprintk((KERN_DEBUG"aacraid: Allocation error in Raw SRB command\n"));
+			rcode = -ENOMEM;
+			goto cleanup;
+		}
+		memcpy (usg, upsg, actual_fibsize - sizeof(struct aac_srb)
+		  + sizeof(struct sgmap));
+		actual_fibsize = sizeof(struct aac_srb) - 
+			sizeof(struct sgentry) + ((usg->count & 0xff) * 
+			 	sizeof(struct sgentry64));
+		if ((data_dir == DMA_NONE) && upsg->count) {
+			kfree (usg);
+			dprintk((KERN_DEBUG"aacraid: SG with no direction specified in Raw SRB command\n"));
 			rcode = -EINVAL;
 			goto cleanup;
 		}
 
-		for (i = 0; i < psg->count; i++) {
-			dma_addr_t addr; 
-			u64 le_addr;
+		for (i = 0; i < usg->count; i++) {
+			u64 addr;
 			void* p;
-			p = kmalloc(psg->sg[i].count,GFP_KERNEL|__GFP_DMA);
+			/* Does this really need to be GFP_DMA? */
+			p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA);
 			if(p == 0) {
-				printk(KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
-				psg->sg[i].count,i,psg->count);
+				kfree (usg);
+				dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
+				  usg->sg[i].count,i,usg->count));
 				rcode = -ENOMEM;
 				goto cleanup;
 			}
-			sg_user[i] = (ulong)psg->sg[i].addr;
-			sg_list[i] = (ulong)p; // save so we can clean up later
-			sg_indx = i + 1;
+			sg_user[i] = (void __user *)(long)usg->sg[i].addr;
+			sg_list[i] = p; // save so we can clean up later
+			sg_indx = i;
 
 			if( flags & SRB_DataOut ){
-				if(copy_from_user(p,psg->sg[i].addr,psg->sg[i].count)){
-					printk(KERN_DEBUG"aacraid: Could not copy sg data from user\n"); 
+				if(copy_from_user(p,sg_user[i],upsg->sg[i].count)){
+					kfree (usg);
+					dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); 
 					rcode = -EFAULT;
 					goto cleanup;
 				}
 			}
-			addr = pci_map_single(dev->pdev, p, psg->sg[i].count, scsi_to_pci_dma_dir(data_dir));
+			addr = pci_map_single(dev->pdev, p, usg->sg[i].count, data_dir);
 
-			le_addr = cpu_to_le64(addr);
-			psg->sg[i].addr[1] = (u32)(le_addr>>32);
-			psg->sg[i].addr[0] = (u32)(le_addr & 0xffffffff);
-			psg->sg[i].count = cpu_to_le32(psg->sg[i].count);  
-			byte_count += psg->sg[i].count;
+			psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff);
+			psg->sg[i].addr[1] = cpu_to_le32(addr>>32);
+			psg->sg[i].count = cpu_to_le32(usg->sg[i].count);  
+			byte_count += usg->sg[i].count;
 		}
+		kfree (usg);
 
 		srbcmd->count = cpu_to_le32(byte_count);
-		status = fib_send(ScsiPortCommand64, srbfib, actual_fibsize, FsaNormal, 1, 1,0,0);
+		psg->count = cpu_to_le32(sg_indx+1);
+#		if (defined(AAC_DEBUG_INSTRUMENT_IOCTL))
+			{
+				u8 * srb = (u8 *)srbfib->hw_fib;
+				unsigned len = actual_fibsize + sizeof(struct aac_fibhdr);
+				char buffer[80];
+				char * cp = buffer;
+
+				strcpy(cp, "FIB=");
+				cp += 4;
+				while (len > 0) {
+					if (cp >= &buffer[sizeof(buffer)-4]) {
+						printk (KERN_INFO "%s\n", buffer);
+						strcpy(cp = buffer, "    ");
+						cp += 4;
+					}
+					sprintf (cp, "%02x ", *(srb++));
+					cp += strlen(cp);
+					--len;
+				}
+				if (cp > &buffer[4])
+					printk (KERN_INFO "%s\n", buffer);
+			}
+			printk(KERN_INFO
+			  "fib_send(ScsiPortCommand64,,%d,...)\n",
+			  actual_fibsize);
+#		endif
+		status = fib_send(ScsiPortCommand64, srbfib, actual_fibsize, FsaNormal, 1, 1,NULL,NULL);
 	} else {
+		struct user_sgmap* upsg = &user_srbcmd->sg;
 		struct sgmap* psg = &srbcmd->sg;
 		byte_count = 0;
 
-		actual_fibsize = sizeof (struct aac_srb) + (((srbcmd->sg.count & 0xff) - 1) * sizeof (struct sgentry));
+		actual_fibsize = sizeof (struct aac_srb) + (((user_srbcmd->sg.count & 0xff) - 1) * sizeof (struct sgentry));
 		if(actual_fibsize != fibsize){ // User made a mistake - should not continue
-			printk(KERN_DEBUG"aacraid: Bad Size specified in Raw SRB command\n");
+			dprintk((KERN_DEBUG"aacraid: Bad Size specified in "
+			  "Raw SRB command calculated fibsize=%d "
+			  "user_srbcmd->sg.count=%d aac_srb=%d sgentry=%d "
+			  "issued fibsize=%d\n",
+			  actual_fibsize, user_srbcmd->sg.count,
+			  sizeof(struct aac_srb), sizeof(struct sgentry),
+			  fibsize));
 			rcode = -EINVAL;
 			goto cleanup;
 		}
-		if ((data_dir == SCSI_DATA_NONE) && psg->count) { // Dogs and cats sleeping with eachother - should not continue
-			printk(KERN_DEBUG"aacraid: SG with no direction specified in Raw SRB command\n");
+		if ((data_dir == DMA_NONE) && upsg->count) {
+			dprintk((KERN_DEBUG"aacraid: SG with no direction specified in Raw SRB command\n"));
 			rcode = -EINVAL;
 			goto cleanup;
 		}
-		for (i = 0; i < psg->count; i++) {
+		for (i = 0; i < upsg->count; i++) {
 			dma_addr_t addr; 
 			void* p;
-			p = kmalloc(psg->sg[i].count,GFP_KERNEL);
+			p = kmalloc(upsg->sg[i].count, GFP_KERNEL);
 			if(p == 0) {
-				printk(KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
-				psg->sg[i].count,i,psg->count);
+				dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
+				  upsg->sg[i].count, i, upsg->count));
 				rcode = -ENOMEM;
 				goto cleanup;
 			}
-			sg_user[i] = (ulong)(psg->sg[i].addr);
-			sg_list[i] = (ulong)p; // save so we can clean up later
-			sg_indx = i + 1;
+			sg_user[i] = (void __user *)(long)upsg->sg[i].addr;
+			sg_list[i] = p; // save so we can clean up later
+			sg_indx = i;
 
 			if( flags & SRB_DataOut ){
-				if(copy_from_user((void*)p,(void*)(ulong)(psg->sg[i].addr),psg->sg[i].count)){
-					printk(KERN_DEBUG"aacraid: Could not copy sg data from user\n"); 
+				if(copy_from_user(p, sg_user[i],
+						upsg->sg[i].count)) {
+					dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); 
 					rcode = -EFAULT;
 					goto cleanup;
 				}
 			}
-			addr = pci_map_single(dev->pdev, p, psg->sg[i].count, scsi_to_pci_dma_dir(data_dir));
+			addr = pci_map_single(dev->pdev, p,
+				upsg->sg[i].count, data_dir);
 
 			psg->sg[i].addr = cpu_to_le32(addr);
-			psg->sg[i].count = cpu_to_le32(psg->sg[i].count);  
-			byte_count += psg->sg[i].count;
+			psg->sg[i].count = cpu_to_le32(upsg->sg[i].count);  
+			byte_count += upsg->sg[i].count;
 		}
 		srbcmd->count = cpu_to_le32(byte_count);
-		status = fib_send(ScsiPortCommand, srbfib, actual_fibsize, FsaNormal, 1, 1, 0, 0);
+		psg->count = cpu_to_le32(sg_indx+1);
+#		if (defined(AAC_DEBUG_INSTRUMENT_IOCTL))
+			{
+				u8 * srb = (u8 *)srbfib->hw_fib;
+				unsigned len = actual_fibsize + sizeof(struct aac_fibhdr);
+				char buffer[80];
+				char * cp = buffer;
+
+				strcpy(cp, "FIB=");
+				cp += 4;
+				while (len > 0) {
+					if (cp >= &buffer[sizeof(buffer)-4]) {
+						printk (KERN_INFO "%s\n", buffer);
+						strcpy(cp = buffer, "    ");
+						cp += 4;
+					}
+					sprintf (cp, "%02x ", *(srb++));
+					cp += strlen(cp);
+					--len;
+				}
+				if (cp > &buffer[4])
+					printk (KERN_INFO "%s\n", buffer);
+			}
+			printk(KERN_INFO
+			  "fib_send(ScsiPortCommand,,%d,...)\n",
+			  actual_fibsize);
+#		endif
+		status = fib_send(ScsiPortCommand, srbfib, actual_fibsize, FsaNormal, 1, 1, NULL, NULL);
 	}
 
 	if (status != 0){
-		printk(KERN_DEBUG"aacraid: Could not send raw srb fib to hba\n"); 
-		rcode = -1;
+		dprintk((KERN_DEBUG"aacraid: Could not send raw srb fib to hba\n")); 
+		rcode = -ENXIO;
 		goto cleanup;
 	}
 
 	if( flags & SRB_DataIn ) {
-		for(i = 0 ; i < sg_indx; i++){
-			if(copy_to_user((void*)(sg_user[i]),(void*)(sg_list[i]),le32_to_cpu(srbcmd->sg.sg[i].count))){
-				printk(KERN_DEBUG"aacraid: Could not copy sg data to user\n"); 
+		for(i = 0 ; i <= sg_indx; i++){
+			byte_count = le32_to_cpu((dev->dac_support == 1)
+			      ? ((struct sgmap64*)&srbcmd->sg)->sg[i].count
+			      : srbcmd->sg.sg[i].count);
+			if(copy_to_user(sg_user[i], sg_list[i], byte_count)){
+				dprintk((KERN_DEBUG"aacraid: Could not copy sg data to user\n")); 
 				rcode = -EFAULT;
 				goto cleanup;
 
@@ -573,14 +857,15 @@ int aac_send_raw_srb(struct aac_dev* dev, void* arg)
 
 	reply = (struct aac_srb_reply *) fib_data(srbfib);
 	if(copy_to_user(user_reply,reply,sizeof(struct aac_srb_reply))){
-		printk(KERN_DEBUG"aacraid: Could not copy reply to user\n"); 
+		dprintk((KERN_DEBUG"aacraid: Could not copy reply to user\n")); 
 		rcode = -EFAULT;
 		goto cleanup;
 	}
 
 cleanup:
-	for(i=0; i < sg_indx; i++){
-		kfree((void*)sg_list[i]);
+	kfree(user_srbcmd);
+	for(i=0; i <= sg_indx; i++){
+		kfree(sg_list[i]);
 	}
 	fib_complete(srbfib);
 	fib_free(srbfib);
@@ -588,42 +873,66 @@ cleanup:
 	return rcode;
 }
 
-
 struct aac_pci_info {
         u32 bus;
         u32 slot;
 };
 
 
-int aac_get_pci_info(struct aac_dev* dev, void* arg)
+static int aac_get_pci_info(struct aac_dev* dev, void __user *arg)
 {
         struct aac_pci_info pci_info;
 
 	pci_info.bus = dev->pdev->bus->number;
 	pci_info.slot = PCI_SLOT(dev->pdev->devfn);
 
-       if(copy_to_user( arg, (void*)&pci_info, sizeof(struct aac_pci_info)))
+       if (copy_to_user(arg, &pci_info, sizeof(struct aac_pci_info))) {
+               dprintk((KERN_DEBUG "aacraid: Could not copy pci info\n"));
                return -EFAULT;
+	}
         return 0;
- }
+}
  
 
-int aac_do_ioctl(struct aac_dev * dev, int cmd, void *arg)
+int aac_do_ioctl(struct aac_dev * dev, int cmd, void __user *arg)
 {
 	int status;
 	
+#if (defined(AAC_DEBUG_INSTRUMENT_IOCTL))
+	if (cmd != FSACTL_GET_NEXT_ADAPTER_FIB)
+		printk("aac_do_ioctl(%p,%x,%p)\n", dev, cmd, arg);
+#endif
 	/*
 	 *	HBA gets first crack
 	 */
 	 
 	status = aac_dev_ioctl(dev, cmd, arg);
-	if(status != -ENOTTY)
+	if(status != -ENOTTY) {
+#if (defined(AAC_DEBUG_INSTRUMENT_IOCTL))
+		printk("aac_do_ioctl returns %d\n", status);
+#endif
+		return status;
+	}
+
+#if (defined(AAC_CSMI))
+	/*
+	 *	HP gets second crack
+	 */
+	 
+	status = aac_csmi_ioctl(dev, cmd, arg);
+	if (status != -ENOTTY) {
+#if (defined(AAC_DEBUG_INSTRUMENT_IOCTL))
+		printk("aac_do_ioctl returns %d\n", status);
+#endif
 		return status;
+	}
 
+#endif
 	switch (cmd) {
 	case FSACTL_MINIPORT_REV_CHECK:
 		status = check_revision(dev, arg);
 		break;
+	case FSACTL_SEND_LARGE_FIB:
 	case FSACTL_SENDFIB:
 		status = ioctl_send_fib(dev, arg);
 		break;
@@ -642,10 +951,19 @@ int aac_do_ioctl(struct aac_dev * dev, int cmd, void *arg)
 	case FSACTL_GET_PCI_INFO:
 		status = aac_get_pci_info(dev,arg);
 		break;
+#if (defined(CODE_STREAM_IDENTIFIER))
+	case FSACTL_GET_VERSION_MATCHING:
+		status = check_code_stream_identifier(dev,arg);
+		break;
+#endif
 	default:
 		status = -ENOTTY;
 	  	break;	
 	}
+#if (defined(AAC_DEBUG_INSTRUMENT_IOCTL))
+	if (cmd != FSACTL_GET_NEXT_ADAPTER_FIB)
+		printk("aac_do_ioctl returns %d\n", status);
+#endif
 	return status;
 }
 
diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c
index 46cd48c..1ff1c5f 100644
--- a/drivers/scsi/aacraid/comminit.c
+++ b/drivers/scsi/aacraid/comminit.c
@@ -29,7 +29,6 @@
  *
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/types.h>
@@ -37,31 +36,50 @@
 #include <linux/pci.h>
 #include <linux/spinlock.h>
 #include <linux/slab.h>
-#include <linux/blk.h>
+#include <linux/blkdev.h>
 #include <linux/completion.h>
 #include <linux/mm.h>
-#include <asm/semaphore.h>
+#include <linux/version.h>	/* Needed for the following */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+//#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#else
 #include "scsi.h"
 #include "hosts.h"
+#endif
+#include <asm/semaphore.h>
 
 #include "aacraid.h"
 
-struct aac_common aac_config;
-
-static struct aac_dev *devices;
+struct aac_common aac_config = {
+	.irq_mod = 1
+};
 
 static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long commsize, unsigned long commalign)
 {
 	unsigned char *base;
 	unsigned long size, align;
-	unsigned long fibsize = 4096;
-	unsigned long printfbufsiz = 256;
+	const unsigned long fibsize = 4096;
+	const unsigned long printfbufsiz = 256;
 	struct aac_init *init;
 	dma_addr_t phys;
 
 	size = fibsize + sizeof(struct aac_init) + commsize + commalign + printfbufsiz;
 
+#if 0 && (defined(CONFIG_X86) || defined(CONFIG_X86_64))
+	base = kmalloc(size, GFP_ATOMIC|GFP_KERNEL);
+	if (base) {
+		phys = pci_map_single(dev->pdev, base, size, DMA_BIDIRECTIONAL);
+		if (phys > (0x80000000UL - size)) {
+			kfree(base);
+			base = NULL;
+		}
+	}
+	if (base == NULL)
+#endif
+ 
 	base = pci_alloc_consistent(dev->pdev, size, &phys);
+
 	if(base == NULL)
 	{
 		printk(KERN_ERR "aacraid: unable to create mapping.\n");
@@ -70,13 +88,15 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co
 	dev->comm_addr = (void *)base;
 	dev->comm_phys = phys;
 	dev->comm_size = size;
-
+	
 	dev->init = (struct aac_init *)(base + fibsize);
 	dev->init_pa = phys + fibsize;
 
 	init = dev->init;
 
 	init->InitStructRevision = cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION);
+	if (dev->max_fib_size != sizeof(struct hw_fib))
+		init->InitStructRevision = cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION_4);
 	init->MiniPortRevision = cpu_to_le32(Sa_MINIPORT_REVISION);
 	init->fsrev = cpu_to_le32(dev->fsrev);
 
@@ -85,13 +105,42 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co
 	 *	start page aligned
 	 */
 	dev->aif_base_va = (struct hw_fib *)base;
-
-	/* We submit the physical address for AIF tags to limit to 32 bits */
-	init->AdapterFibsVirtualAddress = cpu_to_le32(0);
+	
+	init->AdapterFibsVirtualAddress = 0;
 	init->AdapterFibsPhysicalAddress = cpu_to_le32((u32)phys);
 	init->AdapterFibsSize = cpu_to_le32(fibsize);
 	init->AdapterFibAlign = cpu_to_le32(sizeof(struct hw_fib));
-	init->HostPhysMemPages = cpu_to_le32((num_physpages << PAGE_SHIFT) / 4096);		// number of 4k pages of host physical memory
+	/* 
+	 * number of 4k pages of host physical memory. The aacraid fw needs
+	 * this number to be less than 4gb worth of pages. num_physpages is in
+	 * system page units. New firmware doesn't have any issues with the
+	 * mapping system, but older Firmware did, and had *troubles* dealing
+	 * with the math overloading past 32 bits, thus we must limit this
+	 * field.
+	 *
+	 * This assumes the memory is mapped zero->n, which isnt
+	 * always true on real computers. It also has some slight problems
+	 * with the GART on x86-64. I've btw never tried DMA from PCI space
+	 * on this platform but don't be suprised if its problematic.
+	 */
+#ifndef CONFIG_GART_IOMMU
+	if ((num_physpages << (PAGE_SHIFT - 12)) <= AAC_MAX_HOSTPHYSMEMPAGES) {
+		init->HostPhysMemPages = 
+			cpu_to_le32(num_physpages << (PAGE_SHIFT-12));
+	} else 
+#endif	
+	{
+		init->HostPhysMemPages = cpu_to_le32(AAC_MAX_HOSTPHYSMEMPAGES);
+	}
+
+	init->InitFlags = 0;
+	if (dev->new_comm_interface) {
+		init->InitFlags = cpu_to_le32(INITFLAGS_NEW_COMM_SUPPORTED);
+		dprintk((KERN_WARNING"aacraid: New Comm Interface enabled\n"));
+	}
+	init->MaxIoCommands = cpu_to_le32(dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB);
+	init->MaxIoSize = cpu_to_le32(dev->scsi_host_ptr->max_sectors << 9);
+	init->MaxFibSize = cpu_to_le32(dev->max_fib_size);
 
 	/*
 	 * Increment the base address by the amount already used
@@ -134,8 +183,8 @@ static void aac_queue_init(struct aac_dev * dev, struct aac_queue * q, u32 *mem,
 	init_waitqueue_head(&q->qfull);
 	spin_lock_init(&q->lockdata);
 	q->lock = &q->lockdata;
-	q->headers.producer = mem;
-	q->headers.consumer = mem+1;
+	q->headers.producer = (__le32 *)mem;
+	q->headers.consumer = (__le32 *)(mem+1);
 	*(q->headers.producer) = cpu_to_le32(qsize);
 	*(q->headers.consumer) = cpu_to_le32(qsize);
 	q->entries = qsize;
@@ -148,13 +197,15 @@ static void aac_queue_init(struct aac_dev * dev, struct aac_queue * q, u32 *mem,
  *	This routine will send a VM_CloseAll (shutdown) request to the adapter.
  */
 
-static int aac_send_shutdown(struct aac_dev * dev)
+int aac_send_shutdown(struct aac_dev * dev)
 {
 	struct fib * fibctx;
 	struct aac_close *cmd;
 	int status;
 
 	fibctx = fib_alloc(dev);
+	if (!fibctx)
+		return -ENOMEM;
 	fib_init(fibctx);
 
 	cmd = (struct aac_close *) fib_data(fibctx);
@@ -166,7 +217,7 @@ static int aac_send_shutdown(struct aac_dev * dev)
 			  fibctx,
 			  sizeof(struct aac_close),
 			  FsaNormal,
-			  1, 1,
+			  -2 /* Timeout silently */, 1,
 			  NULL, NULL);
 
 	if (status == 0)
@@ -176,37 +227,8 @@ static int aac_send_shutdown(struct aac_dev * dev)
 }
 
 /**
- *	aac_detach	-	detach adapter
- *	@detach: adapter to disconnect
- *
- *	Disconnect and shutdown an AAC based adapter, freeing resources
- *	as we go.
- */
-
-int aac_detach(struct aac_dev *detach)
-{
-	struct aac_dev **dev = &devices;
-	
-	while(*dev)
-	{
-		if(*dev == detach)
-		{
-			*dev = detach->next;
-			aac_send_shutdown(detach);
-			fib_map_free(detach);
-			pci_free_consistent(detach->pdev, detach->comm_size, detach->comm_addr, detach->comm_phys);
-			kfree(detach->queues);
-			return 1;
-		}
-		dev=&((*dev)->next);
-	}
-	BUG();
-	return 0;
-}
-
-/**
  *	aac_comm_init	-	Initialise FSA data structures
- *	@dev:	Adapter to intialise
+ *	@dev:	Adapter to initialise
  *
  *	Initializes the data structures that are required for the FSA commuication
  *	interface to operate. 
@@ -215,7 +237,7 @@ int aac_detach(struct aac_dev *detach)
  *		0 - If there were errors initing. This is a fatal error.
  */
  
-int aac_comm_init(struct aac_dev * dev)
+static int aac_comm_init(struct aac_dev * dev)
 {
 	unsigned long hdrsize = (sizeof(u32) * NUMBER_OF_COMM_QUEUES) * 2;
 	unsigned long queuesize = sizeof(struct aac_entry) * TOTAL_QUEUE_ENTRIES;
@@ -223,7 +245,6 @@ int aac_comm_init(struct aac_dev * dev)
 	struct aac_entry * queues;
 	unsigned long size;
 	struct aac_queue_block * comm = dev->queues;
-
 	/*
 	 *	Now allocate and initialize the zone structures used as our 
 	 *	pool of FIB context records.  The size of the zone is based
@@ -274,7 +295,6 @@ int aac_comm_init(struct aac_dev * dev)
 	/* adapter to host normal priority response queue */
 	comm->queue[HostNormRespQueue].base = queues;
 	aac_queue_init(dev, &comm->queue[HostNormRespQueue], headers, HOST_NORM_RESP_ENTRIES);
-    
 	queues += HOST_NORM_RESP_ENTRIES;
 	headers += 2;
 
@@ -306,9 +326,114 @@ int aac_comm_init(struct aac_dev * dev)
 
 struct aac_dev *aac_init_adapter(struct aac_dev *dev)
 {
+	u32 status[5];
+	struct Scsi_Host * host = dev->scsi_host_ptr;
+
+	/*
+	 *	Check the preferred comm settings, defaults from template.
+	 */
+	dev->max_fib_size = sizeof(struct hw_fib);
+	dev->sg_tablesize = host->sg_tablesize = (dev->max_fib_size
+		- sizeof(struct aac_fibhdr)
+		- sizeof(struct aac_write) + sizeof(struct sgentry))
+			/ sizeof(struct sgentry);
+	dev->new_comm_interface = 0;
+	dev->raw_io_64 = 0;
+	if ((!aac_adapter_sync_cmd(dev, GET_ADAPTER_PROPERTIES,
+		0, 0, 0, 0, 0, 0, status+0, status+1, status+2, NULL, NULL)) &&
+	 		(status[0] == 0x00000001)) {
+		if (status[1] & AAC_OPT_NEW_COMM_64)
+			dev->raw_io_64 = 1;
+		if (status[1] & AAC_OPT_NEW_COMM)
+			dev->new_comm_interface = dev->a_ops.adapter_send != 0;
+		if (dev->new_comm_interface
+		 && (status[2] > dev->base_size)) {
+			iounmap((void * )dev->regs.sa);
+			dev->base_size = status[2];
+			dprintk((KERN_DEBUG "ioremap(%lx,%d)\n",
+			  dev->scsi_host_ptr->base, status[2]));
+			if ((dev->regs.sa = (struct sa_registers *)ioremap(
+			  (unsigned long)dev->scsi_host_ptr->base, status[2]))
+			  == NULL) {
+				/* remap failed, go back ... */
+				dev->new_comm_interface = 0;
+				if ((dev->regs.sa
+				  = (struct sa_registers *)ioremap(
+				    (unsigned long)dev->scsi_host_ptr->base,
+				    AAC_MIN_FOOTPRINT_SIZE)) == NULL) {	
+					printk(KERN_WARNING
+					  "aacraid: unable to map adapter.\n");
+					return NULL;
+				}
+			}
+		}
+	}
+	if ((!aac_adapter_sync_cmd(dev, GET_COMM_PREFERRED_SETTINGS,
+	  0, 0, 0, 0, 0, 0,
+	  status+0, status+1, status+2, status+3, status+4))
+	 && (status[0] == 0x00000001)) {
+		/*
+		 *	status[1] >> 16		maximum command size in KB
+		 *	status[1] & 0xFFFF	maximum FIB size
+		 *	status[2] >> 16		maximum SG elements to driver
+		 *	status[2] & 0xFFFF	maximum SG elements from driver
+		 *	status[3] & 0xFFFF	maximum number FIBs outstanding
+		 */
+		host->max_sectors = (status[1] >> 16) << 1;
+		dev->max_fib_size = status[1] & 0xFFFF;
+		host->sg_tablesize = status[2] >> 16;
+		dev->sg_tablesize = status[2] & 0xFFFF;
+		host->can_queue = (status[3] & 0xFFFF) - AAC_NUM_MGT_FIB;
+		/*
+		 *	NOTE:
+		 *	All these overrides are based on a fixed internal
+		 *	knowledge and understanding of existing adapters,
+		 *	acbsize should be set with caution.
+		 */
+		if (acbsize == 512) {
+			host->max_sectors = AAC_MAX_32BIT_SGBCOUNT;
+			dev->max_fib_size = 512;
+			dev->sg_tablesize = host->sg_tablesize
+			  = (512 - sizeof(struct aac_fibhdr)
+			    - sizeof(struct aac_write) + sizeof(struct sgentry))
+			     / sizeof(struct sgentry);
+			host->can_queue = AAC_NUM_IO_FIB;
+		} else if (acbsize == 2048) {
+			host->max_sectors = 512;
+			dev->max_fib_size = 2048;
+			host->sg_tablesize = 65;
+			dev->sg_tablesize = 81;
+			host->can_queue = 512 - AAC_NUM_MGT_FIB;
+		} else if (acbsize == 4096) {
+			host->max_sectors = 1024;
+			dev->max_fib_size = 4096;
+			host->sg_tablesize = 129;
+			dev->sg_tablesize = 166;
+			host->can_queue = 256 - AAC_NUM_MGT_FIB;
+		} else if (acbsize == 8192) {
+			host->max_sectors = 2048;
+			dev->max_fib_size = 8192;
+			host->sg_tablesize = 257;
+			dev->sg_tablesize = 337;
+			host->can_queue = 128 - AAC_NUM_MGT_FIB;
+		} else if (acbsize > 0) {
+			printk("Illegal acbsize=%d ignored\n", acbsize);
+		}
+	}
+	{
+
+		if (numacb > 0) {
+			if (numacb < host->can_queue)
+				host->can_queue = numacb;
+			else
+				printk("numacb=%d ignored\n", numacb);
+		}
+	}
+
 	/*
 	 *	Ok now init the communication subsystem
 	 */
+
 	dev->queues = (struct aac_queue_block *) kmalloc(sizeof(struct aac_queue_block), GFP_KERNEL);
 	if (dev->queues == NULL) {
 		printk(KERN_ERR "Error could not allocate comm region.\n");
@@ -327,14 +452,10 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev)
 		kfree(dev->queues);
 		return NULL;
 	}
-
+		
 	INIT_LIST_HEAD(&dev->fib_list);
 	init_completion(&dev->aif_completion);
-	/*
-	 *	Add this adapter in to our dev List.
-	 */
-	dev->next = devices;
-	devices = dev;
+
 	return dev;
 }
 
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
index 76056e0..527d38b 100644
--- a/drivers/scsi/aacraid/commsup.c
+++ b/drivers/scsi/aacraid/commsup.c
@@ -3,7 +3,6 @@
  *	(c) Copyright 2001 Red Hat Inc.	<alan@redhat.com>
  *
  * based on the old aacraid driver that is..
-
  * Adaptec aacraid device driver for Linux.
  *
  * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
@@ -26,12 +25,10 @@
  *  commsup.c
  *
  * Abstract: Contain all routines that are required for FSA host/adapter
- *    commuication.
- *
+ *    communication.
  *
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/types.h>
@@ -39,12 +36,26 @@
 #include <linux/pci.h>
 #include <linux/spinlock.h>
 #include <linux/slab.h>
+#include <linux/delay.h>
 #include <linux/completion.h>
-#include <asm/semaphore.h>
-#include <linux/blk.h>
+#include <linux/blkdev.h>
+#include <linux/interrupt.h>
+#include <linux/version.h>	/* Needed for the following */
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
 #include <asm/uaccess.h>
 #include "scsi.h"
 #include "hosts.h"
+#if (!defined(SCSI_HAS_HOST_LOCK))
+#include <linux/blk.h>	/* for io_request_lock definition */
+#endif
+#else
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_driver.h>
+#endif
+#include <asm/semaphore.h>
 
 #include "aacraid.h"
 
@@ -58,7 +69,31 @@
  
 static int fib_map_alloc(struct aac_dev *dev)
 {
-	if((dev->hw_fib_va = pci_alloc_consistent(dev->pdev, sizeof(struct hw_fib) * AAC_NUM_FIB, &dev->hw_fib_pa))==NULL)
+	dprintk((KERN_INFO
+	  "allocate hardware fibs pci_alloc_consistent(%p, %d * (%d + %d), %p)\n",
+	  dev->pdev, dev->max_fib_size, dev->scsi_host_ptr->can_queue,
+	  AAC_NUM_MGT_FIB, &dev->hw_fib_pa));
+#if 0 && (defined(CONFIG_X86) || defined(CONFIG_X86_64))
+	/* Bug in pci_alloc_consistent dealing with respecting dma map */
+	dev->hw_fib_va = kmalloc(
+	  dev->max_fib_size * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB),
+	  GFP_ATOMIC|GFP_KERNEL);
+	if (dev->hw_fib_va) {
+		dev->hw_fib_pa = pci_map_single(dev->pdev, dev->hw_fib_va,
+		  dev->max_fib_size * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB),
+		  DMA_BIDIRECTIONAL);
+		if (dev->hw_fib_pa > (0x80000000UL
+		  - (dev->max_fib_size
+		   * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB)))) {
+			kfree(dev->hw_fib_va);
+			dev->hw_fib_va = NULL;
+		}
+	}
+	if (dev->hw_fib_va == NULL)
+#endif
+	if((dev->hw_fib_va = pci_alloc_consistent(dev->pdev, dev->max_fib_size
+	  * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB),
+	  &dev->hw_fib_pa))==NULL)
 		return -ENOMEM;
 	return 0;
 }
@@ -73,7 +108,7 @@ static int fib_map_alloc(struct aac_dev *dev)
 
 void fib_map_free(struct aac_dev *dev)
 {
-	pci_free_consistent(dev->pdev, sizeof(struct hw_fib) * AAC_NUM_FIB, dev->hw_fib_va, dev->hw_fib_pa);
+	pci_free_consistent(dev->pdev, dev->max_fib_size * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB), dev->hw_fib_va, dev->hw_fib_pa);
 }
 
 /**
@@ -90,17 +125,22 @@ int fib_setup(struct aac_dev * dev)
 	struct hw_fib *hw_fib_va;
 	dma_addr_t hw_fib_pa;
 	int i;
-	
-	if(fib_map_alloc(dev)<0)
+
+	while (((i = fib_map_alloc(dev)) == -ENOMEM)
+	 && (dev->scsi_host_ptr->can_queue > (64 - AAC_NUM_MGT_FIB))) {
+		dev->init->MaxIoCommands = cpu_to_le32((dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB) >> 1);
+		dev->scsi_host_ptr->can_queue = le32_to_cpu(dev->init->MaxIoCommands) - AAC_NUM_MGT_FIB;
+	}
+	if (i<0)
 		return -ENOMEM;
 		
 	hw_fib_va = dev->hw_fib_va;
 	hw_fib_pa = dev->hw_fib_pa;
-	memset(hw_fib_va, 0, sizeof(struct hw_fib) * AAC_NUM_FIB);
+	memset(hw_fib_va, 0, dev->max_fib_size * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB));
 	/*
 	 *	Initialise the fibs
 	 */
-	for (i = 0, fibptr = &dev->fibs[i]; i < AAC_NUM_FIB; i++, fibptr++) 
+	for (i = 0, fibptr = &dev->fibs[i]; i < (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB); i++, fibptr++) 
 	{
 		fibptr->dev = dev;
 		fibptr->hw_fib = hw_fib_va;
@@ -109,15 +149,15 @@ int fib_setup(struct aac_dev * dev)
 		init_MUTEX_LOCKED(&fibptr->event_wait);
 		spin_lock_init(&fibptr->event_lock);
 		hw_fib_va->header.XferState = cpu_to_le32(0xffffffff);
-		hw_fib_va->header.SenderSize = cpu_to_le16(sizeof(struct hw_fib));
+		hw_fib_va->header.SenderSize = cpu_to_le16(dev->max_fib_size);
 		fibptr->hw_fib_pa = hw_fib_pa;
-		hw_fib_va = (struct hw_fib *)((unsigned char *)hw_fib_va + sizeof(struct hw_fib));
-		hw_fib_pa = hw_fib_pa + sizeof(struct hw_fib); 
+		hw_fib_va = (struct hw_fib *)((unsigned char *)hw_fib_va + dev->max_fib_size);
+		hw_fib_pa = hw_fib_pa + dev->max_fib_size;
 	}
 	/*
 	 *	Add the fib chain to the free list
 	 */
-	dev->fibs[AAC_NUM_FIB-1].next = NULL;
+	dev->fibs[dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB - 1].next = NULL;
 	/*
 	 *	Enable this to debug out of queue space
 	 */
@@ -130,18 +170,19 @@ int fib_setup(struct aac_dev * dev)
  *	@dev: Adapter to allocate the fib for
  *
  *	Allocate a fib from the adapter fib pool. If the pool is empty we
- *	wait for fibs to become free.
+ *	return NULL.
  */
  
 struct fib * fib_alloc(struct aac_dev *dev)
 {
 	struct fib * fibptr;
 	unsigned long flags;
-	
 	spin_lock_irqsave(&dev->fib_lock, flags);
 	fibptr = dev->free_fib;	
-	if(!fibptr)
-		BUG();
+	if(!fibptr){
+		spin_unlock_irqrestore(&dev->fib_lock, flags);
+		return fibptr;
+	}
 	dev->free_fib = fibptr->next;
 	spin_unlock_irqrestore(&dev->fib_lock, flags);
 	/*
@@ -153,9 +194,19 @@ struct fib * fib_alloc(struct aac_dev *dev)
 	 *	Null out fields that depend on being zero at the start of
 	 *	each I/O
 	 */
-	fibptr->hw_fib->header.XferState = cpu_to_le32(0);
+	fibptr->hw_fib->header.XferState = 0;
 	fibptr->callback = NULL;
 	fibptr->callback_data = NULL;
+#if (defined(AAC_DEBUG_INSTRUMENT_TIMING))
+	{
+		struct timeval now;
+		do_gettimeofday(&now);
+		fibptr->DriverTimeStartS = now.tv_sec;
+		fibptr->DriverTimeStartuS = now.tv_usec;
+	}
+	fibptr->DriverTimeDoneS = 0;
+	fibptr->DriverTimeDoneuS = 0;
+#endif
 
 	return fibptr;
 }
@@ -172,8 +223,19 @@ void fib_free(struct fib * fibptr)
 {
 	unsigned long flags;
 
+#if (defined(AAC_DEBUG_INSTRUMENT_TIMING))
+	struct timeval now;
+	do_gettimeofday(&now);
+	fibptr->DriverTimeDoneS = now.tv_sec;
+	fibptr->DriverTimeDoneuS = now.tv_usec;
+	flags = (fibptr->DriverTimeDoneS - fibptr->DriverTimeStartS) * 1000000L
+	      + fibptr->DriverTimeDoneuS - fibptr->DriverTimeStartuS;
+	if (flags > aac_config.peak_duration) {
+		aac_config.peak_duration = flags;
+		printk(KERN_INFO "peak_duration %lduseconds\n", flags);
+	}
+#endif
 	spin_lock_irqsave(&fibptr->dev->fib_lock, flags);
-
 	if (fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT) {
 		aac_config.fib_timeouts++;
 		fibptr->next = fibptr->dev->timeout_fib;
@@ -181,7 +243,8 @@ void fib_free(struct fib * fibptr)
 	} else {
 		if (fibptr->hw_fib->header.XferState != 0) {
 			printk(KERN_WARNING "fib_free, XferState != 0, fibptr = 0x%p, XferState = 0x%x\n", 
-				 (void*)fibptr, fibptr->hw_fib->header.XferState);
+				 (void*)fibptr, 
+				 le32_to_cpu(fibptr->hw_fib->header.XferState));
 		}
 		fibptr->next = fibptr->dev->free_fib;
 		fibptr->dev->free_fib = fibptr;
@@ -201,11 +264,11 @@ void fib_init(struct fib *fibptr)
 	struct hw_fib *hw_fib = fibptr->hw_fib;
 
 	hw_fib->header.StructType = FIB_MAGIC;
-	hw_fib->header.Size = cpu_to_le16(sizeof(struct hw_fib));
+	hw_fib->header.Size = cpu_to_le16(fibptr->dev->max_fib_size);
 	hw_fib->header.XferState = cpu_to_le32(HostOwned | FibInitialized | FibEmpty | FastResponseCapable);
 	hw_fib->header.SenderFibAddress = 0; /* Filled in later if needed */
 	hw_fib->header.ReceiverFibAddress = cpu_to_le32(fibptr->hw_fib_pa);
-	hw_fib->header.SenderSize = cpu_to_le16(sizeof(struct hw_fib));
+	hw_fib->header.SenderSize = cpu_to_le16(fibptr->dev->max_fib_size);
 }
 
 /**
@@ -216,12 +279,12 @@ void fib_init(struct fib *fibptr)
  *	caller.
  */
  
-void fib_dealloc(struct fib * fibptr)
+static void fib_dealloc(struct fib * fibptr)
 {
 	struct hw_fib *hw_fib = fibptr->hw_fib;
 	if(hw_fib->header.StructType != FIB_MAGIC) 
 		BUG();
-	hw_fib->header.XferState = cpu_to_le32(0);        
+	hw_fib->header.XferState = 0;        
 }
 
 /*
@@ -247,6 +310,7 @@ void fib_dealloc(struct fib * fibptr)
 static int aac_get_entry (struct aac_dev * dev, u32 qid, struct aac_entry **entry, u32 * index, unsigned long *nonotify)
 {
 	struct aac_queue * q;
+	unsigned long idx;
 
 	/*
 	 *	All of the queues wrap when they reach the end, so we check
@@ -256,32 +320,31 @@ static int aac_get_entry (struct aac_dev * dev, u32 qid, struct aac_entry **entr
 	 */
 
 	q = &dev->queues->queue[qid];
-	
-	*index = le32_to_cpu(*(q->headers.producer));
-	if ((*index - 2) == le32_to_cpu(*(q->headers.consumer)))
+
+	idx = *index = le32_to_cpu(*(q->headers.producer));
+	/* Interrupt Moderation, only interrupt for first two entries */
+	if (idx != le32_to_cpu(*(q->headers.consumer))) {
+		if (--idx == 0) {
+			if (qid == AdapNormCmdQueue)
+				idx = ADAP_NORM_CMD_ENTRIES;
+			else
+				idx = ADAP_NORM_RESP_ENTRIES;
+		}
+		if (idx != le32_to_cpu(*(q->headers.consumer)))
 			*nonotify = 1; 
+	}
 
-	if (qid == AdapHighCmdQueue) {
-	        if (*index >= ADAP_HIGH_CMD_ENTRIES)
-        		*index = 0;
-	} else if (qid == AdapNormCmdQueue) {
+	if (qid == AdapNormCmdQueue) {
 	        if (*index >= ADAP_NORM_CMD_ENTRIES) 
 			*index = 0; /* Wrap to front of the Producer Queue. */
-	}
-	else if (qid == AdapHighRespQueue) 
-	{
-	        if (*index >= ADAP_HIGH_RESP_ENTRIES)
-			*index = 0;
-	}
-	else if (qid == AdapNormRespQueue) 
-	{
+	} else {
 		if (*index >= ADAP_NORM_RESP_ENTRIES) 
 			*index = 0; /* Wrap to front of the Producer Queue. */
 	}
-	else BUG();
 
-        if (*index + 1 == le32_to_cpu(*(q->headers.consumer))) { /* Queue is full */
-		printk(KERN_WARNING "Queue %d full, %ld outstanding.\n", qid, q->numpending);
+        if ((*index + 1) == le32_to_cpu(*(q->headers.consumer))) { /* Queue is full */
+		printk(KERN_WARNING "Queue %d full, %u outstanding.\n",
+				qid, q->numpending);
 		return 0;
 	} else {
 	        *entry = q->base + *index;
@@ -309,12 +372,8 @@ static int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_f
 {
 	struct aac_entry * entry = NULL;
 	int map = 0;
-	struct aac_queue * q = &dev->queues->queue[qid];
-		
-	spin_lock_irqsave(q->lock, q->SavedIrql);
 	    
-	if (qid == AdapHighCmdQueue || qid == AdapNormCmdQueue) 
-	{
+	if (qid == AdapNormCmdQueue) {
 		/*  if no entries wait for some if caller wants to */
         	while (!aac_get_entry(dev, qid, &entry, index, nonotify)) 
         	{
@@ -325,9 +384,7 @@ static int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_f
 	         */
 	        entry->size = cpu_to_le32(le16_to_cpu(hw_fib->header.Size));
 	        map = 1;
-	}
-	else if (qid == AdapHighRespQueue || qid == AdapNormRespQueue)
-	{
+	} else {
 	        while(!aac_get_entry(dev, qid, &entry, index, nonotify)) 
 	        {
 			/* if no entries wait for some if caller wants to */
@@ -340,49 +397,13 @@ static int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_f
      			/* Restore adapters pointer to the FIB */
 		hw_fib->header.ReceiverFibAddress = hw_fib->header.SenderFibAddress;	/* Let the adapter now where to find its data */
         	map = 0;
-	} 
+	}
 	/*
 	 *	If MapFib is true than we need to map the Fib and put pointers
 	 *	in the queue entry.
 	 */
 	if (map)
-		entry->addr = fibptr->hw_fib_pa;
-	return 0;
-}
-
-
-/**
- *	aac_insert_entry	-	insert a queue entry
- *	@dev: Adapter
- *	@index: Index of entry to insert
- *	@qid: Queue number
- *	@nonotify: Suppress adapter notification
- *
- *	Gets the next free QE off the requested priorty adapter command
- *	queue and associates the Fib with the QE. The QE represented by
- *	index is ready to insert on the queue when this routine returns
- *	success.
- */
- 
-static int aac_insert_entry(struct aac_dev * dev, u32 index, u32 qid, unsigned long nonotify) 
-{
-	struct aac_queue * q = &dev->queues->queue[qid];
-
-	if(q == NULL)
-		BUG();
-	*(q->headers.producer) = cpu_to_le32(index + 1);
-	spin_unlock_irqrestore(q->lock, q->SavedIrql);
-
-	if (qid == AdapHighCmdQueue ||
-	    qid == AdapNormCmdQueue ||
-	    qid == AdapHighRespQueue ||
-	    qid == AdapNormRespQueue)
-	{
-		if (!nonotify)
-			aac_adapter_notify(dev, qid);
-	}
-	else
-		printk("Suprise insert!\n");
+		entry->addr = cpu_to_le32(fibptr->hw_fib_pa);
 	return 0;
 }
 
@@ -410,24 +431,27 @@ static int aac_insert_entry(struct aac_dev * dev, u32 index, u32 qid, unsigned l
  *	an event to wait on must be supplied. This event will be set when a
  *	response FIB is received from the adapter.
  */
- 
-int fib_send(u16 command, struct fib * fibptr, unsigned long size,  int priority, int wait, int reply, fib_callback callback, void * callback_data)
+#if (defined(FSACTL_REGISTER_FIB_SEND))
+fib_send_t fib_send = aac_fib_send;
+#endif
+
+int aac_fib_send(u16 command, struct fib * fibptr, unsigned long size,
+		int priority, int wait, int reply, fib_callback callback,
+		void * callback_data)
 {
-	u32 index;
-	u32 qid;
 	struct aac_dev * dev = fibptr->dev;
-	unsigned long nointr = 0;
 	struct hw_fib * hw_fib = fibptr->hw_fib;
 	struct aac_queue * q;
 	unsigned long flags = 0;
+	unsigned long qflags;
 
-	if (!(le32_to_cpu(hw_fib->header.XferState) & HostOwned))
+	if (!(hw_fib->header.XferState & cpu_to_le32(HostOwned)))
 		return -EBUSY;
 	/*
 	 *	There are 5 cases with the wait and reponse requested flags. 
 	 *	The only invalid cases are if the caller requests to wait and
 	 *	does not request a response and if the caller does not want a
-	 *	response and the Fibis not allocated from pool. If a response
+	 *	response and the Fib is not allocated from pool. If a response
 	 *	is not requesed the Fib will just be deallocaed by the DPC
 	 *	routine when the response comes back from the adapter. No
 	 *	further processing will be done besides deleting the Fib. We 
@@ -450,7 +474,7 @@ int fib_send(u16 command, struct fib * fibptr, unsigned long size,  int priority
 	 *	Map the fib into 32bits by using the fib number
 	 */
 
-	hw_fib->header.SenderFibAddress = cpu_to_le32(((u32)(fibptr - dev->fibs)) << 1);
+	hw_fib->header.SenderFibAddress = cpu_to_le32(((u32)(fibptr - dev->fibs)) << 2);
 	hw_fib->header.SenderData = (u32)(fibptr - dev->fibs);
 	/*
 	 *	Set FIB state to indicate where it came from and if we want a
@@ -473,26 +497,8 @@ int fib_send(u16 command, struct fib * fibptr, unsigned long size,  int priority
 	 *	Get a queue entry connect the FIB to it and send an notify
 	 *	the adapter a command is ready.
 	 */
-	if (priority == FsaHigh) {
-		hw_fib->header.XferState |= cpu_to_le32(HighPriority);
-		qid = AdapHighCmdQueue;
-	} else {
-		hw_fib->header.XferState |= cpu_to_le32(NormalPriority);
-		qid = AdapNormCmdQueue;
-	}
-	q = &dev->queues->queue[qid];
+	hw_fib->header.XferState |= cpu_to_le32(NormalPriority);
 
-	if(wait)
-		spin_lock_irqsave(&fibptr->event_lock, flags);
-	if(aac_queue_get( dev, &index, qid, hw_fib, 1, fibptr, &nointr)<0)
-		return -EWOULDBLOCK;
-	dprintk((KERN_DEBUG "fib_send: inserting a queue entry at index %d.\n",index));
-	dprintk((KERN_DEBUG "Fib contents:.\n"));
-	dprintk((KERN_DEBUG "  Command =               %d.\n", hw_fib->header.Command));
-	dprintk((KERN_DEBUG "  XferState  =            %x.\n", hw_fib->header.XferState));
-	dprintk((KERN_DEBUG "  hw_fib va being sent=%p\n",fibptr->hw_fib));
-	dprintk((KERN_DEBUG "  hw_fib pa being sent=%lx\n",(ulong)fibptr->hw_fib_pa));
-	dprintk((KERN_DEBUG "  fib being sent=%p\n",fibptr));
 	/*
 	 *	Fill in the Callback and CallbackContext if we are not
 	 *	going to wait.
@@ -501,29 +507,123 @@ int fib_send(u16 command, struct fib * fibptr, unsigned long size,  int priority
 		fibptr->callback = callback;
 		fibptr->callback_data = callback_data;
 	}
-	FIB_COUNTER_INCREMENT(aac_config.FibsSent);
-	list_add_tail(&fibptr->queue, &q->pendingq);
-	q->numpending++;
 
 	fibptr->done = 0;
 	fibptr->flags = 0;
 
-	if(aac_insert_entry(dev, index, qid, (nointr & aac_config.irq_mod)) < 0)
-		return -EWOULDBLOCK;
+#	if (defined(AAC_DEBUG_INSTRUMENT_FIB))
+		printk(KERN_INFO "Fib content %p[%d] P=%llx:\n",
+		  hw_fib, le16_to_cpu(hw_fib->header.Size), fibptr->hw_fib_pa);
+		{
+			int size = le16_to_cpu(hw_fib->header.Size)
+					/ sizeof(u32);
+			char buffer[80];
+			u32 * up = (u32 *)hw_fib;
+
+			while (size > 0) {
+				sprintf (buffer,
+				  "  %08x %08x %08x %08x %08x %08x %08x %08x\n",
+				  up[0], up[1], up[2], up[3], up[4], up[5],
+				  up[6], up[7]);
+				up += 8;
+				size -= 8;
+				if (size < 0) {
+					buffer[73+(size*9)] = '\n';
+					buffer[74+(size*9)] = '\0';
+				}
+				printk(KERN_INFO "%s", buffer);
+			}
+		}
+#	endif
+	FIB_COUNTER_INCREMENT(aac_config.FibsSent);
+
+	dprintk((KERN_DEBUG "Fib contents:.\n"));
+	dprintk((KERN_DEBUG "  Command =               %d.\n", le32_to_cpu(hw_fib->header.Command)));
+	dprintk((KERN_DEBUG "  SubCommand =            %d.\n", le32_to_cpu(((struct aac_query_mount *)fib_data(fibptr))->command)));
+	dprintk((KERN_DEBUG "  XferState  =            %x.\n", le32_to_cpu(hw_fib->header.XferState)));
+	dprintk((KERN_DEBUG "  hw_fib va being sent=%p\n",fibptr->hw_fib));
+	dprintk((KERN_DEBUG "  hw_fib pa being sent=%lx\n",(ulong)fibptr->hw_fib_pa));
+	dprintk((KERN_DEBUG "  fib being sent=%p\n",fibptr));
+
+	if (!dev->queues)
+		return -ENODEV;
+	q = &dev->queues->queue[AdapNormCmdQueue];
+
+	if(wait)
+		spin_lock_irqsave(&fibptr->event_lock, flags);
+	spin_lock_irqsave(q->lock, qflags);
+	if (dev->new_comm_interface) {
+		unsigned long count = 10000000L; /* 50 seconds */
+		list_add_tail(&fibptr->queue, &q->pendingq);
+		q->numpending++;
+		spin_unlock_irqrestore(q->lock, qflags);
+		while (aac_adapter_send(fibptr) != 0) {
+			if (--count == 0) {
+				if (wait)
+					spin_unlock_irqrestore(&fibptr->event_lock, flags);
+				spin_lock_irqsave(q->lock, qflags);
+				q->numpending--;
+				list_del(&fibptr->queue);
+				spin_unlock_irqrestore(q->lock, qflags);
+				return -ETIMEDOUT;
+			}
+			udelay(5);
+		}
+	} else {
+		u32 index;
+		unsigned long nointr = 0;
+		aac_queue_get( dev, &index, AdapNormCmdQueue, hw_fib, 1, fibptr, &nointr);
+
+		list_add_tail(&fibptr->queue, &q->pendingq);
+		q->numpending++;
+		*(q->headers.producer) = cpu_to_le32(index + 1);
+		spin_unlock_irqrestore(q->lock, qflags);
+		dprintk((KERN_DEBUG "fib_send: inserting a queue entry at index %d.\n",index));
+		if (!(nointr & aac_config.irq_mod))
+			aac_adapter_notify(dev, AdapNormCmdQueue);
+	}
+
 	/*
 	 *	If the caller wanted us to wait for response wait now. 
 	 */
     
 	if (wait) {
 		spin_unlock_irqrestore(&fibptr->event_lock, flags);
-		down(&fibptr->event_wait);
+		/* Only set for first known interruptable command */
+		if (wait < 0) {
+			/*
+			 * *VERY* Dangerous to time out a command, the
+			 * assumption is made that we have no hope of
+			 * functioning because an interrupt routing or other
+			 * hardware failure has occurred.
+			 */
+			unsigned long count = 36000000L; /* 3 minutes */
+			while (down_trylock(&fibptr->event_wait)) {
+				if (--count == 0) {
+					spin_lock_irqsave(q->lock, qflags);
+					q->numpending--;
+					list_del(&fibptr->queue);
+					spin_unlock_irqrestore(q->lock, qflags);
+					if (wait == -1) {
+	        				printk(KERN_ERR "aacraid: fib_send: first asynchronous command timed out.\n"
+						  "Usually a result of a PCI interrupt routing problem;\n"
+						  "update mother board BIOS or consider utilizing one of\n"
+						  "the SAFE mode kernel options (acpi, apic etc)\n");
+					}
+					return -ETIMEDOUT;
+				}
+				udelay(5);
+			}
+		} else
+			down(&fibptr->event_wait);
 		if(fibptr->done == 0)
 			BUG();
 			
-		if((fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT))
+		if((fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT)){
 			return -ETIMEDOUT;
-		else
+		} else {
 			return 0;
+		}
 	}
 	/*
 	 *	If the user does not want a response than return success otherwise
@@ -568,12 +668,6 @@ int aac_consumer_get(struct aac_dev * dev, struct aac_queue * q, struct aac_entr
 	return(status);
 }
 
-int aac_consumer_avail(struct aac_dev *dev, struct aac_queue * q)
-{
-	return (le32_to_cpu(*q->headers.producer) != le32_to_cpu(*q->headers.consumer));
-}
-
-
 /**
  *	aac_consumer_free	-	free consumer entry
  *	@dev: Adapter
@@ -603,15 +697,9 @@ void aac_consumer_free(struct aac_dev * dev, struct aac_queue *q, u32 qid)
 		case HostNormCmdQueue:
 			notify = HostNormCmdNotFull;
 			break;
-		case HostHighCmdQueue:
-			notify = HostHighCmdNotFull;
-			break;
 		case HostNormRespQueue:
 			notify = HostNormRespNotFull;
 			break;
-		case HostHighRespQueue:
-			notify = HostHighRespNotFull;
-			break;
 		default:
 			BUG();
 			return;
@@ -633,13 +721,21 @@ int fib_adapter_complete(struct fib * fibptr, unsigned short size)
 {
 	struct hw_fib * hw_fib = fibptr->hw_fib;
 	struct aac_dev * dev = fibptr->dev;
+	struct aac_queue * q;
 	unsigned long nointr = 0;
-	if (le32_to_cpu(hw_fib->header.XferState) == 0)
+	unsigned long qflags;
+
+	if (hw_fib->header.XferState == 0) {
+		if (dev->new_comm_interface)
+			kfree (hw_fib);
         	return 0;
+	}
 	/*
 	 *	If we plan to do anything check the structure type first.
 	 */ 
 	if ( hw_fib->header.StructType != FIB_MAGIC ) {
+		if (dev->new_comm_interface)
+			kfree (hw_fib);
         	return -EINVAL;
 	}
 	/*
@@ -650,38 +746,24 @@ int fib_adapter_complete(struct fib * fibptr, unsigned short size)
 	 *	send the completed cdb to the adapter.
 	 */
 	if (hw_fib->header.XferState & cpu_to_le32(SentFromAdapter)) {
-	        hw_fib->header.XferState |= cpu_to_le32(HostProcessed);
-	        if (hw_fib->header.XferState & cpu_to_le32(HighPriority)) {
-        		u32 index;
-       			if (size) 
-			{
-				size += sizeof(struct aac_fibhdr);
-				if (size > le16_to_cpu(hw_fib->header.SenderSize))
-					return -EMSGSIZE;
-				hw_fib->header.Size = cpu_to_le16(size);
-			}
-			if(aac_queue_get(dev, &index, AdapHighRespQueue, hw_fib, 1, NULL, &nointr) < 0) {
-				return -EWOULDBLOCK;
-			}
-			if (aac_insert_entry(dev, index, AdapHighRespQueue,  (nointr & (int)aac_config.irq_mod)) != 0) {
-			}
-		}
-		else if (hw_fib->header.XferState & NormalPriority) 
-		{
-			u32 index;
-
+		if (dev->new_comm_interface) {
+			kfree (hw_fib);
+		} else {
+	       		u32 index;
+		        hw_fib->header.XferState |= cpu_to_le32(HostProcessed);
 			if (size) {
 				size += sizeof(struct aac_fibhdr);
 				if (size > le16_to_cpu(hw_fib->header.SenderSize)) 
 					return -EMSGSIZE;
 				hw_fib->header.Size = cpu_to_le16(size);
 			}
-			if (aac_queue_get(dev, &index, AdapNormRespQueue, hw_fib, 1, NULL, &nointr) < 0) 
-				return -EWOULDBLOCK;
-			if (aac_insert_entry(dev, index, AdapNormRespQueue, 
-				(nointr & (int)aac_config.irq_mod)) != 0) 
-			{
-			}
+			q = &dev->queues->queue[AdapNormRespQueue];
+			spin_lock_irqsave(q->lock, qflags);
+			aac_queue_get(dev, &index, AdapNormRespQueue, hw_fib, 1, NULL, &nointr);
+			*(q->headers.producer) = cpu_to_le32(index + 1);
+			spin_unlock_irqrestore(q->lock, qflags);
+			if (!(nointr & (int)aac_config.irq_mod))
+				aac_adapter_notify(dev, AdapNormRespQueue);
 		}
 	}
 	else 
@@ -707,7 +789,7 @@ int fib_complete(struct fib * fibptr)
 	 *	Check for a fib which has already been completed
 	 */
 
-	if (hw_fib->header.XferState == cpu_to_le32(0))
+	if (hw_fib->header.XferState == 0)
         	return 0;
 	/*
 	 *	If we plan to do anything check the structure type first.
@@ -752,22 +834,27 @@ int fib_complete(struct fib * fibptr)
 
 void aac_printf(struct aac_dev *dev, u32 val)
 {
-	int length = val & 0xffff;
-	int level = (val >> 16) & 0xffff;
 	char *cp = dev->printfbuf;
-	
-	/*
-	 *	The size of the printfbuf is set in port.c
-	 *	There is no variable or define for it
-	 */
-	if (length > 255)
-		length = 255;
-	if (cp[length] != 0)
-		cp[length] = 0;
-	if (level == LOG_HIGH_ERROR)
-		printk(KERN_WARNING "aacraid:%s", cp);
-	else
-		printk(KERN_INFO "aacraid:%s", cp);
+#if (!defined(AAC_PRINTF_ENABLED))
+	if (dev->printf_enabled)
+#endif
+	{
+		int length = val & 0xffff;
+		int level = (val >> 16) & 0xffff;
+		
+		/*
+		 *	The size of the printfbuf is set in port.c
+		 *	There is no variable or define for it
+		 */
+		if (length > 255)
+			length = 255;
+		if (cp[length] != 0)
+			cp[length] = 0;
+		if (level == LOG_AAC_HIGH_ERROR)
+			printk(KERN_WARNING "aacraid:%s", cp);
+		else
+			printk(KERN_INFO "aacraid:%s", cp);
+	}
 	memset(cp, 0,  256);
 }
 
@@ -781,127 +868,889 @@ void aac_printf(struct aac_dev *dev, u32 val)
  *	dispatches it to the appropriate routine for handling.
  */
 
-#define CONTAINER_TO_BUS(cont)		(0)
-#define CONTAINER_TO_TARGET(cont)	((cont))
-#define CONTAINER_TO_LUN(cont)		(0)
-
 static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
 {
 	struct hw_fib * hw_fib = fibptr->hw_fib;
 	struct aac_aifcmd * aifcmd = (struct aac_aifcmd *)hw_fib->data;
 	int busy;
 	u32 container;
+	struct scsi_device *device;
+#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) && (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,10)) && defined(MODULE))
+	struct scsi_driver * drv;
+#endif
+	enum {
+		NOTHING,
+		DELETE,
+		ADD,
+		CHANGE
+	} device_config_needed;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+	extern struct proc_dir_entry * proc_scsi;
+#endif
 
 	/* Sniff for container changes */
-	dprintk ((KERN_INFO "AifCmdDriverNotify=%x\n", le32_to_cpu(*(u32 *)aifcmd->data)));
-	switch (le32_to_cpu(*(u32 *)aifcmd->data)) {
-	case AifDenMorphComplete:
-	case AifDenVolumeExtendComplete:
-	case AifEnContainerChange: /* Not really a driver notify Event */
-
-		busy = 0;
-		container = le32_to_cpu(((u32 *)aifcmd->data)[1]);
-		dprintk ((KERN_INFO "container=%d(%d,%d,%d,%d) ",
-		  container,
-		  (dev && dev->scsi_host_ptr)
-		    ? dev->scsi_host_ptr->host_no
-		    : -1,
-		  CONTAINER_TO_BUS(container),
-		  CONTAINER_TO_TARGET(container),
-		  CONTAINER_TO_LUN(container)));
+#if (defined(AAC_DEBUG_INSTRUMENT_AIF))
+	printk (KERN_INFO
+	  "aac_handle_aif: Aif command=%x type=%x container=%d\n",
+	  le32_to_cpu(aifcmd->command), le32_to_cpu(*(u32 *)aifcmd->data),
+	  le32_to_cpu(((u32 *)aifcmd->data)[1]));
+#endif
+
+	if (!dev || !dev->fsa_dev)
+		return;
+	container = (u32)-1;
 
+	/*
+	 *	We have set this up to try and minimize the number of
+	 * re-configures that take place. As a result of this when
+	 * certain AIF's come in we will set a flag waiting for another
+	 * type of AIF before setting the re-config flag.
+	 */
+	switch (le32_to_cpu(aifcmd->command)) {
+	case AifCmdDriverNotify:
+		switch (le32_to_cpu(((u32 *)aifcmd->data)[0])) {
 		/*
-		 *	Find the Scsi_Device associated with the SCSI address,
-		 * and mark it as changed, invalidating the cache. This deals
-		 * with changes to existing device IDs.
+		 *	Morph or Expand complete
 		 */
+		case AifDenMorphComplete:
+		case AifDenVolumeExtendComplete:
+			container = le32_to_cpu(((u32 *)aifcmd->data)[1]);
+			if (container >= dev->maximum_num_containers)
+				break;
+#if (defined(AAC_DEBUG_INSTRUMENT_AIF))
+			printk (KERN_INFO "container=%d(%d,%d,%d,%d)\n",
+			  container,
+			  (dev && dev->scsi_host_ptr)
+			    ? dev->scsi_host_ptr->host_no
+			    : -1,
+			  CONTAINER_TO_CHANNEL(container),
+			  CONTAINER_TO_ID(container),
+			  CONTAINER_TO_LUN(container));
+#endif
 
-		if ((dev != (struct aac_dev *)NULL)
-		 && (dev->scsi_host_ptr != (struct Scsi_Host *)NULL)) {
-			Scsi_Device * device;
-
-			for (device = dev->scsi_host_ptr->host_queue;
-			  device != (Scsi_Device *)NULL;
-			  device = device->next) {
-				dprintk((KERN_INFO
-				  "aifd: device (%d,%d,%d,%d)?\n",
-				  dev->scsi_host_ptr->host_no,
-				  device->channel,
-				  device->id,
-				  device->lun));
-				if ((device->channel == CONTAINER_TO_BUS(container))
-				 && (device->id == CONTAINER_TO_TARGET(container))
-				 && (device->lun == CONTAINER_TO_LUN(container))) {
-					busy |= (device->access_count != 0);
-					if (busy == 0) {
-						device->removable = TRUE;
+			/*
+			 *	Find the Scsi_Device associated with the SCSI
+			 * address. Make sure we have the right array, and if
+			 * so set the flag to initiate a new re-config once we
+			 * see an AifEnConfigChange AIF come through.
+			 */
+
+			if ((dev != (struct aac_dev *)NULL)
+			 && (dev->scsi_host_ptr != (struct Scsi_Host *)NULL)) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
+				shost_for_each_device(device,
+					dev->scsi_host_ptr)
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+				list_for_each_entry(device,
+					&dev->scsi_host_ptr->my_devices,
+					siblings)
+#else
+				for (device = dev->scsi_host_ptr->host_queue;
+				  device != (struct scsi_device *)NULL;
+				  device = device->next)
+#endif
+				{
+					if ((device->channel ==
+						CONTAINER_TO_CHANNEL(container))
+					 && (device->id ==
+						CONTAINER_TO_ID(container))
+					 && (device->lun ==
+						CONTAINER_TO_LUN(container))) {
+
+						dev->fsa_dev[container].config_needed = CHANGE;
+						dev->fsa_dev[container].config_waiting_on = 0;
+						break;
 					}
 				}
 			}
 		}
-		dprintk (("busy=%d\n", busy));
 
 		/*
-		 * if (busy == 0) {
-		 *	scan_scsis(dev->scsi_host_ptr, 1,
-		 *	  CONTAINER_TO_BUS(container),
-		 *	  CONTAINER_TO_TARGET(container),
-		 *	  CONTAINER_TO_LUN(container));
-		 * }
-		 * is not exported as accessible, so we need to go around it
-		 * another way. So, we look for the "proc/scsi/scsi" entry in
-		 * the proc filesystem (using proc_scsi as a shortcut) and send
-		 * it a message. This deals with new devices that have
-		 * appeared. If the device has gone offline, scan_scsis will
-		 * also discover this, but we do not want the device to
-		 * go away. We need to check the access_count for the
-		 * device since we are not wanting the devices to go away.
+		 *	If we are waiting on something and this happens to be
+		 * that thing then set the re-configure flag.
+		 */
+		if (container != (u32)-1) {
+			if (container >= dev->maximum_num_containers)
+				break;
+			if (dev->fsa_dev[container].config_waiting_on ==
+			    le32_to_cpu(*(u32 *)aifcmd->data))
+				dev->fsa_dev[container].config_waiting_on = 0;
+		} else for (container = 0;
+		    container < dev->maximum_num_containers; ++container) {
+			if (dev->fsa_dev[container].config_waiting_on ==
+			    le32_to_cpu(*(u32 *)aifcmd->data))
+				dev->fsa_dev[container].config_waiting_on = 0;
+		}
+		break;
+
+	case AifCmdEventNotify:
+		switch (le32_to_cpu(((u32 *)aifcmd->data)[0])) {
+		/*
+		 *	Add an Array.
+		 */
+		case AifEnAddContainer:
+			container = le32_to_cpu(((u32 *)aifcmd->data)[1]);
+			if (container >= dev->maximum_num_containers)
+				break;
+			dev->fsa_dev[container].config_needed = ADD;
+			dev->fsa_dev[container].config_waiting_on =
+				AifEnConfigChange;
+			break;
+
+		/*
+		 *	Delete an Array.
+		 */
+		case AifEnDeleteContainer:
+			container = le32_to_cpu(((u32 *)aifcmd->data)[1]);
+			if (container >= dev->maximum_num_containers)
+				break;
+			dev->fsa_dev[container].config_needed = DELETE;
+			dev->fsa_dev[container].config_waiting_on =
+				AifEnConfigChange;
+			break;
+
+		/*
+		 *	Container change detected. If we currently are not
+		 * waiting on something else, setup to wait on a Config Change.
+		 */
+		case AifEnContainerChange:
+			container = le32_to_cpu(((u32 *)aifcmd->data)[1]);
+			if (container >= dev->maximum_num_containers)
+				break;
+			if (dev->fsa_dev[container].config_waiting_on)
+				break;
+			dev->fsa_dev[container].config_needed = CHANGE;
+			dev->fsa_dev[container].config_waiting_on =
+				AifEnConfigChange;
+			break;
+
+		case AifEnConfigChange:
+			break;
+
+		}
+
+		/*
+		 *	If we are waiting on something and this happens to be
+		 * that thing then set the re-configure flag.
 		 */
-		if ((busy == 0)
-		 && (proc_scsi != (struct proc_dir_entry *)NULL)) {
-			struct proc_dir_entry * entry;
-
-			dprintk((KERN_INFO "proc_scsi=%p ", proc_scsi));
-			for (entry = proc_scsi->subdir;
-			  entry != (struct proc_dir_entry *)NULL;
-			  entry = entry->next) {
-				dprintk(("\"%.*s\"[%d]=%x ", entry->namelen,
-				  entry->name, entry->namelen, entry->low_ino));
-				if ((entry->low_ino != 0)
-				 && (entry->namelen == 4)
-				 && (memcmp ("scsi", entry->name, 4) == 0)) {
-					dprintk(("%p->write_proc=%p ", entry, entry->write_proc));
-					if (entry->write_proc != (int (*)(struct file *, const char *, unsigned long, void *))NULL) {
-						char buffer[80];
-						int length;
-						mm_segment_t fs;
-
-						sprintf (buffer,
-						  "scsi add-single-device %d %d %d %d\n",
-						  dev->scsi_host_ptr->host_no,
-						  CONTAINER_TO_BUS(container),
-						  CONTAINER_TO_TARGET(container),
-						  CONTAINER_TO_LUN(container));
-						length = strlen (buffer);
-						dprintk((KERN_INFO
-						  "echo %.*s > /proc/scsi/scsi\n",
-						  length-1,
-						  buffer));
-						fs = get_fs();
-						set_fs(get_ds());
-						length = entry->write_proc(
-						  NULL, buffer, length, NULL);
-						set_fs(fs);
-						dprintk((KERN_INFO
-						  "returns %d\n", length));
+		if (container != (u32)-1) {
+			if (container >= dev->maximum_num_containers)
+				break;
+			if (dev->fsa_dev[container].config_waiting_on ==
+			    le32_to_cpu(*(u32 *)aifcmd->data))
+				dev->fsa_dev[container].config_waiting_on = 0;
+		} else for (container = 0;
+		    container < dev->maximum_num_containers; ++container) {
+			if (dev->fsa_dev[container].config_waiting_on ==
+			    le32_to_cpu(*(u32 *)aifcmd->data))
+				dev->fsa_dev[container].config_waiting_on = 0;
+		}
+		break;
+
+	case AifCmdJobProgress:
+		/*
+		 *	These are job progress AIF's. When a Clear is being
+		 * done on a container it is initially created then hidden from
+		 * the OS. When the clear completes we don't get a config
+		 * change so we monitor the job status complete on a clear then
+		 * wait for a container change.
+		 */
+#if (defined(AAC_DEBUG_INSTRUMENT_AIF))
+		printk (KERN_INFO
+		  "aac_handle_aif: Aif command=AifCmdJobProgress job=%x [4]=%x [5]=%x [6]=%x\n",
+		  le32_to_cpu(((u32 *)aifcmd->data)[1]),
+		  le32_to_cpu(((u32 *)aifcmd->data)[4]),
+		  le32_to_cpu(((u32 *)aifcmd->data)[5]),
+		  le32_to_cpu(((u32 *)aifcmd->data)[6]));
+#endif
+
+		if ((((u32 *)aifcmd->data)[1] == cpu_to_le32(AifJobCtrZero))
+		 && ((((u32 *)aifcmd->data)[6] == ((u32 *)aifcmd->data)[5])
+		  || (((u32 *)aifcmd->data)[4] == cpu_to_le32(AifJobStsSuccess)))) {
+			for (container = 0;
+			    container < dev->maximum_num_containers;
+			    ++container) {
+				/*
+				 * Stomp on all config sequencing for all
+				 * containers?
+				 */
+				dev->fsa_dev[container].config_waiting_on =
+					AifEnContainerChange;
+				dev->fsa_dev[container].config_needed = ADD;
+			}
+#if (defined(AAC_DEBUG_INSTRUMENT_AIF))
+			printk (KERN_INFO
+			  "aac_handle_aif: Wait=AifEnContainerChange ADD\n");
+#endif
+		}
+		if ((((u32 *)aifcmd->data)[1] == cpu_to_le32(AifJobCtrZero))
+		 && (((u32 *)aifcmd->data)[6] == 0)
+		 && (((u32 *)aifcmd->data)[4] == cpu_to_le32(AifJobStsRunning))) {
+			for (container = 0;
+			    container < dev->maximum_num_containers;
+			    ++container) {
+				/*
+				 * Stomp on all config sequencing for all
+				 * containers?
+				 */
+				dev->fsa_dev[container].config_waiting_on =
+					AifEnContainerChange;
+				dev->fsa_dev[container].config_needed = DELETE;
+			}
+#if (defined(AAC_DEBUG_INSTRUMENT_AIF))
+			printk (KERN_INFO
+			  "aac_handle_aif: Wait=AifEnContainerChange DELETE\n");
+#endif
+		}
+		break;
+	}
+
+	device_config_needed = NOTHING;
+	for (container = 0; container < dev->maximum_num_containers;
+	    ++container) {
+		if ((dev->fsa_dev[container].config_waiting_on == 0)
+		 && (dev->fsa_dev[container].config_needed != NOTHING)) {
+			device_config_needed =
+				dev->fsa_dev[container].config_needed;
+			dev->fsa_dev[container].config_needed = NOTHING;
+			break;
+		}
+	}
+	if (device_config_needed == NOTHING)
+		return;
+
+	/*
+	 *	If we decided that a re-configuration needs to be done,
+	 * schedule it here on the way out the door, please close the door
+	 * behind you.
+	 */
+
+	busy = 0;
+
+#if (defined(AAC_DEBUG_INSTRUMENT_AIF))
+	printk (KERN_INFO "container=%d(%d,%d,%d,%d)\n",
+	  container,
+	  (dev && dev->scsi_host_ptr)
+	    ? dev->scsi_host_ptr->host_no
+	    : -1,
+	  CONTAINER_TO_CHANNEL(container),
+	  CONTAINER_TO_ID(container),
+	  CONTAINER_TO_LUN(container));
+#endif
+
+	/*
+	 *	Find the Scsi_Device associated with the SCSI address,
+	 * and mark it as changed, invalidating the cache. This deals
+	 * with changes to existing device IDs.
+	 */
+
+	if (!dev || !dev->scsi_host_ptr)
+		return;
+	/*
+	 * force reload of disk info via probe_container
+	 */
+	if ((device_config_needed == CHANGE)
+	 && (dev->fsa_dev[container].valid == 1))
+		dev->fsa_dev[container].valid = 2;
+	if ((device_config_needed == CHANGE) ||
+			(device_config_needed == ADD))
+		probe_container(dev, container);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
+	shost_for_each_device(device, dev->scsi_host_ptr)
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+	list_for_each_entry(device, &dev->scsi_host_ptr->my_devices, siblings)
+#else
+	for (device = dev->scsi_host_ptr->host_queue;
+	  device != (struct scsi_device *)NULL;
+	  device = device->next)
+#endif
+	{
+#if (defined(AAC_DEBUG_INSTRUMENT_AIF))
+		printk(KERN_INFO "aifd: device (%d,%d,%d,%d)?\n",
+		  dev->scsi_host_ptr->host_no, device->channel, device->id,
+		  device->lun);
+#endif
+		if ((device->channel == CONTAINER_TO_CHANNEL(container))
+		 && (device->id == CONTAINER_TO_ID(container))
+		 && (device->lun == CONTAINER_TO_LUN(container))) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
+			busy |= atomic_read(&device->access_count) ||
+				test_bit(SHOST_RECOVERY,
+				(const unsigned long *)&dev->scsi_host_ptr->shost_state);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
+			busy |= device->device_busy ||
+				test_bit(SHOST_RECOVERY,
+				(const unsigned long *)&dev->scsi_host_ptr->shost_state);
+#else
+			busy |= device->access_count ||
+				dev->scsi_host_ptr->in_recovery;
+#endif
+#if (defined(AAC_DEBUG_INSTRUMENT_AIF))
+			printk(KERN_INFO " %s %s\n",
+			  ((busy) ? "BUSY" : "AVAILABLE"),
+			  (device_config_needed == NOTHING)
+			   ? "NOTHING"
+			   : (device_config_needed == DELETE)
+			     ? "DELETE"
+			     : (device_config_needed == ADD)
+			       ? "ADD"
+			       : (device_config_needed == CHANGE)
+			         ? "CHANGE"
+			         : "UNKNOWN");
+#endif
+			if (busy == 0) {
+				device->removable = 1;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+				switch (device_config_needed) {
+#if 0
+				case ADD:
+					/*
+					 *	No need to call
+					 * scsi_scan_single_target
+					 */
+					device_config_needed = CHANGE;
+#if ((LINUX_VERSION_CODE > KERNEL_VERSION(2,6,3)) || !defined(MODULE))
+#if (defined(AAC_DEBUG_INSTRUMENT_AIF))
+					printk(KERN_INFO
+					  "scsi_add_device(%p{%d}, %d, %d, %d)\n",
+					  dev->scsi_host_ptr,
+					  dev->scsi_host_ptr->host_no,
+					  device->channel, device->id,
+					  device->lun);
+#endif
+					scsi_add_device(dev->scsi_host_ptr,
+					  device->channel, device->id,
+					  device->lun);
+					break;
+#endif
+#endif
+				case DELETE:
+#if ((LINUX_VERSION_CODE > KERNEL_VERSION(2,6,3)) || !defined(MODULE))
+#if (defined(AAC_DEBUG_INSTRUMENT_AIF))
+					printk(KERN_INFO
+					  "scsi_remove_device(%p{%d:%d:%d:%d})\n",
+					  device, device->host->host_no,
+					  device->channel, device->id,
+					  device->lun);
+#endif
+					scsi_remove_device(device);
+					break;
+#endif
+				case CHANGE:
+#if ((LINUX_VERSION_CODE > KERNEL_VERSION(2,6,3)) || !defined(MODULE))
+	 				if (!dev->fsa_dev[container].valid) {
+#if (defined(AAC_DEBUG_INSTRUMENT_AIF))
+						printk(KERN_INFO
+						  "scsi_remove_device(%p{%d:%d:%d:%d})\n",
+						  device,
+						  device->host->host_no,
+						  device->channel, device->id,
+						  device->lun);
+#endif
+						scsi_remove_device(device);
+						break;
 					}
+#endif
+#if ((LINUX_VERSION_CODE > KERNEL_VERSION(2,6,10)) || !defined(MODULE))
+#if (defined(AAC_DEBUG_INSTRUMENT_AIF))
+					printk(KERN_INFO
+					  "scsi_rescan_device(&%p{%d:%d:%d:%d}->sdev_gendev)\n",
+					  device, device->host->host_no,
+					  device->channel, device->id,
+					  device->lun);
+#endif
+					scsi_rescan_device(&device->sdev_gendev);
+#else
+					if (!device->sdev_gendev.driver)
+						break;
+					drv = to_scsi_driver(
+						device->sdev_gendev.driver);
+					if (!try_module_get(drv->owner))
+						break;
+#if (defined(AAC_DEBUG_INSTRUMENT_AIF))
+					printk(KERN_INFO
+					  "drv->rescan{%p}(&%p{%d:%d:%d:%d}->sdev_gendev)\n",
+					  drv->rescan, device,
+					  device->host->host_no,
+					  device->channel, device->id,
+					  device->lun);
+#endif
+					/* scsi_rescan_device code fragment */
+					if(drv->rescan)
+						drv->rescan(&device->sdev_gendev);
+					module_put(drv->owner);
+#endif
+
+				default:
 					break;
 				}
+#endif
+			}
+		}
+	}
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0))
+	if (device_config_needed == ADD) {
+#if ((LINUX_VERSION_CODE > KERNEL_VERSION(2,6,3)) || !defined(MODULE))
+#if (defined(AAC_DEBUG_INSTRUMENT_AIF))
+		printk(KERN_INFO
+		  "scsi_add_device(%p{%d}, %d, %d, %d)\n",
+		  dev->scsi_host_ptr,
+		  dev->scsi_host_ptr->host_no,
+		  CONTAINER_TO_CHANNEL(container),
+		  CONTAINER_TO_ID(container),
+		  CONTAINER_TO_LUN(container));
+#endif
+		scsi_add_device(dev->scsi_host_ptr,
+		  CONTAINER_TO_CHANNEL(container),
+		  CONTAINER_TO_ID(container),
+		  CONTAINER_TO_LUN(container));
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,10))
+		scsi_scan_single_target(dev->scsi_host_ptr,
+		  CONTAINER_TO_CHANNEL(container),
+		  CONTAINER_TO_ID(container));
+#elif (!defined(MODULE))
+		scsi_scan_host_selected(dev->scsi_host_ptr,
+		  CONTAINER_TO_CHANNEL(container),
+		  CONTAINER_TO_ID(container),
+		  CONTAINER_TO_LUN(container), 0);
+#endif
+	}
+#endif
+#if (defined(AAC_DEBUG_INSTRUMENT_AIF))
+	printk (KERN_INFO "busy=%d\n", busy);
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+	/*
+	 * if (busy == 0) {
+	 *	scan_scsis(dev->scsi_host_ptr, 1,
+	 *	  CONTAINER_TO_CHANNEL(container),
+	 *	  CONTAINER_TO_ID(container),
+	 *	  CONTAINER_TO_LUN(container));
+	 * }
+	 * is not exported as accessible, so we need to go around it
+	 * another way. So, we look for the "proc/scsi/scsi" entry in
+	 * the proc filesystem (using proc_scsi as a shortcut) and send
+	 * it a message. This deals with new devices that have
+	 * appeared. If the device has gone offline, scan_scsis will
+	 * also discover this, but we do not want the device to
+	 * go away. We need to check the access_count for the
+	 * device since we are not wanting the devices to go away.
+	 */
+	if (busy) {
+		dev->fsa_dev[container].config_waiting_on = 0;
+		dev->fsa_dev[container].config_needed = device_config_needed;
+		return;
+	}
+	if (proc_scsi != (struct proc_dir_entry *)NULL) {
+		struct proc_dir_entry * entry;
+
+#if (defined(AAC_DEBUG_INSTRUMENT_AIF))
+		printk(KERN_INFO "proc_scsi=%p ", proc_scsi);
+#endif
+		for (entry = proc_scsi->subdir;
+		  entry != (struct proc_dir_entry *)NULL;
+		  entry = entry->next) {
+#if (defined(AAC_DEBUG_INSTRUMENT_AIF))
+			printk("\"%.*s\"[%d]=%x ", entry->namelen,
+			  entry->name, entry->namelen, entry->low_ino);
+#endif
+			if ((entry->low_ino != 0)
+			 && (entry->namelen == 4)
+			 && (memcmp ("scsi", entry->name, 4) == 0)) {
+#if (defined(AAC_DEBUG_INSTRUMENT_AIF))
+				printk("%p->write_proc=%p ", entry, entry->write_proc);
+#endif
+				if (entry->write_proc != (int (*)(struct file *, const char *, unsigned long, void *))NULL) {
+					char buffer[80];
+					int length;
+					mm_segment_t fs;
+
+					sprintf (buffer,
+					  "scsi %s-single-device %d %d %d %d\n",
+					  ((device_config_needed == DELETE)
+					   ? "remove"
+					   : "add"),
+					  dev->scsi_host_ptr->host_no,
+					  CONTAINER_TO_CHANNEL(container),
+					  CONTAINER_TO_ID(container),
+					  CONTAINER_TO_LUN(container));
+					length = strlen (buffer);
+#if (defined(AAC_DEBUG_INSTRUMENT_AIF))
+					printk(KERN_INFO
+					  "echo %.*s > /proc/scsi/scsi\n",
+					  length-1, buffer);
+#endif
+					fs = get_fs();
+					set_fs(get_ds());
+					length = entry->write_proc(
+					  NULL, buffer, length, NULL);
+					set_fs(fs);
+#if (defined(AAC_DEBUG_INSTRUMENT_AIF))
+					printk(KERN_INFO "returns %d\n",
+					  length);
+#endif
+				}
+				break;
+			}
+		}
+	}
+#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) */
+}
+
+static int _aac_reset_adapter(struct aac_dev * aac)
+{
+	int index;
+	u32 ret;
+	int retval;
+	struct Scsi_Host * host;
+	struct scsi_device * dev;
+	struct scsi_cmnd * command;
+	struct scsi_cmnd * command_list;
+
+	/*
+	 * Assumptions:
+	 *	- host is locked, unless called by the aacraid thread.
+	 *	- in_reset is asserted, so no new i/o is getting to the
+	 *	  card.
+	 *	- The card is dead, or will be very shortly ;-/ so no new
+	 *	  commands are completing in the interrupt service.
+	 */
+	host = aac->scsi_host_ptr;
+	scsi_block_requests(host);
+	aac_adapter_disable_int(aac);
+	if (aac->thread_pid != current->pid) {
+		kill_proc(aac->thread_pid, SIGKILL, 0);
+		/* Chance of sleeping in this context, must unlock */
+#if (defined(SCSI_HAS_HOST_LOCK) || (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,21)) && ((LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21)) || !defined(CONFIG_CFGNAME))
+		spin_unlock_irq(host->host_lock);
+#else
+		spin_unlock_irq(host->lock);
+#endif
+#else
+		spin_unlock_irq(&io_request_lock);
+#endif
+		wait_for_completion(&aac->aif_completion);
+	}
+
+	/*
+	 *	If a positive health, means in a known DEAD PANIC
+	 * state and the adapter could be reset to `try again'.
+	 */
+	retval = aac_adapter_sync_cmd(aac, IOP_RESET,
+	  0, 0, 0, 0, 0, 0, &ret, NULL, NULL, NULL, NULL);
+
+	if (retval || (ret != 0x00000001)) {
+		if (retval == 0)
+			retval = -ENODEV;
+		goto out;
+	}
+
+	index = aac->cardtype;
+
+	/*
+	 * Re-initialize the adapter, first free resources, then carefully
+	 * apply the initialization sequence to come back again. Only risk
+	 * is a change in Firmware dropping cache, it is assumed the caller
+	 * will ensure that i/o is queisced and the card is flushed in that
+	 * case.
+	 */
+	fib_map_free(aac);
+	aac->hw_fib_va = NULL;
+	aac->hw_fib_pa = 0;
+	pci_free_consistent(aac->pdev, aac->comm_size, aac->comm_addr, aac->comm_phys);
+	aac->comm_addr = NULL;
+	aac->comm_phys = 0;
+	kfree(aac->queues);
+	aac->queues = NULL;
+	free_irq(aac->pdev->irq, aac);
+	kfree(aac->fsa_dev);
+	aac->fsa_dev = NULL;
+	if (aac_get_driver_ident(index)->quirks & AAC_QUIRK_31BIT) {
+		if (((retval = pci_set_dma_mask(aac->pdev, DMA_32BIT_MASK))) ||
+		  ((retval = pci_set_consistent_dma_mask(aac->pdev, DMA_32BIT_MASK))))
+			goto out;
+	} else {
+		if (((retval = pci_set_dma_mask(aac->pdev, 0x7FFFFFFFULL))) ||
+		  ((retval = pci_set_consistent_dma_mask(aac->pdev, 0x7FFFFFFFULL))))
+			goto out;
+	}
+#if (defined(AAC_DEBUG_INSTRUMENT_RESET))
+	printk(KERN_INFO "Calling adapter init\n");
+#endif
+	if ((retval = (*(aac_get_driver_ident(index)->init))(aac)))
+		goto out;
+	if (aac_get_driver_ident(index)->quirks & AAC_QUIRK_31BIT)
+		if ((retval = pci_set_dma_mask(aac->pdev, DMA_32BIT_MASK)))
+			goto out;
+	if (aac->thread_pid != current->pid) {
+		aac->thread_pid = retval = kernel_thread(
+		  (int (*)(void *))aac_command_thread, aac, 0);
+		if (retval < 0)
+			goto out;
+	}
+#if (defined(AAC_DEBUG_INSTRUMENT_RESET))
+	printk(KERN_INFO "Acquiring adapter information\n");
+#endif
+	(void)aac_get_adapter_info(aac);
+ 	if ((aac_get_driver_ident(index)->quirks & AAC_QUIRK_34SG) && 
+	    (host->sg_tablesize > 34)) {
+ 		host->sg_tablesize = 34;
+ 		host->max_sectors = (host->sg_tablesize * 8) + 112;
+ 	}
+#if (defined(AAC_DEBUG_INSTRUMENT_RESET))
+	printk(KERN_INFO "Determine the configuration status\n");
+#endif
+	aac_get_config_status(aac);
+#if (defined(AAC_DEBUG_INSTRUMENT_RESET))
+	printk(KERN_INFO "Probing all arrays to confirm status\n");
+#endif
+	aac_get_containers(aac);
+#if (defined(AAC_DEBUG_INSTRUMENT_RESET))
+	printk(KERN_INFO "Completing all outstanding driver commands as BUSY\n");
+#endif
+	/*
+	 * This is where the assumption that the Adapter is quiesced
+	 * is important.
+	 */
+	command_list = NULL;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+	__shost_for_each_device(dev, host) {
+		unsigned long flags;
+		spin_lock_irqsave(&dev->list_lock, flags);
+		list_for_each_entry(command, &dev->cmd_list, list)
+			if (command->SCp.phase == AAC_OWNER_FIRMWARE) {
+				command->SCp.buffer = (struct scatterlist *)command_list;
+				command_list = command;
+			}
+		spin_unlock_irqrestore(&dev->list_lock, flags);
+	}
+#else
+#ifndef SAM_STAT_TASK_SET_FULL
+# define SAM_STAT_TASK_SET_FULL (QUEUE_FULL << 1)
+#endif
+	for (dev = host->host_queue; dev != (struct scsi_device *)NULL; dev = dev->next)
+		for(command = dev->device_queue; command; command = command->next)
+			if (command->SCp.phase == AAC_OWNER_FIRMWARE) {
+				command->SCp.buffer = (struct scatterlist *)command_list;
+				command_list = command;
+			}
+#endif
+	while ((command = command_list)) {
+		command_list = (struct scsi_cmnd *)command->SCp.buffer;
+		command->SCp.buffer = NULL;
+		command->result = DID_OK << 16
+		  | COMMAND_COMPLETE << 8
+		  | SAM_STAT_TASK_SET_FULL;
+		command->SCp.phase = AAC_OWNER_ERROR_HANDLER;
+		command->scsi_done(command);
+	}
+#if (defined(AAC_DEBUG_INSTRUMENT_RESET))
+	printk(KERN_INFO "Continue where we left off\n");
+#endif
+	retval = 0;
+
+out:
+	aac->in_reset = 0;
+	scsi_unblock_requests(host);
+	if (aac->thread_pid != current->pid) {
+#if (defined(SCSI_HAS_HOST_LOCK) || (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,21)) && ((LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21)) || !defined(CONFIG_CFGNAME))
+		spin_lock_irq(host->host_lock);
+#else
+		spin_lock_irq(host->lock);
+#endif
+#else
+		spin_lock_irq(&io_request_lock);
+#endif
+	}
+	return retval;
+}
+
+int aac_reset_adapter(struct aac_dev * aac)
+{
+	unsigned long flagv = 0;
+	int retval;
+
+	if (spin_trylock_irqsave(&aac->fib_lock, flagv) == 0)
+		return -EBUSY;
+
+	if (aac->in_reset) {
+		spin_unlock_irqrestore(&aac->fib_lock, flagv);
+		return -EBUSY;
+	}
+	aac->in_reset = 1;
+	spin_unlock_irqrestore(&aac->fib_lock, flagv);
+
+	/* Quiesce build, flush cache, write through mode */
+	aac_send_shutdown(aac);
+	retval = _aac_reset_adapter(aac);
+
+	if (retval == -ENODEV) {
+		/* Unwind aac_send_shutdown() IOP_RESET unsupported/disabled */
+		struct fib * fibctx = fib_alloc(aac);
+		if (fibctx) {
+			struct aac_pause *cmd;
+			int status;
+
+			fib_init(fibctx);
+
+			cmd = (struct aac_pause *) fib_data(fibctx);
+
+			cmd->command = cpu_to_le32(VM_ContainerConfig);
+			cmd->type = cpu_to_le32(CT_PAUSE_IO);
+			cmd->timeout = cpu_to_le32(1);
+			cmd->min = cpu_to_le32(1);
+			cmd->noRescan = cpu_to_le32(1);
+
+			status = fib_send(ContainerCommand,
+			  fibctx,
+			  sizeof(struct aac_pause),
+			  FsaNormal,
+			  -2 /* Timeout silently */, 1,
+			  NULL, NULL);
+
+			if (status == 0)
+				fib_complete(fibctx);
+			fib_free(fibctx);
+		}
+	}
+
+	return retval;
+}
+
+int aac_check_health(struct aac_dev * aac)
+{
+	int BlinkLED;
+	unsigned long time_now, flagv = 0;
+	struct list_head * entry;
+	extern int check_reset;
+
+	/* Extending the scope of fib_lock slightly to protect aac->in_reset */
+	if (spin_trylock_irqsave(&aac->fib_lock, flagv) == 0)
+		return 0;
+
+	if (aac->in_reset || !(BlinkLED = aac_adapter_check_health(aac))) {
+		spin_unlock_irqrestore(&aac->fib_lock, flagv);
+		return 0; /* OK */
+	}
+
+	aac->in_reset = 1;
+
+	/* Fake up an AIF:
+	 *	aac_aifcmd.command = AifCmdEventNotify = 1
+	 *	aac_aifcmd.seqnum = 0xFFFFFFFF
+	 *	aac_aifcmd.data[0] = AifEnExpEvent = 23
+	 *	aac_aifcmd.data[1] = AifExeFirmwarePanic = 3
+	 *	aac.aifcmd.data[2] = AifHighPriority = 3
+	 *	aac.aifcmd.data[3] = BlinkLED
+	 */
+		
+	time_now = jiffies/HZ;
+	entry = aac->fib_list.next;
+
+	/*
+	 * For each Context that is on the 
+	 * fibctxList, make a copy of the
+	 * fib, and then set the event to wake up the
+	 * thread that is waiting for it.
+	 */
+	while (entry != &aac->fib_list) {
+		/*
+		 * Extract the fibctx
+		 */
+		struct aac_fib_context *fibctx = list_entry(entry, struct aac_fib_context, next);
+		struct hw_fib * hw_fib;
+		struct fib * fib;
+		/*
+		 * Check if the queue is getting
+		 * backlogged
+		 */
+		if (fibctx->count > 20) {
+			/*
+			 * It's *not* jiffies folks,
+			 * but jiffies / HZ, so do not
+			 * panic ...
+			 */
+			u32 time_last = fibctx->jiffies;
+			/*
+			 * Has it been > 2 minutes 
+			 * since the last read off
+			 * the queue?
+			 */
+			if ((time_now - time_last) > 120) {
+				entry = entry->next;
+				aac_close_fib_context(aac, fibctx);
+				continue;
 			}
 		}
+		/*
+		 * Warning: no sleep allowed while
+		 * holding spinlock
+		 */
+		hw_fib = kmalloc(sizeof(struct hw_fib), GFP_ATOMIC);
+		fib = kmalloc(sizeof(struct fib), GFP_ATOMIC);
+		if (fib && hw_fib) {
+			struct aac_aifcmd * aif;
+
+			memset(hw_fib, 0, sizeof(struct hw_fib));
+			memset(fib, 0, sizeof(struct fib));
+			fib->hw_fib = hw_fib;
+			fib->dev = aac;
+			fib_init(fib);
+			fib->type = FSAFS_NTC_FIB_CONTEXT;
+			fib->size = sizeof (struct fib);
+			fib->data = hw_fib->data;
+			aif = (struct aac_aifcmd *)hw_fib->data;
+			aif->command = AifCmdEventNotify;
+		 	aif->seqnum = 0xFFFFFFFF;
+		 	aif->data[0] = AifEnExpEvent;
+			aif->data[1] = AifExeFirmwarePanic;
+		 	aif->data[2] = AifHighPriority;
+			aif->data[3] = BlinkLED;
+
+			/*
+			 * Put the FIB onto the
+			 * fibctx's fibs
+			 */
+			list_add_tail(&fib->fiblink, &fibctx->fib_list);
+			fibctx->count++;
+			/* 
+			 * Set the event to wake up the
+			 * thread that will waiting.
+			 */
+			up(&fibctx->wait_sem);
+		} else {
+			printk(KERN_WARNING "aifd: didn't allocate NewFib.\n");
+			if(fib)
+				kfree(fib);
+			if(hw_fib)
+				kfree(hw_fib);
+		}
+		entry = entry->next;
 	}
+
+	spin_unlock_irqrestore(&aac->fib_lock, flagv);
+
+	if (BlinkLED < 0) {
+		printk(KERN_ERR "%s: Host adapter dead %d\n", aac->name, BlinkLED);
+		goto out;
+	}
+
+	printk(KERN_ERR "%s: Host adapter BLINK LED 0x%x\n", aac->name, BlinkLED);
+
+	if (check_reset == 0)
+		goto out;
+	
+	return _aac_reset_adapter(aac);
+
+out:
+	aac->in_reset = 0;
+	return BlinkLED;
 }
 
+
 /**
  *	aac_command_thread	-	command processing thread
  *	@dev: Adapter to monitor
@@ -916,11 +1765,19 @@ int aac_command_thread(struct aac_dev * dev)
 {
 	struct hw_fib *hw_fib, *hw_newfib;
 	struct fib *fib, *newfib;
-	struct aac_queue_block *queues = dev->queues;
 	struct aac_fib_context *fibctx;
 	unsigned long flags;
 	DECLARE_WAITQUEUE(wait, current);
-
+	unsigned long next_jiffies = jiffies + HZ;
+	unsigned long next_check_jiffies = next_jiffies;
+	long difference = HZ;
+	extern int update_interval;
+	extern int check_interval;
+
+#if (defined(AAC_DEBUG_INSTRUMENT_RESET))
+	printk(KERN_ERR "update_interval=%d:%02d check_interval=%ds\n",
+	  update_interval / 60, update_interval % 60, check_interval);
+#endif
 	/*
 	 *	We can only have one thread per adapter for AIF's.
 	 */
@@ -930,28 +1787,36 @@ int aac_command_thread(struct aac_dev * dev)
 	 *	Set up the name that will appear in 'ps'
 	 *	stored in  task_struct.comm[16].
 	 */
-	sprintf(current->comm, "aacraid");
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+	daemonize(dev->name);
+	allow_signal(SIGKILL);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4))
+	snprintf(current->comm, sizeof(current->comm), dev->name);
 	daemonize();
+#else
+	sprintf(current->comm, dev->name);
+	daemonize();
+#endif
 	/*
 	 *	Let the DPC know it has a place to send the AIF's to.
 	 */
 	dev->aif_thread = 1;
-	add_wait_queue(&queues->queue[HostNormCmdQueue].cmdready, &wait);
+	add_wait_queue(&dev->queues->queue[HostNormCmdQueue].cmdready, &wait);
 	set_current_state(TASK_INTERRUPTIBLE);
 	dprintk ((KERN_INFO "aac_command_thread start\n"));
 	while(1) 
 	{
-		spin_lock_irqsave(queues->queue[HostNormCmdQueue].lock, flags);
-		while(!list_empty(&(queues->queue[HostNormCmdQueue].cmdq))) {
+		spin_lock_irqsave(dev->queues->queue[HostNormCmdQueue].lock, flags);
+		while(!list_empty(&(dev->queues->queue[HostNormCmdQueue].cmdq))) {
 			struct list_head *entry;
 			struct aac_aifcmd * aifcmd;
 
 			set_current_state(TASK_RUNNING);
-
-			entry = queues->queue[HostNormCmdQueue].cmdq.next;
-			list_del(entry);
 	
-			spin_unlock_irqrestore(queues->queue[HostNormCmdQueue].lock, flags);
+			entry = dev->queues->queue[HostNormCmdQueue].cmdq.next;
+			list_del(entry);
+		
+			spin_unlock_irqrestore(dev->queues->queue[HostNormCmdQueue].lock, flags);
 			fib = list_entry(entry, struct fib, fiblink);
 			/*
 			 *	We will process the FIB here or pass it to a 
@@ -960,7 +1825,6 @@ int aac_command_thread(struct aac_dev * dev)
 			 *	anything defined for this thread to do.
 			 */
 			hw_fib = fib->hw_fib;
-			
 			memset(fib, 0, sizeof(struct fib));
 			fib->type = FSAFS_NTC_FIB_CONTEXT;
 			fib->size = sizeof( struct fib );
@@ -974,8 +1838,8 @@ int aac_command_thread(struct aac_dev * dev)
 			if (aifcmd->command == cpu_to_le32(AifCmdDriverNotify)) {
 				/* Handle Driver Notify Events */
 				aac_handle_aif(dev, fib);
-				*(u32 *)hw_fib->data = cpu_to_le32(ST_OK);
-				fib_adapter_complete(fib, sizeof(u32));
+				*(__le32 *)hw_fib->data = cpu_to_le32(ST_OK);
+				fib_adapter_complete(fib, (u16)sizeof(u32));
 			} else {
 				struct list_head *entry;
 				/* The u32 here is important and intended. We are using
@@ -983,13 +1847,62 @@ int aac_command_thread(struct aac_dev * dev)
 				   
 				u32 time_now, time_last;
 				unsigned long flagv;
-				
+				unsigned num;
+				struct hw_fib ** hw_fib_pool, ** hw_fib_p;
+				struct fib ** fib_pool, ** fib_p;
+			
 				/* Sniff events */
-				if (aifcmd->command == cpu_to_le32(AifCmdEventNotify))
+				if ((aifcmd->command == 
+				     cpu_to_le32(AifCmdEventNotify)) ||
+				    (aifcmd->command == 
+				     cpu_to_le32(AifCmdJobProgress))) {
 					aac_handle_aif(dev, fib);
-
+				}
+ 				
 				time_now = jiffies/HZ;
 
+				/*
+				 * Warning: no sleep allowed while
+				 * holding spinlock. We take the estimate
+				 * and pre-allocate a set of fibs outside the
+				 * lock.
+				 */
+				num = le32_to_cpu(dev->init->AdapterFibsSize)
+				    / sizeof(struct hw_fib); /* some extra */
+				spin_lock_irqsave(&dev->fib_lock, flagv);
+				entry = dev->fib_list.next;
+				while (entry != &dev->fib_list) {
+					entry = entry->next;
+					++num;
+				}
+				spin_unlock_irqrestore(&dev->fib_lock, flagv);
+				hw_fib_pool = NULL;
+				fib_pool = NULL;
+				if (num
+				 && ((hw_fib_pool = kmalloc(sizeof(struct hw_fib *) * num, GFP_ATOMIC|GFP_KERNEL)))
+				 && ((fib_pool = kmalloc(sizeof(struct fib *) * num, GFP_ATOMIC|GFP_KERNEL)))) {
+					hw_fib_p = hw_fib_pool;
+					fib_p = fib_pool;
+					while (hw_fib_p < &hw_fib_pool[num]) {
+						if (!(*(hw_fib_p++) = kmalloc(sizeof(struct hw_fib), GFP_ATOMIC|GFP_KERNEL))) {
+							--hw_fib_p;
+							break;
+						}
+						if (!(*(fib_p++) = kmalloc(sizeof(struct fib), GFP_ATOMIC|GFP_KERNEL))) {
+							kfree(*(--hw_fib_p));
+							break;
+						}
+					}
+					if ((num = hw_fib_p - hw_fib_pool) == 0) {
+						kfree(fib_pool);
+						fib_pool = NULL;
+						kfree(hw_fib_pool);
+						hw_fib_pool = NULL;
+					}
+				} else if (hw_fib_pool) {
+					kfree(hw_fib_pool);
+					hw_fib_pool = NULL;
+				}
 				spin_lock_irqsave(&dev->fib_lock, flagv);
 				entry = dev->fib_list.next;
 				/*
@@ -998,6 +1911,8 @@ int aac_command_thread(struct aac_dev * dev)
 				 * fib, and then set the event to wake up the
 				 * thread that is waiting for it.
 				 */
+				hw_fib_p = hw_fib_pool;
+				fib_p = fib_pool;
 				while (entry != &dev->fib_list) {
 					/*
 					 * Extract the fibctx
@@ -1011,7 +1926,7 @@ int aac_command_thread(struct aac_dev * dev)
 					{
 						/*
 						 * It's *not* jiffies folks,
-						 * but jiffies / HZ, so do not
+						 * but jiffies / HZ so do not
 						 * panic ...
 						 */
 						time_last = fibctx->jiffies;
@@ -1030,12 +1945,13 @@ int aac_command_thread(struct aac_dev * dev)
 					 * Warning: no sleep allowed while
 					 * holding spinlock
 					 */
-					hw_newfib = kmalloc(sizeof(struct hw_fib), GFP_ATOMIC);
-					newfib = kmalloc(sizeof(struct fib), GFP_ATOMIC);
-					if (newfib && hw_newfib) {
+					if (hw_fib_p < &hw_fib_pool[num]) {
+						hw_newfib = *hw_fib_p;
+						*(hw_fib_p++) = NULL;
+						newfib = *fib_p;
+						*(fib_p++) = NULL;
 						/*
 						 * Make the copy of the FIB
-						 * FIXME: check if we need to fix other fields up
 						 */
 						memcpy(hw_newfib, hw_fib, sizeof(struct hw_fib));
 						memcpy(newfib, fib, sizeof(struct fib));
@@ -1048,39 +1964,120 @@ int aac_command_thread(struct aac_dev * dev)
 						fibctx->count++;
 						/* 
 						 * Set the event to wake up the
-						 * thread that will waiting.
+						 * thread that is waiting.
 						 */
 						up(&fibctx->wait_sem);
 					} else {
 						printk(KERN_WARNING "aifd: didn't allocate NewFib.\n");
-						if(newfib)
-							kfree(newfib);
-						if(hw_newfib)
-							kfree(hw_newfib);
 					}
 					entry = entry->next;
 				}
 				/*
 				 *	Set the status of this FIB
 				 */
-				*(u32 *)hw_fib->data = cpu_to_le32(ST_OK);
+				*(__le32 *)hw_fib->data = cpu_to_le32(ST_OK);
 				fib_adapter_complete(fib, sizeof(u32));
 				spin_unlock_irqrestore(&dev->fib_lock, flagv);
+				/* Free up the remaining resources */
+				hw_fib_p = hw_fib_pool;
+				fib_p = fib_pool;
+				while (hw_fib_p < &hw_fib_pool[num]) {
+					if (*hw_fib_p)
+						kfree(*hw_fib_p);
+					if (*fib_p)
+						kfree(*fib_p);
+					++fib_p;
+					++hw_fib_p;
+				}
+				if (hw_fib_pool)
+					kfree(hw_fib_pool);
+				if (fib_pool)
+					kfree(fib_pool);
 			}
-			spin_lock_irqsave(queues->queue[HostNormCmdQueue].lock, flags);
 			kfree(fib);
+			spin_lock_irqsave(dev->queues->queue[HostNormCmdQueue].lock, flags);
 		}
 		/*
 		 *	There are no more AIF's
 		 */
-		spin_unlock_irqrestore(queues->queue[HostNormCmdQueue].lock, flags);
-		schedule();
+		spin_unlock_irqrestore(dev->queues->queue[HostNormCmdQueue].lock, flags);
+
+		/*
+		 *	Background activity
+		 */
+		if ((time_before(next_check_jiffies,next_jiffies))
+		 && ((difference = next_check_jiffies - jiffies) <= 0)) {
+			next_check_jiffies = next_jiffies;
+			if (aac_check_health(dev) == 0) {
+				difference = ((long)(unsigned)check_interval)
+					   * HZ;
+				next_check_jiffies = jiffies + difference;
+			} else if (!dev->queues)
+				break;
+		}
+		if (!time_before(next_check_jiffies,next_jiffies)
+		 && ((difference = next_jiffies - jiffies) <= 0)) {
+			struct timeval now;
+			int ret;
+
+			/* Don't even try to talk to adapter if its sick */
+			ret = aac_check_health(dev);
+			if (!ret && !dev->queues)
+				break;
+			next_check_jiffies = jiffies
+					   + ((long)(unsigned)check_interval)
+					   * HZ;
+			do_gettimeofday(&now);
+
+			/* Synchronize our watches */
+			if (((1000000 - (1000000 / HZ)) > now.tv_usec)
+			 && (now.tv_usec > (1000000 / HZ)))
+				difference = (((1000000 - now.tv_usec) * HZ)
+				  + 500000) / 1000000;
+			else if (ret == 0) {
+				struct fib *fibptr;
+
+				if ((fibptr = fib_alloc(dev))) {
+					u32 * info;
+
+					fib_init(fibptr);
+
+					info = (u32 *) fib_data(fibptr);
+					if (now.tv_usec > 500000)
+						++now.tv_sec;
+
+					*info = cpu_to_le32(now.tv_sec);
+
+					(void)fib_send(SendHostTime,
+						fibptr,
+						sizeof(*info),
+						FsaNormal,
+						1, 1,
+						NULL,
+						NULL);
+					fib_complete(fibptr);
+					fib_free(fibptr);
+				}
+				difference = (long)(unsigned)update_interval*HZ;
+			} else {
+				/* retry shortly */
+				difference = 10 * HZ;
+			}
+			next_jiffies = jiffies + difference;
+			if (time_before(next_check_jiffies,next_jiffies))
+				difference = next_check_jiffies - jiffies;
+		}
+		if (difference <= 0)
+			difference = 1;
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(difference);
 
 		if(signal_pending(current))
 			break;
-		set_current_state(TASK_INTERRUPTIBLE);
 	}
-	remove_wait_queue(&queues->queue[HostNormCmdQueue].cmdready, &wait);
+	if (dev->queues)
+		remove_wait_queue(&dev->queues->queue[HostNormCmdQueue].cmdready, &wait);
 	dev->aif_thread = 0;
 	complete_and_exit(&dev->aif_completion, 0);
+	return 0;
 }
diff --git a/drivers/scsi/aacraid/compat.h b/drivers/scsi/aacraid/compat.h
new file mode 100644
index 0000000..ddc20f3
--- /dev/null
+++ b/drivers/scsi/aacraid/compat.h
@@ -0,0 +1,256 @@
+/*
+ *	Adaptec AAC series RAID controller driver
+ *	(c) Copyright 2001 Red Hat Inc.	<alan@redhat.com>
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+/*
+ * This file is for backwards compatibility with older kernel versions
+ */
+#include <linux/version.h>
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)) && (!defined(SCSI_HAS_SSLEEP))
+#define ssleep(x) scsi_sleep((x)*HZ)
+#endif
+#if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,7)) && !defined(HAS_MSLEEP))
+#define msleep(x) set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(x)
+#endif
+#ifndef BUG_ON
+#ifndef unlikely
+#ifndef __builtin_expect
+#define __builtin_expect(x, expected_value) (x)
+#endif
+#define unlikely(x) __builtin_expect((x),0)
+#endif
+#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while (0)
+#endif
+#ifndef min
+#define min(a,b) (((a)<(b))?(a):(b))
+#endif
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
+ typedef unsigned long dma_addr_t;
+#include <linux/kcomp.h>
+#define PCI_ANY_ID (~0)
+#define SCSI_DATA_UNKNOWN	0
+#define SCSI_DATA_WRITE		1
+#define SCSI_DATA_READ		2
+#define SCSI_DATA_NONE		3
+ /* Sigh ... a *lot* more needs to be done for this Grandpa */
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+#include <linux/time.h>
+static inline unsigned long get_seconds(void)
+{
+	struct timeval now;
+	do_gettimeofday(&now);
+	return now.tv_sec;
+}
+#define scsi_host_template SHT
+#define DMA_BIDIRECTIONAL	SCSI_DATA_UNKNOWN
+#define DMA_TO_DEVICE		SCSI_DATA_WRITE
+#define DMA_FROM_DEVICE		SCSI_DATA_READ
+#define DMA_NONE		SCSI_DATA_NONE
+#define iminor(x) MINOR(x->i_rdev)
+#define scsi_host_alloc(t,s) scsi_register(t,s)
+#define scsi_host_put(s) scsi_unregister(s)
+#ifndef pci_set_consistent_dma_mask
+#define pci_set_consistent_dma_mask(d,m) 0
+#endif
+#ifndef SCSI_HAS_SCSI_SCAN_HOST
+#ifndef scsi_scan_host
+#define scsi_scan_host(s)
+#endif
+#endif
+#define scsi_add_host(s,d) 0
+#if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,4,20)) && !defined(list_for_each_entry))
+#if (!defined(_LINUX_PREFETCH_H))
+static inline void prefetch(const void *x) {;}
+#endif
+#define list_for_each_entry(pos, head, member)                          \
+        for (pos = list_entry((head)->next, typeof(*pos), member),      \
+                     prefetch(pos->member.next);                        \
+             &pos->member != (head);                                    \
+             pos = list_entry(pos->member.next, typeof(*pos), member),  \
+                     prefetch(pos->member.next))
+#endif
+#define scsi_remove_host(s)					\
+	struct proc_dir_entry * entry = NULL;			\
+	struct scsi_device *device;				\
+	extern struct proc_dir_entry * proc_scsi;		\
+	if (proc_scsi != (struct proc_dir_entry *)NULL)		\
+	for (entry = proc_scsi->subdir;				\
+	  entry != (struct proc_dir_entry *)NULL &&		\
+	  (!entry->low_ino ||					\
+	    (entry->namelen != 4) ||				\
+	    memcmp ("scsi", entry->name, 4));			\
+	  entry = entry->next);					\
+	if (entry && entry->write_proc)				\
+	for (device = s->host_queue;				\
+	  device != (struct scsi_device *)NULL;			\
+	  device = device->next)				\
+		if (!device->access_count && !s->in_recovery) {	\
+			char buffer[80];			\
+			int length;				\
+			mm_segment_t fs;			\
+			device->removable = 1;			\
+			sprintf (buffer, "scsi "		\
+			  "remove-single-device %d %d %d %d\n", \
+			  s->host_no, device->channel,		\
+			  device->id, device->lun);		\
+			length = strlen (buffer);		\
+			fs = get_fs();				\
+			set_fs(get_ds());			\
+			length = entry->write_proc(		\
+			  NULL, buffer, length, NULL);		\
+			set_fs(fs);				\
+		}
+#if (!defined(__devexit_p))
+# if (defined(MODULE))
+#  define __devexit_p(x) x
+# else
+#  define __devexit_p(x) NULL
+# endif
+#endif
+#define __user
+#endif
+#if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,6)) && (!defined(SCSI_HAS_SCSI_DEVICE_ONLINE)))
+#define scsi_device_online(d) ((d)->online)
+#endif
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9))
+#define __iomem
+#endif
+#if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)) && !defined(HAS_BITWISE_TYPE))
+typedef u64 __le64;
+typedef u32 __le32;
+typedef u16 __le16;
+#endif
+
+#ifndef DMA_64BIT_MASK
+#define DMA_64BIT_MASK ((dma_addr_t)0xffffffffffffffffULL)
+#endif
+#ifndef DMA_32BIT_MASK
+#define DMA_32BIT_MASK ((dma_addr_t)0xffffffffULL)
+#endif
+#ifndef spin_trylock_irqsave
+#define spin_trylock_irqsave(lock, flags) \
+({ \
+	local_irq_save(flags); \
+	spin_trylock(lock) ? \
+	1 : ({local_irq_restore(flags); 0 ;}); \
+})
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,18)) && (LINUX_VERSION_CODE != KERNEL_VERSION(2,4,9)) && (LINUX_VERSION_CODE != KERNEL_VERSION(2,4,13))
+# define dma_handle ptr
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,11))
+#include <linux/blk.h>
+
+static inline unsigned int block_size(kdev_t dev)
+{
+	int retval = BLOCK_SIZE;
+	int major = MAJOR(dev);
+
+	if (blksize_size[major]) {
+		int minor = MINOR(dev);
+		if (blksize_size[major][minor])
+			retval = blksize_size[major][minor];
+	}
+	return retval;
+}
+#endif
+
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,7))
+
+#ifndef COMPLETION_INITIALIZER
+
+#include <linux/wait.h>
+
+struct completion {
+	unsigned int done;
+	wait_queue_head_t wait;
+};
+#define COMPLETION_INITIALIZER(work) \
+	{ 0, __WAIT_QUEUE_HEAD_INITIALIZER((work).wait) }
+
+#define DECLARE_COMPLETION(work) \
+	struct completion work = COMPLETION_INITIALIZER(work)
+#define INIT_COMPLETION(x)	((x).done = 0)
+
+static inline void init_completion(struct completion *x)
+{
+	x->done = 0;
+	init_waitqueue_head(&x->wait);
+}
+#endif
+
+#ifndef complete_and_exit
+static inline void complete_and_exit(struct completion *comp, long code)
+{
+	/*
+	if (comp)
+		complete(comp);
+
+	do_exit(code);
+	*/
+}
+#endif
+
+#endif
+
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,2))
+
+static inline void scsi_set_pci_device(struct Scsi_Host *SHpnt,
+                                       struct pci_dev *pdev)
+{
+//	SHpnt->pci_dev = pdev;
+}
+
+static inline void wait_for_completion(struct completion *x)
+{
+	spin_lock_irq(&x->wait.lock);
+	if (!x->done) {
+		DECLARE_WAITQUEUE(wait, current);
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0))
+		wait.flags |= WQ_FLAG_EXCLUSIVE;
+#endif
+		__add_wait_queue_tail(&x->wait, &wait);
+		do {
+			__set_current_state(TASK_UNINTERRUPTIBLE);
+			spin_unlock_irq(&x->wait.lock);
+			schedule();
+			spin_lock_irq(&x->wait.lock);
+		} while (!x->done);
+		__remove_wait_queue(&x->wait, &wait);
+	}
+	x->done--;
+	spin_unlock_irq(&x->wait.lock);
+}
+
+static inline int pci_set_dma_mask(struct pci_dev *dev, dma_addr_t mask)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0))
+    dev->dma_mask = mask;
+#endif
+
+    return 0;
+}
+
+#endif
+    
diff --git a/drivers/scsi/aacraid/csmi.c b/drivers/scsi/aacraid/csmi.c
new file mode 100644
index 0000000..16ecae7
--- /dev/null
+++ b/drivers/scsi/aacraid/csmi.c
@@ -0,0 +1,1686 @@
+/*
+ *	Adaptec AAC series RAID controller driver
+ *	(c) Copyright 2004 Adaptec, Inc
+ *
+ * Copyright (c) 2004 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *   csmi.c
+ *
+ * Abstract: All CSMI IOCTL processing is handled here.
+ */
+
+/*
+ * Include Files
+ */
+
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/spinlock.h>
+#include <asm/semaphore.h>
+#include <linux/kernel.h>
+#include <linux/blkdev.h>
+#include <linux/completion.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <asm/uaccess.h> /* For copy_from_user()/copy_to_user() definitions */
+#include <linux/slab.h> /* For kmalloc()/kfree() definitions */
+#include "aacraid.h"
+#include "fwdebug.h"
+#include <linux/version.h> /* For the following test */
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+# include "scsi.h"
+# include "hosts.h"
+#else
+# include <scsi/scsi.h>
+# include <scsi/scsi_host.h>
+# include <linux/pci.h>
+# include <linux/dma-mapping.h>
+#endif
+#if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) ? defined(__x86_64__) : defined(CONFIG_COMPAT))
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,3))
+#include <linux/syscalls.h>
+#include <linux/ioctl32.h>
+#endif
+#if ((KERNEL_VERSION(2,4,19) <= LINUX_VERSION_CODE) && (LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,21)))
+# include <asm-x86_64/ioctl32.h>
+#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+# include <asm/ioctl32.h>
+#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,3))
+# include <linux/ioctl32.h>
+#endif
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+# include <asm/uaccess.h>
+#endif
+#endif
+
+#if (defined(AAC_CSMI))
+
+#include "csmi.h"
+
+
+/*
+ * Routine Description:
+ *	This routine will verify that the *ppHeader is big enough
+ *	for the expected CSMI IOCTL buffer.
+ * Return Value:
+ *	ppHeader
+ *	0 - Success ppHeader set up with successful completion code
+ *	!0 - CSMI_SAS_STATUS_INVALID_PARAMETER as the ReturnCode.
+ */
+static int
+aac_VerifyCSMIBuffer(
+	struct aac_dev ** pDev,
+	void __user * arg,
+	unsigned long csmiBufferSizeToVerify,
+	PIOCTL_HEADER * ppHeader)
+{
+	u32 Length;
+	int Rtnval;
+	struct aac_dev * dev = *pDev;
+	extern struct list_head aac_devices; /* in linit.c */
+
+	fwprintf((dev, HBA_FLAGS_DBG_FUNCTION_ENTRY_B,
+	  "aac_VerifyCSMIBuffer: Enter"));
+
+	*ppHeader = (PIOCTL_HEADER)NULL;
+
+	if (copy_from_user((void *)&Length,
+	  (void __user *)&((PIOCTL_HEADER)arg)->Length, sizeof(u32))) {
+		fwprintf((dev, HBA_FLAGS_DBG_ERROR_B,
+		  "aac_VerifyCSMIBuffer: Acquire Length Failure"));
+		Length = CSMI_SAS_STATUS_INVALID_PARAMETER;
+		/* Will msot probably fail */
+		Rtnval = copy_to_user(
+		  (void __user *)&((PIOCTL_HEADER)arg)->ReturnCode,
+		  (void *)&Length, sizeof(u32));
+		Rtnval = -EFAULT;
+	} else if ((Length < sizeof(IOCTL_HEADER))
+	 || (Length < csmiBufferSizeToVerify)
+	 || (csmiBufferSizeToVerify < sizeof(IOCTL_HEADER))) {
+		fwprintf((dev, HBA_FLAGS_DBG_ERROR_B,
+		  "aac_VerifyCSMIBuffer:"
+		  " sizeof(IOCTL_HEADER)=%u, Length=%u, MinPacketLength=%u",
+		  sizeof(IOCTL_HEADER), Length, csmiBufferSizeToVerify));
+		Length = CSMI_SAS_STATUS_INVALID_PARAMETER;
+		if (copy_to_user(
+		  (void __user *)&((PIOCTL_HEADER)arg)->ReturnCode,
+		  (void *)&Length, sizeof(u32)))
+			Rtnval = -EFAULT;
+		else
+			Rtnval = -EINVAL;
+	} else if (!(*ppHeader = kmalloc(Length, GFP_KERNEL))) {
+		fwprintf((dev, HBA_FLAGS_DBG_ERROR_B,
+		  "aac_VerifyCSMIBuffer: Acquire Memory %u Failure",
+		  Length));
+		Length = CSMI_SAS_STATUS_INVALID_PARAMETER;
+		if (copy_to_user(
+		  (void __user *)&((PIOCTL_HEADER)arg)->ReturnCode,
+		  (void *)&Length, sizeof(u32)))
+			Rtnval = -EFAULT;
+		else
+			Rtnval = -ENOMEM;
+	} else if (copy_from_user((void *)*ppHeader, arg, Length)) {
+		fwprintf((dev, HBA_FLAGS_DBG_ERROR_B,
+		  "aac_VerifyCSMIBuffer: Acquire Content Failure"));
+		kfree(*ppHeader);
+		*ppHeader = NULL;
+		Length = CSMI_SAS_STATUS_INVALID_PARAMETER;
+		/* Will most probably fail */
+		Rtnval = copy_to_user(
+		  (void __user *)&((PIOCTL_HEADER)arg)->ReturnCode,
+		  (void *)&Length, sizeof(u32));
+		Rtnval = -EFAULT;
+	} else {
+		struct aac_dev * found = (struct aac_dev *)NULL;
+		list_for_each_entry(dev, &aac_devices, entry)
+			if (dev->id == (*ppHeader)->IOControllerNumber) {
+				found = dev;
+				break;
+			}
+		dev = found;
+		if (dev == (struct aac_dev *)NULL) {
+			dev = *pDev; /* Return to original host */
+			fwprintf((dev, HBA_FLAGS_DBG_ERROR_B,
+			  "aac_VerifyCSMIBuffer: Acquire %d Indexed Controller Failure",
+			  (*ppHeader)->IOControllerNumber));
+			kfree(*ppHeader);
+			*ppHeader = NULL;
+			Length = CSMI_SAS_STATUS_INVALID_PARAMETER;
+			if (copy_to_user(
+			  (void __user *)&((PIOCTL_HEADER)arg)->ReturnCode,
+			  (void *)&Length, sizeof(u32)))
+				Rtnval = -EFAULT;
+			else
+				Rtnval = -EINVAL;
+		} else {
+			(*ppHeader)->ReturnCode = CSMI_SAS_STATUS_SUCCESS;
+			*pDev = dev;
+			Rtnval = 0;
+		}
+	}
+
+	fwprintf((dev, HBA_FLAGS_DBG_FUNCTION_EXIT_B,
+	  "aac_VerifyCSMIBuffer: Exit, ReturnValue=%d",Rtnval));
+
+	return Rtnval;
+
+}
+
+
+/*
+ * Routine Description:
+ *	This routine will close the *ppHeader.
+ * Return Value:
+ *	0 - Success
+ *	!0 - Failure
+ */
+static inline int
+aac_CloseCSMIBuffer(
+	struct aac_dev * dev,
+	void __user * arg,
+	PIOCTL_HEADER pHeader)
+{
+	int Rtnval = 0;
+
+	fwprintf((dev, HBA_FLAGS_DBG_FUNCTION_ENTRY_B,
+	  "aac_CloseCSMIBuffer: Enter"));
+
+	if (pHeader) {
+		if (copy_to_user(arg, (void *)pHeader, pHeader->Length))
+			Rtnval = -EFAULT;
+		kfree (pHeader);
+	}
+
+	fwprintf((dev, HBA_FLAGS_DBG_FUNCTION_EXIT_B,
+	  "aac_CloseCSMIBuffer: Exit, ReturnValue=%d",Rtnval));
+
+	return Rtnval;
+
+}
+
+typedef struct aac_bus_info DIOCTL;
+typedef DIOCTL * PDIOCTL;
+/* IOCTL Functions */
+#define CsmiGetPhyInfo		0x0070
+#define CsmiSataSignature	0x0071
+
+typedef struct {
+	u32	Status;		/* ST_OK */
+	u32	ObjType;	
+	u32	MethodId;	/* unused */
+	u32	ObjectId;	/* unused */
+	u32	CtlCmd;		/* unused */
+} DIOCTLRESPONSE;
+typedef DIOCTLRESPONSE * PDIOCTLRESPONSE;
+
+#define EnhancedGetBusInfo	0x0000000C
+#define SCSI_MAX_PORTS	10
+#define CSS_BUS_TYPE_SATA 11
+#define CSS_BUS_TYPE_SAS	12
+typedef struct aac_enhanced_bus_info_response {
+	struct aac_bus_info_response BusInfo;
+	/* Enhancements */
+	u32	Version;
+	u32	BusType[SCSI_MAX_PORTS];
+	u8	NumPortsMapped[SCSI_MAX_PORTS];
+	u8	ReservedPad0[2];
+	u32	Reserved[17];
+} ENHANCED_GBI_CSS;
+
+/*
+ * Routine Description:
+ *	This routine is called to request the version information for the
+ *	hardware, firmware, and boot BIOS associated with a storage controller.
+ *
+ * Return Value:
+ *	Status value, to be returned by aac_HandleCSMI, and returned to
+ *	--> Must set CSMI status value in pHeader->ReturnCode.
+ */
+int
+aac_CSMIGetControllerConfig(
+	struct aac_dev * dev,
+	void __user * arg)
+{
+	int Rtnval;
+	PCSMI_SAS_CNTLR_CONFIG_BUFFER pControllerConfigBuffer;
+	PDIOCTL pIoctlInfo;
+	ENHANCED_GBI_CSS * EnhancedBusInfo;
+	struct fib * fibptr;
+	int status;
+
+	fwprintf((dev,
+	  HBA_FLAGS_DBG_FUNCTION_ENTRY_B | HBA_FLAGS_DBG_CSMI_COMMANDS_B,
+	  "aac_CSMIGetControllerConfig: Enter"));
+
+	/*
+	 * Verify buffer size. If buffer is too small, the error status will
+	 * be set for pHeader->ReturnCode in aac_VerifyCSMIBuffer.
+	 */
+	if ((Rtnval = aac_VerifyCSMIBuffer(&dev, arg,
+	  sizeof(CSMI_SAS_CNTLR_CONFIG_BUFFER),
+	  (PIOCTL_HEADER *)&pControllerConfigBuffer))) {
+		fwprintf((dev,
+		  HBA_FLAGS_DBG_FUNCTION_EXIT_B | HBA_FLAGS_DBG_CSMI_COMMANDS_B,
+		  "aac_CSMISTPPassThru: Exit, ReturnValue = %d",
+		  Rtnval));
+		return Rtnval;
+	}
+
+	pControllerConfigBuffer->Configuration.uBaseIoAddress = 0;
+	pControllerConfigBuffer->Configuration.BaseMemoryAddress.uHighPart
+	  = ((u64)dev->scsi_host_ptr->base) >> 32;
+	pControllerConfigBuffer->Configuration.BaseMemoryAddress.uLowPart
+	  = dev->scsi_host_ptr->base & 0xffffffff;
+	pControllerConfigBuffer->Configuration.uBoardID
+	  = (dev->pdev->subsystem_device << 16)
+	  + dev->pdev->subsystem_vendor;
+	/*
+	 * Slot number can be pulled from
+	 * dev->supplement_adapter_info->SlotNumber in later versions of
+	 * the firmware else we could choose to take Linux PCI device slot
+	 * number PCI_SLOT(dev->pdev->devfn) instead?
+	 */
+	if ((dev->supplement_adapter_info.Version < AAC_SIS_VERSION_V3)
+	 || (dev->supplement_adapter_info.SlotNumber == AAC_SIS_SLOT_UNKNOWN)) {
+		pControllerConfigBuffer->Configuration.usSlotNumber
+		  = SLOT_NUMBER_UNKNOWN;
+	} else {
+		pControllerConfigBuffer->Configuration.usSlotNumber
+		 = dev->supplement_adapter_info.SlotNumber;
+	}
+	pControllerConfigBuffer->Configuration.bControllerClass
+	  = CSMI_SAS_CNTLR_CLASS_HBA;
+	pControllerConfigBuffer->Configuration.bIoBusType
+	  = CSMI_SAS_BUS_TYPE_PCI;
+	pControllerConfigBuffer->Configuration.BusAddress.PciAddress.bBusNumber
+	  = dev->pdev->bus->number;
+	pControllerConfigBuffer->Configuration.BusAddress.PciAddress.bDeviceNumber
+	  = PCI_SLOT(dev->pdev->devfn);
+	pControllerConfigBuffer->Configuration.BusAddress.PciAddress.bFunctionNumber
+	  = PCI_FUNC(dev->pdev->devfn);
+	pControllerConfigBuffer->Configuration.szSerialNumber[0] = '\0';
+	if (dev->adapter_info.serial[0] != 0xBAD0)
+		sprintf(pControllerConfigBuffer->Configuration.szSerialNumber,
+		  "%x", dev->adapter_info.serial[0]);
+	/* Get Bus Type */
+	fibptr = fib_alloc(dev);
+	if (fibptr == NULL) {
+		pControllerConfigBuffer->Configuration.uControllerFlags
+		  = CSMI_SAS_CNTLR_SATA_RAID;
+	} else {
+		fib_init(fibptr);
+
+		pIoctlInfo = (PDIOCTL) fib_data(fibptr);
+		pIoctlInfo->Command = cpu_to_le32(VM_Ioctl);
+		pIoctlInfo->ObjType = cpu_to_le32(FT_DRIVE);
+		pIoctlInfo->MethodId = cpu_to_le32(1);
+		pIoctlInfo->ObjectId = 0;
+		pIoctlInfo->CtlCmd = cpu_to_le32(EnhancedGetBusInfo);
+
+		status = fib_send(ContainerCommand, fibptr,
+		  sizeof(*EnhancedBusInfo),
+		  FsaNormal, 1, 1, NULL, NULL);
+	
+		fib_complete(fibptr);
+	
+		EnhancedBusInfo = (struct aac_enhanced_bus_info_response *) pIoctlInfo;
+	
+		if (status < 0) {
+			pControllerConfigBuffer->Configuration.uControllerFlags
+			  = CSMI_SAS_CNTLR_SATA_RAID;
+		} else switch (EnhancedBusInfo->BusType[0]) {
+		case CSS_BUS_TYPE_SATA:
+			pControllerConfigBuffer->Configuration.uControllerFlags
+			  = CSMI_SAS_CNTLR_SATA_RAID;
+			break;
+		case CSS_BUS_TYPE_SAS:
+			pControllerConfigBuffer->Configuration.uControllerFlags
+			  = CSMI_SAS_CNTLR_SAS_RAID;
+			break;
+		default:
+			pControllerConfigBuffer->Configuration.uControllerFlags
+			  = 0;
+			break;
+		}
+		fib_free(fibptr);
+	}
+
+	pControllerConfigBuffer->Configuration.usBIOSBuildRevision
+	  = cpu_to_le16(le32_to_cpu(dev->adapter_info.biosbuild));
+	pControllerConfigBuffer->Configuration.usBIOSMajorRevision
+	  = cpu_to_le16(le32_to_cpu(dev->adapter_info.biosrev) >> 24);
+	pControllerConfigBuffer->Configuration.usBIOSMinorRevision
+	  = cpu_to_le16((le32_to_cpu(dev->adapter_info.biosrev) >> 16) & 0xff);
+	pControllerConfigBuffer->Configuration.usBIOSReleaseRevision
+	  = cpu_to_le16(le32_to_cpu(dev->adapter_info.biosrev) & 0xff);
+	pControllerConfigBuffer->Configuration.usBuildRevision
+	  = cpu_to_le16(le32_to_cpu(dev->adapter_info.kernelbuild));
+	pControllerConfigBuffer->Configuration.usMajorRevision
+	  = cpu_to_le16(le32_to_cpu(dev->adapter_info.kernelrev) >> 24);
+	pControllerConfigBuffer->Configuration.usMinorRevision
+	  = cpu_to_le16((le32_to_cpu(dev->adapter_info.kernelrev) >> 16) & 0xff);
+	pControllerConfigBuffer->Configuration.usReleaseRevision
+	  = cpu_to_le16(le32_to_cpu(dev->adapter_info.kernelrev) & 0xff);
+	pControllerConfigBuffer->Configuration.usRromBIOSBuildRevision = 0;
+	pControllerConfigBuffer->Configuration.usRromBIOSMajorRevision = 0;
+	pControllerConfigBuffer->Configuration.usRromBIOSMinorRevision = 0;
+	pControllerConfigBuffer->Configuration.usRromBIOSReleaseRevision = 0;
+	pControllerConfigBuffer->Configuration.usRromBuildRevision = 0;
+	pControllerConfigBuffer->Configuration.usRromMajorRevision = 0;
+	pControllerConfigBuffer->Configuration.usRromMinorRevision = 0;
+	pControllerConfigBuffer->Configuration.usRromReleaseRevision = 0;
+
+	Rtnval = aac_CloseCSMIBuffer(dev, arg,
+	  (PIOCTL_HEADER)pControllerConfigBuffer);
+
+	fwprintf((dev,
+	  HBA_FLAGS_DBG_FUNCTION_EXIT_B | HBA_FLAGS_DBG_CSMI_COMMANDS_B,
+	  "aac_CSMIGetControllerConfig: Exit, ReturnValue=%d, ReturnCode=%x",
+	  Rtnval, pControllerConfigBuffer->IoctlHeader.ReturnCode));
+
+	return Rtnval;
+
+}
+
+
+/*
+ * Routine Description:
+ *	This routine is called to request the current status of the controller.
+ *
+ * Return Value:
+ *	Status value, to be returned by aac_HandleCSMI, and returned to the OS.
+ *	--> Must set CSMI status value in pHeader->ReturnCode.
+ */
+int
+aac_CSMIGetControllerStatus(
+	struct aac_dev * dev,
+	void __user * arg)
+{
+	int Rtnval;
+	PCSMI_SAS_CNTLR_STATUS_BUFFER pStatusBuffer;
+
+	fwprintf((dev,
+	  HBA_FLAGS_DBG_FUNCTION_ENTRY_B | HBA_FLAGS_DBG_CSMI_COMMANDS_B,
+	  "aac_CSMIGetControllerStatus: Enter"));
+
+	/*
+	 * Verify buffer size. If buffer is too small, the error status will
+	 * be set for pHeader->ReturnCode in aac_VerifyCSMIBuffer.
+	 */
+	if ((Rtnval = aac_VerifyCSMIBuffer(&dev, arg,
+	  sizeof(CSMI_SAS_CNTLR_STATUS_BUFFER),
+	  (PIOCTL_HEADER *)&pStatusBuffer))) {
+		fwprintf((dev,
+		  HBA_FLAGS_DBG_FUNCTION_EXIT_B | HBA_FLAGS_DBG_CSMI_COMMANDS_B,
+		  "aac_CSMIGetControllerStatus: Exit, ReturnValue=%d",
+		  Rtnval));
+		return Rtnval;
+	}
+
+	/*
+	 * Determine and set adapter state
+	 */
+	switch (aac_adapter_check_health(dev)) {
+	case 0:
+		pStatusBuffer->Status.uStatus = CSMI_SAS_CNTLR_STATUS_GOOD;
+		break;
+	case -1:
+	case -2:
+	case -3:
+		pStatusBuffer->Status.uStatus = CSMI_SAS_CNTLR_STATUS_FAILED;
+		break;
+	default:
+		pStatusBuffer->Status.uStatus = CSMI_SAS_CNTLR_STATUS_OFFLINE;
+		pStatusBuffer->Status.uOfflineReason
+		  = CSMI_SAS_OFFLINE_REASON_NO_REASON;
+	}
+
+	Rtnval = aac_CloseCSMIBuffer(dev, arg, (PIOCTL_HEADER)pStatusBuffer);
+
+	fwprintf((dev,
+	  HBA_FLAGS_DBG_FUNCTION_EXIT_B | HBA_FLAGS_DBG_CSMI_COMMANDS_B,
+	  "aac_CSMIGetControllerStatus: Exit, ReturnValue=%d, ReturnCode=%x",
+	  Rtnval, pStatusBuffer->IoctlHeader.ReturnCode));
+
+	return Rtnval;
+
+}
+
+
+/*
+ * Routine Description:
+ *	This routine is called to request information for a specified RAID set
+ *	on a controller that supports RAID.
+ * Return Value:
+ *	Status value, to be returned by aac_HandleCSMI, and returned to the OS
+ *	--> Must set CSMI status value in pHeader->ReturnCode.
+ */
+int
+aac_CSMIGetRAIDConfig(
+	struct aac_dev * dev,
+	void __user * arg)
+{
+	int Rtnval;
+	PCSMI_SAS_RAID_CONFIG_BUFFER pRaidConfigBuffer;
+	typedef struct {
+		u32	command;
+		u32	type;
+		u32	cid;
+		u32	parm1;
+		u32	parm2;
+		u32	uid;
+		u32	offset;
+		u32	parm5;
+	} CONTAINER;
+	CONTAINER * ct;
+#	define CT_PACKET_SIZE (sizeof(((struct hw_fib *)NULL)->data)-(sizeof(u32)*12))
+#	define CT_CONTINUE_DATA		83
+#	define CT_STOP_DATA		84
+#	define CT_GET_RAID_CONFIG	215
+	typedef struct {
+		u32	response;
+		u32	type;
+		u32	status;
+		u32	count;
+		u32	parm2;
+		u32	uid;
+		u32	parm4;
+		u32	parm5;
+		u32	data[1];
+	} CONTAINERRESPONSE;
+	CONTAINERRESPONSE * ctr;
+#	define CT_CONTINUATION_ERROR 199
+	u16 bufferOffset = 0;
+	u16 LoopCount = 0;
+	unsigned long uniqueID = 0, sizeLeft = 0;
+	unsigned char *DestinationBuffer;
+	struct fib * fibptr;
+	int status;
+
+	fwprintf((dev,
+	  HBA_FLAGS_DBG_FUNCTION_ENTRY_B | HBA_FLAGS_DBG_CSMI_COMMANDS_B,
+	  "aac_CSMIGetRAIDConfig: Enter"));
+
+	/*
+	 * Verify buffer size. If buffer is too small, the error status will
+	 * be set for pHeader->ReturnCode in aac_VerifyCSMIBuffer.
+	 */
+	if ((Rtnval = aac_VerifyCSMIBuffer(&dev, arg,
+	  sizeof(CSMI_SAS_RAID_CONFIG_BUFFER),
+	  (PIOCTL_HEADER *)&pRaidConfigBuffer))) {
+		fwprintf((dev,
+		  HBA_FLAGS_DBG_FUNCTION_EXIT_B | HBA_FLAGS_DBG_CSMI_COMMANDS_B,
+		  "aac_CSMIGetRAIDConfig: Exit, ReturnValue = %d",
+		  Rtnval));
+		return Rtnval;
+	}
+
+	/*
+	 * Make sure the requested container number exists
+	 */
+	if ((pRaidConfigBuffer->Configuration.uRaidSetIndex == 0)
+	 || (pRaidConfigBuffer->Configuration.uRaidSetIndex
+	  > dev->maximum_num_containers)
+	 || !dev->fsa_dev
+	 || (!dev->
+	  fsa_dev[pRaidConfigBuffer->Configuration.uRaidSetIndex-1].valid)) {
+		fwprintf((dev, HBA_FLAGS_DBG_ERROR_B,
+		  ((pRaidConfigBuffer->Configuration.uRaidSetIndex
+		    >= dev->maximum_num_containers)
+		      ? "aac_CSMIGetRAIDConfig: RaidIndex=%d > Maximum=%d"
+		      : "aac_CSMIGetRAIDConfig: RaidIndex=%d invalid"),
+		  pRaidConfigBuffer->Configuration.uRaidSetIndex,
+		  dev->maximum_num_containers));
+
+		/*
+		 * Indicate the RaidSetIndex is invalid
+		 */
+		pRaidConfigBuffer->IoctlHeader.ReturnCode
+		  = CSMI_SAS_RAID_SET_OUT_OF_RANGE;
+		Rtnval = aac_CloseCSMIBuffer(dev, arg,
+		  (PIOCTL_HEADER)pRaidConfigBuffer);
+
+		fwprintf((dev,
+		  HBA_FLAGS_DBG_FUNCTION_EXIT_B | HBA_FLAGS_DBG_CSMI_COMMANDS_B,
+		  "aac_CSMIGetRAIDConfig: Exit, ReturnValue=%d,"
+		  " ReturnCode=CSMI_SAS_RAID_SET_OUT_OF_RANGE",
+		  Rtnval));
+		return Rtnval;
+	}
+
+	fibptr = fib_alloc(dev);
+	if (fibptr == NULL) {
+		pRaidConfigBuffer->IoctlHeader.ReturnCode
+		  = CSMI_SAS_STATUS_FAILED;
+		Rtnval = aac_CloseCSMIBuffer(dev, arg,
+		  (PIOCTL_HEADER)pRaidConfigBuffer);
+		fwprintf((dev,
+		  HBA_FLAGS_DBG_FUNCTION_EXIT_B | HBA_FLAGS_DBG_CSMI_COMMANDS_B,
+		  "aac_CSMIGetRAIDConfig: Exit, ReturnValue=%d,"
+		  " ReturnCode=CSMI_SAS_STATUS_FAILED",
+		  Rtnval));
+		return Rtnval;
+	}
+	fib_init (fibptr);
+	fibptr->hw_fib->header.SenderSize = cpu_to_le16(sizeof(struct hw_fib));
+
+	/*
+	 * Setup and send CT_GET_RAID_CONFIG command to FW to
+	 * fill in IOCTL buffer
+	 */
+	ct = (CONTAINER *) fib_data(fibptr);
+	ct->command = cpu_to_le32(VM_ContainerConfig);
+	ct->type = cpu_to_le32(CT_GET_RAID_CONFIG);
+ 	/* Container number */
+	ct->cid = cpu_to_le32(pRaidConfigBuffer->Configuration.uRaidSetIndex-1);
+
+	status = fib_send(ContainerCommand, fibptr, sizeof(CONTAINER),
+	  FsaNormal, 1, 1, NULL, NULL);
+	fib_complete(fibptr);
+
+	if (status < 0) {
+		fib_free(fibptr);
+		pRaidConfigBuffer->IoctlHeader.ReturnCode
+		  = CSMI_SAS_STATUS_FAILED;
+		Rtnval = aac_CloseCSMIBuffer(dev, arg,
+		  (PIOCTL_HEADER)pRaidConfigBuffer);
+		fwprintf((dev,
+		  HBA_FLAGS_DBG_FUNCTION_EXIT_B | HBA_FLAGS_DBG_CSMI_COMMANDS_B,
+		  "aac_CSMIGetRAIDConfig: Exit, ReturnValue=%d,"
+		  " ReturnCode=CSMI_SAS_STATUS_FAILED",
+		  Rtnval));
+		return Rtnval;
+	}
+
+	ctr = (CONTAINERRESPONSE *) ct;
+	/*
+	 * Check for error conditions
+	 */
+	if (ctr->status == cpu_to_le32(CT_CONTINUATION_ERROR)) {
+		fib_free(fibptr);
+		/*
+		 * Indicate failure for this IOCTL
+		 */
+		pRaidConfigBuffer->IoctlHeader.ReturnCode
+		  = CSMI_SAS_STATUS_FAILED;
+		Rtnval = aac_CloseCSMIBuffer(dev, arg,
+		  (PIOCTL_HEADER)pRaidConfigBuffer);
+		fwprintf((dev,
+		  HBA_FLAGS_DBG_FUNCTION_EXIT_B | HBA_FLAGS_DBG_CSMI_COMMANDS_B,
+		  "aac_CSMIGetRAIDConfig: Exit, ReturnValue=%d,"
+		  " ReturnCode=CSMI_SAS_STATUS_FAILED",
+		  Rtnval));
+		return Rtnval;
+	}
+
+	/*
+	 * Grab the total size of data to be returned so we can loop through
+	 * and get it all
+	 */
+	sizeLeft = le32_to_cpu(ctr->count);
+
+	/*
+	 * Get Unique ID for this continuation session
+	 */
+	uniqueID = ctr->uid;
+
+	/*
+	 * If there is more data, continue looping until we're done
+	 */
+	DestinationBuffer = (unsigned char *)(&pRaidConfigBuffer->Configuration);
+
+	while (sizeLeft) {
+		fib_init (fibptr);
+		fibptr->hw_fib->header.SenderSize
+		  = cpu_to_le16(sizeof(struct hw_fib));
+
+		ct->command = cpu_to_le32(VM_ContainerConfig);
+		ct->type = cpu_to_le32(CT_CONTINUE_DATA);
+		ct->uid = uniqueID;
+		ct->offset = cpu_to_le32(LoopCount);
+
+		status = fib_send(ContainerCommand, fibptr, sizeof(CONTAINER),
+		  FsaNormal, 1, 1, NULL, NULL);
+		fib_complete(fibptr);
+
+		if (status < 0) {
+			/*
+			 * Indicate failure for this IOCTL
+			 */
+			pRaidConfigBuffer->IoctlHeader.ReturnCode
+			  = CSMI_SAS_STATUS_FAILED;
+			break;
+		}
+
+		/*
+		 * Check for error conditions
+		 */
+		if (ctr->status == cpu_to_le32(CT_CONTINUATION_ERROR)) {
+			/*
+			 * Indicate failure for this IOCTL
+			 */
+			pRaidConfigBuffer->IoctlHeader.ReturnCode
+			  = CSMI_SAS_STATUS_FAILED;
+			break;
+		}
+
+		/*
+		 * No error so copy the remaining data
+		 */
+		/*
+		 * Move the full packet size and update for the next loop
+		 */
+		if (sizeLeft >= CT_PACKET_SIZE) {
+			memcpy(DestinationBuffer, ctr->data, CT_PACKET_SIZE);
+
+			/*
+			 * Set current offset in buffer, so we can continue
+			 * copying data.
+			 */
+			bufferOffset += CT_PACKET_SIZE;
+			DestinationBuffer += CT_PACKET_SIZE;
+			sizeLeft -= CT_PACKET_SIZE;
+			++LoopCount;
+		}
+
+		/*
+		 * last transfer; is less than CT_PACKET_SIZE, so just use
+		 * sizeLeft
+		 */
+		else {
+			memcpy(DestinationBuffer, ctr->data, sizeLeft);
+			sizeLeft = 0;
+		}
+	}
+
+	/*
+	 * At this point, we have copied back
+	 * all of the data. Send a STOP command
+	 * to finish things off.
+	 */
+	fib_init (fibptr);
+
+	ct->command = cpu_to_le32(VM_ContainerConfig);
+	ct->type = cpu_to_le32(CT_STOP_DATA);
+	ct->uid = uniqueID;
+
+	fib_send(ContainerCommand, fibptr, sizeof(CONTAINER),
+	  FsaNormal, 1, 1, NULL, NULL);
+	fib_complete(fibptr);
+	fib_free(fibptr);
+
+	Rtnval = aac_CloseCSMIBuffer(dev, arg, (PIOCTL_HEADER)pRaidConfigBuffer);
+	fwprintf((dev,
+	  HBA_FLAGS_DBG_FUNCTION_EXIT_B | HBA_FLAGS_DBG_CSMI_COMMANDS_B,
+	  "aac_CSMIGetRAIDConfig: Exit, ReturnValue=%d, ReturnCode=%x",
+	  Rtnval, pRaidConfigBuffer->IoctlHeader.ReturnCode));
+
+	return Rtnval;
+
+}
+
+
+/*
+ * Routine Description:
+ *	This routine is called to request information on the number of RAID
+ *	volumes and number of physical drives on a controller.
+ * Return Value:
+ *	Status value, to be returned by aac_HandleCSMI, and returned to the OS.
+ *	--> Must set CSMI status value in pHeader->ReturnCode.
+ */
+int
+aac_CSMIGetRAIDInfo(
+	struct aac_dev * dev,
+	void __user * arg)
+{
+	int Rtnval;
+	PCSMI_SAS_RAID_INFO_BUFFER pRaidInfoBuffer;
+	u16 NumRaidSets = 0;
+	int lcv;
+	PDIOCTL pIoctlInfo;
+	ENHANCED_GBI_CSS * EnhancedBusInfo;
+	struct fib * fibptr;
+	int status;
+
+	fwprintf((dev,
+	  HBA_FLAGS_DBG_FUNCTION_ENTRY_B | HBA_FLAGS_DBG_CSMI_COMMANDS_B,
+	  "aac_CSMIGetRAIDInfo: Enter"));
+
+	/*
+	 * Verify buffer size. If buffer is too small, the error status will
+	 * be set for pHeader->ReturnCode in aac_VerifyCSMIBuffer.
+	 */
+	if ((Rtnval = aac_VerifyCSMIBuffer(&dev, arg,
+	  sizeof(CSMI_SAS_RAID_INFO_BUFFER),
+	  (PIOCTL_HEADER *)&pRaidInfoBuffer))) {
+		fwprintf((dev,
+		  HBA_FLAGS_DBG_FUNCTION_EXIT_B | HBA_FLAGS_DBG_CSMI_COMMANDS_B,
+		  "aac_CSMIGetRAIDInfo: Exit, ReturnValue=%d",
+		  Rtnval));
+		return Rtnval;
+	}
+
+	/*
+	 * Traverse the container list and count all containers
+	 */
+	if (dev->fsa_dev)
+	for (lcv = 0; lcv < dev->maximum_num_containers; lcv++)
+		if (dev->fsa_dev[lcv].valid)
+			NumRaidSets++;
+	pRaidInfoBuffer->Information.uNumRaidSets = NumRaidSets;
+
+	/*
+	 * Find the absolute maximum number of physical drives that can make
+	 * up a container. It's pretty ambiquous so we'll default it to the
+	 * Falcon maximum number of drives supported and then try to figure
+	 * out from firmware the max number of drives we can attach to this
+	 * controller.
+	 */
+	pRaidInfoBuffer->Information.uMaxDrivesPerSet = 128;
+	fibptr = fib_alloc(dev);
+	if (fibptr) {
+		fib_init(fibptr);
+
+		pIoctlInfo = (PDIOCTL) fib_data(fibptr);
+		pIoctlInfo->Command = cpu_to_le32(VM_Ioctl);
+		pIoctlInfo->ObjType = cpu_to_le32(FT_DRIVE);
+		pIoctlInfo->MethodId = cpu_to_le32(1);
+		pIoctlInfo->ObjectId = 0;
+		pIoctlInfo->CtlCmd = cpu_to_le32(EnhancedGetBusInfo);
+
+		status = fib_send(ContainerCommand, fibptr,
+		  sizeof(*EnhancedBusInfo),
+		  FsaNormal, 1, 1, NULL, NULL);
+	
+		fib_complete(fibptr);
+	
+		EnhancedBusInfo = (struct aac_enhanced_bus_info_response *) pIoctlInfo;
+	
+		if (status >= 0) switch (EnhancedBusInfo->BusType[0]) {
+		case CSS_BUS_TYPE_SATA:
+			pRaidInfoBuffer->Information.uMaxDrivesPerSet
+			  = dev->supplement_adapter_info.MaxNumberPorts;
+			break;
+		case CSS_BUS_TYPE_SAS:
+			pRaidInfoBuffer->Information.uMaxDrivesPerSet = 128;
+			break;
+		default:
+			pRaidInfoBuffer->Information.uMaxDrivesPerSet
+			  = dev->maximum_num_physicals
+			  * dev->maximum_num_channels;
+			break;
+		}
+		fib_free(fibptr);
+	}
+
+	Rtnval = aac_CloseCSMIBuffer(dev, arg, (PIOCTL_HEADER)pRaidInfoBuffer);
+
+	fwprintf((dev,
+	  HBA_FLAGS_DBG_FUNCTION_EXIT_B | HBA_FLAGS_DBG_CSMI_COMMANDS_B,
+	  "aac_CSMIGetRAIDInfo: Exit, ReturnValue=%d, ReturnCode=%x",
+	  Rtnval, pRaidInfoBuffer->IoctlHeader.ReturnCode));
+
+	return Rtnval;
+}
+
+
+/*
+ * Routine Description:
+ *	This routine is called to request information about physical
+ *	characteristics and interconnect to the SATA or SAS domain.
+ * Return Value:
+ *	Status value, to be returned by aac_HandleCSMI, and returned to the OS.
+ *	--> Must set CSMI status value in pHeader->ReturnCode.
+ */
+int
+aac_CSMIGetPhyInfo(
+	struct aac_dev * dev,
+	void __user * arg)
+{
+	int Rtnval;
+	PCSMI_SAS_PHY_INFO_BUFFER pPhyInfoBuffer;
+	PDIOCTL pIoctlInfo;
+	PDIOCTLRESPONSE pIoctlResp;
+	struct fib * fibptr;
+	int status;
+	u32 Length;
+
+	fwprintf((dev,
+	  HBA_FLAGS_DBG_FUNCTION_ENTRY_B | HBA_FLAGS_DBG_CSMI_COMMANDS_B,
+	  "aac_CSMIGetPhyInfo: Enter scsi%d",
+	  dev->scsi_host_ptr->host_no));
+
+#if 0
+	/* Command can not be issued to the adapter */
+	if (!(dev->supplement_adapter_info.FeatureBits
+	 & le32_to_cpu(AAC_FEATURE_FALCON))) {
+		Rtnval = -ENOENT;
+		fwprintf((dev,
+		  HBA_FLAGS_DBG_FUNCTION_EXIT_B | HBA_FLAGS_DBG_CSMI_COMMANDS_B,
+		  "aac_CSMIGetPhyInfo: Exit, ReturnValue=-ENOENT",
+		  Rtnval));
+		return Rtnval;
+	}
+#endif
+	/*
+	 * Verify buffer size. If buffer is too small, the error status will
+	 * be set for pHeader->ReturnCode in aac_VerifyCSMIBuffer.
+	 */
+	if ((Rtnval = aac_VerifyCSMIBuffer(&dev, arg,
+	  sizeof(CSMI_SAS_PHY_INFO_BUFFER),
+	  (PIOCTL_HEADER *)&pPhyInfoBuffer))) {
+		fwprintf((dev,
+		  HBA_FLAGS_DBG_FUNCTION_EXIT_B | HBA_FLAGS_DBG_CSMI_COMMANDS_B,
+		  "aac_CSMIGetPhyInfo: Exit, ReturnValue=%d",
+		  Rtnval));
+		return Rtnval;
+	}
+
+	/* TODO : Figure out the correct size to send or do a continue fib */
+
+	fibptr = fib_alloc(dev);
+	if (fibptr == NULL) {
+		pPhyInfoBuffer->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+		Rtnval = aac_CloseCSMIBuffer(dev, arg,
+		  (PIOCTL_HEADER)pPhyInfoBuffer);
+		fwprintf((dev,
+		  HBA_FLAGS_DBG_FUNCTION_EXIT_B | HBA_FLAGS_DBG_CSMI_COMMANDS_B,
+		  "aac_CSMIGetPhyInfo: Exit, ReturnValue=%d,"
+		  " ReturnCode=CSMI_SAS_STATUS_FAILED",
+		  Rtnval));
+		return Rtnval;
+	}
+	fib_init(fibptr);
+	fibptr->hw_fib->header.SenderSize = cpu_to_le16(sizeof(struct hw_fib));
+
+	pIoctlInfo = (PDIOCTL) fib_data(fibptr);
+	pIoctlInfo->Command = cpu_to_le32(VM_Ioctl);
+	pIoctlInfo->ObjType = cpu_to_le32(FT_DRIVE);
+	pIoctlInfo->MethodId = cpu_to_le32(1);
+	pIoctlInfo->ObjectId = 0;
+	pIoctlInfo->CtlCmd = cpu_to_le32(CsmiGetPhyInfo);
+	Length = pPhyInfoBuffer->IoctlHeader.Length;
+	/* Issue a Larger FIB? */
+	if (Length > (sizeof(struct hw_fib) - sizeof(struct aac_fibhdr)
+					- sizeof(*pIoctlInfo))) {
+		Length = sizeof(struct hw_fib) - sizeof(struct aac_fibhdr)
+		       - sizeof(*pIoctlInfo);
+		pPhyInfoBuffer->IoctlHeader.Length = Length;
+	}
+	memcpy(((char *)pIoctlInfo) + sizeof(*pIoctlInfo),
+	  pPhyInfoBuffer, Length);
+
+	status = fib_send(ContainerCommand, fibptr,
+	  Length + sizeof(*pIoctlInfo),
+	  FsaNormal, 1, 1, NULL, NULL);
+
+	fib_complete(fibptr);
+
+	if (status < 0) {
+		fib_free(fibptr);
+		pPhyInfoBuffer->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+		Rtnval = aac_CloseCSMIBuffer(dev, arg,
+		  (PIOCTL_HEADER)pPhyInfoBuffer);
+		fwprintf((dev,
+		  HBA_FLAGS_DBG_FUNCTION_EXIT_B | HBA_FLAGS_DBG_CSMI_COMMANDS_B,
+		  "aac_CSMIGetPhyInfo: Exit, ReturnValue=%d,"
+		  " ReturnCode=CSMI_SAS_STATUS_FAILED",
+		  Rtnval));
+		return Rtnval;
+	}
+
+	pIoctlResp = (PDIOCTLRESPONSE) pIoctlInfo;
+
+	/*
+	 * Copy back the filled out buffer to complete the
+	 * request
+	 */
+	memcpy(pPhyInfoBuffer, ((char *)pIoctlResp) + sizeof(*pIoctlResp),
+	  Length);
+
+	fib_free(fibptr);
+
+	Rtnval = aac_CloseCSMIBuffer(dev, arg, (PIOCTL_HEADER)pPhyInfoBuffer);
+
+	fwprintf((dev,
+	  HBA_FLAGS_DBG_FUNCTION_EXIT_B | HBA_FLAGS_DBG_CSMI_COMMANDS_B,
+	  "aac_CSMIGetPhyInfo: Exit, Rtnval, ReturnCode=%x",
+	  Rtnval, pPhyInfoBuffer->IoctlHeader.ReturnCode));
+
+	return Rtnval;
+
+}
+
+
+/*
+ * Routine Description:
+ *	This routine is called to obtain the initial SATA signature (the
+ *	initial Register Device to the Host FIS) from a directly attached SATA
+ *	device.
+ * Return Value:
+ *	Status value, to be returned by aac_HandleCSMI, and returned to the OS.
+ *	--> Must set CSMI status value in pHeader->ReturnCode.
+ */
+int
+aac_CSMIGetSATASignature(
+	struct aac_dev * dev,
+	void __user * arg)
+{
+	int Rtnval;
+	PCSMI_SAS_SATA_SIGNATURE_BUFFER pSataSignatureBuffer;
+	PDIOCTL pIoctlInfo;
+	PDIOCTLRESPONSE pIoctlResp;
+	struct fib * fibptr;
+	int status;
+
+	fwprintf((dev,
+	  HBA_FLAGS_DBG_FUNCTION_ENTRY_B | HBA_FLAGS_DBG_CSMI_COMMANDS_B,
+	  "aac_CSMIGetSATASignature: Enter scsi%d",
+	  dev->scsi_host_ptr->host_no));
+
+	/*
+	 * Verify buffer size. If buffer is too small, the error status will
+	 * be set for pHeader->ReturnCode in aac_VerifyCSMIBuffer.
+	 */
+	if ((Rtnval = aac_VerifyCSMIBuffer(&dev, arg,
+	  sizeof(CSMI_SAS_SATA_SIGNATURE_BUFFER),
+	  (PIOCTL_HEADER *)&pSataSignatureBuffer))) {
+		fwprintf((dev,
+		  HBA_FLAGS_DBG_FUNCTION_EXIT_B | HBA_FLAGS_DBG_CSMI_COMMANDS_B,
+		  "aac_CSMIGetSATASignature: Exit, ReturnValue=%d",
+		  Rtnval));
+		return Rtnval;
+	}
+
+	pSataSignatureBuffer->IoctlHeader.ReturnCode = CSMI_SAS_NO_SATA_DEVICE;
+
+	fibptr = fib_alloc(dev);
+	if (fibptr == NULL) {
+		pSataSignatureBuffer->IoctlHeader.ReturnCode
+		  = CSMI_SAS_STATUS_FAILED;
+		Rtnval = aac_CloseCSMIBuffer(dev, arg,
+		  (PIOCTL_HEADER)pSataSignatureBuffer);
+		fwprintf((dev,
+		  HBA_FLAGS_DBG_FUNCTION_EXIT_B | HBA_FLAGS_DBG_CSMI_COMMANDS_B,
+		  "aac_CSMIGetSATASignature: Exit, ReturnValue=%d,"
+		  " ReturnCode=CSMI_SAS_STATUS_FAILED",
+		  Rtnval));
+		return Rtnval;
+	}
+	fib_init(fibptr);
+
+	pIoctlInfo = (PDIOCTL) fib_data(fibptr);
+	pIoctlInfo->Command = cpu_to_le32(VM_Ioctl);
+	pIoctlInfo->ObjType = cpu_to_le32(FT_DRIVE);
+	pIoctlInfo->MethodId = cpu_to_le32(1);
+	pIoctlInfo->ObjectId = 0;
+	pIoctlInfo->CtlCmd = cpu_to_le32(CsmiSataSignature);
+	memcpy(((char *)pIoctlInfo) + sizeof(*pIoctlInfo),
+	  pSataSignatureBuffer,sizeof(CSMI_SAS_SATA_SIGNATURE_BUFFER));
+
+	status = fib_send(ContainerCommand, fibptr, sizeof(*pIoctlInfo)
+	  - sizeof(u32) + sizeof(CSMI_SAS_SATA_SIGNATURE_BUFFER), FsaNormal,
+	  1, 1, NULL, NULL);
+
+	fib_complete(fibptr);
+
+	if (status < 0) {
+		fib_free(fibptr);
+		pSataSignatureBuffer->IoctlHeader.ReturnCode
+		  = CSMI_SAS_STATUS_FAILED;
+		Rtnval = aac_CloseCSMIBuffer(dev, arg,
+		  (PIOCTL_HEADER)pSataSignatureBuffer);
+		fwprintf((dev,
+		  HBA_FLAGS_DBG_FUNCTION_EXIT_B | HBA_FLAGS_DBG_CSMI_COMMANDS_B,
+		  "aac_CSMIGetSATASignature: Exit, ReturnValue=%d,"
+		  " ReturnCode=CSMI_SAS_STATUS_FAILED",
+		  Rtnval));
+		return Rtnval;
+	}
+
+	pIoctlResp = (PDIOCTLRESPONSE) pIoctlInfo;
+
+	/*
+	 * Copy back the filled out buffer to complete the
+	 * request
+	 */
+	memcpy(pSataSignatureBuffer,
+	  ((char *)pIoctlResp) + sizeof(*pIoctlResp),
+	  sizeof(CSMI_SAS_SATA_SIGNATURE_BUFFER));
+
+	fib_free(fibptr);
+
+	/*
+	 * Indicate success for this IOCTL
+	 *	pSataSignatureBuffer->IoctlHeader.ReturnCode
+	 *		= CSMI_SAS_STATUS_SUCCESS;
+	 * is set by the Firmware Response.
+	 */
+	Rtnval = aac_CloseCSMIBuffer(dev, arg,
+	  (PIOCTL_HEADER)pSataSignatureBuffer);
+
+	fwprintf((dev,
+	  HBA_FLAGS_DBG_FUNCTION_EXIT_B | HBA_FLAGS_DBG_CSMI_COMMANDS_B,
+	  "aac_CSMIGetSATASignature: Exit, ReturnValue=%d,"
+	  " ReturnCode=CSMI_SAS_STATUS_SUCCESS",
+	  Rtnval));
+
+	return Rtnval;
+
+}
+
+
+/*
+ * Routine Description:
+ *	This routine is called to return the driver information.
+ * Return Value:
+ *	Status value, to be returned by aac_HandleCSMI, and returned to the OS.
+ *	--> Must set CSMI status value in pHeader->ReturnCode.
+ */
+int
+aac_CSMIGetDriverInfo(
+	struct aac_dev * dev,
+	void __user * arg)
+{
+	int Rtnval;
+	PCSMI_SAS_DRIVER_INFO_BUFFER pDriverInfoBuffer;
+	char * driver_version = aac_driver_version;
+
+	fwprintf((dev,
+	  HBA_FLAGS_DBG_FUNCTION_ENTRY_B | HBA_FLAGS_DBG_CSMI_COMMANDS_B,
+	  "aac_CSMIGetDriverInfo: Enter"));
+
+	/*
+	 * Verify buffer size. If buffer is too small, the error status will
+	 * be set for pHeader->ReturnCode in aac_VerifyCSMIBuffer.
+	 */
+	if ((Rtnval = aac_VerifyCSMIBuffer(&dev, arg,
+	  sizeof(CSMI_SAS_DRIVER_INFO_BUFFER),
+	  (PIOCTL_HEADER *)&pDriverInfoBuffer))) {
+		fwprintf((dev,
+		  HBA_FLAGS_DBG_FUNCTION_EXIT_B | HBA_FLAGS_DBG_CSMI_COMMANDS_B,
+		  "aac_CSMIGetDriverInfo: Exit, ReturnValue=%d",
+		  Rtnval));
+		return Rtnval;
+	}
+
+	/*
+	 * Fill in the information member of the pDriverInfoBuffer
+	 * structure.
+	 */
+
+	/*
+	 * Driver name
+	 */
+	strncpy(pDriverInfoBuffer->Information.szName,
+	  (dev->scsi_host_ptr->hostt->info
+	    ? dev->scsi_host_ptr->hostt->info(dev->scsi_host_ptr)
+	    : dev->scsi_host_ptr->hostt->name),
+	  sizeof(pDriverInfoBuffer->Information.szName));
+
+	/*
+	 * Driver Description
+	 */
+	sprintf(pDriverInfoBuffer->Information.szDescription,
+	  "Adaptec %s driver",
+	  dev->scsi_host_ptr->hostt->name);
+
+	/*
+	 * Set version number information
+	 */
+	pDriverInfoBuffer->Information.usMajorRevision
+	  = cpu_to_le16(simple_strtol(driver_version, &driver_version, 10));
+	pDriverInfoBuffer->Information.usMinorRevision
+	  = cpu_to_le16(simple_strtol(driver_version + 1, &driver_version, 10));
+#if (defined(AAC_DRIVER_BUILD))
+	pDriverInfoBuffer->Information.usBuildRevision = cpu_to_le16(AAC_DRIVER_BUILD);
+#else
+	pDriverInfoBuffer->Information.usBuildRevision = cpu_to_le16(9999);
+#endif
+	pDriverInfoBuffer->Information.usReleaseRevision
+	  = cpu_to_le16(simple_strtol(driver_version + 1, NULL, 10));
+	pDriverInfoBuffer->Information.usCSMIMajorRevision
+	  = cpu_to_le16(CSMI_MAJOR_REVISION);
+	pDriverInfoBuffer->Information.usCSMIMinorRevision
+	  = cpu_to_le16(CSMI_MINOR_REVISION);
+
+	Rtnval = aac_CloseCSMIBuffer(dev, arg, (PIOCTL_HEADER)pDriverInfoBuffer);
+	fwprintf((dev,
+	  HBA_FLAGS_DBG_FUNCTION_EXIT_B | HBA_FLAGS_DBG_CSMI_COMMANDS_B,
+	  "aac_CSMIGetDriverInfo: Exit, ReturnValue=%d, ReturnCode=%x",
+	  Rtnval, pDriverInfoBuffer->IoctlHeader.ReturnCode));
+
+	return Rtnval;
+
+}
+
+
+
+/*
+ * Routine Description:
+ *	This routine is called to change the physical characteristics of a phy.
+ *	We currently do not support this functionality, and are not required to
+ *	in order to support CSMI.
+ * Return Value:
+ *	Status value, to be returned by aac_HandleCSMI, and returned to the OS.
+ *	--> Must set CSMI status value in pHeader->ReturnCode.
+ */
+int
+aac_CSMISetPhyInfo(
+	struct aac_dev * dev,
+	void __user * arg)
+{
+	int Rtnval;
+	u32 ReturnCode;
+
+	fwprintf((dev,
+	  HBA_FLAGS_DBG_FUNCTION_ENTRY_B | HBA_FLAGS_DBG_CSMI_COMMANDS_B,
+	  "aac_CSMISetPhyInfo: Enter scsi%d",
+	  dev->scsi_host_ptr->host_no));
+
+	ReturnCode = CSMI_SAS_PHY_INFO_NOT_CHANGEABLE;
+	Rtnval = 0;
+	if (copy_to_user((void __user *)&((PIOCTL_HEADER)arg)->ReturnCode,
+	  (void *)&ReturnCode, sizeof(u32)))
+		Rtnval = -EFAULT;
+
+	fwprintf((dev,
+	  HBA_FLAGS_DBG_FUNCTION_EXIT_B | HBA_FLAGS_DBG_CSMI_COMMANDS_B,
+	  "aac_CSMISetPhyInfo: Exit, ReturnValue=%d,"
+	  " ReturnCode=CSMI_SAS_PHY_INFO_NOT_CHANGEABLE",
+	  Rtnval));
+
+	return Rtnval;
+
+}
+
+
+/*
+ * Routine Description:
+ *	This routine is called to send generic STP or SATA commands to a
+ *	specific SAS address.
+ * Return Value:
+ *	Status value, to be returned by aac_HandleCSMI, and returned to the OS.
+ *	--> Must set CSMI status value in pHeader->ReturnCode.
+ */
+int
+aac_CSMISTPPassThru(
+	struct aac_dev * dev,
+	void __user * arg)
+{
+	int Rtnval;
+	PCSMI_SAS_STP_PASSTHRU_BUFFER pPassThruBuffer;
+	unsigned bytesLeft = 0;
+	u8 * pDataPointer = NULL;
+	/* function */
+#	define SATAPASSTHROUGH_REGISTER		0x00000000
+#	define SATAPASSTHROUGH_SOFTRESET	0x00000001
+	typedef struct {
+		u32	function;
+		u32	bus;
+		u32	targetId;
+		u32	lun;
+		u32	timeOutValue;
+		u32	srbFlags;
+#			define	HOSTSRB_FLAGS_NO_DATA_TRANSFER	0x00000000
+#			define	HOSTSRB_FLAGS_DATA_IN		0x00000040
+#			define	HOSTSRB_FLAGS_DATA_OUT		0x00000080
+		u32	dataTransferLength;
+		u32	retryLimit;
+		u32	cdbLength;
+		u8	command;
+		u8	features;
+		u8	sectorNumber;
+		u8	cylinderLow;
+		u8	cylinderHigh;
+		u8	deviceHead;
+		u8	sectorNumber_Exp;
+		u8	cylinderLow_Exp;
+		u8	cylinderHigh_Exp;
+		u8	features_Exp;
+		u8	sectorCount;
+		u8	sectorCount_Exp;
+		u8	reserved;
+		u8	control;
+		u8	reserved1[2];
+		u32	reserved2[4];
+		struct sgmap64	sgMap;
+	} HOST_SATA_REQUEST_BLOCK;
+	typedef HOST_SATA_REQUEST_BLOCK * PHOST_SATA_REQUEST_BLOCK;
+	PHOST_SATA_REQUEST_BLOCK pSataRequest;
+	typedef struct {
+		u32	status;
+		u32	srbStatus;
+		u32	scsiStatus;
+		u32	dataTransferLength;
+		u32	senseInfoBufferLength;
+		u8	statusReg;
+		u8	error;
+		u8	sectorNumber;
+		u8	cylinderLow;
+		u8	cylinderHigh;
+		u8	deviceHead;
+		u8	sectorNumber_Exp;
+		u8	cylinderLow_Exp;
+		u8	cylinderHigh_Exp;
+		u8	deviceRegister_Exp;
+		u8	features;
+		u8	featuers_Exp;
+		u8	reserved1[4];
+	} HOST_SATA_REQUEST_BLOCK_RESULT;
+	typedef HOST_SATA_REQUEST_BLOCK_RESULT * PHOST_SATA_REQUEST_BLOCK_RESULT;
+	PHOST_SATA_REQUEST_BLOCK_RESULT pSataResponse;
+	struct sgmap64 * pSgMap;
+	struct fib * fibptr;
+	int status;
+	dma_addr_t addr;
+	void * p = NULL;
+#	define SataPortCommandU64	602
+
+	fwprintf((dev,
+	  HBA_FLAGS_DBG_FUNCTION_ENTRY_B | HBA_FLAGS_DBG_CSMI_COMMANDS_B,
+	  "aac_CSMISTPPassThru: Enter scsi%d",
+	  dev->scsi_host_ptr->host_no));
+
+	/*
+	 * Verify buffer size. If buffer is too small, the error status will
+	 * be set for pHeader->ReturnCode in aac_VerifyCSMIBuffer.
+	 */
+	if ((Rtnval = aac_VerifyCSMIBuffer(&dev, arg,
+	  sizeof(CSMI_SAS_STP_PASSTHRU_BUFFER),
+	  (PIOCTL_HEADER *)&pPassThruBuffer))) {
+		fwprintf((dev,
+		  HBA_FLAGS_DBG_FUNCTION_EXIT_B | HBA_FLAGS_DBG_CSMI_COMMANDS_B,
+		  "aac_CSMISTPPassThru: Exit, ReturnValue=%d",
+		  Rtnval));
+		return Rtnval;
+	}
+	/*
+	 * Weed out the flags we don't support
+	 */
+	if ((pPassThruBuffer->Parameters.uFlags & CSMI_SAS_STP_DMA)
+	 || (pPassThruBuffer->Parameters.uFlags & CSMI_SAS_STP_DMA_QUEUED)) {
+		/*
+		 * Indicate failure for this IOCTL
+		 */
+		pPassThruBuffer->IoctlHeader.ReturnCode
+		  = CSMI_SAS_STATUS_FAILED;
+		Rtnval = aac_CloseCSMIBuffer(dev, arg,
+		  (PIOCTL_HEADER)pPassThruBuffer);
+		fwprintf((dev,
+		  HBA_FLAGS_DBG_FUNCTION_EXIT_B | HBA_FLAGS_DBG_CSMI_COMMANDS_B,
+		  "aac_CSMISTPPassThru: Exit, ReturnValue=%d,"
+		  " ReturnCode=CSMI_SAS_STATUS_FAILED",
+		  Rtnval));
+		return Rtnval;
+	}
+
+	fibptr = fib_alloc(dev);
+	if (fibptr == NULL) {
+		pPassThruBuffer->IoctlHeader.ReturnCode
+		  = CSMI_SAS_STATUS_FAILED;
+		Rtnval = aac_CloseCSMIBuffer(dev, arg,
+		  (PIOCTL_HEADER)pPassThruBuffer);
+		fwprintf((dev,
+		  HBA_FLAGS_DBG_FUNCTION_EXIT_B | HBA_FLAGS_DBG_CSMI_COMMANDS_B,
+		  "aac_CSMISTPPassThru: Exit, ReturnValue=%d,"
+		  " ReturnCode=CSMI_SAS_STATUS_FAILED",
+		  Rtnval));
+		return Rtnval;
+	}
+	fib_init(fibptr);
+
+	pSataRequest = (PHOST_SATA_REQUEST_BLOCK) fib_data(fibptr);
+	pSgMap = &pSataRequest->sgMap;
+	pSataResponse = (PHOST_SATA_REQUEST_BLOCK_RESULT) pSataRequest;
+
+	/*
+	 * Setup HOST_SATA_REQUEST_BLOCK structure
+	 */
+	memset(pSataRequest,0,sizeof(*pSataRequest));
+	memset(pSataResponse,0,sizeof(HOST_SATA_REQUEST_BLOCK_RESULT));
+	if (pPassThruBuffer->Parameters.uFlags & CSMI_SAS_STP_RESET_DEVICE)
+		pSataRequest->function = SATAPASSTHROUGH_SOFTRESET;
+	else
+		pSataRequest->function = SATAPASSTHROUGH_REGISTER;
+
+	/*
+	 * Pull relevant data from header.
+	 */
+	if (pPassThruBuffer->Parameters.uFlags & CSMI_SAS_STP_READ)
+		pSataRequest->srbFlags = HOSTSRB_FLAGS_DATA_IN;
+	else
+		pSataRequest->srbFlags = HOSTSRB_FLAGS_DATA_OUT;
+	pSataRequest->timeOutValue = pPassThruBuffer->IoctlHeader.Timeout;
+
+	/*
+	 * Obsolete parameter - adapter firmware ignores this
+	 */
+	pSataRequest->retryLimit = 0;
+	pSataRequest->cdbLength = 14;
+
+	/*
+	 * Fill in remaining data from IOCTL Parameters
+	 */
+	/* Someday will be: SAS_ADDR_TO_BUS((*((u64*)pPassThruBuffer->Parameters.bDestinationSASAddress))); */
+	pSataRequest->bus = 0;
+	/* Someday will be: SAS_ADDR_TO_TARGET((*((u64*)pPassThruBuffer->Parameters.bDestinationSASAddress))); */
+	pSataRequest->targetId = pPassThruBuffer->Parameters.bPhyIdentifier;
+	/* Someday will be: SAS_ADDR_TO_LUN((*((u64*)pPassThruBuffer->Parameters.bDestinationSASAddress))); */
+	pSataRequest->lun = 0;
+	pSataRequest->dataTransferLength
+	  = pPassThruBuffer->Parameters.uDataLength;
+
+	/*
+	 * SATA Task Set Register Listing
+	 */
+	pSataRequest->command = pPassThruBuffer->Parameters.bCommandFIS[2];
+	pSataRequest->features = pPassThruBuffer->Parameters.bCommandFIS[3];
+	pSataRequest->sectorNumber = pPassThruBuffer->Parameters.bCommandFIS[4];
+	pSataRequest->cylinderLow = pPassThruBuffer->Parameters.bCommandFIS[5];
+	pSataRequest->cylinderHigh = pPassThruBuffer->Parameters.bCommandFIS[6];
+	pSataRequest->deviceHead = pPassThruBuffer->Parameters.bCommandFIS[7];
+	pSataRequest->sectorNumber_Exp
+	  = pPassThruBuffer->Parameters.bCommandFIS[8];
+	pSataRequest->cylinderLow_Exp
+	  = pPassThruBuffer->Parameters.bCommandFIS[9];
+	pSataRequest->cylinderHigh_Exp
+	  = pPassThruBuffer->Parameters.bCommandFIS[10];
+	pSataRequest->features_Exp
+	  = pPassThruBuffer->Parameters.bCommandFIS[11];
+	pSataRequest->sectorCount
+	  = pPassThruBuffer->Parameters.bCommandFIS[12];
+	pSataRequest->sectorCount_Exp
+	  = pPassThruBuffer->Parameters.bCommandFIS[13];
+	pSataRequest->control = pPassThruBuffer->Parameters.bCommandFIS[15];
+
+	/*
+	 * Build SGMAP
+	 */
+	if (pPassThruBuffer->Parameters.uDataLength) {
+
+		pDataPointer = &pPassThruBuffer->bDataBuffer[0];
+		bytesLeft = pPassThruBuffer->Parameters.uDataLength;
+
+		/*
+		 * Get physical address and length of
+		 * contiguous physical buffer
+		 */
+		p = pci_alloc_consistent(dev->pdev, bytesLeft, &addr);
+		if(p == 0) {
+			fib_free(fibptr);
+			pPassThruBuffer->IoctlHeader.ReturnCode
+			  = CSMI_SAS_STATUS_FAILED;
+			Rtnval = aac_CloseCSMIBuffer(dev, arg,
+			  (PIOCTL_HEADER)pPassThruBuffer);
+			fwprintf((dev, HBA_FLAGS_DBG_FUNCTION_EXIT_B
+			   | HBA_FLAGS_DBG_CSMI_COMMANDS_B,
+			  "aac_CSMISTPPassThru: Exit, ReturnValue=%d,"
+			  " ReturnCode=CSMI_SAS_STATUS_FAILED",
+			  Rtnval));
+			return Rtnval;
+		}
+		memcpy(p, pDataPointer, bytesLeft);
+
+		pSgMap->sg[0].addr[1] = cpu_to_le32((u32)((u64)addr>>32));
+		pSgMap->sg[0].addr[0] = cpu_to_le32((u32)(addr & 0xffffffff));
+
+		/*
+		 * Store the length for this entry
+		 */
+		pSgMap->sg[0].count = bytesLeft;
+
+		/*
+		 * Store final count of entries
+		 */
+		pSgMap->count = 1;
+
+	} else
+		pSataRequest->srbFlags = HOSTSRB_FLAGS_NO_DATA_TRANSFER;
+
+	/*
+	 * Send FIB
+	 */
+	status = fib_send(SataPortCommandU64, fibptr, sizeof(*pSataRequest),
+	  FsaNormal, 1, 1, NULL, NULL);
+
+	fib_complete(fibptr);
+
+	if (status < 0) {
+		if (pPassThruBuffer->Parameters.uDataLength)
+			pci_free_consistent(dev->pdev, bytesLeft,p, addr);
+		fib_free(fibptr);
+		pPassThruBuffer->IoctlHeader.ReturnCode
+		  = CSMI_SAS_STATUS_FAILED;
+		Rtnval = aac_CloseCSMIBuffer(dev, arg,
+		  (PIOCTL_HEADER)pPassThruBuffer);
+		fwprintf((dev,
+		  HBA_FLAGS_DBG_FUNCTION_EXIT_B | HBA_FLAGS_DBG_CSMI_COMMANDS_B,
+		  "aac_CSMIGetSATASignature: Exit, ReturnValue=%d,"
+		  " ReturnCode=CSMI_SAS_STATUS_FAILED",
+		  Rtnval));
+		return Rtnval;
+	}
+
+	if (pPassThruBuffer->Parameters.uDataLength) {
+		memcpy(pDataPointer, p, bytesLeft);
+		pci_free_consistent(dev->pdev, bytesLeft,p, addr);
+	}
+
+	/*
+	 * pull response data and respond to IOCTL
+	 */
+
+	/*
+	 * Return relevant data
+	 */
+	pPassThruBuffer->Status.bConnectionStatus = CSMI_SAS_OPEN_ACCEPT;
+	pPassThruBuffer->Status.bStatusFIS[2] = pSataResponse->statusReg;
+
+	/*
+	 * pPassThruBuffer->Status.uSCR = ??;
+	 */
+	pPassThruBuffer->Status.uDataBytes = pSataResponse->dataTransferLength;
+
+	fib_free(fibptr);
+
+	/*
+	 * Indicate success for this IOCTL
+	 */
+	pPassThruBuffer->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
+	Rtnval = aac_CloseCSMIBuffer(dev, arg, (PIOCTL_HEADER)pPassThruBuffer);
+
+	fwprintf((dev,
+	  HBA_FLAGS_DBG_FUNCTION_EXIT_B | HBA_FLAGS_DBG_CSMI_COMMANDS_B,
+	  "aac_CSMISTPPassThru: Exit, ReturnValue=%d,"
+	  " ReturnCode=CSMI_SAS_STATUS_SUCCESS",
+	  Rtnval));
+
+	return Rtnval;
+
+}
+
+
+/*
+ *
+ * Routine Description:
+ *
+ *   This routine is the main entry point for all CSMI function calls.
+ *
+ */
+int aac_csmi_ioctl(
+	struct aac_dev * dev,
+	int cmd,
+	void __user * arg)
+{
+	int returnStatus = -ENOTTY;
+
+	fwprintf((dev,
+	  HBA_FLAGS_DBG_FUNCTION_ENTRY_B | HBA_FLAGS_DBG_CSMI_COMMANDS_B,
+	  "aac_HandleCSMI: Enter, (scsi%d) ControlCode = %x",
+	  dev->scsi_host_ptr->host_no, cmd));
+
+	/*
+	 * Handle the supported CSMI commands
+	 */
+	switch (cmd) {
+	case CC_CSMI_SAS_GET_DRIVER_INFO:
+		returnStatus = aac_CSMIGetDriverInfo(dev, arg);
+		break;
+
+	case CC_CSMI_SAS_GET_CNTLR_CONFIG:
+		returnStatus = aac_CSMIGetControllerConfig(dev, arg);
+		break;
+
+	case CC_CSMI_SAS_GET_CNTLR_STATUS:
+		returnStatus = aac_CSMIGetControllerStatus(dev, arg);
+		break;
+
+	case CC_CSMI_SAS_GET_RAID_INFO:
+		returnStatus = aac_CSMIGetRAIDInfo(dev, arg);
+		break;
+
+	case CC_CSMI_SAS_GET_PHY_INFO:
+		returnStatus = aac_CSMIGetPhyInfo(dev, arg);
+		break;
+
+	case CC_CSMI_SAS_SET_PHY_INFO:
+		returnStatus = aac_CSMISetPhyInfo(dev, arg);
+		break;
+
+	case CC_CSMI_SAS_GET_SATA_SIGNATURE:
+		returnStatus = aac_CSMIGetSATASignature(dev, arg);
+		break;
+
+	case CC_CSMI_SAS_GET_RAID_CONFIG:
+		returnStatus = aac_CSMIGetRAIDConfig(dev, arg);
+		break;
+
+	case CC_CSMI_SAS_STP_PASSTHRU:
+		returnStatus = aac_CSMISTPPassThru(dev, arg);
+		break;
+
+	/*
+	 * Unsupported CSMI control code
+	 */
+	case CC_CSMI_SAS_FIRMWARE_DOWNLOAD:
+	case CC_CSMI_SAS_GET_SCSI_ADDRESS:
+	case CC_CSMI_SAS_GET_DEVICE_ADDRESS:
+	case CC_CSMI_SAS_SMP_PASSTHRU:
+	case CC_CSMI_SAS_SSP_PASSTHRU:
+	case CC_CSMI_SAS_GET_LINK_ERRORS:
+	case CC_CSMI_SAS_TASK_MANAGEMENT:
+	case CC_CSMI_SAS_GET_CONNECTOR_INFO:
+	case CC_CSMI_SAS_PHY_CONTROL:
+	{
+		PIOCTL_HEADER pHeader;
+
+		/*
+		 * Verify buffer size. If buffer is too small, the error
+		 * status will be set for pHeader->ReturnCode in
+		 * aac_VerifyCSMIBuffer.
+		 */
+		if (!(returnStatus = aac_VerifyCSMIBuffer(&dev, arg,
+		  sizeof(PIOCTL_HEADER), &pHeader))) {
+			pHeader->ReturnCode = CSMI_SAS_STATUS_BAD_CNTL_CODE;
+			if (!(returnStatus = aac_CloseCSMIBuffer(dev, arg,
+			  pHeader)))
+				returnStatus = -EINVAL;
+		}
+		fwprintf((dev, HBA_FLAGS_DBG_CSMI_COMMANDS_B,
+		  "aac_HandleCSMI: Unsupported ControlCode=%x",
+		  cmd));
+		break;
+	}
+	}
+
+	fwprintf((dev,
+	  HBA_FLAGS_DBG_FUNCTION_EXIT_B | HBA_FLAGS_DBG_CSMI_COMMANDS_B,
+	  "aac_HandleCSMI: Exit, ReturnCode=%d", returnStatus));
+
+	return(returnStatus);
+}
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11))
+#if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) ? defined(__x86_64__) : defined(CONFIG_COMPAT))
+void aac_csmi_register_ioctl32_conversion(void)
+{
+	register_ioctl32_conversion(CC_CSMI_SAS_GET_DRIVER_INFO,
+	  (int(*)(unsigned int,unsigned int,unsigned long,struct file*))sys_ioctl);
+	register_ioctl32_conversion(CC_CSMI_SAS_GET_CNTLR_CONFIG,
+	  (int(*)(unsigned int,unsigned int,unsigned long,struct file*))sys_ioctl);
+	register_ioctl32_conversion(CC_CSMI_SAS_GET_CNTLR_STATUS,
+	  (int(*)(unsigned int,unsigned int,unsigned long,struct file*))sys_ioctl);
+	register_ioctl32_conversion(CC_CSMI_SAS_GET_RAID_INFO,
+	  (int(*)(unsigned int,unsigned int,unsigned long,struct file*))sys_ioctl);
+	register_ioctl32_conversion(CC_CSMI_SAS_GET_PHY_INFO,
+	  (int(*)(unsigned int,unsigned int,unsigned long,struct file*))sys_ioctl);
+	register_ioctl32_conversion(CC_CSMI_SAS_SET_PHY_INFO,
+	  (int(*)(unsigned int,unsigned int,unsigned long,struct file*))sys_ioctl);
+	register_ioctl32_conversion(CC_CSMI_SAS_GET_SATA_SIGNATURE,
+	  (int(*)(unsigned int,unsigned int,unsigned long,struct file*))sys_ioctl);
+	register_ioctl32_conversion(CC_CSMI_SAS_GET_RAID_CONFIG,
+	  (int(*)(unsigned int,unsigned int,unsigned long,struct file*))sys_ioctl);
+	register_ioctl32_conversion(CC_CSMI_SAS_STP_PASSTHRU,
+	  (int(*)(unsigned int,unsigned int,unsigned long,struct file*))sys_ioctl);
+	register_ioctl32_conversion(CC_CSMI_SAS_FIRMWARE_DOWNLOAD,
+	  (int(*)(unsigned int,unsigned int,unsigned long,struct file*))sys_ioctl);
+	register_ioctl32_conversion(CC_CSMI_SAS_GET_SCSI_ADDRESS,
+	  (int(*)(unsigned int,unsigned int,unsigned long,struct file*))sys_ioctl);
+	register_ioctl32_conversion(CC_CSMI_SAS_GET_DEVICE_ADDRESS,
+	  (int(*)(unsigned int,unsigned int,unsigned long,struct file*))sys_ioctl);
+	register_ioctl32_conversion(CC_CSMI_SAS_SMP_PASSTHRU,
+	  (int(*)(unsigned int,unsigned int,unsigned long,struct file*))sys_ioctl);
+	register_ioctl32_conversion(CC_CSMI_SAS_SSP_PASSTHRU,
+	  (int(*)(unsigned int,unsigned int,unsigned long,struct file*))sys_ioctl);
+	register_ioctl32_conversion(CC_CSMI_SAS_GET_LINK_ERRORS,
+	  (int(*)(unsigned int,unsigned int,unsigned long,struct file*))sys_ioctl);
+	register_ioctl32_conversion(CC_CSMI_SAS_TASK_MANAGEMENT,
+	  (int(*)(unsigned int,unsigned int,unsigned long,struct file*))sys_ioctl);
+	register_ioctl32_conversion(CC_CSMI_SAS_GET_CONNECTOR_INFO,
+	  (int(*)(unsigned int,unsigned int,unsigned long,struct file*))sys_ioctl);
+	register_ioctl32_conversion(CC_CSMI_SAS_PHY_CONTROL,
+	  (int(*)(unsigned int,unsigned int,unsigned long,struct file*))sys_ioctl);
+}
+
+void aac_csmi_unregister_ioctl32_conversion(void)
+{
+	unregister_ioctl32_conversion(CC_CSMI_SAS_GET_DRIVER_INFO);
+	unregister_ioctl32_conversion(CC_CSMI_SAS_GET_CNTLR_CONFIG);
+	unregister_ioctl32_conversion(CC_CSMI_SAS_GET_CNTLR_STATUS);
+	unregister_ioctl32_conversion(CC_CSMI_SAS_GET_RAID_INFO);
+	unregister_ioctl32_conversion(CC_CSMI_SAS_GET_PHY_INFO);
+	unregister_ioctl32_conversion(CC_CSMI_SAS_SET_PHY_INFO);
+	unregister_ioctl32_conversion(CC_CSMI_SAS_GET_SATA_SIGNATURE);
+	unregister_ioctl32_conversion(CC_CSMI_SAS_GET_RAID_CONFIG);
+	unregister_ioctl32_conversion(CC_CSMI_SAS_STP_PASSTHRU);
+	unregister_ioctl32_conversion(CC_CSMI_SAS_FIRMWARE_DOWNLOAD);
+	unregister_ioctl32_conversion(CC_CSMI_SAS_GET_SCSI_ADDRESS);
+	unregister_ioctl32_conversion(CC_CSMI_SAS_GET_DEVICE_ADDRESS);
+	unregister_ioctl32_conversion(CC_CSMI_SAS_SMP_PASSTHRU);
+	unregister_ioctl32_conversion(CC_CSMI_SAS_SSP_PASSTHRU);
+	unregister_ioctl32_conversion(CC_CSMI_SAS_GET_LINK_ERRORS);
+	unregister_ioctl32_conversion(CC_CSMI_SAS_TASK_MANAGEMENT);
+	unregister_ioctl32_conversion(CC_CSMI_SAS_GET_CONNECTOR_INFO);
+	unregister_ioctl32_conversion(CC_CSMI_SAS_PHY_CONTROL);
+}
+#endif
+#endif
+
+#endif
diff --git a/drivers/scsi/aacraid/csmi.h b/drivers/scsi/aacraid/csmi.h
new file mode 100644
index 0000000..f5ac158
--- /dev/null
+++ b/drivers/scsi/aacraid/csmi.h
@@ -0,0 +1,402 @@
+/*
+ *	Adaptec AAC series RAID controller driver
+ *	(c) Copyright 2004 Adaptec, Inc
+ *
+ * Copyright (c) 2004 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *   csmi.h
+ *
+ * Abstract: All CSMI IOCTL definitions are here
+ */
+
+/*
+ *	This file is based on the following CSMI revision
+ */
+#define	CSMI_MAJOR_REVISION	0
+#define	CSMI_MINOR_REVISION	82
+
+/*
+ *	IoctlHeader.ReturnCode
+ */
+#define	CSMI_SAS_STATUS_SUCCESS			0
+#define	CSMI_SAS_STATUS_FAILED			1
+#define	CSMI_SAS_STATUS_BAD_CNTL_CODE		2
+#define	CSMI_SAS_STATUS_INVALID_PARAMETER	3
+#define CSMI_SAS_PHY_INFO_NOT_CHANGEABLE	2000
+#define CSMI_SAS_NO_SATA_DEVICE			2009
+
+/*
+ *	Status.uStatus
+ */
+#define	CSMI_SAS_CNTLR_STATUS_GOOD	1
+#define	CSMI_SAS_CNTLR_STATUS_FAILED	2
+#define CSMI_SAS_CNTLR_STATUS_OFFLINE	3
+
+/*
+ *	Status.uOfflineReason
+ */
+#define CSMI_SAS_OFFLINE_REASON_NO_REASON	0
+
+/*
+ *	IoctlHeader.ControlCode
+ */
+#define CSMI_SAS_RAID_SET_OUT_OF_RANGE	1000
+
+/*
+ *	Parameters.uFlags
+ */
+#define	CSMI_SAS_STP_READ		0x00000001
+#define	CSMI_SAS_STP_DMA		0x00000020
+#define	CSMI_SAS_STP_DMA_QUEUED		0x00000080
+#define	CSMI_SAS_STP_RESET_DEVICE	0x00000200	
+
+/*
+ *	Status.bConnectionStatus
+ */
+#define	CSMI_SAS_OPEN_ACCEPT		0
+
+/*
+ *	Configuration.bIoBusType
+ */
+#define	CSMI_SAS_BUS_TYPE_PCI		3
+
+/*
+ *	Configuration.bControllerClass
+ */
+#define	CSMI_SAS_CNTLR_CLASS_HBA	5
+
+/*
+ *	Configuration.uControllerFlags
+ */
+#define	CSMI_SAS_CNTLR_SAS_HBA		0x00000001
+#define	CSMI_SAS_CNTLR_SAS_RAID		0x00000002
+#define	CSMI_SAS_CNTLR_SATA_HBA		0x00000004
+#define	CSMI_SAS_CNTLR_SATA_RAID	0x00000008
+
+/*
+ *	Configuration.usSlotNumber
+ */
+#define SLOT_NUMBER_UNKNOWN		0xFFFF
+
+/*
+ *	CSMI ioctl commands
+ */
+/* #define CSMI_ALL_SIGNATURE		"CSMIALL" */
+#define	CC_CSMI_SAS_GET_DRIVER_INFO	0xCC770001
+#define	CC_CSMI_SAS_GET_CNTLR_CONFIG	0xCC770002
+#define	CC_CSMI_SAS_GET_CNTLR_STATUS	0xCC770003
+#define	CC_CSMI_SAS_FIRMWARE_DOWNLOAD	0xCC770004
+
+/* #define CSMI_RAID_SIGNATURE		"CSMIARY" */
+#define	CC_CSMI_SAS_GET_RAID_INFO	0xCC77000A
+#define	CC_CSMI_SAS_GET_RAID_CONFIG	0xCC77000B
+
+/* #define CSMI_SAS_SIGNATURE		"CSMISAS" */
+#define	CC_CSMI_SAS_GET_PHY_INFO	0xCC770014
+#define	CC_CSMI_SAS_SET_PHY_INFO	0xCC770015
+#define	CC_CSMI_SAS_GET_LINK_ERRORS	0xCC770016
+#define	CC_CSMI_SAS_SSP_PASSTHRU	0xCC770017
+#define	CC_CSMI_SAS_SMP_PASSTHRU	0xCC770018
+#define	CC_CSMI_SAS_STP_PASSTHRU	0xCC770019
+#define CC_CSMI_SAS_GET_SATA_SIGNATURE	0xCC770020
+#define	CC_CSMI_SAS_GET_SCSI_ADDRESS	0xCC770021
+#define	CC_CSMI_SAS_GET_DEVICE_ADDRESS	0xCC770022
+#define	CC_CSMI_SAS_TASK_MANAGEMENT	0xCC770023
+#define	CC_CSMI_SAS_GET_CONNECTOR_INFO	0xCC770024
+
+/* #define CSMI_PHY_SIGNATURE		"CSMIPHY" */
+#define CC_CSMI_SAS_PHY_CONTROL		0xCC77003C
+
+typedef struct {
+	u32	IOControllerNumber;
+	u32	Length;
+	u32	ReturnCode;
+	u32	Timeout;
+	u16	Direction;
+#if (defined(CSMI_8_BYTE_ALIGNED))
+	u16	Reserved[3];
+#endif
+} IOCTL_HEADER;
+typedef IOCTL_HEADER *PIOCTL_HEADER;
+
+/* CC_CSMI_SAS_GET_DRIVER_INFO */
+
+typedef struct {
+	u8	szName[81];
+	u8	szDescription[81];
+	u16	usMajorRevision;
+	u16	usMinorRevision;
+	u16	usBuildRevision;
+	u16	usReleaseRevision;
+	u16	usCSMIMajorRevision;
+	u16	usCSMIMinorRevision;
+#if (defined(CSMI_8_BYTE_ALIGNED))
+	u16	usReserved;
+#endif
+} CSMI_SAS_DRIVER_INFO;
+
+typedef struct {
+	IOCTL_HEADER	IoctlHeader;
+	CSMI_SAS_DRIVER_INFO	Information;
+} CSMI_SAS_DRIVER_INFO_BUFFER;
+typedef CSMI_SAS_DRIVER_INFO_BUFFER * PCSMI_SAS_DRIVER_INFO_BUFFER;
+
+/* CC_CSMI_SAS_GET_CNTLR_CONFIG */
+
+typedef struct {
+	u8	bBusNumber;
+	u8	bDeviceNumber;
+	u8	bFunctionNumber;
+	u8	bReserved;
+} CSMI_SAS_PCI_BUS_ADDRESS;
+
+typedef union {
+	CSMI_SAS_PCI_BUS_ADDRESS	PciAddress;
+	u8	bReserved[32];
+} CSMI_SAS_IO_BUS_ADDRESS;
+
+typedef struct {
+	u32	uBaseIoAddress;
+#if (defined(CSMI_8_BYTE_ALIGNED))
+	u32	uReserved;
+#endif
+	struct {
+		u32	uLowPart;
+		u32	uHighPart;
+	} BaseMemoryAddress;
+	u32	uBoardID;
+	u16	usSlotNumber;
+	u8	bControllerClass;
+	u8	bIoBusType;
+	CSMI_SAS_IO_BUS_ADDRESS	BusAddress;
+	u8	szSerialNumber[81];
+#if (defined(CSMI_8_BYTE_ALIGNED))
+	u8	bReserve;
+#endif
+	u16	usMajorRevision;
+	u16	usMinorRevision;
+	u16	usBuildRevision;
+	u16	usReleaseRevision;
+	u16	usBIOSMajorRevision;
+	u16	usBIOSMinorRevision;
+	u16	usBIOSBuildRevision;
+	u16	usBIOSReleaseRevision;
+#if (defined(CSMI_8_BYTE_ALIGNED))
+	u16	usReserved;
+#endif
+	u32	uControllerFlags;
+	u16	usRromMajorRevision;
+	u16	usRromMinorRevision;
+	u16	usRromBuildRevision;
+	u16	usRromReleaseRevision;
+	u16	usRromBIOSMajorRevision;
+	u16	usRromBIOSMinorRevision;
+	u16	usRromBIOSBuildRevision;
+	u16	usRromBIOSReleaseRevision;
+	u8	bReserved[7];
+#if (defined(CSMI_8_BYTE_ALIGNED))
+	u8	bReserved1;
+#endif
+} CSMI_SAS_CNTLR_CONFIG;
+
+typedef struct {
+	IOCTL_HEADER	IoctlHeader;
+	CSMI_SAS_CNTLR_CONFIG	Configuration;
+} CSMI_SAS_CNTLR_CONFIG_BUFFER;
+typedef CSMI_SAS_CNTLR_CONFIG_BUFFER * PCSMI_SAS_CNTLR_CONFIG_BUFFER;
+
+/* CC_CSMI_SAS_GET_CNTLR_STATUS */
+
+typedef struct {
+	u32	uStatus;
+	u32	uOfflineReason;
+	u8	bReserved[28];
+#if (defined(CSMI_8_BYTE_ALIGNED))
+	u8	bReserved[4];
+#endif
+} CSMI_SAS_CNTLR_STATUS;
+
+typedef struct {
+	IOCTL_HEADER	IoctlHeader;
+	CSMI_SAS_CNTLR_STATUS	Status;
+} CSMI_SAS_CNTLR_STATUS_BUFFER;
+typedef CSMI_SAS_CNTLR_STATUS_BUFFER * PCSMI_SAS_CNTLR_STATUS_BUFFER;
+
+/* CC_CSMI_SAS_GET_SATA_SIGNATURE */
+
+typedef struct {
+	u8	pPhyIdentifier;
+	u8	bReserved[3];
+	u8	bSignatureFIS[20];
+} CSMI_SAS_SATA_SIGNATURE;
+
+typedef struct {
+	IOCTL_HEADER IoctlHeader;
+	CSMI_SAS_SATA_SIGNATURE Signature;
+} CSMI_SAS_SATA_SIGNATURE_BUFFER;
+typedef CSMI_SAS_SATA_SIGNATURE_BUFFER * PCSMI_SAS_SATA_SIGNATURE_BUFFER;
+
+/* CC_CSMI_SAS_GET_RAID_INFO */
+
+typedef struct {
+	u32	uNumRaidSets;
+	u32	uMaxDrivesPerSet;
+	u8	bReserved[92];
+#if (defined(CSMI_8_BYTE_ALIGNED))
+	u8	bReserved1[4];
+#endif
+} CSMI_SAS_RAID_INFO;
+
+typedef struct {
+	IOCTL_HEADER	IoctlHeader;
+	CSMI_SAS_RAID_INFO	Information;
+} CSMI_SAS_RAID_INFO_BUFFER;
+typedef CSMI_SAS_RAID_INFO_BUFFER * PCSMI_SAS_RAID_INFO_BUFFER;
+
+/* CC_CSMI_SAS_GET_RAID_CONFIG */
+
+typedef struct {
+	u8	bModel[40];
+	u8	bFirmware[8];
+	u8	bSerialNumber[40];
+	u8	bSASAddress[8];
+	u8	bSASLun[8];
+	u8	bDriveStatus;
+	u8	bDriveUsage;
+	u8	bReserved[30];
+} CSMI_SAS_RAID_DRIVES;
+
+typedef struct {
+	u32	uRaidSetIndex;
+	u32	uCapacity;
+	u32	uStripeSize;
+	u8	bRaidType;
+	u8	bStatus;
+	u8	bInformation;
+	u8	bDriveCount;
+	u8	bReserved[20];
+#if (defined(CSMI_8_BYTE_ALIGNED))
+	u8	bReserved1[4];
+#endif
+	CSMI_SAS_RAID_DRIVES	Drives[1];
+} CSMI_SAS_RAID_CONFIG;
+
+typedef struct {
+	IOCTL_HEADER IoctlHeader;
+	CSMI_SAS_RAID_CONFIG Configuration;
+} CSMI_SAS_RAID_CONFIG_BUFFER;
+typedef CSMI_SAS_RAID_CONFIG_BUFFER * PCSMI_SAS_RAID_CONFIG_BUFFER;
+
+/* CC_CSMI_SAS_GET_PHY_INFO */
+
+typedef struct {
+	u8	bDeviceType;
+	u8	bRestricted;
+	u8	bInitiatorPortProtocol;
+	u8	bTargetPortProtocol;
+	u8	bRestricted2[8];
+	u8	bSASAddress[8];
+	u8	bPhyIdentifier;
+	u8	bSignalClass;
+	u8	bReserved[6];
+#if (defined(CSMI_8_BYTE_ALIGNED))
+	u8	bReserved1[4];
+#endif
+} CSMI_SAS_IDENTIFY;
+
+typedef struct {
+	CSMI_SAS_IDENTIFY	Identify;
+	u8	bPortIdentifier;
+	u8	bNegotiatedLinkRate;
+	u8	bMinimumLinkRate;
+	u8	bMaximumLinkRate;
+	u8	bPhyChangeCount;
+	u8	bAutoDiscover;
+	u8	bReserved[2];
+	CSMI_SAS_IDENTIFY	Attached;
+} CSMI_SAS_PHY_ENTITY;
+
+typedef struct {
+	u8	bNumberofPhys;
+	u8	bReserved[3];
+#if (defined(CSMI_8_BYTE_ALIGNED))
+	u8	bReserved1[4];
+#endif
+	CSMI_SAS_PHY_ENTITY Phy[32];
+} CSMI_SAS_PHY_INFO;
+
+typedef struct {
+	IOCTL_HEADER IoctlHeader;
+	CSMI_SAS_PHY_INFO Information;
+} CSMI_SAS_PHY_INFO_BUFFER;
+typedef CSMI_SAS_PHY_INFO_BUFFER * PCSMI_SAS_PHY_INFO_BUFFER;
+
+/* CC_CSMI_SAS_SET_PHY_INFO */
+
+typedef struct {
+	u8	bPhyIdentifier;
+	u8	bNegotiatedLinkRate;
+	u8	bProgrammedMinimumLinkRate;
+	u8	bProgrammedMaximumLinkRate;
+	u8	bSignalClass;
+	u8	bReserved[3];
+} CSMI_SAS_SET_PHY_INFO;
+
+typedef struct {
+	IOCTL_HEADER IoctlHeader;
+	CSMI_SAS_SET_PHY_INFO Information;
+} CSMI_SAS_SET_PHY_INFO_BUFFER;
+typedef CSMI_SAS_SET_PHY_INFO_BUFFER * PCSMI_SAS_SET_PHY_INFO_BUFFER;
+
+/* CC_CSMI_SAS_STP_PASSTHRU */
+
+typedef struct {
+	u8	bPhyIdentifier;
+	u8	bPortIdentifier;
+	u8	bConnectionRate;
+	u8	bReserved;
+	u8	bDestinationSASAddress[8];
+	u8	bReserved2[4];
+	u8	bCommandFIS[20];
+	u32	uFlags;
+	u32	uDataLength;
+#if (defined(CSMI_8_BYTE_ALIGNED))
+	u32	uReserved;
+#endif
+} CSMI_SAS_STP_PASSTHRU;
+
+typedef struct {
+	u8	bConnectionStatus;
+	u8	bReserved[3];
+	u8	bStatusFIS[20];
+	u32	uSCR[16];
+	u32	uDataBytes;
+#if (defined(CSMI_8_BYTE_ALIGNED))
+	u32	uReserved;
+#endif
+} CSMI_SAS_STP_PASSTHRU_STATUS;
+
+typedef struct {
+	IOCTL_HEADER	IoctlHeader;
+	CSMI_SAS_STP_PASSTHRU	Parameters;
+	CSMI_SAS_STP_PASSTHRU_STATUS	Status;
+	u8	bDataBuffer[1];
+} CSMI_SAS_STP_PASSTHRU_BUFFER;
+typedef CSMI_SAS_STP_PASSTHRU_BUFFER * PCSMI_SAS_STP_PASSTHRU_BUFFER;
+
+int aac_csmi_ioctl(struct aac_dev *, int, void __user *);
diff --git a/drivers/scsi/aacraid/dpcsup.c b/drivers/scsi/aacraid/dpcsup.c
index c8651bc..612c430 100644
--- a/drivers/scsi/aacraid/dpcsup.c
+++ b/drivers/scsi/aacraid/dpcsup.c
@@ -29,7 +29,6 @@
  *
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/types.h>
@@ -38,10 +37,9 @@
 #include <linux/spinlock.h>
 #include <linux/slab.h>
 #include <linux/completion.h>
-#include <linux/blk.h>
+#include <linux/blkdev.h>
 #include <asm/semaphore.h>
-#include "scsi.h"
-#include "hosts.h"
+#include <linux/version.h>
 
 #include "aacraid.h"
 
@@ -65,7 +63,6 @@ unsigned int aac_response_normal(struct aac_queue * q)
 	unsigned long flags;
 
 	spin_lock_irqsave(q->lock, flags);	
-
 	/*
 	 *	Keep pulling response QEs off the response queue and waking
 	 *	up the waiters until there are no more QEs. We then return
@@ -75,12 +72,11 @@ unsigned int aac_response_normal(struct aac_queue * q)
 	while(aac_consumer_get(dev, q, &entry))
 	{
 		int fast;
-		u32 index;
-		index = le32_to_cpu(entry->addr);
+		u32 index = le32_to_cpu(entry->addr);
 		fast = index & 0x01;
-		fib = &dev->fibs[index >> 1];
+		fib = &dev->fibs[index >> 2];
 		hwfib = fib->hw_fib;
-
+		
 		aac_consumer_free(dev, q, HostNormRespQueue);
 		/*
 		 *	Remove this fib from the Outstanding I/O queue.
@@ -95,6 +91,7 @@ unsigned int aac_response_normal(struct aac_queue * q)
 			dev->queues->queue[AdapNormCmdQueue].numpending--;
 		} else {
 			printk(KERN_WARNING "aacraid: FIB timeout (%x).\n", fib->flags);
+			printk(KERN_DEBUG"aacraid: hwfib=%p fib index=%i fib=%p\n",hwfib, hwfib->header.SenderData,fib);
 			continue;
 		}
 		spin_unlock_irqrestore(q->lock, flags);
@@ -103,7 +100,7 @@ unsigned int aac_response_normal(struct aac_queue * q)
 			/*
 			 *	Doctor the fib
 			 */
-			*(u32 *)hwfib->data = cpu_to_le32(ST_OK);
+			*(__le32 *)hwfib->data = cpu_to_le32(ST_OK);
 			hwfib->header.XferState |= cpu_to_le32(AdapterProcessed);
 		}
 
@@ -111,7 +108,7 @@ unsigned int aac_response_normal(struct aac_queue * q)
 
 		if (hwfib->header.Command == cpu_to_le16(NuFileSystem))
 		{
-			u32 *pstatus = (u32 *)hwfib->data;
+			__le32 *pstatus = (__le32 *)hwfib->data;
 			if (*pstatus & cpu_to_le32(0xffff0000))
 				*pstatus = cpu_to_le32(ST_OK);
 		}
@@ -138,8 +135,12 @@ unsigned int aac_response_normal(struct aac_queue * q)
 		spin_lock_irqsave(q->lock, flags);
 	}
 
-	if (consumed > aac_config.peak_fibs)
+	if (consumed > aac_config.peak_fibs) {
 		aac_config.peak_fibs = consumed;
+#if (defined(AAC_DEBUG_INSTRUMENT_AAC_CONFIG))
+		printk("peak_fibs=%d\n", aac_config.peak_fibs);
+#endif
+	}
 	if (consumed == 0) 
 		aac_config.zero_fibs++;
 
@@ -171,29 +172,35 @@ unsigned int aac_command_normal(struct aac_queue *q)
 	 *	up the waiters until there are no more QEs. We then return
 	 *	back to the system.
 	 */
-	dprintk((KERN_INFO
-	  "dev=%p, dev->comm_phys=%x, dev->comm_addr=%p, dev->comm_size=%u\n",
-	  dev, (u32)dev->comm_phys, dev->comm_addr, (unsigned)dev->comm_size));
-
 	while(aac_consumer_get(dev, q, &entry))
 	{
 		struct fib fibctx;
 		struct hw_fib * hw_fib;
 		u32 index;
 		struct fib *fib = &fibctx;
-
-		index = le32_to_cpu(entry->addr / sizeof(struct hw_fib));
-		hw_fib = &dev->aif_base_va[index];
-
+		
 		/*
-		 *	Allocate a FIB at all costs. For non queued stuff
+		 *	Allocate a FIB. For non queued stuff
 		 *	we can just use the stack so we are happy. We need
 		 *	a fib object in order to manage the linked lists
 		 */
-		if (dev->aif_thread)
-			if((fib = kmalloc(sizeof(struct fib), GFP_ATOMIC))==NULL)
+		if (dev->aif_thread) {
+			/* Limit the number we retreive from fib pool */
+			struct list_head * each;
+			int i = (le32_to_cpu(dev->init->AdapterFibsSize) / sizeof(struct hw_fib)) - 1;
+			list_for_each(each, &(q->cmdq))
+				if (--i <= 0)
+					break;
+			if ((i <= 0) || (!(fib = kmalloc(sizeof(struct fib),GFP_ATOMIC))))
 				fib = &fibctx;
-			
+		}
+		index = le32_to_cpu(entry->addr) / sizeof(struct hw_fib);
+#if (defined(AAC_DEBUG_INSTRUMENT_FIB))
+		printk(KERN_INFO "index=%d or %d\n", index,
+		  le32_to_cpu(entry->addr / sizeof(struct hw_fib)));
+#endif
+		hw_fib = &dev->aif_base_va[index];
+		
 		memset(fib, 0, sizeof(struct fib));
 		INIT_LIST_HEAD(&fib->fiblink);
 		fib->type = FSAFS_NTC_FIB_CONTEXT;
@@ -202,9 +209,9 @@ unsigned int aac_command_normal(struct aac_queue *q)
 		fib->data = hw_fib->data;
 		fib->dev = dev;
 		
-		if (dev->aif_thread && fib != &fibctx)
-		{		
-			list_add_tail(&fib->fiblink, &q->cmdq);
+				
+		if (dev->aif_thread && fib != &fibctx) {
+		        list_add_tail(&fib->fiblink, &q->cmdq);
 	 	        aac_consumer_free(dev, q, HostNormCmdQueue);
 		        wake_up_interruptible(&q->cmdready);
 		} else {
@@ -213,7 +220,7 @@ unsigned int aac_command_normal(struct aac_queue *q)
 			/*
 			 *	Set the status of this FIB
 			 */
-			*(u32 *)hw_fib->data = cpu_to_le32(ST_OK);
+			*(__le32 *)hw_fib->data = cpu_to_le32(ST_OK);
 			fib_adapter_complete(fib, sizeof(u32));
 			spin_lock_irqsave(q->lock, flags);
 		}		
@@ -221,3 +228,139 @@ unsigned int aac_command_normal(struct aac_queue *q)
 	spin_unlock_irqrestore(q->lock, flags);
 	return 0;
 }
+
+
+/**
+ *	aac_intr_normal	-	Handle command replies
+ *	@dev: Device
+ *	@index: completion reference
+ *
+ *	This DPC routine will be run when the adapter interrupts us to let us
+ *	know there is a response on our normal priority queue. We will pull off
+ *	all QE there are and wake up all the waiters before exiting.
+ */
+
+unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index)
+{
+	u32 index = le32_to_cpu(Index);
+
+	dprintk((KERN_INFO "aac_intr_normal(%p,%x)\n", dev, Index));
+	if ((index & 0x00000002L)) {
+		struct hw_fib * hw_fib;
+		struct fib * fib;
+		struct aac_queue *q = &dev->queues->queue[HostNormCmdQueue];
+		unsigned long flags;
+
+		if (index == 0xFFFFFFFEL) /* Special Case */
+			return 0;	  /* Do nothing */
+		/*
+		 *	Allocate a FIB. For non queued stuff we can just use
+		 * the stack so we are happy. We need a fib object in order to
+		 * manage the linked lists.
+		 */
+		if ((!dev->aif_thread)
+		 || (!(fib = kmalloc(sizeof(struct fib),GFP_ATOMIC))))
+			return 1;
+		if (!(hw_fib = kmalloc(sizeof(struct hw_fib),GFP_ATOMIC))) {
+			kfree (fib);
+			return 1;
+		}
+		memset(hw_fib, 0, sizeof(struct hw_fib));
+		memcpy(hw_fib, (struct hw_fib *)(((char *)(dev->regs.sa)) + (index & ~0x00000002L)), sizeof(struct hw_fib));
+		memset(fib, 0, sizeof(struct fib));
+		INIT_LIST_HEAD(&fib->fiblink);
+		fib->type = FSAFS_NTC_FIB_CONTEXT;
+		fib->size = sizeof(struct fib);
+		fib->hw_fib = hw_fib;
+		fib->data = hw_fib->data;
+		fib->dev = dev;
+	
+		spin_lock_irqsave(q->lock, flags);
+		list_add_tail(&fib->fiblink, &q->cmdq);
+	        wake_up_interruptible(&q->cmdready);
+		spin_unlock_irqrestore(q->lock, flags);
+		return 1;
+	} else {
+		int fast = index & 0x01;
+		struct fib * fib = &dev->fibs[index >> 2];
+		struct hw_fib * hwfib = fib->hw_fib;
+
+		/*
+		 *	Remove this fib from the Outstanding I/O queue.
+		 *	But only if it has not already been timed out.
+		 *
+		 *	If the fib has been timed out already, then just 
+		 *	continue. The caller has already been notified that
+		 *	the fib timed out.
+		 */
+		if ((fib->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) {
+			printk(KERN_WARNING "aacraid: FIB timeout (%x).\n", fib->flags);
+			printk(KERN_DEBUG"aacraid: hwfib=%p index=%i fib=%p\n",hwfib, hwfib->header.SenderData,fib);
+			return 0;
+		}
+
+#if (defined(AAC_DEBUG_INSTRUMENT_FIB))
+		if (fib->queue.prev == NULL)
+			printk(KERN_WARNING
+			  "aacraid: empty fib %d list prev\n", index >> 1);
+#if (defined(LIST_POISON2))
+		else if (fib->queue.prev == LIST_POISON2)
+			printk(KERN_WARNING
+			  "aacraid: poison fib %d list prev\n", index >> 1);
+#endif
+		if (fib->queue.next == NULL)
+			printk(KERN_WARNING
+			  "aacraid: empty fib %d list next\n", index >> 1);
+#if (defined(LIST_POISON1))
+		else if (fib->queue.next == LIST_POISON1)
+			printk(KERN_WARNING
+			  "aacraid: poison fib %d list next\n", index >> 1);
+#endif
+		else if ((fib->queue.prev != NULL)
+#if (defined(LIST_POISON2))
+		 && (fib->queue.prev != LIST_POISON2)
+#endif
+		)
+#endif
+		list_del(&fib->queue);
+		dev->queues->queue[AdapNormCmdQueue].numpending--;
+
+		if (fast) {
+			/*
+			 *	Doctor the fib
+			 */
+			*(__le32 *)hwfib->data = cpu_to_le32(ST_OK);
+			hwfib->header.XferState |= cpu_to_le32(AdapterProcessed);
+		}
+
+		FIB_COUNTER_INCREMENT(aac_config.FibRecved);
+
+		if (hwfib->header.Command == cpu_to_le16(NuFileSystem))
+		{
+			u32 *pstatus = (u32 *)hwfib->data;
+			if (*pstatus & cpu_to_le32(0xffff0000))
+				*pstatus = cpu_to_le32(ST_OK);
+		}
+		if (hwfib->header.XferState & cpu_to_le32(NoResponseExpected | Async)) 
+		{
+	        	if (hwfib->header.XferState & cpu_to_le32(NoResponseExpected))
+				FIB_COUNTER_INCREMENT(aac_config.NoResponseRecved);
+			else 
+				FIB_COUNTER_INCREMENT(aac_config.AsyncRecved);
+			/*
+			 *	NOTE:  we cannot touch the fib after this
+			 *	    call, because it may have been deallocated.
+			 */
+			fib->callback(fib->callback_data, fib);
+		} else {
+			unsigned long flagv;
+	  		dprintk((KERN_INFO "event_wait up\n"));
+			spin_lock_irqsave(&fib->event_lock, flagv);
+			fib->done = 1;
+			up(&fib->event_wait);
+			spin_unlock_irqrestore(&fib->event_lock, flagv);
+			FIB_COUNTER_INCREMENT(aac_config.NormalRecved);
+		}
+		return 0;
+	}
+}
diff --git a/drivers/scsi/aacraid/fwdebug.c b/drivers/scsi/aacraid/fwdebug.c
new file mode 100644
index 0000000..5942b26
--- /dev/null
+++ b/drivers/scsi/aacraid/fwdebug.c
@@ -0,0 +1,343 @@
+/*
+ *	Adaptec AAC series RAID controller driver
+ *
+ * Copyright (c) 2004 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdarg.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/spinlock.h>
+#include <asm/semaphore.h>
+#include <linux/kernel.h>
+#include <linux/blkdev.h>
+#include <linux/completion.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/version.h>
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_host.h>
+#else
+#include "scsi.h"
+#include "hosts.h"
+#endif
+#include "aacraid.h"
+#include "fwdebug.h"
+
+/*
+ * Debug flags to be put into the HBA flags field when initialized
+ */
+const unsigned long aac_debug_flags = /* Variable to setup with above flags. */
+/*			HBA_FLAGS_DBG_KERNEL_PRINT_B |		*/
+			HBA_FLAGS_DBG_FW_PRINT_B |
+			HBA_FLAGS_DBG_FUNCTION_ENTRY_B |
+			HBA_FLAGS_DBG_FUNCTION_EXIT_B |
+			HBA_FLAGS_DBG_ERROR_B |
+/*			HBA_FLAGS_DBG_INIT_B |			*/
+/*			HBA_FLAGS_DBG_OS_COMMANDS_B |		*/
+/*			HBA_FLAGS_DBG_SCAN_B |			*/
+/*			HBA_FLAGS_DBG_COALESCE_B |		*/
+/*			HBA_FLAGS_DBG_IOCTL_COMMANDS_B |	*/
+/*			HBA_FLAGS_DBG_SYNC_COMMANDS_B |		*/
+/*			HBA_FLAGS_DBG_COMM_B |			*/
+/*			HBA_FLAGS_DBG_AIF_B |			*/
+/*			HBA_FLAGS_DBG_CSMI_COMMANDS_B | 	*/
+/*			HBA_FLAGS_DBG_FLAGS_MASK | 		*/
+0;
+
+int aac_get_fw_debug_buffer(struct aac_dev * dev)
+{
+if (nblank(fwprintf(x))) {
+	u32 MonDriverBufferPhysAddrLow = 0;
+	u32 MonDriverBufferPhysAddrHigh = 0;
+	u32 MonDriverBufferSize = 0;
+	u32 MonDriverHeaderSize = 0;
+	u32 ReturnStatus = 0;
+
+	/*
+	 * Initialize the firmware print buffer fields
+	 */
+	dev->FwDebugBuffer_P = NULL;
+	dev->FwDebugFlags_P = NULL;
+	dev->FwDebugStrLength_P = NULL;
+	dev->FwDebugBLEDvalue_P = NULL;
+	dev->FwDebugBLEDflag_P = NULL;
+	dev->FwDebugBufferSize = 0;
+	dev->FwDebugFlags = 0;
+	dev->DebugFlags = 0;
+
+	/*
+	 * Get the firmware print buffer parameters from the firmware
+	 * If the command was successful map in the address.
+	 */
+	if (!aac_adapter_sync_cmd(dev, GET_DRIVER_BUFFER_PROPERTIES,
+	  0, 0, 0, 0, 0, 0,
+	  &ReturnStatus,
+	  &MonDriverBufferPhysAddrLow,
+	  &MonDriverBufferPhysAddrHigh,
+	  &MonDriverBufferSize,
+	  &MonDriverHeaderSize) && MonDriverBufferSize) {
+		unsigned long Offset = MonDriverBufferPhysAddrLow
+		                     - (dev->scsi_host_ptr->base & 0xffffffff);
+
+		/*
+		 * See if the address is already mapped in and if so set it up
+		 * from the base address
+		 */
+		if (((u32)(((u64)dev->scsi_host_ptr->base) >> 32)
+		  == MonDriverBufferPhysAddrHigh)
+		 && ((Offset + MonDriverBufferSize) < dev->base_size))
+			dev->FwDebugBuffer_P
+			  = ((unsigned char *)dev->regs.sa + Offset);
+
+		/*
+		 * If mapping went well, Set up the debug buffer fields in the
+		 * HBA structure from the data returned
+		 */
+		if (dev->FwDebugBuffer_P != NULL) {
+			dev->FwDebugFlags_P
+			  = (u32 *)(dev->FwDebugBuffer_P
+			  + FW_DEBUG_FLAGS_OFFSET);
+			dev->FwDebugStrLength_P
+			  = (u32 *)(dev->FwDebugBuffer_P
+			  + FW_DEBUG_STR_LENGTH_OFFSET);
+			dev->FwDebugBLEDvalue_P
+			  = dev->FwDebugBuffer_P
+			  + FW_DEBUG_BLED_OFFSET;
+			dev->FwDebugBLEDflag_P
+			  = dev->FwDebugBLEDvalue_P + 1;
+			dev->FwDebugBufferSize = MonDriverBufferSize;
+			dev->FwDebugBuffer_P += MonDriverHeaderSize;
+			dev->FwDebugFlags = 0;
+			dev->DebugFlags = aac_debug_flags;
+			return 1;
+		}
+	}
+
+	/*
+	 * The GET_DRIVER_BUFFER_PROPERTIES command failed
+	 */
+}
+	return 0;
+}
+
+#define PRINT_TIMEOUT (HZ/4) /* 1/4 second */
+
+void aac_fw_printf(struct aac_dev * dev, unsigned long PrintFlags, const char * fmt, ...)
+{
+if (nblank(fwprintf(x))) {
+	va_list args;
+	u32 Count;
+	unsigned long next_jiffies;
+	char PrintBuffer_P[PRINT_BUFFER_SIZE];
+
+	if ((((PrintFlags
+	  & ~(HBA_FLAGS_DBG_KERNEL_PRINT_B|HBA_FLAGS_DBG_FW_PRINT_B)) != 0)
+	  && (dev != NULL)
+	  && ((dev->DebugFlags & PrintFlags) == 0))
+	 || ((dev != NULL) && (dev->DebugFlags
+	   & (HBA_FLAGS_DBG_KERNEL_PRINT_B|HBA_FLAGS_DBG_FW_PRINT_B)) == 0))
+		return;
+	/*
+	 * Set up parameters and call sprintf function to format the data
+	 */
+	va_start(args, fmt);
+	vsprintf(PrintBuffer_P, fmt, args);
+	va_end(args);
+
+	/*
+	 * Make sure the HBA structure has been passed in for this section
+	 */
+	if ((dev != NULL) && (dev->FwDebugBufferSize)) {
+		/*
+		 * If we are set up for a Firmware print
+		 */
+		if ((dev->DebugFlags & HBA_FLAGS_DBG_FW_PRINT_B)
+		 && ((PrintFlags
+		  & (HBA_FLAGS_DBG_KERNEL_PRINT_B|HBA_FLAGS_DBG_FW_PRINT_B))
+		  != HBA_FLAGS_DBG_KERNEL_PRINT_B)) {
+			/*
+			 * Make sure the string size is within boundaries
+			 */
+			Count = strlen(PrintBuffer_P);
+			if (Count > dev->FwDebugBufferSize)
+				Count = (u16)dev->FwDebugBufferSize;
+
+			/*
+			 * Wait for no more than PRINT_TIMEOUT for the previous
+			 * message length to clear (the handshake).
+			 */
+			next_jiffies = jiffies + PRINT_TIMEOUT;
+			while ((next_jiffies - jiffies) >= 0) {
+				if (!(*dev->FwDebugStrLength_P))
+					break;
+				schedule();
+			}
+
+			/*
+			 * If the Length is clear, copy over the message, the
+			 * flags, and the length. Make sure the length is the
+			 * last because that is the signal for the Firmware to
+			 * pick it up.
+			 */
+			if (!(*dev->FwDebugStrLength_P)) {
+				memcpy(dev->FwDebugBuffer_P,
+				  PrintBuffer_P, Count);
+				*dev->FwDebugFlags_P = cpu_to_le32(dev->FwDebugFlags);
+				*dev->FwDebugStrLength_P = cpu_to_le32(Count);
+			} else
+				dev->DebugFlags &= ~HBA_FLAGS_DBG_FW_PRINT_B;
+		}
+
+		/*
+		 * If the Kernel Debug Print flag is set, send it off to the
+		 * Kernel debugger
+		 */
+		if ((dev->DebugFlags & HBA_FLAGS_DBG_KERNEL_PRINT_B)
+		 && ((PrintFlags
+		  & (HBA_FLAGS_DBG_KERNEL_PRINT_B|HBA_FLAGS_DBG_FW_PRINT_B))
+		  != HBA_FLAGS_DBG_FW_PRINT_B)) {
+			if (dev->FwDebugFlags & FW_DEBUG_FLAGS_NO_HEADERS_B)
+				printk ("%s", PrintBuffer_P);
+			else
+				printk (KERN_INFO "%s: %s\n",
+				  dev->scsi_host_ptr->hostt->proc_name,
+				  PrintBuffer_P);
+		}
+	}
+
+	/*
+	 * No HBA structure passed in so it has to be for the Kernel Debugger
+	 */
+	else if ((PrintFlags
+	  & (HBA_FLAGS_DBG_KERNEL_PRINT_B|HBA_FLAGS_DBG_FW_PRINT_B))
+	  != HBA_FLAGS_DBG_FW_PRINT_B) {
+		if ((dev != NULL)
+		 && (dev->FwDebugFlags & FW_DEBUG_FLAGS_NO_HEADERS_B))
+			printk ("%s", PrintBuffer_P);
+		else if (dev != NULL)
+			printk (KERN_INFO "%s: %s\n",
+			  dev->scsi_host_ptr->hostt->proc_name,
+			  PrintBuffer_P);
+		else
+			printk(KERN_INFO "%s\n", PrintBuffer_P);
+	}
+}
+}
+
+void aac_fw_print_mem(struct aac_dev * dev, unsigned long PrintFlags, u8 * Addr, int Count)
+{
+if (nblank(fwprintf(x))) {
+	int Offset, i;
+	u32 DebugFlags = 0;
+	char Buffer[100];
+	char * LineBuffer_P;
+
+	/*
+	 * If we have an HBA structure, save off the flags and set the no
+	 * headers flag so we don't have garbage between our lines of data
+	 */
+	if (dev != NULL) {
+		DebugFlags = dev->FwDebugFlags;
+		dev->FwDebugFlags |= FW_DEBUG_FLAGS_NO_HEADERS_B;
+	}
+
+	Offset = 0;
+
+	/*
+	 * Loop through all the data
+	 */
+	while (Offset < Count) {
+		/*
+		 * We will format each line into a buffer and then print out
+		 * the entire line so set the pointer to the beginning of the
+		 * buffer
+		 */
+		LineBuffer_P = Buffer;
+
+		/*
+		 * Set up the address in HEX
+		 */
+		sprintf(LineBuffer_P, "\n%04x  ", Offset);
+		LineBuffer_P += 6;
+
+		/*
+		 * Set up 16 bytes in HEX format
+		 */
+		for (i = 0; i < 16; ++i) {
+			/*
+			 * If we are past the count of data bytes to output,
+			 * pad with blanks
+			 */
+			sprintf (LineBuffer_P,
+			  (((Offset + i) >= Count) ? "   " : "%02x "),
+			  Addr[Offset + i]);
+			LineBuffer_P += 3;
+
+			/*
+			 * At the mid point we will put in a divider
+			 */
+			if (i == 7) {
+				sprintf (LineBuffer_P, "- ");
+				LineBuffer_P += 2;
+			}
+		}
+		/*
+		 * Now do the same 16 bytes at the end of the line in ASCII
+		 * format
+		 */
+		sprintf (LineBuffer_P, "  ");
+		LineBuffer_P += 2;
+		for (i = 0; i < 16; ++i) {
+			/*
+			 * If all data processed, OUT-O-HERE
+			 */
+			if ((Offset + i) >= Count)
+				break;
+
+			/*
+			 * If this is a printable ASCII character, convert it
+			 */
+			sprintf (LineBuffer_P,
+			  (((Addr[Offset + i] > 0x1F)
+			   && (Addr[Offset + i] < 0x7F))
+				? "%c"
+				: "."), Addr[Offset + i]);
+
+			++LineBuffer_P;
+		}
+		/*
+		 * The line is now formatted, so print it out
+		 */
+		aac_fw_printf(dev, PrintFlags, "%s", Buffer);
+
+		/*
+		 * Bump the offset by 16 for the next line
+		 */
+		Offset += 16;
+
+	}
+
+	/*
+	 * Restore the saved off flags
+	 */
+	if (dev != NULL)
+		dev->FwDebugFlags = DebugFlags;
+}
+}
diff --git a/drivers/scsi/aacraid/fwdebug.h b/drivers/scsi/aacraid/fwdebug.h
new file mode 100644
index 0000000..8cb26b8
--- /dev/null
+++ b/drivers/scsi/aacraid/fwdebug.h
@@ -0,0 +1,51 @@
+/*
+ *	Adaptec AAC series RAID controller driver
+ *
+ * Copyright (c) 2004 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef PRINT_BUFFER_SIZE
+
+#define PRINT_BUFFER_SIZE     512       /* Debugging print buffer size */
+
+#define HBA_FLAGS_DBG_FLAGS_MASK         0x0000ffff  /* Mask for debug flags */
+#define HBA_FLAGS_DBG_KERNEL_PRINT_B     0x00000001  /* Kernel Debugger Print */
+#define HBA_FLAGS_DBG_FW_PRINT_B         0x00000002  /* Firmware Debugger Print */
+#define HBA_FLAGS_DBG_FUNCTION_ENTRY_B   0x00000004  /* Function Entry Point */
+#define HBA_FLAGS_DBG_FUNCTION_EXIT_B    0x00000008  /* Function Exit */
+#define HBA_FLAGS_DBG_ERROR_B            0x00000010  /* Error Conditions */
+#define HBA_FLAGS_DBG_INIT_B             0x00000020  /* Init Prints */
+#define HBA_FLAGS_DBG_OS_COMMANDS_B      0x00000040  /* OS Command Info */
+#define HBA_FLAGS_DBG_SCAN_B             0x00000080  /* Device Scan */
+#define HBA_FLAGS_DBG_COALESCE_B         0x00000100  /* Coalescing Queueing flags */
+#define HBA_FLAGS_DBG_IOCTL_COMMANDS_B   0x00000200  /* IOCTL Command Info */
+#define HBA_FLAGS_DBG_SYNC_COMMANDS_B    0x00000400  /* SYNC Command Info */
+#define HBA_FLAGS_DBG_COMM_B             0x00000800  /* Comm Info */
+#define HBA_FLAGS_DBG_CSMI_COMMANDS_B    0x00001000  /* CSMI Command Info */
+#define HBA_FLAGS_DBG_AIF_B              0x00001000  /* Aif Info */
+
+#define FW_DEBUG_STR_LENGTH_OFFSET       0x00
+#define FW_DEBUG_FLAGS_OFFSET            0x04
+#define FW_DEBUG_BLED_OFFSET             0x08
+#define FW_DEBUG_FLAGS_NO_HEADERS_B      0x01 
+
+int aac_get_fw_debug_buffer(struct aac_dev *);
+void aac_fw_printf(struct aac_dev *, unsigned long, const char *, ...);
+void aac_fw_print_mem(struct aac_dev *, unsigned long, u8 *, int);
+
+#endif
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index 57d0a40..58c30ec 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -25,370 +25,440 @@
  *   linit.c
  *
  * Abstract: Linux Driver entry module for Adaptec RAID Array Controller
- *				
- *	Provides the following driver entry points:
- *		aac_detect()
- *		aac_release()
- *		aac_queuecommand()
- *		aac_resetcommand()
- *		aac_biosparm()
- *	
  */
 
+#define AAC_DRIVER_VERSION		"1.1-5"
+#ifndef AAC_DRIVER_BRANCH
+#define AAC_DRIVER_BRANCH		""
+#endif
+#define AAC_DRIVER_BUILD_DATE		__DATE__ " " __TIME__
+#define AAC_DRIVERNAME			"aacraid"
+
+#include <linux/version.h> /* for the following test */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,3))
+#include <linux/compat.h>
+#endif
+#include <linux/blkdev.h>
+#include <linux/completion.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
 #include <linux/module.h>
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,3))
+#include <linux/moduleparam.h>
+#else
 #include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/types.h>
 #include <linux/sched.h>
+#endif
 #include <linux/pci.h>
-#include <linux/spinlock.h>
 #include <linux/slab.h>
-#include <linux/completion.h>
+#include <linux/spinlock.h>
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,3))
+#include <linux/syscalls.h>
+#include <linux/ioctl32.h>
+#endif
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,9)) || defined(SCSI_HAS_SSLEEP)
+#include <linux/delay.h>
+#endif
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+#include <linux/dma-mapping.h>
+#endif
 #include <asm/semaphore.h>
-#include <linux/blk.h>
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)) && !defined(BLIST_NO_ULD_ATTACH))
+#include <scsi/scsi_devinfo.h>	/* Pick up BLIST_NO_ULD_ATTACH? */
+#endif
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsicam.h>
+#include <scsi/scsi_eh.h>
+#else
 #include "scsi.h"
 #include "hosts.h"
-
-#include "aacraid.h"
 #include "sd.h"
+#if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) && defined(SCSI_HAS_DUMP))
+#include "scsi_dump.h"
+#endif
+#include <linux/blk.h>	/* for io_request_lock definition */
+#endif
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11))
+#if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) ? defined(__x86_64__) : defined(CONFIG_COMPAT))
+#if ((KERNEL_VERSION(2,4,19) <= LINUX_VERSION_CODE) && (LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,21)))
+# include <asm-x86_64/ioctl32.h>
+#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+# include <asm/ioctl32.h>
+#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,3))
+# include <linux/ioctl32.h>
+#endif
+  /* Cast the function, since sys_ioctl does not match */
+# define aac_ioctl32(x,y) register_ioctl32_conversion((x), \
+    (int(*)(unsigned int,unsigned int,unsigned long,struct file*))(y))
+#endif
+#endif
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+# include <asm/uaccess.h>
+#endif
+#if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)) || ((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)) && !defined(PCI_HAS_SHUTDOWN)))
+#include <linux/reboot.h>
+#endif
 
-#define AAC_DRIVER_NAME	"aacraid"
+#include "aacraid.h"
+#include "fwdebug.h"
+
+#ifdef CONFIG_DEVFS_FS
+#include <linux/devfs_fs_kernel.h>
+#else
+#include <linux/fs.h>
+#endif
+
+#if (defined(AAC_DRIVER_BUILD))
+#define _str(x) #x
+#define str(x) _str(x)
+#define AAC_DRIVER_FULL_VERSION	AAC_DRIVER_VERSION "[" str(AAC_DRIVER_BUILD) "]" AAC_DRIVER_BRANCH
+#else
+#define AAC_DRIVER_FULL_VERSION	AAC_DRIVER_VERSION AAC_DRIVER_BRANCH " " AAC_DRIVER_BUILD_DATE
+#endif
 
 MODULE_AUTHOR("Red Hat Inc and Adaptec");
-MODULE_DESCRIPTION("Supports Dell PERC2, 2/Si, 3/Si, 3/Di, Adaptec Advanced Raid Products, and HP NetRAID-4M devices. http://domsch.com/linux/ or http://linux.adaptec.com");
+MODULE_DESCRIPTION("Dell PERC2, 2/Si, 3/Si, 3/Di, "
+		   "Adaptec Advanced Raid Products, "
+		   "HP NetRAID-4M, IBM ServeRAID & ICP SCSI driver");
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,7))
 MODULE_LICENSE("GPL");
-
-struct aac_dev *aac_devices[MAXIMUM_NUM_ADAPTERS];
-
-static unsigned aac_count = 0;
+#endif
+#if ((LINUX_VERSION_CODE > KERNEL_VERSION(2,6,3)) || defined(MODULE_VERSION))
+MODULE_VERSION(AAC_DRIVER_FULL_VERSION);
+#endif
+
+LIST_HEAD(aac_devices);
+#ifdef CONFIG_DEVFS_FS
+static devfs_handle_t devfs_handle;
+#endif
 static int aac_cfg_major = -1;
+char aac_driver_version[] = AAC_DRIVER_FULL_VERSION;
 
 /*
  * Because of the way Linux names scsi devices, the order in this table has
  * become important.  Check for on-board Raid first, add-in cards second.
  *
+ * Note: The last field is used to index into aac_drivers below.
+ */
+static struct pci_device_id aac_pci_tbl[] = {
+	{ 0x1028, 0x0001, 0x1028, 0x0001, 0, 0, 0 }, /* PERC 2/Si (Iguana/PERC2Si) */
+	{ 0x1028, 0x0002, 0x1028, 0x0002, 0, 0, 1 }, /* PERC 3/Di (Opal/PERC3Di) */
+	{ 0x1028, 0x0003, 0x1028, 0x0003, 0, 0, 2 }, /* PERC 3/Si (SlimFast/PERC3Si */
+	{ 0x1028, 0x0004, 0x1028, 0x00d0, 0, 0, 3 }, /* PERC 3/Di (Iguana FlipChip/PERC3DiF */
+	{ 0x1028, 0x0002, 0x1028, 0x00d1, 0, 0, 4 }, /* PERC 3/Di (Viper/PERC3DiV) */
+	{ 0x1028, 0x0002, 0x1028, 0x00d9, 0, 0, 5 }, /* PERC 3/Di (Lexus/PERC3DiL) */
+	{ 0x1028, 0x000a, 0x1028, 0x0106, 0, 0, 6 }, /* PERC 3/Di (Jaguar/PERC3DiJ) */
+	{ 0x1028, 0x000a, 0x1028, 0x011b, 0, 0, 7 }, /* PERC 3/Di (Dagger/PERC3DiD) */
+	{ 0x1028, 0x000a, 0x1028, 0x0121, 0, 0, 8 }, /* PERC 3/Di (Boxster/PERC3DiB) */
+	{ 0x9005, 0x0283, 0x9005, 0x0283, 0, 0, 9 }, /* catapult */
+	{ 0x9005, 0x0284, 0x9005, 0x0284, 0, 0, 10 }, /* tomcat */
+	{ 0x9005, 0x0285, 0x9005, 0x0286, 0, 0, 11 }, /* Adaptec 2120S (Crusader) */
+	{ 0x9005, 0x0285, 0x9005, 0x0285, 0, 0, 12 }, /* Adaptec 2200S (Vulcan) */
+	{ 0x9005, 0x0285, 0x9005, 0x0287, 0, 0, 13 }, /* Adaptec 2200S (Vulcan-2m) */
+	{ 0x9005, 0x0285, 0x17aa, 0x0286, 0, 0, 14 }, /* Legend S220 (Legend Crusader) */
+	{ 0x9005, 0x0285, 0x17aa, 0x0287, 0, 0, 15 }, /* Legend S230 (Legend Vulcan) */
+
+	{ 0x9005, 0x0285, 0x9005, 0x0288, 0, 0, 16 }, /* Adaptec 3230S (Harrier) */
+	{ 0x9005, 0x0285, 0x9005, 0x0289, 0, 0, 17 }, /* Adaptec 3240S (Tornado) */
+	{ 0x9005, 0x0285, 0x9005, 0x028a, 0, 0, 18 }, /* ASR-2020ZCR SCSI PCI-X ZCR (Skyhawk) */
+	{ 0x9005, 0x0285, 0x9005, 0x028b, 0, 0, 19 }, /* ASR-2025ZCR SCSI SO-DIMM PCI-X ZCR (Terminator) */
+	{ 0x9005, 0x0286, 0x9005, 0x028c, 0, 0, 20 }, /* ASR-2230S + ASR-2230SLP PCI-X (Lancer) */
+	{ 0x9005, 0x0286, 0x9005, 0x028d, 0, 0, 21 }, /* ASR-2130S (Lancer) */
+	{ 0x9005, 0x0286, 0x9005, 0x029b, 0, 0, 22 }, /* AAR-2820SA (Intruder) */
+	{ 0x9005, 0x0286, 0x9005, 0x029c, 0, 0, 23 }, /* AAR-2620SA (Intruder) */
+	{ 0x9005, 0x0286, 0x9005, 0x029d, 0, 0, 24 }, /* AAR-2420SA (Intruder) */
+	{ 0x9005, 0x0286, 0x9005, 0x029e, 0, 0, 25 }, /* ICP9024R0 (Lancer) */
+	{ 0x9005, 0x0286, 0x9005, 0x029f, 0, 0, 26 }, /* ICP9014R0 (Lancer) */
+	{ 0x9005, 0x0286, 0x9005, 0x02a0, 0, 0, 27 }, /* ICP9047MA (Lancer) */
+	{ 0x9005, 0x0286, 0x9005, 0x02a1, 0, 0, 28 }, /* ICP9087MA (Lancer) */
+	{ 0x9005, 0x0286, 0x9005, 0x02a3, 0, 0, 29 }, /* ICP5085AU (Hurricane) */
+	{ 0x9005, 0x0285, 0x9005, 0x02a4, 0, 0, 30 }, /* ICP9085LI (Marauder-X) */
+	{ 0x9005, 0x0285, 0x9005, 0x02a5, 0, 0, 31 }, /* ICP5085BR (Marauder-E) */
+	{ 0x9005, 0x0286, 0x9005, 0x02a6, 0, 0, 32 }, /* ICP9067MA (Intruder-6) */
+	{ 0x9005, 0x0287, 0x9005, 0x0800, 0, 0, 33 }, /* Themisto Jupiter Platform */
+	{ 0x9005, 0x0200, 0x9005, 0x0200, 0, 0, 33 }, /* Themisto Jupiter Platform */
+	{ 0x9005, 0x0286, 0x9005, 0x0800, 0, 0, 34 }, /* Callisto Jupiter Platform */
+	{ 0x9005, 0x0285, 0x9005, 0x028e, 0, 0, 35 }, /* ASR-2020SA SATA PCI-X ZCR (Skyhawk) */
+	{ 0x9005, 0x0285, 0x9005, 0x028f, 0, 0, 36 }, /* ASR-2025SA SATA SO-DIMM PCI-X ZCR (Terminator) */
+	{ 0x9005, 0x0285, 0x9005, 0x0290, 0, 0, 37 }, /* AAR-2410SA PCI SATA 4ch (Jaguar II) */
+	{ 0x9005, 0x0285, 0x1028, 0x0291, 0, 0, 38 }, /* CERC SATA RAID 2 PCI SATA 6ch (DellCorsair) */
+	{ 0x9005, 0x0285, 0x9005, 0x0292, 0, 0, 39 }, /* AAR-2810SA PCI SATA 8ch (Corsair-8) */
+	{ 0x9005, 0x0285, 0x9005, 0x0293, 0, 0, 40 }, /* AAR-21610SA PCI SATA 16ch (Corsair-16) */
+	{ 0x9005, 0x0285, 0x9005, 0x0294, 0, 0, 41 }, /* ESD SO-DIMM PCI-X SATA ZCR (Prowler) */
+	{ 0x9005, 0x0285, 0x103C, 0x3227, 0, 0, 42 }, /* AAR-2610SA PCI SATA 6ch */
+	{ 0x9005, 0x0285, 0x9005, 0x0296, 0, 0, 43 }, /* ASR-2240S (SabreExpress) */
+	{ 0x9005, 0x0285, 0x9005, 0x0297, 0, 0, 44 }, /* ASR-4005SAS */
+	{ 0x9005, 0x0285, 0x1014, 0x02F2, 0, 0, 45 }, /* IBM 8i (AvonPark) */
+	{ 0x9005, 0x0285, 0x1014, 0x0312, 0, 0, 45 }, /* IBM 8i (AvonPark Lite) */
+	{ 0x9005, 0x0286, 0x1014, 0x9580, 0, 0, 46 }, /* IBM 8k/8k-l8 (Aurora) */
+	{ 0x9005, 0x0286, 0x1014, 0x9540, 0, 0, 47 }, /* IBM 8k/8k-l4 (Aurora Lite) */
+	{ 0x9005, 0x0285, 0x9005, 0x0298, 0, 0, 48 }, /* ASR-4000SAS (BlackBird) */
+	{ 0x9005, 0x0285, 0x9005, 0x0299, 0, 0, 49 }, /* ASR-4800SAS (Marauder-X) */
+	{ 0x9005, 0x0285, 0x9005, 0x029a, 0, 0, 50 }, /* ASR-4805SAS (Marauder-E) */
+	{ 0x9005, 0x0286, 0x9005, 0x02a2, 0, 0, 51 }, /* ASR-4810SAS (Hurricane */
+
+	{ 0x9005, 0x0285, 0x1028, 0x0287, 0, 0, 52 }, /* Perc 320/DC*/
+	{ 0x1011, 0x0046, 0x9005, 0x0365, 0, 0, 53 }, /* Adaptec 5400S (Mustang)*/
+	{ 0x1011, 0x0046, 0x9005, 0x0364, 0, 0, 54 }, /* Adaptec 5400S (Mustang)*/
+	{ 0x1011, 0x0046, 0x9005, 0x1364, 0, 0, 55 }, /* Dell PERC2/QC */
+	{ 0x1011, 0x0046, 0x103c, 0x10c2, 0, 0, 56 }, /* HP NetRAID-4M */
+
+	{ 0x9005, 0x0285, 0x1028, PCI_ANY_ID, 0, 0, 57 }, /* Dell Catchall */
+	{ 0x9005, 0x0285, 0x17aa, PCI_ANY_ID, 0, 0, 58 }, /* Legend Catchall */
+	{ 0x9005, 0x0285, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 59 }, /* Adaptec Catch All */
+	{ 0x9005, 0x0286, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 60 }, /* Adaptec Rocket Catch All */
+	{ 0,}
+};
+MODULE_DEVICE_TABLE(pci, aac_pci_tbl);
+
+/*
  * dmb - For now we add the number of channels to this structure.  
  * In the future we should add a fib that reports the number of channels
  * for the card.  At that time we can remove the channels from here
  */
- 
 static struct aac_driver_ident aac_drivers[] = {
-	{ 0x1028, 0x0001, 0x1028, 0x0001, aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2 }, 		/* PERC 2/Si (Iguana/PERC2Si) */
-	{ 0x1028, 0x0002, 0x1028, 0x0002, aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2 }, 		/* PERC 3/Di (Opal/PERC3Di) */
-	{ 0x1028, 0x0003, 0x1028, 0x0003, aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2 }, 		/* PERC 3/Si (SlimFast/PERC3Si */
-	{ 0x1028, 0x0004, 0x1028, 0x00d0, aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2 }, 		/* PERC 3/Di (Iguana FlipChip/PERC3DiF */
-	{ 0x1028, 0x0002, 0x1028, 0x00d1, aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2 }, 		/* PERC 3/Di (Viper/PERC3DiV) */
-	{ 0x1028, 0x0002, 0x1028, 0x00d9, aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2 }, 		/* PERC 3/Di (Lexus/PERC3DiL) */
-	{ 0x1028, 0x000a, 0x1028, 0x0106, aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2 }, 		/* PERC 3/Di (Jaguar/PERC3DiJ) */
-	{ 0x1028, 0x000a, 0x1028, 0x011b, aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2 }, 		/* PERC 3/Di (Dagger/PERC3DiD) */
-	{ 0x1028, 0x000a, 0x1028, 0x0121, aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2 }, 		/* PERC 3/Di (Boxster/PERC3DiB) */
-	{ 0x9005, 0x0283, 0x9005, 0x0283, aac_rx_init, "aacraid",  "ADAPTEC ", "catapult        ", 2 }, 		/* catapult */
-	{ 0x9005, 0x0284, 0x9005, 0x0284, aac_rx_init, "aacraid",  "ADAPTEC ", "tomcat          ", 2 }, 		/* tomcat */
-	{ 0x9005, 0x0285, 0x9005, 0x0286, aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2120S   ", 1, AAC_QUIRK_31BIT },/* Adaptec 2120S (Crusader) */
-	{ 0x9005, 0x0285, 0x9005, 0x0285, aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2200S   ", 2, AAC_QUIRK_31BIT },/* Adaptec 2200S (Vulcan) */
-	{ 0x9005, 0x0285, 0x9005, 0x0287, aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2200S   ", 2, AAC_QUIRK_31BIT },/* Adaptec 2200S (Vulcan-2m) */
-	{ 0x9005, 0x0285, 0x17aa, 0x0286, aac_rx_init, "aacraid",  "Legend  ", "Legend S220     ", 1 }, 		/* Legend S220 (Legend Crusader) */
-	{ 0x9005, 0x0285, 0x17aa, 0x0287, aac_rx_init, "aacraid",  "Legend  ", "Legend S230     ", 2 }, 		/* Legend S230 (Legend Vulcan) */
-
-	{ 0x9005, 0x0285, 0x9005, 0x0288, aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 3230S   ", 2 }, 		/* Adaptec 3230S (Harrier) */
-	{ 0x9005, 0x0285, 0x9005, 0x0289, aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 3240S   ", 2 }, 		/* Adaptec 3240S (Tornado) */
-	{ 0x9005, 0x0285, 0x9005, 0x028a, aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-2020S PCI-X ", 2 }, 		/* ASR-2020S PCI-X ZCR (Skyhawk) */
-	{ 0x9005, 0x0285, 0x9005, 0x028b, aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-2020S PCI-X ", 2 }, 		/* ASR-2020S SO-DIMM PCI-X ZCR (Terminator) */
-	{ 0x9005, 0x0285, 0x9005, 0x0290, aac_rx_init, "aacraid",  "ADAPTEC ", "AAR-2410SA SATA ", 2 }, 		/* AAR-2410SA PCI SATA 4ch (Jaguar II) */
-	{ 0x9005, 0x0285, 0x1028, 0x0291, aac_rx_init, "aacraid",  "DELL    ", "CERC SATA RAID 2 ", 2 },		/* CERC SATA RAID 2 PCI SATA 8ch (DellCorsair) */
-	{ 0x9005, 0x0285, 0x9005, 0x0292, aac_rx_init, "aacraid",  "ADAPTEC ", "AAR-2810SA SATA ", 2 }, 		/* AAR-2810SA PCI SATA 8ch (Corsair-8) */
-	{ 0x9005, 0x0285, 0x9005, 0x0293, aac_rx_init, "aacraid",  "ADAPTEC ", "AAR-21610SA SATA ", 2 },		/* AAR-21610SA PCI SATA 16ch (Corsair-16) */
-	{ 0x9005, 0x0285, 0x9005, 0x0294, aac_rx_init, "aacraid",  "ADAPTEC ", "SO-DIMM SATA ZCR ", 2 },		/* ESD SO-DIMM PCI-X SATA ZCR (Prowler) */
-	{ 0x9005, 0x0285, 0x0E11, 0x0295, aac_rx_init, "aacraid",  "ADAPTEC ", "SATA 6Channel   ", 1 }, 		/* SATA 6Ch (Bearcat) */
-
-	{ 0x9005, 0x0285, 0x1028, 0x0287, aac_rx_init, "percraid", "DELL    ", "PERC 320/DC     ", 2 },			/* Perc 320/DC*/
-	{ 0x1011, 0x0046, 0x9005, 0x0365, aac_sa_init, "aacraid",  "ADAPTEC ", "Adaptec 5400S   ", 4 }, 		/* Adaptec 5400S (Mustang)*/
-	{ 0x1011, 0x0046, 0x9005, 0x0364, aac_sa_init, "aacraid",  "ADAPTEC ", "AAC-364         ", 4 },			/* Adaptec 5400S (Mustang)*/
-	{ 0x1011, 0x0046, 0x9005, 0x1364, aac_sa_init, "percraid", "DELL    ", "PERCRAID        ", 4 },			/* Dell PERC2 "Quad Channel" */
-	{ 0x1011, 0x0046, 0x103c, 0x10c2, aac_sa_init, "hpnraid",  "HP      ", "NetRAID         ", 4 },			/* HP NetRAID-4M */
-	{ 0x9005, 0x0285, 0x1028, PCI_ANY_ID,
-					  aac_rx_init, "aacraid",  "DELL    ", "RAID            ", 2, AAC_QUIRK_31BIT },/* Dell Catchall */
-	{ 0x9005, 0x0285, 0x17aa, PCI_ANY_ID,
-					  aac_rx_init, "aacraid",  "Legend  ", "RAID            ", 2, AAC_QUIRK_31BIT },/* Legend Catchall */
-	{ 0x9005, 0x0285, PCI_ANY_ID, PCI_ANY_ID,
-					  aac_rx_init, "aacraid",  "ADAPTEC ", "RAID            ", 2, AAC_QUIRK_31BIT } /* Adaptec Catch All */
-};
-
-#define NUM_AACTYPES	(sizeof(aac_drivers) / sizeof(struct aac_driver_ident))
-static int num_aacdrivers = NUM_AACTYPES;
-
-static int aac_cfg_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg);
-static int aac_cfg_open(struct inode * inode, struct file * file);
-static int aac_cfg_release(struct inode * inode,struct file * file);
-
-static struct file_operations aac_cfg_fops = {
-	owner: THIS_MODULE,
-	ioctl: aac_cfg_ioctl,
-	open: aac_cfg_open,
-	release: aac_cfg_release
+	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 2/Si (Iguana/PERC2Si) */
+	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Opal/PERC3Di) */
+	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Si (SlimFast/PERC3Si */
+	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Iguana FlipChip/PERC3DiF */
+	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Viper/PERC3DiV) */
+	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Lexus/PERC3DiL) */
+	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Jaguar/PERC3DiJ) */
+	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Dagger/PERC3DiD) */
+	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Boxster/PERC3DiB) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "catapult        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* catapult */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "tomcat          ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* tomcat */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2120S   ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Adaptec 2120S (Crusader) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2200S   ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Adaptec 2200S (Vulcan) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2200S   ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Adaptec 2200S (Vulcan-2m) */
+	{ aac_rx_init, "aacraid",  "Legend  ", "Legend S220     ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Legend S220 (Legend Crusader) */
+	{ aac_rx_init, "aacraid",  "Legend  ", "Legend S230     ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Legend S230 (Legend Vulcan) */
+
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 3230S   ", 2 }, /* Adaptec 3230S (Harrier) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 3240S   ", 2 }, /* Adaptec 3240S (Tornado) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-2020ZCR     ", 2 }, /* ASR-2020ZCR SCSI PCI-X ZCR (Skyhawk) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-2025ZCR     ", 2 }, /* ASR-2025ZCR SCSI SO-DIMM PCI-X ZCR (Terminator) */
+	{ aac_rkt_init, "aacraid",  "ADAPTEC ", "ASR-2230S PCI-X ", 2 }, /* ASR-2230S + ASR-2230SLP PCI-X (Lancer) */
+	{ aac_rkt_init, "aacraid",  "ADAPTEC ", "ASR-2130S PCI-X ", 1 }, /* ASR-2130S (Lancer) */
+	{ aac_rkt_init, "aacraid",  "ADAPTEC ", "AAR-2820SA      ", 1 }, /* AAR-2820SA (Intruder) */
+	{ aac_rkt_init, "aacraid",  "ADAPTEC ", "AAR-2620SA      ", 1 }, /* AAR-2620SA (Intruder) */
+	{ aac_rkt_init, "aacraid",  "ADAPTEC ", "AAR-2420SA      ", 1 }, /* AAR-2420SA (Intruder) */
+	{ aac_rkt_init, "aacraid",  "ICP     ", "ICP9024R0       ", 2 }, /* ICP9024R0 (Lancer) */
+	{ aac_rkt_init, "aacraid",  "ICP     ", "ICP9014R0       ", 1 }, /* ICP9014R0 (Lancer) */
+	{ aac_rkt_init, "aacraid",  "ICP     ", "ICP9047MA       ", 1 }, /* ICP9047MA (Lancer) */
+	{ aac_rkt_init, "aacraid",  "ICP     ", "ICP9087MA       ", 1 }, /* ICP9087MA (Lancer) */
+	{ aac_rkt_init, "aacraid",  "ICP     ", "ICP5085AU       ", 1 }, /* ICP5085AU (Hurricane) */
+	{ aac_rx_init, "aacraid",  "ICP     ", "ICP9085LI       ", 1 }, /* ICP9085LI (Marauder-X) */
+	{ aac_rx_init, "aacraid",  "ICP     ", "ICP5085BR       ", 1 }, /* ICP5085BR (Marauder-E) */
+	{ aac_rkt_init, "aacraid",  "ICP     ", "ICP9067MA       ", 1 }, /* ICP9067MA (Intruder-6) */
+	{ NULL        , "aacraid",  "ADAPTEC ", "Themisto        ", 0, AAC_QUIRK_SLAVE }, /* Jupiter Platform */
+	{ aac_rkt_init, "aacraid",  "ADAPTEC ", "Callisto        ", 2, AAC_QUIRK_MASTER }, /* Jupiter Platform */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-2020SA       ", 1 }, /* ASR-2020SA SATA PCI-X ZCR (Skyhawk) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-2025SA       ", 1 }, /* ASR-2025SA SATA SO-DIMM PCI-X ZCR (Terminator) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "AAR-2410SA SATA ", 1 }, /* AAR-2410SA PCI SATA 4ch (Jaguar II) */
+	{ aac_rx_init, "aacraid",  "DELL    ", "CERC SR2        ", 1 }, /* CERC SATA RAID 2 PCI SATA 6ch (DellCorsair) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "AAR-2810SA SATA ", 1 }, /* AAR-2810SA PCI SATA 8ch (Corsair-8) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "AAR-21610SA SATA", 1 }, /* AAR-21610SA PCI SATA 16ch (Corsair-16) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-2026ZCR     ", 1 }, /* ESD SO-DIMM PCI-X SATA ZCR (Prowler) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "AAR-2610SA      ", 1 }, /* SATA 6Ch (Bearcat) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-2240S       ", 1 }, /* ASR-2240S (SabreExpress) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-4005SAS     ", 1 }, /* ASR-4005SAS */
+	{ aac_rx_init, "ServeRAID","IBM     ", "ServeRAID 8i    ", 1 }, /* IBM 8i (AvonPark) */
+	{ aac_rkt_init, "ServeRAID","IBM     ", "ServeRAID 8k-l8 ", 1 }, /* IBM 8k/8k-l8 (Aurora) */
+	{ aac_rkt_init, "ServeRAID","IBM     ", "ServeRAID 8k-l4 ", 1 }, /* IBM 8k/8k-l4 (Aurora Lite) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-4000SAS     ", 1 }, /* ASR-4000SAS (BlackBird & AvonPark) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-4800SAS     ", 1 }, /* ASR-4800SAS (Marauder-X) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-4805SAS     ", 1 }, /* ASR-4805SAS (Marauder-E) */
+	{ aac_rkt_init, "aacraid",  "ADAPTEC ", "ASR-4810SAS     ", 1 }, /* ASR-4810SAS (Hurricane) */
+
+	{ aac_rx_init, "percraid", "DELL    ", "PERC 320/DC     ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Perc 320/DC*/
+	{ aac_sa_init, "aacraid",  "ADAPTEC ", "Adaptec 5400S   ", 4, AAC_QUIRK_34SG }, /* Adaptec 5400S (Mustang)*/
+	{ aac_sa_init, "aacraid",  "ADAPTEC ", "AAC-364         ", 4, AAC_QUIRK_34SG }, /* Adaptec 5400S (Mustang)*/
+	{ aac_sa_init, "percraid", "DELL    ", "PERCRAID        ", 4, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Dell PERC2/QC */
+	{ aac_sa_init, "hpnraid",  "HP      ", "NetRAID         ", 4, AAC_QUIRK_34SG }, /* HP NetRAID-4M */
+
+	{ aac_rx_init, "aacraid",  "DELL    ", "RAID            ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Dell Catchall */
+	{ aac_rx_init, "aacraid",  "Legend  ", "RAID            ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Legend Catchall */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "RAID            ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Adaptec Catch All */
+	{ aac_rkt_init, "aacraid", "ADAPTEC ", "RAID            ", 2 } /* Adaptec Rocket Catch All */
 };
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11))
 
-static int aac_detect(Scsi_Host_Template *);
-static int aac_release(struct Scsi_Host *);
-static int aac_queuecommand(Scsi_Cmnd *, void (*CompletionRoutine)(Scsi_Cmnd *));
-static int aac_biosparm(Scsi_Disk *, kdev_t, int *);
-static int aac_procinfo(char *, char **, off_t, int, int, int);
-static int aac_ioctl(Scsi_Device *, int, void *);
-static int aac_eh_abort(Scsi_Cmnd * cmd);
-static int aac_eh_device_reset(Scsi_Cmnd* cmd);
-static int aac_eh_bus_reset(Scsi_Cmnd* cmd);
-static int aac_eh_reset(Scsi_Cmnd* cmd);
+#if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) ? defined(__x86_64__) : defined(CONFIG_COMPAT))
+/* 
+ * Promote 32 bit apps that call get_next_adapter_fib_ioctl to 64 bit version 
+ */
+static int aac_get_next_adapter_fib_ioctl(unsigned int fd, unsigned int cmd, 
+		unsigned long arg, struct file *file)
+{
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+	struct fib_ioctl f;
+	mm_segment_t fs;
+	int retval;
+
+	memset (&f, 0, sizeof(f));
+	if (copy_from_user(&f, (void __user *)arg, sizeof(f) - sizeof(u32)))
+		return -EFAULT;
+	fs = get_fs();
+	set_fs(get_ds());
+	retval = sys_ioctl(fd, cmd, (unsigned long)&f);
+	set_fs(fs);
+	return retval;
+#else
+	struct fib_ioctl __user *f;
+
+	f = compat_alloc_user_space(sizeof(*f));
+	if (!access_ok(VERIFY_WRITE, f, sizeof(*f)))
+		return -EFAULT;
+
+	clear_user(f, sizeof(*f));
+	if (copy_in_user(f, (void __user *)arg, sizeof(*f) - sizeof(u32)))
+		return -EFAULT;
+
+	return sys_ioctl(fd, cmd, (unsigned long)f);
+#endif
+}
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+#define sys_ioctl NULL	/* register_ioctl32_conversion defaults to this when NULL passed in as a handler */
+#endif
+#endif
 
-static void aac_queuedepth(struct Scsi_Host *, Scsi_Device *);
+#endif
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0))
+#if (!defined(SCSI_HAS_SCSI_IN_DETECTION))
+static struct Scsi_Host * aac_dummy;
+#endif
 
 /**
  *	aac_detect	-	Probe for aacraid cards
  *	@template: SCSI driver template
  *
- *	Probe for AAC Host Adapters initialize, register, and report the 
- *	configuration of each AAC Host Adapter found.
- *	Returns the number of adapters successfully initialized and 
- *	registered.
- *	Initializes all data necessary for this particular SCSI driver.
- *	Notes:
- *	The detect routine must not call any of the mid level functions 
- *	to queue commands because things are not guaranteed to be set 
- *	up yet. The detect routine can send commands to the host adapter 
- *	as long as the program control will not be passed to scsi.c in 
- *	the processing of the command. Note especially that 
- *	scsi_malloc/scsi_free must not be called.
- *
+ *	This is but a stub to convince the 2.4 scsi layer to scan targets,
+ *	the pci scan has already picked up the adapters.
  */
- 
 static int aac_detect(Scsi_Host_Template *template)
 {
-	int index;
-	int container;
-	u16 vendor_id, device_id;
-	struct Scsi_Host *host_ptr;
-	struct pci_dev *dev = NULL;
-	struct aac_dev *aac;
-	struct fsa_scsi_hba *fsa_dev_ptr;
-	char *name = NULL;
-	
-	printk(KERN_INFO "Red Hat/Adaptec %s driver (%d.%d-%d %s)\n",
-		AAC_DRIVER_NAME,
-		AAC_DRIVER_VERSION >> 24,
-		(AAC_DRIVER_VERSION >> 16) & 0xFF,
-		(AAC_DRIVER_VERSION >> 8) & 0xFF,
-		AAC_DRIVER_BUILD_DATE);
-		
-	/* setting up the proc directory structure */
-	
-	template->proc_name = "aacraid";
-	spin_unlock_irq(&io_request_lock);
-
-	for( index = 0; index != num_aacdrivers; index++ )
-	{
-		device_id = aac_drivers[index].device;
-		vendor_id = aac_drivers[index].vendor;
-		name = aac_drivers[index].name;
-		dprintk((KERN_DEBUG "Checking %s %x/%x/%x/%x.\n", 
-			name, vendor_id, device_id,
-			aac_drivers[index].subsystem_vendor,
-			aac_drivers[index].subsystem_device));
-
-		dev = NULL;
-		while((dev = pci_find_device(vendor_id, device_id, dev))) {
-			if (pci_enable_device(dev))
-				continue;
-			pci_set_master(dev);
-			
-			if(aac_drivers[index].quirks & AAC_QUIRK_31BIT)
-				pci_set_dma_mask(dev, 0x7FFFFFFFULL);
-			else
-				pci_set_dma_mask(dev, 0xFFFFFFFFULL);
-
-			if((dev->subsystem_vendor != aac_drivers[index].subsystem_vendor) || 
-			   (dev->subsystem_device != aac_drivers[index].subsystem_device))
-					continue;
-
-			dprintk((KERN_DEBUG "%s device detected.\n", name));
-			dprintk((KERN_DEBUG "%x/%x/%x/%x.\n", vendor_id, device_id, 
-				aac_drivers[index].subsystem_vendor, aac_drivers[index].subsystem_device));
-			/*
-			 * scsi_register() allocates memory for a Scsi_Hosts structure and
-			 * links it into the linked list of host adapters. This linked list
-			 * contains the data for all possible <supported> scsi hosts.
-			 * This is similar to the Scsi_Host_Template, except that we have
-			 * one entry for each actual physical host adapter on the system,
-			 * stored as a linked list. If there are two AAC boards, then we
-			 * will need to make two Scsi_Host entries, but there will be only
-			 * one Scsi_Host_Template entry. The second argument to scsi_register()
-			 * specifies the size of the extra memory we want to hold any device 
-			 * specific information.
-			 */
-			host_ptr = scsi_register( template, sizeof(struct aac_dev) );
-			if(host_ptr == NULL)
-				continue;
-			/* Increment the host adapter count */
-			aac_count++;
-			/* 
-			 * These three parameters can be used to allow for wide SCSI 
-			 * and for host adapters that support multiple buses.
-			 */
-			host_ptr->irq = dev->irq;		/* Adapter IRQ number */
-			/* host_ptr->base = ( char * )(dev->resource[0].start & ~0xff); */
-			host_ptr->base = dev->resource[0].start;
-			scsi_set_pci_device(host_ptr, dev);
-			dprintk((KERN_DEBUG "Device base address = 0x%lx [0x%lx].\n", host_ptr->base, dev->resource[0].start));
-			dprintk((KERN_DEBUG "Device irq = 0x%x.\n", dev->irq));
-			/*
-			 * The unique_id field is a unique identifier that must
-			 * be assigned so that we have some way of identifying
-			 * each host adapter properly and uniquely. For hosts 
-			 * that do not support more than one card in the
-			 * system, this does not need to be set. It is
-			 * initialized to zero in scsi_register(). This is the 
-			 * value returned as aac->id.
-			 */
-			host_ptr->unique_id = aac_count - 1;
-			/*
-			 *	This function is called after the device list has
-			 *	been built to find the tagged queueing depth 
-			 *	supported for each device.
-			 */
-			host_ptr->select_queue_depths = aac_queuedepth;
-			aac = (struct aac_dev *)host_ptr->hostdata;
-			/* attach a pointer back to Scsi_Host */
-			aac->scsi_host_ptr = host_ptr;	
-			aac->pdev = dev;
-			aac->name = aac->scsi_host_ptr->hostt->name;
-			aac->id = aac->scsi_host_ptr->unique_id;
-			aac->cardtype =  index;
-
-			aac->fibs = (struct fib*) kmalloc(sizeof(struct fib)*AAC_NUM_FIB, GFP_KERNEL);
-			spin_lock_init(&aac->fib_lock);
-
-			/* Initialize the ordinal number of the device to -1 */
-			fsa_dev_ptr = &(aac->fsa_dev);
-			for( container = 0; container < MAXIMUM_NUM_CONTAINERS; container++ )
-				fsa_dev_ptr->devno[container] = -1;
-
-			dprintk((KERN_DEBUG "Initializing Hardware...\n"));
-			if((*aac_drivers[index].init)(aac , host_ptr->unique_id) != 0)
-			{
-				/* device initialization failed */
-				printk(KERN_WARNING "aacraid: device initialization failed.\n");
-				scsi_unregister(host_ptr);
-				aac_count--;
-				continue;
-			} 
-			dprintk((KERN_DEBUG "%s:%d device initialization successful.\n", name, host_ptr->unique_id));
-			aac_get_adapter_info(aac);
-			if(aac->nondasd_support == 1)
-			{
-				/*
-				 * max channel will be the physical channels plus 1 virtual channel 
-				 * all containers are on the virtual channel 0
-				 * physical channels are address by their actual physical number+1
-				 */
-				host_ptr->max_channel = aac_drivers[index].channels+1;
-			} else {
-				host_ptr->max_channel = 1;
- 			}
-			dprintk((KERN_DEBUG "Device has %d logical channels\n", host_ptr->max_channel));
-			aac_get_containers(aac);
-			aac_devices[aac_count-1] = aac;
-
-			/*
-			 * dmb - we may need to move the setting of these parms somewhere else once
-			 * we get a fib that can report the actual numbers
-			 */
-			host_ptr->max_id = AAC_MAX_TARGET;
-			host_ptr->max_lun = AAC_MAX_LUN;
-		}
+#if (defined(AAC_DEBUG_INSTRUMENT_INIT))
+	printk(KERN_INFO "aac_detect(%p)\n", template);
+#endif
+#if (!defined(SCSI_HAS_SCSI_IN_DETECTION))
+	/* By changing the host list we trick a scan */
+	if (aac_dummy) {
+#if (defined(AAC_DEBUG_INSTRUMENT_INIT))
+		printk(KERN_INFO "scsi_host_put(%p)\n", aac_dummy);
+#endif
+		scsi_host_put(aac_dummy);
+		aac_dummy = NULL;
 	}
-
-	if( aac_count ){
-		if((aac_cfg_major = register_chrdev( 0, "aac", &aac_cfg_fops))<0)
-			printk(KERN_WARNING "aacraid: unable to register \"aac\" device.\n");
-	}
-	spin_lock_irq(&io_request_lock);
-
-	template->present = aac_count; /* # of cards of this type found */
-	return aac_count;
+#if (defined(AAC_DEBUG_INSTRUMENT_INIT))
+	printk(KERN_INFO "aac_detect()=%d\n", !list_empty(&aac_devices));
+#endif
+	return !list_empty(&aac_devices);
+#else
+	return template->present = 1;
+#endif
 }
 
-/**
- *	aac_release	-	release SCSI host resources
- *	@host_ptr: SCSI host to clean up
- *
- *	Release all resources previously acquired to support a specific Host 
- *	Adapter and unregister the AAC Host Adapter.
- *
- *	BUGS: Does not wait for the thread it kills to die.
- */
-
-static int aac_release(struct Scsi_Host *host_ptr)
-{
-	struct aac_dev *dev;
-	dprintk((KERN_DEBUG "aac_release.\n"));
-	dev = (struct aac_dev *)host_ptr->hostdata;
-	/*
-	 *	kill any threads we started
-	 */
-	kill_proc(dev->thread_pid, SIGKILL, 0);
-	wait_for_completion(&dev->aif_completion);
-	/*
-	 *	Call the comm layer to detach from this adapter
-	 */
-	aac_detach(dev);
-	/* Check free orderings... */
-	/* remove interrupt binding */
-	free_irq(host_ptr->irq, dev);
-	iounmap((void * )dev->regs.sa);
-	/* unregister adapter */
-	scsi_unregister(host_ptr);
-	/*
-	 *	FIXME: This assumes no hot plugging is going on...
-	 */
-	if( aac_cfg_major >= 0 )
-	{
-		unregister_chrdev(aac_cfg_major, "aac");
-		aac_cfg_major = -1;
-	}
-	return 0;
-}
+#endif
 
 /**
  *	aac_queuecommand	-	queue a SCSI command
- *	@scsi_cmnd_ptr:	SCSI command to queue
- *	@CompletionRoutine: Function to call on command completion
+ *	@cmd:		SCSI command to queue
+ *	@done:		Function to call on command completion
  *
  *	Queues a command for execution by the associated Host Adapter.
+ *
+ *	TODO: unify with aac_scsi_cmd().
  */ 
 
-static int aac_queuecommand(Scsi_Cmnd *scsi_cmnd_ptr, void (*complete)(Scsi_Cmnd *))
+static int aac_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
 {
-	int ret;
-
-	scsi_cmnd_ptr->scsi_done = complete;
-	/*
-	 *	aac_scsi_cmd() handles command processing, setting the 
-	 *	result code and calling completion routine. 
-	 */
-	if((ret = aac_scsi_cmd(scsi_cmnd_ptr)) != 0)
-		dprintk((KERN_DEBUG "aac_scsi_cmd failed.\n"));
-	return ret;
+#if (defined(AAC_DEBUG_INSTRUMENT_TIMING))
+	u64 lba;
+	u32 count = 0;
+	struct timeval now;
+	do_gettimeofday(&now);
+	if ((cmd->cmnd[0] == WRITE_6)	/* 6 byte command */
+	 || (cmd->cmnd[0] == READ_6)) {
+		lba = ((cmd->cmnd[1] & 0x1F) << 16)
+		    | (cmd->cmnd[2] << 8) | cmd->cmnd[3];
+		count = cmd->cmnd[4];
+		if (count == 0)
+			count = 256;
+#if (defined(WRITE_16))
+	} else if ((cmd->cmnd[0] == WRITE_16) /* 16 byte command */
+	 || (cmd->cmnd[0] == READ_16)) {
+		lba = ((u64)cmd->cmnd[2] << 56)
+		    | ((u64)cmd->cmnd[3] << 48)
+		    | ((u64)cmd->cmnd[4] << 40)
+		    | ((u64)cmd->cmnd[9] << 32)
+		    | (cmd->cmnd[6] << 24)
+		    | (cmd->cmnd[7] << 16)
+		    | (cmd->cmnd[8] << 8) | cmd->cmnd[9];
+		count = (cmd->cmnd[10] << 24)
+		      | (cmd->cmnd[11] << 16)
+		      | (cmd->cmnd[12] << 8) | cmd->cmnd[13];
+#endif
+	} else if ((cmd->cmnd[0] == WRITE_12) /* 12 byte command */
+	 || (cmd->cmnd[0] == READ_12)) {
+		lba = (cmd->cmnd[2] << 24)
+		    | (cmd->cmnd[3] << 16)
+		    | (cmd->cmnd[4] << 8) | cmd->cmnd[5];
+		count = (cmd->cmnd[6] << 24)
+		      | (cmd->cmnd[7] << 16)
+		      | (cmd->cmnd[8] << 8) | cmd->cmnd[9];
+	} else if ((cmd->cmnd[0] == WRITE_10) /* 10 byte command */
+	 || (cmd->cmnd[0] == READ_10)) {
+		lba = (cmd->cmnd[2] << 24)
+		    | (cmd->cmnd[3] << 16)
+		    | (cmd->cmnd[4] << 8) | cmd->cmnd[5];
+		count = (cmd->cmnd[7] << 8) | cmd->cmnd[8];
+	} else
+		lba = (u64)(long)cmd;
+	printk(((count)
+	  ? KERN_DEBUG "%lu.%06lu q%lu %llu[%u]\n"
+	  : KERN_DEBUG "%lu.%06lu q%lu 0x%llx\n"),
+ 	  now.tv_sec % 100, now.tv_usec,
+	  ((struct aac_dev *)cmd->device->host->hostdata)->queues->queue[AdapNormCmdQueue].numpending,
+	  lba, count);
+#endif
+	cmd->scsi_done = done;
+	cmd->SCp.phase = AAC_OWNER_LOWLEVEL;
+	return (aac_scsi_cmd(cmd) ? FAILED : 0);
 } 
 
 /**
- *	aac_driverinfo		-	Returns the host adapter name
- *	@host_ptr:	Scsi host to report on
+ *	aac_info		-	Returns the host adapter name
+ *	@shost:		Scsi host to report on
  *
  *	Returns a static string describing the device in question
  */
 
-const char *aac_driverinfo(struct Scsi_Host *host_ptr)
+static const char *aac_info(struct Scsi_Host *shost)
 {
-	struct aac_dev *dev = (struct aac_dev *)host_ptr->hostdata;
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0))
+	struct aac_dev *dev;
+#if (!defined(SCSI_HAS_SCSI_IN_DETECTION))
+	if (shost == aac_dummy)
+		return shost->hostt->name;
+#endif
+	dev = (struct aac_dev *)shost->hostdata;
+	if (!dev
+	 || (dev->cardtype >= (sizeof(aac_drivers)/sizeof(aac_drivers[0]))))
+		return shost->hostt->name;
+	if (dev->scsi_host_ptr != shost)
+		return shost->hostt->name;
+#else
+	struct aac_dev *dev = (struct aac_dev *)shost->hostdata;
+#endif
 	return aac_drivers[dev->cardtype].name;
 }
 
@@ -398,15 +468,21 @@ const char *aac_driverinfo(struct Scsi_Host *host_ptr)
  *
  * 	Returns a pointer to the entry in the driver lookup table.
  */
+
 struct aac_driver_ident* aac_get_driver_ident(int devtype)
 {
-	return  &aac_drivers[devtype];
+	return &aac_drivers[devtype];
 }
 
 /**
  *	aac_biosparm	-	return BIOS parameters for disk
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
  *	@disk: SCSI disk object to process
  *	@device: kdev_t of the disk in question
+#endif
+ *	@sdev: The scsi device corresponding to the disk
+ *	@bdev: the block device corresponding to the disk
+ *	@capacity: the sector capacity of the disk
  *	@geom: geometry block to fill in
  *
  *	Return the Heads/Sectors/Cylinders BIOS Disk Parameters for Disk.  
@@ -424,77 +500,80 @@ struct aac_driver_ident* aac_get_driver_ident(int devtype)
  *	be displayed.
  */
  
-static int aac_biosparm(Scsi_Disk *disk, kdev_t dev, int *geom)
+static int aac_biosparm(
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+	struct scsi_device *sdev, struct block_device *bdev, sector_t capacity,
+#else
+	Scsi_Disk *disk, kdev_t dev,
+#endif
+	int *geom)
 {
 	struct diskparm *param = (struct diskparm *)geom;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+	unsigned char *buf;
+#else
 	struct buffer_head * buf;
+	sector_t capacity = disk->capacity;
+#endif
 
 	dprintk((KERN_DEBUG "aac_biosparm.\n"));
 
 	/*
 	 *	Assuming extended translation is enabled - #REVISIT#
 	 */
-	if( disk->capacity >= 2 * 1024 * 1024 ) /* 1 GB in 512 byte sectors */
-	{
-		if( disk->capacity >= 4 * 1024 * 1024 ) /* 2 GB in 512 byte sectors */
-		{
+	if (capacity >= 2 * 1024 * 1024) { /* 1 GB in 512 byte sectors */
+		if(capacity >= 4 * 1024 * 1024) { /* 2 GB in 512 byte sectors */
 			param->heads = 255;
 			param->sectors = 63;
-		}
-		else
-		{
+		} else {
 			param->heads = 128;
 			param->sectors = 32;
 		}
-	}
-	else
-	{
+	} else {
 		param->heads = 64;
 		param->sectors = 32;
 	}
 
-	param->cylinders = disk->capacity/(param->heads * param->sectors);
+	param->cylinders = cap_to_cyls(capacity, param->heads * param->sectors);
 
-	/*
-	 *	Read the first 1024 bytes from the disk device
+	/* 
+	 *	Read the first 1024 bytes from the disk device, if the boot
+	 *	sector partition table is valid, search for a partition table
+	 *	entry whose end_head matches one of the standard geometry 
+	 *	translations ( 64/32, 128/32, 255/63 ).
 	 */
-
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+	buf = scsi_bios_ptable(bdev);
+#else
 	buf = bread(MKDEV(MAJOR(dev), MINOR(dev)&~0xf), 0, block_size(dev));
 	if(buf == NULL)
 		return 0;
-	/* 
-	 *	If the boot sector partition table is valid, search for a partition 
-	 *	table entry whose end_head matches one of the standard geometry 
-	 *	translations ( 64/32, 128/32, 255/63 ).
-	 */
-	 
-	if(*(unsigned short *)(buf->b_data + 0x1fe) == cpu_to_le16(0xaa55))
-	{
+#endif
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+	if(*(__le16 *)(buf + 0x40) == cpu_to_le16(0xaa55)) {
+		struct partition *first = (struct partition * )buf;
+#else
+	if(*(unsigned short *)(buf->b_data + 0x1fe) == cpu_to_le16(0xaa55)) {
 		struct partition *first = (struct partition * )(buf->b_data + 0x1be);
+#endif
 		struct partition *entry = first;
 		int saved_cylinders = param->cylinders;
 		int num;
 		unsigned char end_head, end_sec;
 
-		for(num = 0; num < 4; num++)
-		{
+		for(num = 0; num < 4; num++) {
 			end_head = entry->end_head;
 			end_sec = entry->end_sector & 0x3f;
 
-			if(end_head == 63)
-			{
+			if(end_head == 63) {
 				param->heads = 64;
 				param->sectors = 32;
 				break;
-			}
-			else if(end_head == 127)
-			{
+			} else if(end_head == 127) {
 				param->heads = 128;
 				param->sectors = 32;
 				break;
-			}
-			else if(end_head == 254) 
-			{
+			} else if(end_head == 254) {
 				param->heads = 255;
 				param->sectors = 63;
 				break;
@@ -502,32 +581,95 @@ static int aac_biosparm(Scsi_Disk *disk, kdev_t dev, int *geom)
 			entry++;
 		}
 
-		if(num == 4)
-		{
+		if (num == 4) {
 			end_head = first->end_head;
 			end_sec = first->end_sector & 0x3f;
 		}
 
-		param->cylinders = disk->capacity / (param->heads * param->sectors);
-
-		if(num < 4 && end_sec == param->sectors)
-		{
-			if(param->cylinders != saved_cylinders)
+		param->cylinders = cap_to_cyls(capacity, param->heads * param->sectors);
+		if (num < 4 && end_sec == param->sectors) {
+			if (param->cylinders != saved_cylinders)
 				dprintk((KERN_DEBUG "Adopting geometry: heads=%d, sectors=%d from partition table %d.\n",
 					param->heads, param->sectors, num));
-		}
-		else if(end_head > 0 || end_sec > 0)
-		{
+		} else if (end_head > 0 || end_sec > 0) {
 			dprintk((KERN_DEBUG "Strange geometry: heads=%d, sectors=%d in partition table %d.\n",
 				end_head + 1, end_sec, num));
 			dprintk((KERN_DEBUG "Using geometry: heads=%d, sectors=%d.\n",
 					param->heads, param->sectors));
 		}
 	}
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+	kfree(buf);
+#else
 	brelse(buf);
+#endif
 	return 0;
 }
 
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+/**
+ *	aac_slave_configure		-	compute queue depths
+ *	@sdev:	SCSI device we are considering
+ *
+ *	Selects queue depths for each target device based on the host adapter's
+ *	total capacity and the queue depth supported by the target device.
+ *	A queue depth of one automatically disables tagged queueing.
+ */
+
+static int aac_slave_configure(struct scsi_device *sdev)
+{
+#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)) || defined(BLIST_NO_ULD_ATTACH))
+	if ((sdev->type == TYPE_DISK) && (sdev->channel != 0)) {
+		struct aac_dev *aac = (struct aac_dev *)sdev->host->hostdata;
+		if (!aac->raid_scsi_mode || (sdev->channel != 2))
+			sdev->no_uld_attach = 1;
+	}
+#endif
+	if (sdev->tagged_supported && (sdev->type == TYPE_DISK)
+#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)) || defined(BLIST_NO_ULD_ATTACH))
+	 && (sdev->no_uld_attach == 0)
+#endif
+	 && (sdev->channel == 0)) {
+		struct scsi_device * dev;
+		struct Scsi_Host *host = sdev->host;
+		unsigned num_lsu = 0;
+		unsigned num_one = 0;
+		unsigned depth;
+
+		__shost_for_each_device(dev, host) {
+			if (dev->tagged_supported && (dev->type == TYPE_DISK)
+#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)) || defined(BLIST_NO_ULD_ATTACH))
+			 && (dev->no_uld_attach == 0)
+#endif
+			 && (dev->channel == 0))
+				++num_lsu;
+			else
+				++num_one;
+		}
+		if (num_lsu == 0)
+			++num_lsu;
+		depth = (host->can_queue - num_one) / num_lsu;
+		if (depth > 256)
+			depth = 256;
+		else if (depth < 2)
+			depth = 2;
+		scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, depth);
+		if (!(((struct aac_dev *)host->hostdata)->adapter_info.options
+		  & AAC_OPT_NEW_COMM))
+			blk_queue_max_segment_size(sdev->request_queue, 65536);
+	} else
+		scsi_adjust_queue_depth(sdev, 0, 1);
+#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) && defined(AAC_EXTENDED_TIMEOUT))
+	{
+		extern int extendedtimeout;
+
+		if (extendedtimeout != -1)
+			sdev->timeout = extendedtimeout * HZ;
+	}
+#endif
+	return 0;
+}
+#else
 /**
  *	aac_queuedepth		-	compute queue depths
  *	@host:	SCSI host in question
@@ -538,39 +680,67 @@ static int aac_biosparm(Scsi_Disk *disk, kdev_t dev, int *geom)
  *	A queue depth of one automatically disables tagged queueing.
  */
 
-static void aac_queuedepth(struct Scsi_Host * host, Scsi_Device * dev )
+static void aac_queuedepth(struct Scsi_Host * host, struct scsi_device * dev )
 {
-	Scsi_Device * dptr;
+	struct scsi_device * dptr;
+	unsigned num = 0;
+	unsigned depth;
 
+#if (defined(AAC_DEBUG_INSTRUMENT_INIT))
+	printk(KERN_INFO "aac_queuedepth(%p,%p)\n", host, dev);
+#endif
+	for(dptr = dev; dptr != NULL; dptr = dptr->next)
+		if((dptr->host == host) && (dptr->type == 0))
+			++num;
+
+	dprintk((KERN_DEBUG "can_queue=%d num=%d\n", host->can_queue, num));
+#if (defined(AAC_DEBUG_INSTRUMENT_INIT))
+	printk(KERN_INFO "can_queue=%d num=%d\n", host->can_queue, num);
+#endif
+	if (num == 0)
+		++num;
+	depth = host->can_queue / num;
+	if (depth > 255)
+		depth = 255;
+	else if (depth < 2)
+		depth = 2;
 	dprintk((KERN_DEBUG "aac_queuedepth.\n"));
 	dprintk((KERN_DEBUG "Device #   Q Depth   Online\n"));
 	dprintk((KERN_DEBUG "---------------------------\n"));
+#if (defined(AAC_DEBUG_INSTRUMENT_INIT))
+	printk(KERN_INFO "aac_queuedepth.\n");
+	printk(KERN_INFO "Device #   Q Depth   Online\n");
+	printk(KERN_INFO "---------------------------\n");
+#endif
 	for(dptr = dev; dptr != NULL; dptr = dptr->next)
 	{
 		if(dptr->host == host)
 		{
-			dptr->queue_depth = 10;		
+			dptr->queue_depth = depth;
 			dprintk((KERN_DEBUG "  %2d         %d        %d\n", 
-				dptr->id, dptr->queue_depth, dptr->online));
+				dptr->id, dptr->queue_depth, scsi_device_online(dptr)));
+#if (defined(AAC_DEBUG_INSTRUMENT_INIT))
+	printk(KERN_INFO "  %2d         %d        %d\n", dptr->id, dptr->queue_depth, scsi_device_online(dptr));
+#endif
 		}
 	}
 }
+#endif
 
-
-/**
- *	aac_eh_abort	-	Abort command if possible.
- *	@cmd:	SCSI command block to abort
- *
- *	Called when the midlayer wishes to abort a command. We don't support
- *	this facility, and our firmware looks after life for us. We just
- *	report this as failing
- */
- 
-static int aac_eh_abort(Scsi_Cmnd *cmd)
+static int aac_ioctl(struct scsi_device *sdev, int cmd, void __user * arg)
 {
-	return FAILED;
+	struct aac_dev *dev = (struct aac_dev *)sdev->host->hostdata;
+#if (defined(AAC_DEBUG_INSTRUMENT_IOCTL))
+	int retval;
+	printk("aac_ioctl(%p, %x, %p)\n", sdev, cmd, arg);
+	retval = aac_do_ioctl(dev, cmd, arg);
+	printk("aac_ioctl returns %d\n", retval);
+	return retval;
+#endif
+	return aac_do_ioctl(dev, cmd, arg);
 }
 
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
 /**
  *	aac_eh_device_reset	-	Reset command handling
  *	@cmd:	SCSI command block causing the reset
@@ -580,7 +750,7 @@ static int aac_eh_abort(Scsi_Cmnd *cmd)
  *	is a no-op. We just return FAILED.
  */
 
-static int aac_eh_device_reset(Scsi_Cmnd *cmd)
+static int aac_eh_device_reset(struct scsi_cmnd *cmd)
 {
 	return FAILED;
 }
@@ -594,43 +764,201 @@ static int aac_eh_device_reset(Scsi_Cmnd *cmd)
  *	is a no-op. We just return FAILED.
  */
 
-static int aac_eh_bus_reset(Scsi_Cmnd* cmd)
+static int aac_eh_bus_reset(struct scsi_cmnd* cmd)
 {
 	return FAILED;
 }
 
-/**
- *	aac_eh_hba_reset	-	Reset command handling
+#endif
+/*
+ *	aac_eh_reset	- Reset command handling
  *	@scsi_cmd:	SCSI command block causing the reset
  *
- *	Issue a reset of a SCSI host. If things get this bad then arguably we should
- *	go take a look at what the host adapter is doing and see if something really
- *	broke (as can occur at least on my Dell QC card if a drive keeps failing spinup)
  */
+#if (defined(__arm__))
+//DEBUG
+#define AAC_DEBUG_INSTRUMENT_RESET
+#endif
+#if (defined(AAC_DEBUG_INSTRUMENT_RESET))
+# undef dprintk
+# define dprintk(x)	printk x
+#endif
+static int aac_eh_reset(struct scsi_cmnd* cmd)
+{
+#if (!defined(AAC_DEBUG_INSTRUMENT_RESET) && defined(__arm__))
+//	return FAILED;
+	return SUCCESS; /* Cause an immediate retry of the command with a ten second delay after successful tur */
+#else
+	struct scsi_device * dev = cmd->device;
+	struct Scsi_Host * host = dev->host;
+	struct scsi_cmnd * command;
+	int count;
+	struct aac_dev * aac;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+	unsigned long flags;
+#endif
+
+	printk(KERN_ERR "%s: Host adapter reset request. SCSI hang ?\n", 
+					AAC_DRIVERNAME);
+	aac = (struct aac_dev *)host->hostdata;
+	fwprintf((aac, HBA_FLAGS_DBG_FW_PRINT_B, "SCSI hang ?"));
+	if (nblank(dprintk(x))) {
+		int active = 0;
+		unsigned long DebugFlags = aac->FwDebugFlags;
+
+		active = active;
+		dprintk((KERN_ERR
+		  "%s: Outstanding commands on (%d,%d,%d,%d):\n",
+		  AAC_DRIVERNAME,
+		  host->host_no, dev->channel, dev->id, dev->lun));
+		aac->FwDebugFlags |= FW_DEBUG_FLAGS_NO_HEADERS_B;
+		fwprintf((aac, HBA_FLAGS_DBG_FW_PRINT_B,
+		  "%s: Outstanding commands on (%d,%d,%d,%d):\n",
+		  AAC_DRIVERNAME,
+		  host->host_no, dev->channel, dev->id, dev->lun));
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+		spin_lock_irqsave(&dev->list_lock, flags);
+		list_for_each_entry(command, &dev->cmd_list, list)
+#else
+		for(command = dev->device_queue; command; command = command->next)
+#endif
+		{
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12))
+			if ((command->state != SCSI_STATE_FINISHED)
+			 && (command->state != 0))
+#endif
+			dprintk((KERN_ERR
+			  "%4d %c%c %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+			  active++,
+			  (command->SCp.phase == AAC_OWNER_FIRMWARE) ? 'A' : 'C',
+			  (cmd == command) ? '*' : ' ',
+			  command->cmnd[0], command->cmnd[1], command->cmnd[2],
+			  command->cmnd[3], command->cmnd[4], command->cmnd[5],
+			  command->cmnd[6], command->cmnd[7], command->cmnd[8],
+			  command->cmnd[9]));
+			fwprintf((aac, HBA_FLAGS_DBG_FW_PRINT_B,
+			  "%4d %c%c %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+			  active++,
+			  (command->SCp.phase == AAC_OWNER_FIRMWARE) ? 'A' : 'C',
+			  (cmd == command) ? '*' : ' ',
+			  command->cmnd[0], command->cmnd[1], command->cmnd[2],
+			  command->cmnd[3], command->cmnd[4], command->cmnd[5],
+			  command->cmnd[6], command->cmnd[7], command->cmnd[8],
+			  command->cmnd[9]));
+		}
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+		spin_unlock_irqrestore(&dev->list_lock, flags);
+#endif
+		aac->FwDebugFlags = DebugFlags;
+	}
 
-static int aac_eh_reset(Scsi_Cmnd* cmd)
+	if ((count = aac_check_health(aac)))
+		return count;
+	/*
+	 * Wait for all commands to complete to this specific
+	 * target (block maximum 60 seconds).
+	 */
+	for (count = 60; count; --count) {
+		int active = aac->in_reset;
+	
+		if (active == 0)
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+		__shost_for_each_device(dev, host) {
+			spin_lock_irqsave(&dev->list_lock, flags);
+			list_for_each_entry(command, &dev->cmd_list, list) {
+				if ((command != cmd)
+				 && (command->SCp.phase == AAC_OWNER_FIRMWARE)) {
+					active++;
+					break;
+				}
+			}
+			spin_unlock_irqrestore(&dev->list_lock, flags);
+			if (active)
+				break;
+
+		}
+#else
+		for (dev = host->host_queue; dev != (struct scsi_device *)NULL; dev = dev->next) {
+			for(command = dev->device_queue; command; command = command->next) {
+				if ((command != cmd)
+				 && (command->SCp.phase == AAC_OWNER_FIRMWARE)) {
+					++active;
+					break;
+				}
+			}
+		}
+#endif
+		/*
+		 * We can exit If all the commands are complete
+		 */
+		if (active == 0)
+			return SUCCESS;
+#if (defined(SCSI_HAS_HOST_LOCK) || (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,21)) && ((LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21)) || !defined(CONFIG_CFGNAME))
+		spin_unlock_irq(host->host_lock);
+#else
+		spin_unlock_irq(host->lock);
+#endif
+#else
+		spin_unlock_irq(&io_request_lock);
+#endif
+		ssleep(1);
+#if (defined(SCSI_HAS_HOST_LOCK) || (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,21)) && ((LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21)) || !defined(CONFIG_CFGNAME))
+		spin_lock_irq(host->host_lock);
+#else
+		spin_lock_irq(host->lock);
+#endif
+#else
+		spin_lock_irq(&io_request_lock);
+#endif
+	}
+	printk(KERN_ERR "%s: SCSI bus appears hung\n", AAC_DRIVERNAME);
+	fwprintf((aac, HBA_FLAGS_DBG_FW_PRINT_B, "SCSI bus appears hung"));
+//	return -ETIMEDOUT;
+	return SUCCESS; /* Cause an immediate retry of the command with a ten second delay after successful tur */
+#endif
+}
+#if (defined(AAC_DEBUG_INSTRUMENT_RESET))
+/* We are making an assumption that dprintk was turned off */
+# undef dprintk
+# define dprintk(x)
+#endif
+#if (defined(SCSI_HAS_DUMP))
+#if (defined(SCSI_HAS_DUMP_SANITY_CHECK))
+static int aac_sanity_check(struct scsi_device * sdev)
 {
-	printk(KERN_ERR "%s: Host adapter reset request. SCSI hang ?\n", AAC_DRIVER_NAME);
-	return FAILED;
+	return 0;
 }
 
-/**
- *	aac_ioctl 	-	Handle SCSI ioctls
- *	@scsi_dev_ptr: scsi device to operate upon
- *	@cmd: ioctl command to use issue
- *	@arg: ioctl data pointer
- *
- *	Issue an ioctl on an aacraid device. Returns a standard unix error code or
- *	zero for success
- */
- 
-static int aac_ioctl(Scsi_Device * scsi_dev_ptr, int cmd, void * arg)
+#endif
+static void aac_poll(struct scsi_device * sdev)
 {
-	struct aac_dev *dev;
-	dprintk((KERN_DEBUG "aac_ioctl.\n"));
-	dev = (struct aac_dev *)scsi_dev_ptr->host->hostdata;
-	return aac_do_ioctl(dev, cmd, arg);
+	struct Scsi_Host * shost = sdev->host;
+	struct aac_dev *dev = (struct aac_dev *)shost->hostdata;
+	unsigned long flags;
+
+#if (defined(SCSI_HAS_HOST_LOCK) || (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,21)) && ((LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21)) || !defined(CONFIG_CFGNAME))
+	spin_lock_irqsave(shost->host_lock, flags);
+#else
+	spin_lock_irqsave(shost->lock, flags);
+#endif
+#else
+	spin_lock_irqsave(&io_request_lock, flags);
+#endif
+	aac_adapter_intr(dev);
+#if (defined(SCSI_HAS_HOST_LOCK) || (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,21)) && ((LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21)) || !defined(CONFIG_CFGNAME))
+	spin_unlock_irqrestore(shost->host_lock, flags);
+#else
+	spin_unlock_irqrestore(shost->lock, flags);
+#endif
+#else
+	spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 }
+#endif
 
 /**
  *	aac_cfg_open		-	open a configuration file
@@ -644,14 +972,24 @@ static int aac_ioctl(Scsi_Device * scsi_dev_ptr, int cmd, void * arg)
  *	so we can support hot plugging, and to ref count adapters.
  */
 
-static int aac_cfg_open(struct inode * inode, struct file * file )
+static int aac_cfg_open(struct inode *inode, struct file *file)
 {
-	unsigned minor_number = MINOR(inode->i_rdev);
-	if(minor_number >= aac_count)
-		return -ENODEV;
-	return 0;
+	struct aac_dev *aac;
+	unsigned minor_number = iminor(inode);
+	int err = -ENODEV;
+
+	list_for_each_entry(aac, &aac_devices, entry) {
+		if (aac->id == minor_number) {
+			file->private_data = aac;
+			err = 0;
+			break;
+		}
+	}
+
+	return err;
 }
 
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
 /**
  *	aac_cfg_release		-	close down an AAC config device
  *	@inode: inode of configuration file
@@ -666,6 +1004,7 @@ static int aac_cfg_release(struct inode * inode, struct file * file )
 	return 0;
 }
 
+#endif
 /**
  *	aac_cfg_ioctl		-	AAC configuration request
  *	@inode: inode of device
@@ -680,43 +1019,459 @@ static int aac_cfg_release(struct inode * inode, struct file * file )
  *	Bugs: Needs to handle hot plugging
  */
  
-static int aac_cfg_ioctl(struct inode * inode,  struct file * file, unsigned int cmd, unsigned long arg )
+static int aac_cfg_ioctl(struct inode *inode,  struct file *file,
+		unsigned int cmd, unsigned long arg)
 {
-	struct aac_dev *dev = aac_devices[MINOR(inode->i_rdev)];
-	return aac_do_ioctl(dev, cmd, (void *)arg);
+#if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)) && defined(__VMKERNEL_MODULE__))
+	list_for_each_entry(aac, &aac_devices, entry) {
+		if (aac->id == iminor(inode);
+			file->private_data = aac;
+			break;
+		}
+	}
+	if (file->private_data == NULL)
+		return -ENODEV;
+#endif
+#if (defined(AAC_DEBUG_INSTRUMENT_IOCTL))
+	int retval;
+	if (cmd != FSACTL_GET_NEXT_ADAPTER_FIB)
+		printk("aac_cfg_ioctl(%p,%p,%x,%lx)\n", inode, file, cmd, arg);
+	retval = aac_do_ioctl(file->private_data, cmd, (void __user *)arg);
+	if (cmd != FSACTL_GET_NEXT_ADAPTER_FIB)
+		printk("aac_cfg_ioctl returns %d\n", retval);
+	return retval;
+#else
+	return aac_do_ioctl(file->private_data, cmd, (void __user *)arg);
+#endif
 }
 
-/*
- *	To use the low level SCSI driver support using the linux kernel loadable 
- *	module interface we should initialize the global variable driver_interface  
- *	(datatype Scsi_Host_Template) and then include the file scsi_module.c.
- */
- 
-static Scsi_Host_Template driver_template = {
-	module:			THIS_MODULE,
-	name:           	"AAC",
-	proc_info:      	aac_procinfo,
-	detect:         	aac_detect,
-	release:        	aac_release,
-	info:           	aac_driverinfo,
-	ioctl:          	aac_ioctl,
-	queuecommand:   	aac_queuecommand,
-	bios_param:     	aac_biosparm,	
-	can_queue:      	AAC_NUM_IO_FIB,	
-	this_id:        	16,
-	sg_tablesize:   	16,
-	max_sectors:    	128,
-	cmd_per_lun:    	AAC_NUM_IO_FIB,
-	eh_abort_handler:       aac_eh_abort,
-	eh_device_reset_handler:aac_eh_device_reset,
-	eh_bus_reset_handler:	aac_eh_bus_reset,
-	eh_host_reset_handler:	aac_eh_reset,
-	use_new_eh_code:	1, 
-
-	use_clustering:		ENABLE_CLUSTERING,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11))
+#ifdef CONFIG_COMPAT
+static long aac_compat_do_ioctl(struct aac_dev *dev, unsigned cmd, unsigned long arg)
+{
+	long ret;
+	lock_kernel();
+	switch (cmd) { 
+	case FSACTL_MINIPORT_REV_CHECK:
+	case FSACTL_SENDFIB:
+	case FSACTL_OPEN_GET_ADAPTER_FIB:
+	case FSACTL_CLOSE_GET_ADAPTER_FIB:
+	case FSACTL_SEND_RAW_SRB:
+	case FSACTL_GET_PCI_INFO:
+	case FSACTL_QUERY_DISK:
+	case FSACTL_DELETE_DISK:
+	case FSACTL_FORCE_DELETE_DISK:
+	case FSACTL_GET_CONTAINERS: 
+	case FSACTL_GET_VERSION_MATCHING:
+	case FSACTL_SEND_LARGE_FIB:
+#if (defined(FSACTL_REGISTER_FIB_SEND))
+	case FSACTL_REGISTER_FIB_SEND:
+#endif
+		ret = aac_do_ioctl(dev, cmd, (void __user *)arg);
+		break;
+
+	case FSACTL_GET_NEXT_ADAPTER_FIB: {
+		struct fib_ioctl __user *f;
+		
+		f = compat_alloc_user_space(sizeof(*f));
+		ret = 0;
+		if (clear_user(f, sizeof(*f) != sizeof(*f)))
+			ret = -EFAULT;
+		if (copy_in_user(f, (void __user *)arg, sizeof(struct fib_ioctl) - sizeof(u32)))
+			ret = -EFAULT;
+		if (!ret)
+			ret = aac_do_ioctl(dev, cmd, (void __user *)arg);
+		break;
+	}
+
+	default:
+#if (defined(AAC_CSMI))
+		ret = aac_csmi_ioctl(dev, cmd, (void __user *)arg);
+		if (ret == -ENOTTY)
+#endif
+		ret = -ENOIOCTLCMD; 
+		break;
+	} 
+	unlock_kernel();
+	return ret;
+}
+
+static int aac_compat_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
+{
+	struct aac_dev *dev = (struct aac_dev *)sdev->host->hostdata;
+	return aac_compat_do_ioctl(dev, cmd, (unsigned long)arg);
+}
+
+static long aac_compat_cfg_ioctl(struct file *file, unsigned cmd, unsigned long arg)
+{
+	return aac_compat_do_ioctl((struct aac_dev *)file->private_data, cmd, arg);
+}
+#endif
+#endif
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+
+#define class_device Scsi_Host
+#define class_to_shost(class_dev) class_dev
+#endif
+
+static ssize_t aac_show_model(struct class_device *class_dev,
+		char *buf)
+{
+	struct aac_dev *dev = (struct aac_dev*)class_to_shost(class_dev)->hostdata;
+	int len;
+
+	if (dev->supplement_adapter_info.AdapterTypeText[0]) {
+		char * cp = dev->supplement_adapter_info.AdapterTypeText;
+		while (*cp && *cp != ' ')
+			++cp;
+		while (*cp == ' ')
+			++cp;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,4))
+		len = snprintf(buf, PAGE_SIZE, "%s\n", cp);
+#else
+		len = sprintf(buf, "%s\n", cp);
+#endif
+	} else
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,4))
+		len = snprintf(buf, PAGE_SIZE, "%s\n",
+#else
+		len = sprintf(buf, "%s\n",
+#endif
+		  aac_drivers[dev->cardtype].model);
+	return len;
+}
+
+static ssize_t aac_show_vendor(struct class_device *class_dev,
+		char *buf)
+{
+	struct aac_dev *dev = (struct aac_dev*)class_to_shost(class_dev)->hostdata;
+	int len;
+
+	if (dev->supplement_adapter_info.AdapterTypeText[0]) {
+		char * cp = dev->supplement_adapter_info.AdapterTypeText;
+		while (*cp && *cp != ' ')
+			++cp;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,4))
+		len = snprintf(buf, PAGE_SIZE, "%.*s\n",
+#else
+		len = sprintf(buf, "%.*s\n",
+#endif
+		  (int)(cp - (char *)dev->supplement_adapter_info.AdapterTypeText),
+		  dev->supplement_adapter_info.AdapterTypeText);
+	} else
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,4))
+		len = snprintf(buf, PAGE_SIZE, "%s\n",
+#else
+		len = sprintf(buf, "%s\n",
+#endif
+		  aac_drivers[dev->cardtype].vname);
+	return len;
+}
+
+static ssize_t aac_show_flags(struct class_device *class_dev, char *buf)
+{
+	int len = 0;
+#if ((defined(SERVICE_ACTION_IN) && defined(SAI_READ_CAPACITY_16)) || defined(AAC_DEBUG_INSTRUMENT_PENDING))
+	struct aac_dev *dev = (struct aac_dev*)class_to_shost(class_dev)->hostdata;
+#endif
+
+	if (nblank(dprintk(x)))
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,4))
+		len = snprintf(buf, PAGE_SIZE, "dprintk\n");
+#else
+		len = sprintf(buf, "dprintk\n");
+#endif
+#	if (defined(AAC_DETAILED_STATUS_INFO))
+		len += snprintf(buf + len, PAGE_SIZE - len,
+		  "AAC_DETAILED_STATUS_INFO\n");
+#	endif
+#	if (defined(AAC_DEBUG_INSTRUMENT_AAC_CONFIG))
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,4))
+		len += snprintf(buf + len, PAGE_SIZE - len,
+#else
+		len += sprintf(buf + len,
+#endif
+		  "AAC_DEBUG_INSTRUMENT_AAC_CONFIG\n");
+#	endif
+#	if (defined(AAC_DEBUG_INSTRUMENT_AIF))
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,4))
+		len += snprintf(buf + len, PAGE_SIZE - len,
+#else
+		len += sprintf(buf + len,
+#endif
+		  "AAC_DEBUG_INSTRUMENT_AIF\n");
+#	endif
+#	if (defined(AAC_DEBUG_INSTRUMENT_IOCTL))
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,4))
+		len += snprintf(buf + len, PAGE_SIZE - len,
+#else
+		len += sprintf(buf + len,
+#endif
+		  "AAC_DEBUG_INSTRUMENT_IOCTL\n");
+#	endif
+#	if (defined(AAC_DEBUG_INSTRUMENT_TIMING))
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,4))
+		len += snprintf(buf + len, PAGE_SIZE - len,
+#else
+		len += snprintf(buf + len,
+#endif
+		  "AAC_DEBUG_INSTRUMENT_TIMING\n");
+#	endif
+#	if (defined(AAC_DEBUG_INSTRUMENT_RESET))
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,4))
+		len += snprintf(buf + len, PAGE_SIZE - len,
+#else
+		len += sprintf(buf + len,
+#endif
+		  "AAC_DEBUG_INSTRUMENT_RESET\n");
+#	endif
+#	if (defined(AAC_DEBUG_INSTRUMENT_FIB))
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,4))
+		len += snprintf(buf + len, PAGE_SIZE - len,
+#else
+		len += sprintf(buf + len,
+#endif
+		  "AAC_DEBUG_INSTRUMENT_FIB\n");
+#	endif
+#	if (defined(AAC_DEBUG_INSTRUMENT_2TB))
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,4))
+		len += snprintf(buf + len, PAGE_SIZE - len,
+#else
+		len += sprintf(buf + len,
+#endif
+		  "AAC_DEBUG_INSTRUMENT_2TB\n");
+#	endif
+#	if (defined(AAC_DEBUG_INSTRUMENT_IOCTL_SENDFIB))
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,4))
+		len += snprintf(buf + len, PAGE_SIZE - len,
+#else
+		len += sprintf(buf + len,
+#endif
+		  "AAC_DEBUG_INSTRUMENT_IOCTL_SENDFIB\n");
+#	endif
+#	if (defined(AAC_DEBUG_INSTRUMENT_IO))
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,4))
+		len += snprintf(buf + len, PAGE_SIZE - len,
+#else
+		len += sprintf(buf + len,
+#endif
+		  "AAC_DEBUG_INSTRUMENT_IO\n");
+#	endif
+#	if (defined(AAC_DEBUG_INSTRUMENT_SG))
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,4))
+		len += snprintf(buf + len, PAGE_SIZE - len,
+#else
+		len += sprintf(buf + len,
+#endif
+		  "AAC_DEBUG_INSTRUMENT_SG\n");
+#	endif
+#	if (defined(AAC_DEBUG_INSTRUMENT_SG_PROBE))
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,4))
+		len += snprintf(buf + len, PAGE_SIZE - len,
+#else
+		len += sprintf(buf + len,
+#endif
+		  "AAC_DEBUG_INSTRUMENT_SG_PROBE\n");
+#	endif
+#	if (defined(AAC_DEBUG_INSTRUMENT_VM_NAMESERVE))
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,4))
+		len += snprintf(buf + len, PAGE_SIZE - len,
+#else
+		len += sprintf(buf + len,
+#endif
+		  "AAC_DEBUG_INSTRUMENT_VM_NAMESERVE\n");
+#	endif
+#if (defined(SERVICE_ACTION_IN) && defined(SAI_READ_CAPACITY_16))
+	if (dev->raw_io_interface && dev->raw_io_64)
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,4))
+		len += snprintf(buf + len, PAGE_SIZE - len,
+#else
+		len += sprintf(buf + len,
+#endif
+		  "SAI_READ_CAPACITY_16\n");
+#endif
+#	if (defined(SCSI_HAS_VARY_IO))
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,4))
+		len += snprintf(buf + len, PAGE_SIZE - len,
+#else
+		len += sprintf(buf + len,
+#endif
+		  "SCSI_HAS_VARY_IO\n");
+#	endif
+#	if (defined(SCSI_HAS_DUMP))
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,4))
+		len += snprintf(buf + len, PAGE_SIZE - len,
+#else
+		len += sprintf(buf + len,
+#endif
+		  "SCSI_HAS_DUMP\n");
+#	endif
+#	if (defined(AAC_DEBUG_INSTRUMENT_PENDING))
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,4))
+		len += snprintf(buf + len, PAGE_SIZE - len,
+#else
+		len += sprintf(buf + len,
+#endif
+		  "AAC_DEBUG_INSTRUMENT_PENDING=%u\n",
+		  dev->queues->queue[AdapNormCmdQueue].numpending);
+#	endif
+	return len;
+}
+
+static ssize_t aac_show_kernel_version(struct class_device *class_dev,
+		char *buf)
+{
+	struct aac_dev *dev = (struct aac_dev*)class_to_shost(class_dev)->hostdata;
+	int len, tmp;
+
+	tmp = le32_to_cpu(dev->adapter_info.kernelrev);
+	len = snprintf(buf, PAGE_SIZE, "%d.%d-%d[%d]\n", 
+	  tmp >> 24, (tmp >> 16) & 0xff, tmp & 0xff,
+	  le32_to_cpu(dev->adapter_info.kernelbuild));
+	return len;
+}
+
+static ssize_t aac_show_monitor_version(struct class_device *class_dev,
+		char *buf)
+{
+	struct aac_dev *dev = (struct aac_dev*)class_to_shost(class_dev)->hostdata;
+	int len, tmp;
+
+	tmp = le32_to_cpu(dev->adapter_info.monitorrev);
+	len = snprintf(buf, PAGE_SIZE, "%d.%d-%d[%d]\n", 
+	  tmp >> 24, (tmp >> 16) & 0xff, tmp & 0xff,
+	  le32_to_cpu(dev->adapter_info.monitorbuild));
+	return len;
+}
+
+static ssize_t aac_show_bios_version(struct class_device *class_dev,
+		char *buf)
+{
+	struct aac_dev *dev = (struct aac_dev*)class_to_shost(class_dev)->hostdata;
+	int len, tmp;
+
+	tmp = le32_to_cpu(dev->adapter_info.biosrev);
+	len = snprintf(buf, PAGE_SIZE, "%d.%d-%d[%d]\n", 
+	  tmp >> 24, (tmp >> 16) & 0xff, tmp & 0xff,
+	  le32_to_cpu(dev->adapter_info.biosbuild));
+	return len;
+}
+
+static ssize_t aac_show_serial_number(struct class_device *class_dev,
+		char *buf)
+{
+	struct aac_dev *dev = (struct aac_dev*)class_to_shost(class_dev)->hostdata;
+	int len = 0;
+
+	if (le32_to_cpu(dev->adapter_info.serial[0]) != 0xBAD0)
+		len = snprintf(buf, PAGE_SIZE, "%x\n",
+		  le32_to_cpu(dev->adapter_info.serial[0]));
+	return len;
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+static ssize_t aac_store_reset_adapter(struct class_device *class_dev,
+		const char *buf, size_t count)
+{
+	struct Scsi_Host *shost;
+	unsigned long flags;
+	int retval = -EACCES;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return retval;
+	shost = class_to_shost(class_dev);
+	spin_lock_irqsave(shost->host_lock, flags);
+	retval = aac_reset_adapter((struct aac_dev*)shost->hostdata);
+	spin_unlock_irqrestore(shost->host_lock, flags);
+	if (retval >= 0)
+		retval = count;
+	return retval;
+}
+
+static ssize_t aac_show_reset_adapter(struct class_device *class_dev,
+		char *buf)
+{
+	struct aac_dev *dev = (struct aac_dev*)class_to_shost(class_dev)->hostdata;
+	int len, tmp;
+
+	tmp = aac_adapter_check_health(dev);
+	if ((tmp == 0) && dev->in_reset)
+		tmp=-EBUSY;
+	len = snprintf(buf, PAGE_SIZE, "0x%x", tmp);
+	return len;
+}
+
+static struct class_device_attribute aac_model = {
+	.attr = {
+		.name = "model",
+		.mode = S_IRUGO,
+	},
+	.show = aac_show_model,
+};
+static struct class_device_attribute aac_vendor = {
+	.attr = {
+		.name = "vendor",
+		.mode = S_IRUGO,
+	},
+	.show = aac_show_vendor,
+};
+static struct class_device_attribute aac_flags = {
+	.attr = {
+		.name = "flags",
+		.mode = S_IRUGO,
+	},
+	.show = aac_show_flags,
+};
+static struct class_device_attribute aac_kernel_version = {
+	.attr = {
+		.name = "hba_kernel_version",
+		.mode = S_IRUGO,
+	},
+	.show = aac_show_kernel_version,
+};
+static struct class_device_attribute aac_monitor_version = {
+	.attr = {
+		.name = "hba_monitor_version",
+		.mode = S_IRUGO,
+	},
+	.show = aac_show_monitor_version,
+};
+static struct class_device_attribute aac_bios_version = {
+	.attr = {
+		.name = "hba_bios_version",
+		.mode = S_IRUGO,
+	},
+	.show = aac_show_bios_version,
+};
+static struct class_device_attribute aac_serial_number = {
+	.attr = {
+		.name = "serial_number",
+		.mode = S_IRUGO,
+	},
+	.show = aac_show_serial_number,
+};
+static struct class_device_attribute aac_reset = {
+	.attr = {
+		.name = "reset_host",
+		.mode = S_IWUSR|S_IRUGO,
+	},
+	.store = aac_store_reset_adapter,
+	.show = aac_show_reset_adapter,
 };
 
-#include "scsi_module.c"
+static struct class_device_attribute *aac_attrs[] = {
+	&aac_model,
+	&aac_vendor,
+	&aac_flags,
+	&aac_kernel_version,
+	&aac_monitor_version,
+	&aac_bios_version,
+	&aac_serial_number,
+	&aac_reset,
+	NULL
+};
+#endif
+#if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) || defined(CONFIG_SCSI_PROC_FS))
 
 /**
  *	aac_procinfo	-	Implement /proc/scsi/<drivername>/<n>
@@ -740,45 +1495,768 @@ static Scsi_Host_Template driver_template = {
  *
  *	Bugs:	Only offset zero is handled
  */
-
-static int aac_procinfo(char *proc_buffer, char **start_ptr,off_t offset,
-			int bytes_available, int host_no, int write)
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+#define shost_to_class(shost) &shost->shost_classdev
+#else
+#define shost_to_class(shost) shost
+#endif
+
+static int aac_procinfo(
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+	struct Scsi_Host * shost,
+#endif
+	char *proc_buffer, char **start_ptr,off_t offset,
+	int bytes_available,
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+	int host_no,
+#endif
+	int write)
 {
-	struct aac_dev * dev;
-	int index, ret, tmp;
-
+	struct aac_dev * dev = (struct aac_dev *)NULL;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+	struct Scsi_Host * shost = (struct Scsi_Host *)NULL;
+#endif
+	char *buf;
+	int len;
+	int total_len = 0;
+
+#if (defined(AAC_LM_SENSOR) || defined(IOP_RESET))
+	if(offset > 0)
+#else
 	if(write || offset > 0)
+#endif
 		return 0;
 	*start_ptr = proc_buffer;
-	ret = sprintf(proc_buffer,
-		  "Adaptec Raid Controller %d.%d-%d %s, scsi hba number %d\n",
-		  AAC_DRIVER_VERSION >> 24,
-		  (AAC_DRIVER_VERSION >> 16) & 0xFF,
-		  (AAC_DRIVER_VERSION >> 8) & 0xFF,
-		  AAC_DRIVER_BUILD_DATE,
-		  host_no);
-	for (index = 0; index < aac_count; ++index) {
-		if (((dev = aac_devices[index]) != NULL) && dev->scsi_host_ptr->host_no == host_no)
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+	list_for_each_entry(dev, &aac_devices, entry) {
+		shost = dev->scsi_host_ptr;
+		if (shost->host_no == host_no)
 			break;
 	}
-	if (index >= aac_count || dev == NULL)
-		return ret;
-	tmp = dev->adapter_info.kernelrev;
-	ret += sprintf(proc_buffer + ret, "kernel: %d.%d-%d[%d]\n", 
-		tmp >> 24, (tmp >> 16) & 0xff, (tmp >> 8) & 0xff,
-		dev->adapter_info.kernelbuild);
-	tmp = dev->adapter_info.monitorrev;
-	ret += sprintf(proc_buffer + ret, "monitor: %d.%d-%d[%d]\n", 
-		tmp >> 24, (tmp >> 16) & 0xff, (tmp >> 8) & 0xff,
-		dev->adapter_info.monitorbuild);
-	tmp = dev->adapter_info.biosrev;
-	ret += sprintf(proc_buffer + ret, "bios: %d.%d-%d[%d]\n", 
-		tmp >> 24, (tmp >> 16) & 0xff, (tmp >> 8) & 0xff,
-		dev->adapter_info.biosbuild);
-	ret += sprintf(proc_buffer + ret, "serial: %x%x\n",
-		dev->adapter_info.serial[0],
-		dev->adapter_info.serial[1]);
-	return ret;
+	if (shost == (struct Scsi_Host *)NULL)
+		return 0;
+#endif
+	dev = (struct aac_dev *)shost->hostdata;
+	if (dev == (struct aac_dev *)NULL)
+		return 0;
+	if (!write) {
+		buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+		if (!buf)
+			return 0;
+		len = snprintf(proc_buffer, bytes_available,
+		  "Adaptec Raid Controller: %s\n", aac_driver_version);
+		total_len += len;
+		proc_buffer += len;
+		len = aac_show_vendor(shost_to_class(shost), buf);
+		len = snprintf(proc_buffer, bytes_available - total_len,
+		  "Vendor: %.*s  ", len - 1, buf);
+		total_len += len;
+		proc_buffer += len;
+		len = aac_show_model(shost_to_class(shost), buf);
+		len = snprintf(proc_buffer, bytes_available - total_len,
+		  "Model: %.*s", len, buf);
+		total_len += len;
+		proc_buffer += len;
+		len = aac_show_flags(shost_to_class(shost), buf);
+		if (len) {
+			char *cp = proc_buffer;
+			len = snprintf(cp, bytes_available - total_len,
+			  "flags=%.*s", len, buf);
+			total_len += len;
+			proc_buffer += len;
+			while (--len > 0) {
+				if (*cp == '\n')
+					*cp = '+';
+				++cp;
+			}
+		}
+		len = aac_show_kernel_version(shost_to_class(shost), buf);
+		len = snprintf(proc_buffer, bytes_available - total_len,
+		  "kernel: %.*s", len, buf);
+		total_len += len;
+		proc_buffer += len;
+		len = aac_show_monitor_version(shost_to_class(shost), buf);
+		len = snprintf(proc_buffer, bytes_available - total_len,
+		  "monitor: %.*s", len, buf);
+		total_len += len;
+		proc_buffer += len;
+		len = aac_show_bios_version(shost_to_class(shost), buf);
+		len = snprintf(proc_buffer, bytes_available - total_len,
+		  "bios: %.*s", len, buf);
+		total_len += len;
+		proc_buffer += len;
+		len = aac_show_serial_number(shost_to_class(shost), buf);
+		if (len) {
+			len = snprintf(proc_buffer, bytes_available - total_len,
+			  "serial: %.*s", len, buf);
+			total_len += len;
+		}
+		kfree(buf);
+		return total_len;
+	}
+#if (defined(IOP_RESET))
+	{
+		static char reset[] = "reset_host";
+		if (strnicmp (proc_buffer, reset, sizeof(reset) - 1) == 0) {
+			unsigned long flags;
+
+			if (!capable(CAP_SYS_ADMIN))
+				return bytes_available;
+#if (defined(SCSI_HAS_HOST_LOCK) || (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,21)) && ((LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21)) || !defined(CONFIG_CFGNAME))
+			spin_lock_irqsave(shost->host_lock, flags);
+#else
+			spin_lock_irqsave(shost->lock, flags);
+#endif
+#else
+			spin_lock_irqsave(&io_request_lock, flags);
+#endif
+			(void)aac_reset_adapter(dev);
+#if (defined(SCSI_HAS_HOST_LOCK) || (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,21)) && ((LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21)) || !defined(CONFIG_CFGNAME))
+			spin_unlock_irqrestore(shost->host_lock, flags);
+#else
+			spin_unlock_irqrestore(shost->lock, flags);
+#endif
+#else
+			spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
+			return bytes_available;
+		}
+	}
+#endif
+#if (defined(AAC_LM_SENSOR))
+	{
+		int ret, tmp, index;
+		s32 temp[5];
+		static char temperature[] = "temperature=";
+		if (strnicmp (proc_buffer, temperature, sizeof(temperature) - 1))
+			return bytes_available;
+		for (index = 0;
+		  index < (sizeof(temp)/sizeof(temp[0]));
+		  ++index)
+			temp[index] = 0x80000000;
+		ret = sizeof(temperature) - 1;
+		for (index = 0;
+		  index < (sizeof(temp)/sizeof(temp[0]));
+		  ++index) {
+			int sign, mult, c;
+			if (ret >= bytes_available)
+				break;
+			c = proc_buffer[ret];
+			if (c == '\n') {
+				++ret;
+				break;
+			}
+			if (c == ',') {
+				++ret;
+				continue;
+			}
+			sign = 1;
+			mult = 0;
+			tmp = 0;
+			if (c == '-') {
+				sign = -1;
+				++ret;
+			}
+			for (;
+			  (ret < bytes_available) && ((c = proc_buffer[ret]));
+			  ++ret) {
+				if (('0' <= c) && (c <= '9')) {
+					tmp *= 10;
+					tmp += c - '0';
+					mult *= 10;
+				} else if ((c == '.') && (mult == 0))
+					mult = 1;
+				else
+					break;
+			}
+			if ((ret < bytes_available)
+			 && ((c == ',') || (c == '\n')))
+				++ret;
+			if (!mult)
+				mult = 1;
+			if (sign < 0)
+				tmp = -tmp;
+			temp[index] = ((tmp << 8) + (mult >> 1)) / mult;
+			if (c == '\n')
+				break;
+		}
+		ret = index;
+		if (nblank(dprintk(x))) {
+			for (index = 0; index < ret; ++index) {
+				int sign;
+				tmp = temp[index];
+				sign = tmp < 0;
+				if (sign)
+					tmp = -tmp;
+				dprintk((KERN_DEBUG "%s%s%d.%08doC",
+				  (index ? "," : ""),
+				  (sign ? "-" : ""),
+				  tmp >> 8, (tmp % 256) * 390625));
+			}
+		}
+		/* Send temperature message to Firmware */
+		(void)aac_adapter_sync_cmd(dev, RCV_TEMP_READINGS,
+		  ret, temp[0], temp[1], temp[2], temp[3], temp[4],
+		  NULL, NULL, NULL, NULL, NULL);
+		return bytes_available;
+	}
+#endif
+	return 0;
+}
+#endif
+
+
+static struct file_operations aac_cfg_fops = {
+	.owner		= THIS_MODULE,
+	.ioctl		= aac_cfg_ioctl,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11))
+#ifdef CONFIG_COMPAT
+	.compat_ioctl   = aac_compat_cfg_ioctl,
+#endif
+#endif
+	.open		= aac_cfg_open,
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+	.release	= aac_cfg_release
+#endif
+};
+#if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) && defined(SCSI_HAS_DUMP))
+static struct scsi_dump_ops aac_dump_ops = {
+#if (defined(SCSI_HAS_DUMP_SANITY_CHECK))
+	.sanity_check	= aac_sanity_check,
+#endif
+	.poll		= aac_poll,
+};
+
+#define aac_driver_template aac_driver_template_dump.hostt
+static struct SHT_dump aac_driver_template_dump = {
+	.hostt = {
+#else
+
+static struct scsi_host_template aac_driver_template = {
+#endif
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+	.detect				= aac_detect,
+#endif
+	.module				= THIS_MODULE,
+	.name           		= "AAC",
+	.proc_name			= AAC_DRIVERNAME,
+	.info           		= aac_info,
+	.ioctl          		= aac_ioctl,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11))
+#ifdef CONFIG_COMPAT
+	.compat_ioctl			= aac_compat_ioctl,
+#endif
+#endif
+	.queuecommand   		= aac_queuecommand,
+	.bios_param     		= aac_biosparm,	
+#if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) || defined(CONFIG_SCSI_PROC_FS))
+	.proc_info      		= aac_procinfo,
+#endif
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+	.shost_attrs			= aac_attrs,
+	.slave_configure		= aac_slave_configure,
+#endif
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+	.eh_device_reset_handler	= aac_eh_device_reset,
+	.eh_bus_reset_handler		= aac_eh_bus_reset,
+#endif
+	.eh_host_reset_handler		= aac_eh_reset,
+	.can_queue      		= AAC_NUM_IO_FIB,	
+	.this_id        		= MAXIMUM_NUM_CONTAINERS,
+	.sg_tablesize   		= 16,
+	.max_sectors    		= 128,
+#if (AAC_NUM_IO_FIB > 256)
+	.cmd_per_lun			= 256,
+#else		
+	.cmd_per_lun    		= AAC_NUM_IO_FIB, 
+#endif	
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+	.use_new_eh_code		= 1, 
+#endif
+	.use_clustering			= ENABLE_CLUSTERING,
+#if (defined(SCSI_HAS_VARY_IO))
+	.vary_io			= 1,
+#endif
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0))
+#if (defined(SCSI_HAS_DUMP))
+#if (defined(SCSI_HAS_DUMP_SANITY_CHECK))
+	.dump_sanity_check		= aac_sanity_check,
+#endif
+	.dump_poll			= aac_poll,
+#endif
+#elif (defined(SCSI_HAS_DUMP))
+	.disk_dump			= 1,
+},
+	.dump_ops			= &aac_dump_ops,
+#endif
+};
+
+
+static int __devinit aac_probe_one(struct pci_dev *pdev,
+		const struct pci_device_id *id)
+{
+	unsigned index = id->driver_data;
+	struct Scsi_Host *shost;
+	struct aac_dev *aac;
+	struct list_head *insert = &aac_devices;
+	int error = -ENODEV;
+	int unique_id = 0;
