patch-2.2.17 linux/drivers/block/DAC960.c

Next file: linux/drivers/block/DAC960.h
Previous file: linux/arch/sparc64/lib/blockops.S
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.2.16/drivers/block/DAC960.c linux/drivers/block/DAC960.c
@@ -1,8 +1,8 @@
 /*
 
-  Linux Driver for Mylex DAC960 and DAC1100 PCI RAID Controllers
+  Linux Driver for Mylex DAC960/AcceleRAID/eXtremeRAID PCI RAID Controllers
 
-  Copyright 1998-1999 by Leonard N. Zubkoff <lnz@dandelion.com>
+  Copyright 1998-2000 by Leonard N. Zubkoff <lnz@dandelion.com>
 
   This program is free software; you may redistribute and/or modify it under
   the terms of the GNU General Public License Version 2 as published by the
@@ -19,8 +19,8 @@
 */
 
 
-#define DAC960_DriverVersion			"2.2.5"
-#define DAC960_DriverDate			"23 January 2000"
+#define DAC960_DriverVersion			"2.2.8"
+#define DAC960_DriverDate			"19 August 2000"
 
 
 #include <linux/version.h>
@@ -55,7 +55,7 @@
 
 
 /*
-  DAC960_ActiveControllerCount is the number of Active DAC960 Controllers
+  DAC960_ActiveControllerCount is the number of active DAC960 Controllers
   detected.
 */
 
@@ -130,7 +130,7 @@
 */
 
 static boolean DAC960_Failure(DAC960_Controller_T *Controller,
-			      char *ErrorMessage)
+			      unsigned char *ErrorMessage)
 {
   DAC960_Error("While configuring DAC960 PCI RAID Controller at\n",
 	       Controller);
@@ -150,17 +150,128 @@
 
 
 /*
-  DAC960_ClearCommand clears critical fields of Command.
+  DAC960_CreateAuxiliaryStructures allocates and initializes the auxiliary
+  data structures for Controller.  It returns true on success and false on
+  failure.
 */
 
-static inline void DAC960_ClearCommand(DAC960_Command_T *Command)
+static boolean DAC960_CreateAuxiliaryStructures(DAC960_Controller_T *Controller)
 {
-  DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
-  CommandMailbox->Words[0] = 0;
-  CommandMailbox->Words[1] = 0;
-  CommandMailbox->Words[2] = 0;
-  CommandMailbox->Words[3] = 0;
-  Command->CommandStatus = 0;
+  int CommandAllocationLength, CommandAllocationGroupSize;
+  int CommandsRemaining = 0, CommandIdentifier, CommandGroupByteCount;
+  void *AllocationPointer = NULL;
+  if (Controller->FirmwareType == DAC960_V1_Controller)
+    {
+      CommandAllocationLength = offsetof(DAC960_Command_T, V1.EndMarker);
+      CommandAllocationGroupSize = DAC960_V1_CommandAllocationGroupSize;
+    }
+  else
+    {
+      CommandAllocationLength = offsetof(DAC960_Command_T, V2.EndMarker);
+      CommandAllocationGroupSize = DAC960_V2_CommandAllocationGroupSize;
+    }
+  Controller->CommandAllocationGroupSize = CommandAllocationGroupSize;
+  Controller->FreeCommands = NULL;
+  for (CommandIdentifier = 1;
+       CommandIdentifier <= Controller->DriverQueueDepth;
+       CommandIdentifier++)
+    {
+      DAC960_Command_T *Command;
+      if (--CommandsRemaining <= 0)
+	{
+	  CommandsRemaining =
+	    Controller->DriverQueueDepth - CommandIdentifier + 1;
+	  if (CommandsRemaining > CommandAllocationGroupSize)
+	    CommandsRemaining = CommandAllocationGroupSize;
+	  CommandGroupByteCount =
+	    CommandsRemaining * CommandAllocationLength;
+	  AllocationPointer = kmalloc(CommandGroupByteCount, GFP_ATOMIC);
+	  if (AllocationPointer == NULL)
+	    return DAC960_Failure(Controller, "AUXILIARY STRUCTURE CREATION");
+	  memset(AllocationPointer, 0, CommandGroupByteCount);
+	}
+      Command = (DAC960_Command_T *) AllocationPointer;
+      AllocationPointer += CommandAllocationLength;
+      Command->CommandIdentifier = CommandIdentifier;
+      Command->Controller = Controller;
+      Command->Next = Controller->FreeCommands;
+      Controller->FreeCommands = Command;
+      Controller->Commands[CommandIdentifier-1] = Command;
+    }
+  return true;
+}
+
+
+/*
+  DAC960_DestroyAuxiliaryStructures deallocates the auxiliary data
+  structures for Controller.
+*/
+
+static void DAC960_DestroyAuxiliaryStructures(DAC960_Controller_T *Controller)
+{
+  int i;
+  Controller->FreeCommands = NULL;
+  for (i = 0; i < Controller->DriverQueueDepth; i++)
+    {
+      DAC960_Command_T *Command = Controller->Commands[i];
+      if (Command != NULL &&
+	  (Command->CommandIdentifier
+	   % Controller->CommandAllocationGroupSize) == 1)
+	kfree(Command);
+      Controller->Commands[i] = NULL;
+    }
+  if (Controller->CombinedStatusBuffer != NULL)
+    {
+      kfree(Controller->CombinedStatusBuffer);
+      Controller->CombinedStatusBuffer = NULL;
+      Controller->CurrentStatusBuffer = NULL;
+    }
+  if (Controller->FirmwareType == DAC960_V1_Controller) return;
+  for (i = 0; i < DAC960_MaxLogicalDrives; i++)
+    if (Controller->V2.LogicalDeviceInformation[i] != NULL)
+      {
+	kfree(Controller->V2.LogicalDeviceInformation[i]);
+	Controller->V2.LogicalDeviceInformation[i] = NULL;
+      }
+  for (i = 0; i < DAC960_V2_MaxPhysicalDevices; i++)
+    {
+      if (Controller->V2.PhysicalDeviceInformation[i] != NULL)
+	{
+	  kfree(Controller->V2.PhysicalDeviceInformation[i]);
+	  Controller->V2.PhysicalDeviceInformation[i] = NULL;
+	}
+      if (Controller->V2.InquiryUnitSerialNumber[i] != NULL)
+	{
+	  kfree(Controller->V2.InquiryUnitSerialNumber[i]);
+	  Controller->V2.InquiryUnitSerialNumber[i] = NULL;
+	}
+    }
+}
+
+
+/*
+  DAC960_V1_ClearCommand clears critical fields of Command for DAC960 V1
+  Firmware Controllers.
+*/
+
+static inline void DAC960_V1_ClearCommand(DAC960_Command_T *Command)
+{
+  DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
+  memset(CommandMailbox, 0, sizeof(DAC960_V1_CommandMailbox_T));
+  Command->V1.CommandStatus = 0;
+}
+
+
+/*
+  DAC960_V2_ClearCommand clears critical fields of Command for DAC960 V2
+  Firmware Controllers.
+*/
+
+static inline void DAC960_V2_ClearCommand(DAC960_Command_T *Command)
+{
+  DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
+  memset(CommandMailbox, 0, sizeof(DAC960_V2_CommandMailbox_T));
+  Command->V2.CommandStatus = 0;
 }
 
 
@@ -211,66 +322,181 @@
 
 
 /*
-  DAC960_QueueCommand queues Command.
+  DAC960_BA_QueueCommand queues Command for DAC960 BA Series Controllers.
 */
 
-static void DAC960_QueueCommand(DAC960_Command_T *Command)
+static void DAC960_BA_QueueCommand(DAC960_Command_T *Command)
 {
   DAC960_Controller_T *Controller = Command->Controller;
   void *ControllerBaseAddress = Controller->BaseAddress;
-  DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
-  DAC960_CommandMailbox_T *NextCommandMailbox;
-  CommandMailbox->Common.CommandIdentifier = Command - Controller->Commands;
-  switch (Controller->ControllerType)
-    {
-    case DAC960_V5_Controller:
-      NextCommandMailbox = Controller->NextCommandMailbox;
-      DAC960_V5_WriteCommandMailbox(NextCommandMailbox, CommandMailbox);
-      if (Controller->PreviousCommandMailbox1->Words[0] == 0 ||
-	  Controller->PreviousCommandMailbox2->Words[0] == 0)
-	{
-	  if (Controller->DualModeMemoryMailboxInterface)
-	    DAC960_V5_MemoryMailboxNewCommand(ControllerBaseAddress);
-	  else DAC960_V5_HardwareMailboxNewCommand(ControllerBaseAddress);
-	}
-      Controller->PreviousCommandMailbox2 = Controller->PreviousCommandMailbox1;
-      Controller->PreviousCommandMailbox1 = NextCommandMailbox;
-      if (++NextCommandMailbox > Controller->LastCommandMailbox)
-	NextCommandMailbox = Controller->FirstCommandMailbox;
-      Controller->NextCommandMailbox = NextCommandMailbox;
-      break;
-    case DAC960_V4_Controller:
-      NextCommandMailbox = Controller->NextCommandMailbox;
-      DAC960_V4_WriteCommandMailbox(NextCommandMailbox, CommandMailbox);
-      if (Controller->PreviousCommandMailbox1->Words[0] == 0 ||
-	  Controller->PreviousCommandMailbox2->Words[0] == 0)
-	{
-	  if (Controller->DualModeMemoryMailboxInterface)
-	    DAC960_V4_MemoryMailboxNewCommand(ControllerBaseAddress);
-	  else DAC960_V4_HardwareMailboxNewCommand(ControllerBaseAddress);
-	}
-      Controller->PreviousCommandMailbox2 = Controller->PreviousCommandMailbox1;
-      Controller->PreviousCommandMailbox1 = NextCommandMailbox;
-      if (++NextCommandMailbox > Controller->LastCommandMailbox)
-	NextCommandMailbox = Controller->FirstCommandMailbox;
-      Controller->NextCommandMailbox = NextCommandMailbox;
-      break;
-    case DAC960_V3_Controller:
-      while (DAC960_V3_MailboxFullP(ControllerBaseAddress))
-	udelay(1);
-      DAC960_V3_WriteCommandMailbox(ControllerBaseAddress, CommandMailbox);
-      DAC960_V3_NewCommand(ControllerBaseAddress);
-      break;
-    }
+  DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
+  DAC960_V2_CommandMailbox_T *NextCommandMailbox =
+    Controller->V2.NextCommandMailbox;
+  CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier;
+  DAC960_BA_WriteCommandMailbox(NextCommandMailbox, CommandMailbox);
+  if (Controller->V2.PreviousCommandMailbox1->Words[0] == 0 ||
+      Controller->V2.PreviousCommandMailbox2->Words[0] == 0)
+    DAC960_BA_MemoryMailboxNewCommand(ControllerBaseAddress);
+  Controller->V2.PreviousCommandMailbox2 =
+    Controller->V2.PreviousCommandMailbox1;
+  Controller->V2.PreviousCommandMailbox1 = NextCommandMailbox;
+  if (++NextCommandMailbox > Controller->V2.LastCommandMailbox)
+    NextCommandMailbox = Controller->V2.FirstCommandMailbox;
+  Controller->V2.NextCommandMailbox = NextCommandMailbox;
 }
 
 
 /*
-  DAC960_ExecuteCommand executes Command and waits for completion.  It
-  returns true on success and false on failure.
+  DAC960_LP_QueueCommand queues Command for DAC960 LP Series Controllers.
+*/
+
+static void DAC960_LP_QueueCommand(DAC960_Command_T *Command)
+{
+  DAC960_Controller_T *Controller = Command->Controller;
+  void *ControllerBaseAddress = Controller->BaseAddress;
+  DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
+  DAC960_V2_CommandMailbox_T *NextCommandMailbox =
+    Controller->V2.NextCommandMailbox;
+  CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier;
+  DAC960_LP_WriteCommandMailbox(NextCommandMailbox, CommandMailbox);
+  if (Controller->V2.PreviousCommandMailbox1->Words[0] == 0 ||
+      Controller->V2.PreviousCommandMailbox2->Words[0] == 0)
+    DAC960_LP_MemoryMailboxNewCommand(ControllerBaseAddress);
+  Controller->V2.PreviousCommandMailbox2 =
+    Controller->V2.PreviousCommandMailbox1;
+  Controller->V2.PreviousCommandMailbox1 = NextCommandMailbox;
+  if (++NextCommandMailbox > Controller->V2.LastCommandMailbox)
+    NextCommandMailbox = Controller->V2.FirstCommandMailbox;
+  Controller->V2.NextCommandMailbox = NextCommandMailbox;
+}
+
+
+/*
+  DAC960_LA_QueueCommandDualMode queues Command for DAC960 LA Series
+  Controllers with Dual Mode Firmware.
+*/
+
+static void DAC960_LA_QueueCommandDualMode(DAC960_Command_T *Command)
+{
+  DAC960_Controller_T *Controller = Command->Controller;
+  void *ControllerBaseAddress = Controller->BaseAddress;
+  DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
+  DAC960_V1_CommandMailbox_T *NextCommandMailbox =
+    Controller->V1.NextCommandMailbox;
+  CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier;
+  DAC960_LA_WriteCommandMailbox(NextCommandMailbox, CommandMailbox);
+  if (Controller->V1.PreviousCommandMailbox1->Words[0] == 0 ||
+      Controller->V1.PreviousCommandMailbox2->Words[0] == 0)
+    DAC960_LA_MemoryMailboxNewCommand(ControllerBaseAddress);
+  Controller->V1.PreviousCommandMailbox2 =
+    Controller->V1.PreviousCommandMailbox1;
+  Controller->V1.PreviousCommandMailbox1 = NextCommandMailbox;
+  if (++NextCommandMailbox > Controller->V1.LastCommandMailbox)
+    NextCommandMailbox = Controller->V1.FirstCommandMailbox;
+  Controller->V1.NextCommandMailbox = NextCommandMailbox;
+}
+
+
+/*
+  DAC960_LA_QueueCommandSingleMode queues Command for DAC960 LA Series
+  Controllers with Single Mode Firmware.
+*/
+
+static void DAC960_LA_QueueCommandSingleMode(DAC960_Command_T *Command)
+{
+  DAC960_Controller_T *Controller = Command->Controller;
+  void *ControllerBaseAddress = Controller->BaseAddress;
+  DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
+  DAC960_V1_CommandMailbox_T *NextCommandMailbox =
+    Controller->V1.NextCommandMailbox;
+  CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier;
+  DAC960_LA_WriteCommandMailbox(NextCommandMailbox, CommandMailbox);
+  if (Controller->V1.PreviousCommandMailbox1->Words[0] == 0 ||
+      Controller->V1.PreviousCommandMailbox2->Words[0] == 0)
+    DAC960_LA_HardwareMailboxNewCommand(ControllerBaseAddress);
+  Controller->V1.PreviousCommandMailbox2 =
+    Controller->V1.PreviousCommandMailbox1;
+  Controller->V1.PreviousCommandMailbox1 = NextCommandMailbox;
+  if (++NextCommandMailbox > Controller->V1.LastCommandMailbox)
+    NextCommandMailbox = Controller->V1.FirstCommandMailbox;
+  Controller->V1.NextCommandMailbox = NextCommandMailbox;
+}
+
+
+/*
+  DAC960_PG_QueueCommandDualMode queues Command for DAC960 PG Series
+  Controllers with Dual Mode Firmware.
+*/
+
+static void DAC960_PG_QueueCommandDualMode(DAC960_Command_T *Command)
+{
+  DAC960_Controller_T *Controller = Command->Controller;
+  void *ControllerBaseAddress = Controller->BaseAddress;
+  DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
+  DAC960_V1_CommandMailbox_T *NextCommandMailbox =
+    Controller->V1.NextCommandMailbox;
+  CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier;
+  DAC960_PG_WriteCommandMailbox(NextCommandMailbox, CommandMailbox);
+  if (Controller->V1.PreviousCommandMailbox1->Words[0] == 0 ||
+      Controller->V1.PreviousCommandMailbox2->Words[0] == 0)
+    DAC960_PG_MemoryMailboxNewCommand(ControllerBaseAddress);
+  Controller->V1.PreviousCommandMailbox2 =
+    Controller->V1.PreviousCommandMailbox1;
+  Controller->V1.PreviousCommandMailbox1 = NextCommandMailbox;
+  if (++NextCommandMailbox > Controller->V1.LastCommandMailbox)
+    NextCommandMailbox = Controller->V1.FirstCommandMailbox;
+  Controller->V1.NextCommandMailbox = NextCommandMailbox;
+}
+
+
+/*
+  DAC960_PG_QueueCommandSingleMode queues Command for DAC960 PG Series
+  Controllers with Single Mode Firmware.
+*/
+
+static void DAC960_PG_QueueCommandSingleMode(DAC960_Command_T *Command)
+{
+  DAC960_Controller_T *Controller = Command->Controller;
+  void *ControllerBaseAddress = Controller->BaseAddress;
+  DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
+  DAC960_V1_CommandMailbox_T *NextCommandMailbox =
+    Controller->V1.NextCommandMailbox;
+  CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier;
+  DAC960_PG_WriteCommandMailbox(NextCommandMailbox, CommandMailbox);
+  if (Controller->V1.PreviousCommandMailbox1->Words[0] == 0 ||
+      Controller->V1.PreviousCommandMailbox2->Words[0] == 0)
+    DAC960_PG_HardwareMailboxNewCommand(ControllerBaseAddress);
+  Controller->V1.PreviousCommandMailbox2 =
+    Controller->V1.PreviousCommandMailbox1;
+  Controller->V1.PreviousCommandMailbox1 = NextCommandMailbox;
+  if (++NextCommandMailbox > Controller->V1.LastCommandMailbox)
+    NextCommandMailbox = Controller->V1.FirstCommandMailbox;
+  Controller->V1.NextCommandMailbox = NextCommandMailbox;
+}
+
+
+/*
+  DAC960_PD_QueueCommand queues Command for DAC960 PD Series Controllers.
+*/
+
+static void DAC960_PD_QueueCommand(DAC960_Command_T *Command)
+{
+  DAC960_Controller_T *Controller = Command->Controller;
+  void *ControllerBaseAddress = Controller->BaseAddress;
+  DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
+  CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier;
+  while (DAC960_PD_MailboxFullP(ControllerBaseAddress))
+    udelay(1);
+  DAC960_PD_WriteCommandMailbox(ControllerBaseAddress, CommandMailbox);
+  DAC960_PD_NewCommand(ControllerBaseAddress);
+}
+
+
+/*
+  DAC960_ExecuteCommand executes Command and waits for completion.
 */
 
-static boolean DAC960_ExecuteCommand(DAC960_Command_T *Command)
+static void DAC960_ExecuteCommand(DAC960_Command_T *Command)
 {
   DAC960_Controller_T *Controller = Command->Controller;
   Semaphore_T Semaphore = MUTEX_LOCKED;
@@ -279,227 +505,386 @@
   DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
   DAC960_QueueCommand(Command);
   DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
-  if (!in_interrupt())
-    down(&Semaphore);
-  return Command->CommandStatus == DAC960_NormalCompletion;
+  if (in_interrupt()) return;
+  down(&Semaphore);
 }
 
 
 /*
-  DAC960_ExecuteType3 executes a DAC960 Type 3 Command and waits for
-  completion.  It returns true on success and false on failure.
+  DAC960_V1_ExecuteType3 executes a DAC960 V1 Firmware Controller Type 3
+  Command and waits for completion.  It returns true on success and false
+  on failure.
 */
 
-static boolean DAC960_ExecuteType3(DAC960_Controller_T *Controller,
-				   DAC960_CommandOpcode_T CommandOpcode,
-				   void *DataPointer)
+static boolean DAC960_V1_ExecuteType3(DAC960_Controller_T *Controller,
+				      DAC960_V1_CommandOpcode_T CommandOpcode,
+				      void *DataPointer)
 {
   DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
-  DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
-  boolean Result;
-  DAC960_ClearCommand(Command);
+  DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
+  DAC960_V1_CommandStatus_T CommandStatus;
+  DAC960_V1_ClearCommand(Command);
   Command->CommandType = DAC960_ImmediateCommand;
   CommandMailbox->Type3.CommandOpcode = CommandOpcode;
   CommandMailbox->Type3.BusAddress = Virtual_to_Bus(DataPointer);
-  Result = DAC960_ExecuteCommand(Command);
+  DAC960_ExecuteCommand(Command);
+  CommandStatus = Command->V1.CommandStatus;
   DAC960_DeallocateCommand(Command);
-  return Result;
+  return (CommandStatus == DAC960_V1_NormalCompletion);
 }
 
 
 /*
-  DAC960_ExecuteType3D executes a DAC960 Type 3D Command and waits for
-  completion.  It returns true on success and false on failure.
+  DAC960_V1_ExecuteType3D executes a DAC960 V1 Firmware Controller Type 3D
+  Command and waits for completion.  It returns true on success and false
+  on failure.
 */
 
-static boolean DAC960_ExecuteType3D(DAC960_Controller_T *Controller,
-				    DAC960_CommandOpcode_T CommandOpcode,
-				    unsigned char Channel,
-				    unsigned char TargetID,
-				    void *DataPointer)
+static boolean DAC960_V1_ExecuteType3D(DAC960_Controller_T *Controller,
+				       DAC960_V1_CommandOpcode_T CommandOpcode,
+				       unsigned char Channel,
+				       unsigned char TargetID,
+				       void *DataPointer)
 {
   DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
-  DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
-  boolean Result;
-  DAC960_ClearCommand(Command);
+  DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
+  DAC960_V1_CommandStatus_T CommandStatus;
+  DAC960_V1_ClearCommand(Command);
   Command->CommandType = DAC960_ImmediateCommand;
   CommandMailbox->Type3D.CommandOpcode = CommandOpcode;
   CommandMailbox->Type3D.Channel = Channel;
   CommandMailbox->Type3D.TargetID = TargetID;
   CommandMailbox->Type3D.BusAddress = Virtual_to_Bus(DataPointer);
-  Result = DAC960_ExecuteCommand(Command);
+  DAC960_ExecuteCommand(Command);
+  CommandStatus = Command->V1.CommandStatus;
   DAC960_DeallocateCommand(Command);
-  return Result;
+  return (CommandStatus == DAC960_V1_NormalCompletion);
 }
 
 
 /*
-  DAC960_ReportErrorStatus reports Controller BIOS Messages passed through
-  the Error Status Register when the driver performs the BIOS handshaking.
-  It returns true for fatal errors and false otherwise.
+  DAC960_V2_GeneralInfo executes a DAC960 V2 Firmware General Information
+  Reading IOCTL Command and waits for completion.  It returns true on success
+  and false on failure.
 */
 
-static boolean DAC960_ReportErrorStatus(DAC960_Controller_T *Controller,
-					unsigned char ErrorStatus,
-					unsigned char Parameter0,
-					unsigned char Parameter1)
+static boolean DAC960_V2_GeneralInfo(DAC960_Controller_T *Controller,
+				     DAC960_V2_IOCTL_Opcode_T IOCTL_Opcode,
+				     void *DataPointer,
+				     unsigned int DataByteCount)
 {
-  switch (ErrorStatus)
-    {
-    case 0x00:
-      DAC960_Notice("Physical Drive %d:%d Not Responding\n",
-		    Controller, Parameter1, Parameter0);
-      break;
-    case 0x08:
-      if (Controller->DriveSpinUpMessageDisplayed) break;
-      DAC960_Notice("Spinning Up Drives\n", Controller);
-      Controller->DriveSpinUpMessageDisplayed = true;
-      break;
-    case 0x30:
-      DAC960_Notice("Configuration Checksum Error\n", Controller);
-      break;
-    case 0x60:
-      DAC960_Notice("Mirror Race Recovery Failed\n", Controller);
-      break;
-    case 0x70:
-      DAC960_Notice("Mirror Race Recovery In Progress\n", Controller);
-      break;
-    case 0x90:
-      DAC960_Notice("Physical Drive %d:%d COD Mismatch\n",
-		    Controller, Parameter1, Parameter0);
-      break;
-    case 0xA0:
-      DAC960_Notice("Logical Drive Installation Aborted\n", Controller);
-      break;
-    case 0xB0:
-      DAC960_Notice("Mirror Race On A Critical Logical Drive\n", Controller);
-      break;
-    case 0xD0:
-      DAC960_Notice("New Controller Configuration Found\n", Controller);
-      break;
-    case 0xF0:
-      DAC960_Error("Fatal Memory Parity Error for Controller at\n", Controller);
-      return true;
-    default:
-      DAC960_Error("Unknown Initialization Error %02X for Controller at\n",
-		   Controller, ErrorStatus);
-      return true;
-    }
-  return false;
+  DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
+  DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
+  DAC960_V2_CommandStatus_T CommandStatus;
+  DAC960_V2_ClearCommand(Command);
+  Command->CommandType = DAC960_ImmediateCommand;
+  CommandMailbox->Common.CommandOpcode = DAC960_V2_IOCTL;
+  CommandMailbox->Common.CommandControlBits
+			.DataTransferControllerToHost = true;
+  CommandMailbox->Common.CommandControlBits
+			.NoAutoRequestSense = true;
+  CommandMailbox->Common.DataTransferSize = DataByteCount;
+  CommandMailbox->Common.IOCTL_Opcode = IOCTL_Opcode;
+  CommandMailbox->Common.DataTransferMemoryAddress
+			.ScatterGatherSegments[0]
+			.SegmentDataPointer =
+    Virtual_to_Bus(DataPointer);
+  CommandMailbox->Common.DataTransferMemoryAddress
+			.ScatterGatherSegments[0]
+			.SegmentByteCount =
+    CommandMailbox->Common.DataTransferSize;
+  DAC960_ExecuteCommand(Command);
+  CommandStatus = Command->V2.CommandStatus;
+  DAC960_DeallocateCommand(Command);
+  return (CommandStatus == DAC960_V2_NormalCompletion);
 }
 
 
 /*
-  DAC960_EnableMemoryMailboxInterface enables the Memory Mailbox Interface.
+  DAC960_V2_ControllerInfo executes a DAC960 V2 Firmware Controller
+  Information Reading IOCTL Command and waits for completion.  It returns
+  true on success and false on failure.
 */
 
-static boolean DAC960_EnableMemoryMailboxInterface(DAC960_Controller_T
-						   *Controller)
+static boolean DAC960_V2_ControllerInfo(DAC960_Controller_T *Controller,
+					DAC960_V2_IOCTL_Opcode_T IOCTL_Opcode,
+					void *DataPointer,
+					unsigned int DataByteCount)
+{
+  DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
+  DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
+  DAC960_V2_CommandStatus_T CommandStatus;
+  DAC960_V2_ClearCommand(Command);
+  Command->CommandType = DAC960_ImmediateCommand;
+  CommandMailbox->ControllerInfo.CommandOpcode = DAC960_V2_IOCTL;
+  CommandMailbox->ControllerInfo.CommandControlBits
+				.DataTransferControllerToHost = true;
+  CommandMailbox->ControllerInfo.CommandControlBits
+				.NoAutoRequestSense = true;
+  CommandMailbox->ControllerInfo.DataTransferSize = DataByteCount;
+  CommandMailbox->ControllerInfo.ControllerNumber = 0;
+  CommandMailbox->ControllerInfo.IOCTL_Opcode = IOCTL_Opcode;
+  CommandMailbox->ControllerInfo.DataTransferMemoryAddress
+				.ScatterGatherSegments[0]
+				.SegmentDataPointer =
+    Virtual_to_Bus(DataPointer);
+  CommandMailbox->ControllerInfo.DataTransferMemoryAddress
+				.ScatterGatherSegments[0]
+				.SegmentByteCount =
+    CommandMailbox->ControllerInfo.DataTransferSize;
+  DAC960_ExecuteCommand(Command);
+  CommandStatus = Command->V2.CommandStatus;
+  DAC960_DeallocateCommand(Command);
+  return (CommandStatus == DAC960_V2_NormalCompletion);
+}
+
+
+/*
+  DAC960_V2_LogicalDeviceInfo executes a DAC960 V2 Firmware Controller Logical
+  Device Information Reading IOCTL Command and waits for completion.  It
+  returns true on success and false on failure.
+*/
+
+static boolean DAC960_V2_LogicalDeviceInfo(DAC960_Controller_T *Controller,
+					   DAC960_V2_IOCTL_Opcode_T
+					     IOCTL_Opcode,
+					   unsigned short
+					     LogicalDeviceNumber,
+					   void *DataPointer,
+					   unsigned int DataByteCount)
+{
+  DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
+  DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
+  DAC960_V2_CommandStatus_T CommandStatus;
+  DAC960_V2_ClearCommand(Command);
+  Command->CommandType = DAC960_ImmediateCommand;
+  CommandMailbox->LogicalDeviceInfo.CommandOpcode = DAC960_V2_IOCTL;
+  CommandMailbox->LogicalDeviceInfo.CommandControlBits
+				   .DataTransferControllerToHost = true;
+  CommandMailbox->LogicalDeviceInfo.CommandControlBits
+				   .NoAutoRequestSense = true;
+  CommandMailbox->LogicalDeviceInfo.DataTransferSize = DataByteCount;
+  CommandMailbox->LogicalDeviceInfo.LogicalDevice.LogicalDeviceNumber =
+    LogicalDeviceNumber;
+  CommandMailbox->LogicalDeviceInfo.IOCTL_Opcode = IOCTL_Opcode;
+  CommandMailbox->LogicalDeviceInfo.DataTransferMemoryAddress
+				   .ScatterGatherSegments[0]
+				   .SegmentDataPointer =
+    Virtual_to_Bus(DataPointer);
+  CommandMailbox->LogicalDeviceInfo.DataTransferMemoryAddress
+				   .ScatterGatherSegments[0]
+				   .SegmentByteCount =
+    CommandMailbox->LogicalDeviceInfo.DataTransferSize;
+  DAC960_ExecuteCommand(Command);
+  CommandStatus = Command->V2.CommandStatus;
+  DAC960_DeallocateCommand(Command);
+  return (CommandStatus == DAC960_V2_NormalCompletion);
+}
+
+
+/*
+  DAC960_V2_PhysicalDeviceInfo executes a DAC960 V2 Firmware Controller Physical
+  Device Information Reading IOCTL Command and waits for completion.  It
+  returns true on success and false on failure.
+*/
+
+static boolean DAC960_V2_PhysicalDeviceInfo(DAC960_Controller_T *Controller,
+					    DAC960_V2_IOCTL_Opcode_T
+					      IOCTL_Opcode,
+					    unsigned char Channel,
+					    unsigned char TargetID,
+					    unsigned char LogicalUnit,
+					    void *DataPointer,
+					    unsigned int DataByteCount)
+{
+  DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
+  DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
+  DAC960_V2_CommandStatus_T CommandStatus;
+  DAC960_V2_ClearCommand(Command);
+  Command->CommandType = DAC960_ImmediateCommand;
+  CommandMailbox->PhysicalDeviceInfo.CommandOpcode = DAC960_V2_IOCTL;
+  CommandMailbox->PhysicalDeviceInfo.CommandControlBits
+				    .DataTransferControllerToHost = true;
+  CommandMailbox->PhysicalDeviceInfo.CommandControlBits
+				    .NoAutoRequestSense = true;
+  CommandMailbox->PhysicalDeviceInfo.DataTransferSize = DataByteCount;
+  CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.LogicalUnit = LogicalUnit;
+  CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.TargetID = TargetID;
+  CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.Channel = Channel;
+  CommandMailbox->PhysicalDeviceInfo.IOCTL_Opcode = IOCTL_Opcode;
+  CommandMailbox->PhysicalDeviceInfo.DataTransferMemoryAddress
+				    .ScatterGatherSegments[0]
+				    .SegmentDataPointer =
+    Virtual_to_Bus(DataPointer);
+  CommandMailbox->PhysicalDeviceInfo.DataTransferMemoryAddress
+				    .ScatterGatherSegments[0]
+				    .SegmentByteCount =
+    CommandMailbox->PhysicalDeviceInfo.DataTransferSize;
+  DAC960_ExecuteCommand(Command);
+  CommandStatus = Command->V2.CommandStatus;
+  DAC960_DeallocateCommand(Command);
+  return (CommandStatus == DAC960_V2_NormalCompletion);
+}
+
+
+/*
+  DAC960_V2_DeviceOperation executes a DAC960 V2 Firmware Controller Device
+  Operation IOCTL Command and waits for completion.  It returns true on
+  success and false on failure.
+*/
+
+static boolean DAC960_V2_DeviceOperation(DAC960_Controller_T *Controller,
+					 DAC960_V2_IOCTL_Opcode_T IOCTL_Opcode,
+					 DAC960_V2_OperationDevice_T
+					   OperationDevice)
+{
+  DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
+  DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
+  DAC960_V2_CommandStatus_T CommandStatus;
+  DAC960_V2_ClearCommand(Command);
+  Command->CommandType = DAC960_ImmediateCommand;
+  CommandMailbox->DeviceOperation.CommandOpcode = DAC960_V2_IOCTL;
+  CommandMailbox->DeviceOperation.CommandControlBits
+				 .DataTransferControllerToHost = true;
+  CommandMailbox->DeviceOperation.CommandControlBits
+    				 .NoAutoRequestSense = true;
+  CommandMailbox->DeviceOperation.IOCTL_Opcode = IOCTL_Opcode;
+  CommandMailbox->DeviceOperation.OperationDevice = OperationDevice;
+  DAC960_ExecuteCommand(Command);
+  CommandStatus = Command->V2.CommandStatus;
+  DAC960_DeallocateCommand(Command);
+  return (CommandStatus == DAC960_V2_NormalCompletion);
+}
+
+
+/*
+  DAC960_V1_EnableMemoryMailboxInterface enables the Memory Mailbox Interface
+  for DAC960 V1 Firmware Controllers.
+*/
+
+static boolean DAC960_V1_EnableMemoryMailboxInterface(DAC960_Controller_T
+						      *Controller)
 {
   void *ControllerBaseAddress = Controller->BaseAddress;
-  DAC960_CommandMailbox_T *CommandMailboxesMemory;
-  DAC960_StatusMailbox_T *StatusMailboxesMemory;
-  DAC960_CommandMailbox_T CommandMailbox;
-  DAC960_CommandStatus_T CommandStatus;
+  DAC960_V1_CommandMailbox_T *CommandMailboxesMemory;
+  DAC960_V1_StatusMailbox_T *StatusMailboxesMemory;
+  DAC960_V1_CommandMailbox_T CommandMailbox;
+  DAC960_V1_CommandStatus_T CommandStatus;
+  unsigned long MemoryMailboxPagesAddress;
+  unsigned long MemoryMailboxPagesOrder;
+  unsigned long MemoryMailboxPagesSize;
   void *SavedMemoryMailboxesAddress = NULL;
   short NextCommandMailboxIndex = 0;
   short NextStatusMailboxIndex = 0;
   int TimeoutCounter = 1000000, i;
-  if (Controller->ControllerType == DAC960_V5_Controller)
-    DAC960_V5_RestoreMemoryMailboxInfo(Controller,
+  MemoryMailboxPagesOrder = 0;
+  MemoryMailboxPagesSize =
+    DAC960_V1_CommandMailboxCount * sizeof(DAC960_V1_CommandMailbox_T) +
+    DAC960_V1_StatusMailboxCount * sizeof(DAC960_V1_StatusMailbox_T);
+  while (MemoryMailboxPagesSize > PAGE_SIZE << MemoryMailboxPagesOrder)
+    MemoryMailboxPagesOrder++;
+  if (Controller->HardwareType == DAC960_LA_Controller)
+    DAC960_LA_RestoreMemoryMailboxInfo(Controller,
 				       &SavedMemoryMailboxesAddress,
 				       &NextCommandMailboxIndex,
 				       &NextStatusMailboxIndex);
-  else DAC960_V4_RestoreMemoryMailboxInfo(Controller,
+  else DAC960_PG_RestoreMemoryMailboxInfo(Controller,
 					  &SavedMemoryMailboxesAddress,
 					  &NextCommandMailboxIndex,
 					  &NextStatusMailboxIndex);
   if (SavedMemoryMailboxesAddress == NULL)
-    CommandMailboxesMemory =
-      (DAC960_CommandMailbox_T *) __get_free_pages(GFP_KERNEL, 1);
+    {
+      MemoryMailboxPagesAddress =
+	__get_free_pages(GFP_KERNEL, MemoryMailboxPagesOrder);
+      Controller->MemoryMailboxPagesAddress = MemoryMailboxPagesAddress;
+      CommandMailboxesMemory =
+	(DAC960_V1_CommandMailbox_T *) MemoryMailboxPagesAddress;
+    }
   else CommandMailboxesMemory = SavedMemoryMailboxesAddress;
-  memset(CommandMailboxesMemory, 0, PAGE_SIZE << 1);
-  Controller->FirstCommandMailbox = CommandMailboxesMemory;
-  CommandMailboxesMemory += DAC960_CommandMailboxCount - 1;
-  Controller->LastCommandMailbox = CommandMailboxesMemory;
-  Controller->NextCommandMailbox =
-    &Controller->FirstCommandMailbox[NextCommandMailboxIndex];
+  if (CommandMailboxesMemory == NULL) return false;
+  Controller->MemoryMailboxPagesOrder = MemoryMailboxPagesOrder;
+  memset(CommandMailboxesMemory, 0, MemoryMailboxPagesSize);
+  Controller->V1.FirstCommandMailbox = CommandMailboxesMemory;
+  CommandMailboxesMemory += DAC960_V1_CommandMailboxCount - 1;
+  Controller->V1.LastCommandMailbox = CommandMailboxesMemory;
+  Controller->V1.NextCommandMailbox =
+    &Controller->V1.FirstCommandMailbox[NextCommandMailboxIndex];
   if (--NextCommandMailboxIndex < 0)
-    NextCommandMailboxIndex = DAC960_CommandMailboxCount - 1;
-  Controller->PreviousCommandMailbox1 =
-    &Controller->FirstCommandMailbox[NextCommandMailboxIndex];
+    NextCommandMailboxIndex = DAC960_V1_CommandMailboxCount - 1;
+  Controller->V1.PreviousCommandMailbox1 =
+    &Controller->V1.FirstCommandMailbox[NextCommandMailboxIndex];
   if (--NextCommandMailboxIndex < 0)
-    NextCommandMailboxIndex = DAC960_CommandMailboxCount - 1;
-  Controller->PreviousCommandMailbox2 =
-    &Controller->FirstCommandMailbox[NextCommandMailboxIndex];
+    NextCommandMailboxIndex = DAC960_V1_CommandMailboxCount - 1;
+  Controller->V1.PreviousCommandMailbox2 =
+    &Controller->V1.FirstCommandMailbox[NextCommandMailboxIndex];
   StatusMailboxesMemory =
-    (DAC960_StatusMailbox_T *) (CommandMailboxesMemory + 1);
-  Controller->FirstStatusMailbox = StatusMailboxesMemory;
-  StatusMailboxesMemory += DAC960_StatusMailboxCount - 1;
-  Controller->LastStatusMailbox = StatusMailboxesMemory;
-  Controller->NextStatusMailbox =
-    &Controller->FirstStatusMailbox[NextStatusMailboxIndex];
+    (DAC960_V1_StatusMailbox_T *) (CommandMailboxesMemory + 1);
+  Controller->V1.FirstStatusMailbox = StatusMailboxesMemory;
+  StatusMailboxesMemory += DAC960_V1_StatusMailboxCount - 1;
+  Controller->V1.LastStatusMailbox = StatusMailboxesMemory;
+  Controller->V1.NextStatusMailbox =
+    &Controller->V1.FirstStatusMailbox[NextStatusMailboxIndex];
   if (SavedMemoryMailboxesAddress != NULL) return true;
   /* Enable the Memory Mailbox Interface. */
-  Controller->DualModeMemoryMailboxInterface = true;
+  Controller->V1.DualModeMemoryMailboxInterface = true;
   CommandMailbox.TypeX.CommandOpcode = 0x2B;
   CommandMailbox.TypeX.CommandIdentifier = 0;
   CommandMailbox.TypeX.CommandOpcode2 = 0x14;
   CommandMailbox.TypeX.CommandMailboxesBusAddress =
-    Virtual_to_Bus(Controller->FirstCommandMailbox);
+    Virtual_to_Bus(Controller->V1.FirstCommandMailbox);
   CommandMailbox.TypeX.StatusMailboxesBusAddress =
-    Virtual_to_Bus(Controller->FirstStatusMailbox);
+    Virtual_to_Bus(Controller->V1.FirstStatusMailbox);
   for (i = 0; i < 2; i++)
-    switch (Controller->ControllerType)
+    switch (Controller->HardwareType)
       {
-      case DAC960_V5_Controller:
+      case DAC960_LA_Controller:
 	while (--TimeoutCounter >= 0)
 	  {
-	    if (!DAC960_V5_HardwareMailboxFullP(ControllerBaseAddress))
+	    if (!DAC960_LA_HardwareMailboxFullP(ControllerBaseAddress))
 	      break;
 	    udelay(10);
 	  }
 	if (TimeoutCounter < 0) return false;
-	DAC960_V5_WriteHardwareMailbox(ControllerBaseAddress, &CommandMailbox);
-	DAC960_V5_HardwareMailboxNewCommand(ControllerBaseAddress);
+	DAC960_LA_WriteHardwareMailbox(ControllerBaseAddress, &CommandMailbox);
+	DAC960_LA_HardwareMailboxNewCommand(ControllerBaseAddress);
 	while (--TimeoutCounter >= 0)
 	  {
-	    if (DAC960_V5_HardwareMailboxStatusAvailableP(
+	    if (DAC960_LA_HardwareMailboxStatusAvailableP(
 		  ControllerBaseAddress))
 	      break;
 	    udelay(10);
 	  }
 	if (TimeoutCounter < 0) return false;
-	CommandStatus = DAC960_V5_ReadStatusRegister(ControllerBaseAddress);
-	DAC960_V5_AcknowledgeHardwareMailboxInterrupt(ControllerBaseAddress);
-	DAC960_V5_AcknowledgeHardwareMailboxStatus(ControllerBaseAddress);
-	if (CommandStatus == DAC960_NormalCompletion) return true;
-	Controller->DualModeMemoryMailboxInterface = false;
+	CommandStatus = DAC960_LA_ReadStatusRegister(ControllerBaseAddress);
+	DAC960_LA_AcknowledgeHardwareMailboxInterrupt(ControllerBaseAddress);
+	DAC960_LA_AcknowledgeHardwareMailboxStatus(ControllerBaseAddress);
+	if (CommandStatus == DAC960_V1_NormalCompletion) return true;
+	Controller->V1.DualModeMemoryMailboxInterface = false;
 	CommandMailbox.TypeX.CommandOpcode2 = 0x10;
 	break;
-      case DAC960_V4_Controller:
+      case DAC960_PG_Controller:
 	while (--TimeoutCounter >= 0)
 	  {
-	    if (!DAC960_V4_HardwareMailboxFullP(ControllerBaseAddress))
+	    if (!DAC960_PG_HardwareMailboxFullP(ControllerBaseAddress))
 	      break;
 	    udelay(10);
 	  }
 	if (TimeoutCounter < 0) return false;
-	DAC960_V4_WriteHardwareMailbox(ControllerBaseAddress, &CommandMailbox);
-	DAC960_V4_HardwareMailboxNewCommand(ControllerBaseAddress);
+	DAC960_PG_WriteHardwareMailbox(ControllerBaseAddress, &CommandMailbox);
+	DAC960_PG_HardwareMailboxNewCommand(ControllerBaseAddress);
 	while (--TimeoutCounter >= 0)
 	  {
-	    if (DAC960_V4_HardwareMailboxStatusAvailableP(
+	    if (DAC960_PG_HardwareMailboxStatusAvailableP(
 		  ControllerBaseAddress))
 	      break;
 	    udelay(10);
 	  }
 	if (TimeoutCounter < 0) return false;
-	CommandStatus = DAC960_V4_ReadStatusRegister(ControllerBaseAddress);
-	DAC960_V4_AcknowledgeHardwareMailboxInterrupt(ControllerBaseAddress);
-	DAC960_V4_AcknowledgeHardwareMailboxStatus(ControllerBaseAddress);
-	if (CommandStatus == DAC960_NormalCompletion) return true;
-	Controller->DualModeMemoryMailboxInterface = false;
+	CommandStatus = DAC960_PG_ReadStatusRegister(ControllerBaseAddress);
+	DAC960_PG_AcknowledgeHardwareMailboxInterrupt(ControllerBaseAddress);
+	DAC960_PG_AcknowledgeHardwareMailboxStatus(ControllerBaseAddress);
+	if (CommandStatus == DAC960_V1_NormalCompletion) return true;
+	Controller->V1.DualModeMemoryMailboxInterface = false;
 	CommandMailbox.TypeX.CommandOpcode2 = 0x10;
 	break;
       default:
@@ -510,283 +895,165 @@
 
 
 /*
-  DAC960_DetectControllers detects DAC960 PCI RAID Controllers by interrogating
-  the PCI Configuration Space for Controller Type.
+  DAC960_V2_EnableMemoryMailboxInterface enables the Memory Mailbox Interface
+  for DAC960 V2 Firmware Controllers.
 */
 
-static void DAC960_DetectControllers(DAC960_ControllerType_T ControllerType)
+static boolean DAC960_V2_EnableMemoryMailboxInterface(DAC960_Controller_T
+						      *Controller)
 {
-  unsigned short VendorID = 0, DeviceID = 0;
-  unsigned int MemoryWindowSize = 0;
-  PCI_Device_T *PCI_Device = NULL;
-  switch (ControllerType)
+  void *ControllerBaseAddress = Controller->BaseAddress;
+  DAC960_V2_CommandMailbox_T *CommandMailboxesMemory;
+  DAC960_V2_StatusMailbox_T *StatusMailboxesMemory;
+  DAC960_V2_CommandMailbox_T CommandMailbox;
+  DAC960_V2_CommandStatus_T CommandStatus = 0;
+  unsigned long MemoryMailboxPagesAddress;
+  unsigned long MemoryMailboxPagesOrder;
+  unsigned long MemoryMailboxPagesSize;
+  MemoryMailboxPagesOrder = 0;
+  MemoryMailboxPagesSize =
+    DAC960_V2_CommandMailboxCount * sizeof(DAC960_V2_CommandMailbox_T) +
+    DAC960_V2_StatusMailboxCount * sizeof(DAC960_V2_StatusMailbox_T) +
+    sizeof(DAC960_V2_HealthStatusBuffer_T);
+  while (MemoryMailboxPagesSize > PAGE_SIZE << MemoryMailboxPagesOrder)
+    MemoryMailboxPagesOrder++;
+  MemoryMailboxPagesAddress =
+    __get_free_pages(GFP_KERNEL, MemoryMailboxPagesOrder);
+  Controller->MemoryMailboxPagesAddress = MemoryMailboxPagesAddress;
+  CommandMailboxesMemory =
+    (DAC960_V2_CommandMailbox_T *) MemoryMailboxPagesAddress;
+  if (CommandMailboxesMemory == NULL) return false;
+  Controller->MemoryMailboxPagesOrder = MemoryMailboxPagesOrder;
+  memset(CommandMailboxesMemory, 0, MemoryMailboxPagesSize);
+  Controller->V2.FirstCommandMailbox = CommandMailboxesMemory;
+  CommandMailboxesMemory += DAC960_V2_CommandMailboxCount - 1;
+  Controller->V2.LastCommandMailbox = CommandMailboxesMemory;
+  Controller->V2.NextCommandMailbox = Controller->V2.FirstCommandMailbox;
+  Controller->V2.PreviousCommandMailbox1 = Controller->V2.LastCommandMailbox;
+  Controller->V2.PreviousCommandMailbox2 =
+    Controller->V2.LastCommandMailbox - 1;
+  StatusMailboxesMemory =
+    (DAC960_V2_StatusMailbox_T *) (CommandMailboxesMemory + 1);
+  Controller->V2.FirstStatusMailbox = StatusMailboxesMemory;
+  StatusMailboxesMemory += DAC960_V2_StatusMailboxCount - 1;
+  Controller->V2.LastStatusMailbox = StatusMailboxesMemory;
+  Controller->V2.NextStatusMailbox = Controller->V2.FirstStatusMailbox;
+  Controller->V2.HealthStatusBuffer =
+    (DAC960_V2_HealthStatusBuffer_T *) (StatusMailboxesMemory + 1);
+  /* Enable the Memory Mailbox Interface. */
+  memset(&CommandMailbox, 0, sizeof(DAC960_V2_CommandMailbox_T));
+  CommandMailbox.SetMemoryMailbox.CommandIdentifier = 1;
+  CommandMailbox.SetMemoryMailbox.CommandOpcode = DAC960_V2_IOCTL;
+  CommandMailbox.SetMemoryMailbox.CommandControlBits.NoAutoRequestSense = true;
+  CommandMailbox.SetMemoryMailbox.FirstCommandMailboxSizeKB =
+    (DAC960_V2_CommandMailboxCount * sizeof(DAC960_V2_CommandMailbox_T)) >> 10;
+  CommandMailbox.SetMemoryMailbox.FirstStatusMailboxSizeKB =
+    (DAC960_V2_StatusMailboxCount * sizeof(DAC960_V2_StatusMailbox_T)) >> 10;
+  CommandMailbox.SetMemoryMailbox.SecondCommandMailboxSizeKB = 0;
+  CommandMailbox.SetMemoryMailbox.SecondStatusMailboxSizeKB = 0;
+  CommandMailbox.SetMemoryMailbox.RequestSenseSize = 0;
+  CommandMailbox.SetMemoryMailbox.IOCTL_Opcode = DAC960_V2_SetMemoryMailbox;
+  CommandMailbox.SetMemoryMailbox.HealthStatusBufferSizeKB = 1;
+  CommandMailbox.SetMemoryMailbox.HealthStatusBufferBusAddress =
+    Virtual_to_Bus(Controller->V2.HealthStatusBuffer);
+  CommandMailbox.SetMemoryMailbox.FirstCommandMailboxBusAddress =
+    Virtual_to_Bus(Controller->V2.FirstCommandMailbox);
+  CommandMailbox.SetMemoryMailbox.FirstStatusMailboxBusAddress =
+    Virtual_to_Bus(Controller->V2.FirstStatusMailbox);
+  switch (Controller->HardwareType)
     {
-    case DAC960_V5_Controller:
-      VendorID = PCI_VENDOR_ID_DEC;
-      DeviceID = PCI_DEVICE_ID_DEC_21285;
-      MemoryWindowSize = DAC960_V5_RegisterWindowSize;
+    case DAC960_BA_Controller:
+      while (DAC960_BA_HardwareMailboxFullP(ControllerBaseAddress))
+	udelay(1);
+      DAC960_BA_WriteHardwareMailbox(ControllerBaseAddress, &CommandMailbox);
+      DAC960_BA_HardwareMailboxNewCommand(ControllerBaseAddress);
+      while (!DAC960_BA_HardwareMailboxStatusAvailableP(ControllerBaseAddress))
+	udelay(1);
+      CommandStatus = DAC960_BA_ReadCommandStatus(ControllerBaseAddress);
+      DAC960_BA_AcknowledgeHardwareMailboxInterrupt(ControllerBaseAddress);
+      DAC960_BA_AcknowledgeHardwareMailboxStatus(ControllerBaseAddress);
       break;
-    case DAC960_V4_Controller:
-      VendorID = PCI_VENDOR_ID_MYLEX;
-      DeviceID = PCI_DEVICE_ID_MYLEX_DAC960P_V4;
-      MemoryWindowSize = DAC960_V4_RegisterWindowSize;
+    case DAC960_LP_Controller:
+      while (DAC960_LP_HardwareMailboxFullP(ControllerBaseAddress))
+	udelay(1);
+      DAC960_LP_WriteHardwareMailbox(ControllerBaseAddress, &CommandMailbox);
+      DAC960_LP_HardwareMailboxNewCommand(ControllerBaseAddress);
+      while (!DAC960_LP_HardwareMailboxStatusAvailableP(ControllerBaseAddress))
+	udelay(1);
+      CommandStatus = DAC960_LP_ReadCommandStatus(ControllerBaseAddress);
+      DAC960_LP_AcknowledgeHardwareMailboxInterrupt(ControllerBaseAddress);
+      DAC960_LP_AcknowledgeHardwareMailboxStatus(ControllerBaseAddress);
       break;
-    case DAC960_V3_Controller:
-      VendorID = PCI_VENDOR_ID_MYLEX;
-      DeviceID = PCI_DEVICE_ID_MYLEX_DAC960P_V3;
-      MemoryWindowSize = DAC960_V3_RegisterWindowSize;
+    default:
       break;
     }
-  while ((PCI_Device = pci_find_device(VendorID, DeviceID, PCI_Device)) != NULL)
+  return (CommandStatus == DAC960_V2_NormalCompletion);
+}
+
+
+/*
+  DAC960_V1_ReadControllerConfiguration reads the Configuration Information
+  from DAC960 V1 Firmware Controllers and initializes the Controller structure.
+*/
+
+static boolean DAC960_V1_ReadControllerConfiguration(DAC960_Controller_T
+						     *Controller)
+{
+  DAC960_V1_Enquiry2_T Enquiry2;
+  DAC960_V1_Config2_T Config2;
+  int LogicalDriveNumber, Channel, TargetID;
+  if (!DAC960_V1_ExecuteType3(Controller, DAC960_V1_Enquiry,
+			      &Controller->V1.Enquiry))
+    return DAC960_Failure(Controller, "ENQUIRY");
+  if (!DAC960_V1_ExecuteType3(Controller, DAC960_V1_Enquiry2, &Enquiry2))
+    return DAC960_Failure(Controller, "ENQUIRY2");
+  if (!DAC960_V1_ExecuteType3(Controller, DAC960_V1_ReadConfig2, &Config2))
+    return DAC960_Failure(Controller, "READ CONFIG2");
+  if (!DAC960_V1_ExecuteType3(Controller, DAC960_V1_GetLogicalDriveInformation,
+			      &Controller->V1.LogicalDriveInformation))
+    return DAC960_Failure(Controller, "GET LOGICAL DRIVE INFORMATION");
+  for (Channel = 0; Channel < Enquiry2.ActualChannels; Channel++)
+    for (TargetID = 0; TargetID < Enquiry2.MaxTargets; TargetID++)
+      if (!DAC960_V1_ExecuteType3D(Controller, DAC960_V1_GetDeviceState,
+				   Channel, TargetID,
+				   &Controller->V1.DeviceState
+						   [Channel][TargetID]))
+	return DAC960_Failure(Controller, "GET DEVICE STATE");
+  /*
+    Initialize the Controller Model Name and Full Model Name fields.
+  */
+  switch (Enquiry2.HardwareID.SubModel)
     {
-      DAC960_Controller_T *Controller = (DAC960_Controller_T *)
-	kmalloc(sizeof(DAC960_Controller_T), GFP_ATOMIC);
-      DAC960_IO_Address_T IO_Address = 0;
-      DAC960_PCI_Address_T PCI_Address = 0;
-      unsigned char Bus = PCI_Device->bus->number;
-      unsigned char DeviceFunction = PCI_Device->devfn;
-      unsigned char Device = DeviceFunction >> 3;
-      unsigned char Function = DeviceFunction & 0x7;
-      unsigned char ErrorStatus, Parameter0, Parameter1;
-      unsigned int IRQ_Channel = PCI_Device->irq;
-      unsigned long BaseAddress0 = PCI_Device->base_address[0];
-      unsigned long BaseAddress1 = PCI_Device->base_address[1];
-      unsigned short SubsystemVendorID, SubsystemDeviceID;
-      int CommandIdentifier;
-      void *BaseAddress;
-      pci_read_config_word(PCI_Device, PCI_SUBSYSTEM_VENDOR_ID,
-			   &SubsystemVendorID);
-      pci_read_config_word(PCI_Device, PCI_SUBSYSTEM_ID,
-			   &SubsystemDeviceID);
-      switch (ControllerType)
-	{
-	case DAC960_V5_Controller:
-	  if (!(SubsystemVendorID == PCI_VENDOR_ID_MYLEX &&
-		SubsystemDeviceID == PCI_DEVICE_ID_MYLEX_DAC960P_V5))
-	    goto Ignore;
-	  PCI_Address = BaseAddress0 & PCI_BASE_ADDRESS_MEM_MASK;
-	  break;
-	case DAC960_V4_Controller:
-	  PCI_Address = BaseAddress0 & PCI_BASE_ADDRESS_MEM_MASK;
-	  break;
-	case DAC960_V3_Controller:
-	  IO_Address = BaseAddress0 & PCI_BASE_ADDRESS_IO_MASK;
-	  PCI_Address = BaseAddress1 & PCI_BASE_ADDRESS_MEM_MASK;
-	  break;
-	}
-      if (DAC960_ControllerCount == DAC960_MaxControllers)
-	{
-	  DAC960_Error("More than %d DAC960 Controllers detected - "
-		       "ignoring from Controller at\n",
-		       NULL, DAC960_MaxControllers);
-	  goto Ignore;
-	}
-      if (Controller == NULL)
-	{
-	  DAC960_Error("Unable to allocate Controller structure for "
-		       "Controller at\n", NULL);
-	  goto Ignore;
-	}
-      memset(Controller, 0, sizeof(DAC960_Controller_T));
-      Controller->ControllerNumber = DAC960_ControllerCount;
-      DAC960_Controllers[DAC960_ControllerCount++] = Controller;
-      DAC960_AnnounceDriver(Controller);
-      Controller->ControllerType = ControllerType;
-      Controller->IO_Address = IO_Address;
-      Controller->PCI_Address = PCI_Address;
-      Controller->Bus = Bus;
-      Controller->Device = Device;
-      Controller->Function = Function;
-      sprintf(Controller->ControllerName, "c%d", Controller->ControllerNumber);
-      /*
-	Map the Controller Register Window.
-      */
-      if (MemoryWindowSize < PAGE_SIZE)
-	MemoryWindowSize = PAGE_SIZE;
-      Controller->MemoryMappedAddress =
-	ioremap_nocache(PCI_Address & PAGE_MASK, MemoryWindowSize);
-      Controller->BaseAddress =
-	Controller->MemoryMappedAddress + (PCI_Address & ~PAGE_MASK);
-      if (Controller->MemoryMappedAddress == NULL)
-	{
-	  DAC960_Error("Unable to map Controller Register Window for "
-		       "Controller at\n", Controller);
-	  goto Failure;
-	}
-      BaseAddress = Controller->BaseAddress;
-      switch (ControllerType)
-	{
-	case DAC960_V5_Controller:
-	  DAC960_V5_DisableInterrupts(BaseAddress);
-	  DAC960_V5_AcknowledgeHardwareMailboxStatus(BaseAddress);
-	  udelay(1000);
-	  while (DAC960_V5_InitializationInProgressP(BaseAddress))
-	    {
-	      if (DAC960_V5_ReadErrorStatus(BaseAddress, &ErrorStatus,
-					    &Parameter0, &Parameter1) &&
-		  DAC960_ReportErrorStatus(Controller, ErrorStatus,
-					   Parameter0, Parameter1))
-		goto Failure;
-	      udelay(10);
-	    }
-	  if (!DAC960_EnableMemoryMailboxInterface(Controller))
-	    {
-	      DAC960_Error("Unable to Enable Memory Mailbox Interface "
-			   "for Controller at\n", Controller);
-	      goto Failure;
-	    }
-	  DAC960_V5_EnableInterrupts(BaseAddress);
-	  break;
-	case DAC960_V4_Controller:
-	  DAC960_V4_DisableInterrupts(BaseAddress);
-	  DAC960_V4_AcknowledgeHardwareMailboxStatus(BaseAddress);
-	  udelay(1000);
-	  while (DAC960_V4_InitializationInProgressP(BaseAddress))
-	    {
-	      if (DAC960_V4_ReadErrorStatus(BaseAddress, &ErrorStatus,
-					    &Parameter0, &Parameter1) &&
-		  DAC960_ReportErrorStatus(Controller, ErrorStatus,
-					   Parameter0, Parameter1))
-		goto Failure;
-	      udelay(10);
-	    }
-	  if (!DAC960_EnableMemoryMailboxInterface(Controller))
-	    {
-	      DAC960_Error("Unable to Enable Memory Mailbox Interface "
-			   "for Controller at\n", Controller);
-	      goto Failure;
-	    }
-	  DAC960_V4_EnableInterrupts(BaseAddress);
-	  break;
-	case DAC960_V3_Controller:
-	  request_region(Controller->IO_Address, 0x80,
-			 Controller->FullModelName);
-	  DAC960_V3_DisableInterrupts(BaseAddress);
-	  DAC960_V3_AcknowledgeStatus(BaseAddress);
-	  udelay(1000);
-	  while (DAC960_V3_InitializationInProgressP(BaseAddress))
-	    {
-	      if (DAC960_V3_ReadErrorStatus(BaseAddress, &ErrorStatus,
-					    &Parameter0, &Parameter1) &&
-		  DAC960_ReportErrorStatus(Controller, ErrorStatus,
-					   Parameter0, Parameter1))
-		goto Failure;
-	      udelay(10);
-	    }
-	  DAC960_V3_EnableInterrupts(BaseAddress);
-	  break;
-	}
-      /*
-	Acquire shared access to the IRQ Channel.
-      */
-      if (IRQ_Channel == 0)
-	{
-	  DAC960_Error("IRQ Channel %d illegal for Controller at\n",
-		       Controller, IRQ_Channel);
-	  goto Failure;
-	}
-      strcpy(Controller->FullModelName, "DAC960");
-      if (request_irq(IRQ_Channel, DAC960_InterruptHandler,
-		      SA_SHIRQ, Controller->FullModelName, Controller) < 0)
-	{
-	  DAC960_Error("Unable to acquire IRQ Channel %d for Controller at\n",
-		       Controller, IRQ_Channel);
-	  goto Failure;
-	}
-      Controller->IRQ_Channel = IRQ_Channel;
-      DAC960_ActiveControllerCount++;
-      for (CommandIdentifier = 0;
-	   CommandIdentifier < DAC960_MaxChannels;
-	   CommandIdentifier++)
-	{
-	  Controller->Commands[CommandIdentifier].Controller = Controller;
-	  Controller->Commands[CommandIdentifier].Next =
-	    Controller->FreeCommands;
-	  Controller->FreeCommands = &Controller->Commands[CommandIdentifier];
-	}
-      continue;
-    Failure:
-      if (IO_Address == 0)
-	DAC960_Error("PCI Bus %d Device %d Function %d I/O Address N/A "
-		     "PCI Address 0x%X\n", Controller,
-		     Bus, Device, Function, PCI_Address);
-      else DAC960_Error("PCI Bus %d Device %d Function %d I/O Address "
-			"0x%X PCI Address 0x%X\n", Controller,
-			Bus, Device, Function, IO_Address, PCI_Address);
-      if (Controller == NULL) break;
-      if (Controller->MemoryMappedAddress != NULL)
-	iounmap(Controller->MemoryMappedAddress);
-      DAC960_Controllers[Controller->ControllerNumber] = NULL;
-      if (Controller->IRQ_Channel > 0)
-	free_irq(IRQ_Channel, Controller);
-    Ignore:
-      kfree(Controller);
-    }
-}
-
-
-/*
-  DAC960_ReadControllerConfiguration reads the Configuration Information
-  from Controller and initializes the Controller structure.
-*/
-
-static boolean DAC960_ReadControllerConfiguration(DAC960_Controller_T
-						  *Controller)
-{
-  DAC960_Enquiry2_T Enquiry2;
-  DAC960_Config2_T Config2;
-  int LogicalDriveNumber, Channel, TargetID;
-  if (!DAC960_ExecuteType3(Controller, DAC960_Enquiry,
-			   &Controller->Enquiry[0]))
-    return DAC960_Failure(Controller, "ENQUIRY");
-  if (!DAC960_ExecuteType3(Controller, DAC960_Enquiry2, &Enquiry2))
-    return DAC960_Failure(Controller, "ENQUIRY2");
-  if (!DAC960_ExecuteType3(Controller, DAC960_ReadConfig2, &Config2))
-    return DAC960_Failure(Controller, "READ CONFIG2");
-  if (!DAC960_ExecuteType3(Controller, DAC960_GetLogicalDriveInformation,
-			   &Controller->LogicalDriveInformation[0]))
-    return DAC960_Failure(Controller, "GET LOGICAL DRIVE INFORMATION");
-  for (Channel = 0; Channel < Enquiry2.ActualChannels; Channel++)
-    for (TargetID = 0; TargetID < DAC960_MaxTargets; TargetID++)
-      if (!DAC960_ExecuteType3D(Controller, DAC960_GetDeviceState,
-				Channel, TargetID,
-				&Controller->DeviceState[0][Channel][TargetID]))
-	return DAC960_Failure(Controller, "GET DEVICE STATE");
-  /*
-    Initialize the Controller Model Name and Full Model Name fields.
-  */
-  switch (Enquiry2.HardwareID.SubModel)
-    {
-    case DAC960_P_PD_PU:
-      if (Enquiry2.SCSICapability.BusSpeed == DAC960_Ultra)
+    case DAC960_V1_P_PD_PU:
+      if (Enquiry2.SCSICapability.BusSpeed == DAC960_V1_Ultra)
 	strcpy(Controller->ModelName, "DAC960PU");
       else strcpy(Controller->ModelName, "DAC960PD");
       break;
-    case DAC960_PL:
+    case DAC960_V1_PL:
       strcpy(Controller->ModelName, "DAC960PL");
       break;
-    case DAC960_PG:
+    case DAC960_V1_PG:
       strcpy(Controller->ModelName, "DAC960PG");
       break;
-    case DAC960_PJ:
+    case DAC960_V1_PJ:
       strcpy(Controller->ModelName, "DAC960PJ");
       break;
-    case DAC960_PR:
+    case DAC960_V1_PR:
       strcpy(Controller->ModelName, "DAC960PR");
       break;
-    case DAC960_PT:
+    case DAC960_V1_PT:
       strcpy(Controller->ModelName, "DAC960PT");
       break;
-    case DAC960_PTL0:
+    case DAC960_V1_PTL0:
       strcpy(Controller->ModelName, "DAC960PTL0");
       break;
-    case DAC960_PRL:
+    case DAC960_V1_PRL:
       strcpy(Controller->ModelName, "DAC960PRL");
       break;
-    case DAC960_PTL1:
+    case DAC960_V1_PTL1:
       strcpy(Controller->ModelName, "DAC960PTL1");
       break;
-    case DAC1164_P:
+    case DAC960_V1_1164P:
       strcpy(Controller->ModelName, "DAC1164P");
       break;
     default:
@@ -818,61 +1085,197 @@
       return false;
     }
   /*
-    Initialize the Controller Channels, Memory Size, and SAF-TE Enclosure
-    Management Enabled fields.
+    Initialize the Controller Channels, Targets, Memory Size, and SAF-TE
+    Enclosure Management Enabled fields.
   */
   Controller->Channels = Enquiry2.ActualChannels;
+  Controller->Targets = Enquiry2.MaxTargets;
   Controller->MemorySize = Enquiry2.MemorySize >> 20;
-  Controller->SAFTE_EnclosureManagementEnabled =
-    Enquiry2.FaultManagementType == DAC960_SAFTE;
+  Controller->V1.SAFTE_EnclosureManagementEnabled =
+    (Enquiry2.FaultManagementType == DAC960_V1_SAFTE);
   /*
     Initialize the Controller Queue Depth, Driver Queue Depth, Logical Drive
-    Count, Maximum Blocks per Command, and Maximum Scatter/Gather Segments.
-    The Driver Queue Depth must be at most one less than the Controller Queue
-    Depth to allow for an automatic drive rebuild operation.
+    Count, Maximum Blocks per Command, Controller Scatter/Gather Limit, and
+    Driver Scatter/Gather Limit.  The Driver Queue Depth must be at most one
+    less than the Controller Queue Depth to allow for an automatic drive
+    rebuild operation.
   */
-  Controller->ControllerQueueDepth = Controller->Enquiry[0].MaxCommands;
+  Controller->ControllerQueueDepth = Controller->V1.Enquiry.MaxCommands;
   Controller->DriverQueueDepth = Controller->ControllerQueueDepth - 1;
-  Controller->LogicalDriveCount = Controller->Enquiry[0].NumberOfLogicalDrives;
+  if (Controller->DriverQueueDepth > DAC960_MaxDriverQueueDepth)
+    Controller->DriverQueueDepth = DAC960_MaxDriverQueueDepth;
+  Controller->LogicalDriveCount =
+    Controller->V1.Enquiry.NumberOfLogicalDrives;
   Controller->MaxBlocksPerCommand = Enquiry2.MaxBlocksPerCommand;
-  Controller->MaxScatterGatherSegments = Enquiry2.MaxScatterGatherEntries;
+  Controller->ControllerScatterGatherLimit = Enquiry2.MaxScatterGatherEntries;
+  Controller->DriverScatterGatherLimit =
+    Controller->ControllerScatterGatherLimit;
+  if (Controller->DriverScatterGatherLimit > DAC960_V1_ScatterGatherLimit)
+    Controller->DriverScatterGatherLimit = DAC960_V1_ScatterGatherLimit;
   /*
     Initialize the Stripe Size, Segment Size, and Geometry Translation.
   */
-  Controller->StripeSize = Config2.BlocksPerStripe * Config2.BlockFactor
-			   >> (10 - DAC960_BlockSizeBits);
-  Controller->SegmentSize = Config2.BlocksPerCacheLine * Config2.BlockFactor
-			    >> (10 - DAC960_BlockSizeBits);
+  Controller->V1.StripeSize = Config2.BlocksPerStripe * Config2.BlockFactor
+			      >> (10 - DAC960_BlockSizeBits);
+  Controller->V1.SegmentSize = Config2.BlocksPerCacheLine * Config2.BlockFactor
+			       >> (10 - DAC960_BlockSizeBits);
   switch (Config2.DriveGeometry)
     {
-    case DAC960_Geometry_128_32:
-      Controller->GeometryTranslationHeads = 128;
-      Controller->GeometryTranslationSectors = 32;
-      break;
-    case DAC960_Geometry_255_63:
-      Controller->GeometryTranslationHeads = 255;
-      Controller->GeometryTranslationSectors = 63;
+    case DAC960_V1_Geometry_128_32:
+      Controller->V1.GeometryTranslationHeads = 128;
+      Controller->V1.GeometryTranslationSectors = 32;
+      break;
+    case DAC960_V1_Geometry_255_63:
+      Controller->V1.GeometryTranslationHeads = 255;
+      Controller->V1.GeometryTranslationSectors = 63;
       break;
     default:
       return DAC960_Failure(Controller, "CONFIG2 DRIVE GEOMETRY");
     }
   /*
-    Initialize the Logical Drive Initial State.
+    Initialize the Logical Drive Initially Accessible flag.
   */
   for (LogicalDriveNumber = 0;
        LogicalDriveNumber < Controller->LogicalDriveCount;
        LogicalDriveNumber++)
-    Controller->LogicalDriveInitialState[LogicalDriveNumber] =
-      Controller->LogicalDriveInformation[0]
-		  [LogicalDriveNumber].LogicalDriveState;
-  Controller->LastRebuildStatus = DAC960_NoRebuildOrCheckInProgress;
+    if (Controller->V1.LogicalDriveInformation
+		       [LogicalDriveNumber].LogicalDriveState !=
+	DAC960_V1_LogicalDrive_Offline)
+      Controller->LogicalDriveInitiallyAccessible[LogicalDriveNumber] = true;
+  Controller->V1.LastRebuildStatus = DAC960_V1_NoRebuildOrCheckInProgress;
   return true;
 }
 
 
 /*
-  DAC960_ReportControllerConfiguration reports the Configuration Information of
-  Controller.
+  DAC960_V2_ReadControllerConfiguration reads the Configuration Information
+  from DAC960 V2 Firmware Controllers and initializes the Controller structure.
+*/
+
+static boolean DAC960_V2_ReadControllerConfiguration(DAC960_Controller_T
+						     *Controller)
+{
+  DAC960_V2_ControllerInfo_T *ControllerInfo =
+    &Controller->V2.ControllerInformation;
+  unsigned short LogicalDeviceNumber = 0;
+  int ModelNameLength;
+  if (!DAC960_V2_ControllerInfo(Controller, DAC960_V2_GetControllerInfo,
+				ControllerInfo,
+				sizeof(DAC960_V2_ControllerInfo_T)))
+    return DAC960_Failure(Controller, "GET CONTROLLER INFO");
+  if (!DAC960_V2_GeneralInfo(Controller, DAC960_V2_GetHealthStatus,
+			     Controller->V2.HealthStatusBuffer,
+			     sizeof(DAC960_V2_HealthStatusBuffer_T)))
+    return DAC960_Failure(Controller, "GET HEALTH STATUS");
+  /*
+    Initialize the Controller Model Name and Full Model Name fields.
+  */
+  ModelNameLength = sizeof(ControllerInfo->ControllerName);
+  if (ModelNameLength > sizeof(Controller->ModelName)-1)
+    ModelNameLength = sizeof(Controller->ModelName)-1;
+  memcpy(Controller->ModelName, ControllerInfo->ControllerName,
+	 ModelNameLength);
+  ModelNameLength--;
+  while (Controller->ModelName[ModelNameLength] == ' ' ||
+	 Controller->ModelName[ModelNameLength] == '\0')
+    ModelNameLength--;
+  Controller->ModelName[++ModelNameLength] = '\0';
+  strcpy(Controller->FullModelName, "Mylex ");
+  strcat(Controller->FullModelName, Controller->ModelName);
+  /*
+    Initialize the Controller Firmware Version field.
+  */
+  sprintf(Controller->FirmwareVersion, "%d.%02d-%02d",
+	  ControllerInfo->FirmwareMajorVersion,
+	  ControllerInfo->FirmwareMinorVersion,
+	  ControllerInfo->FirmwareTurnNumber);
+  if (ControllerInfo->FirmwareMajorVersion == 6 &&
+      ControllerInfo->FirmwareMinorVersion == 0 &&
+      ControllerInfo->FirmwareTurnNumber < 1)
+    {
+      DAC960_Info("FIRMWARE VERSION %s DOES NOT PROVIDE THE CONTROLLER\n",
+		  Controller, Controller->FirmwareVersion);
+      DAC960_Info("STATUS MONITORING FUNCTIONALITY NEEDED BY THIS DRIVER.\n",
+		  Controller);
+      DAC960_Info("PLEASE UPGRADE TO VERSION 6.00-01 OR ABOVE.\n",
+		  Controller);
+    }
+  /*
+    Initialize the Controller Channels, Targets, and Memory Size.
+  */
+  Controller->Channels = ControllerInfo->NumberOfPhysicalChannelsPresent;
+  Controller->Targets =
+    ControllerInfo->MaximumTargetsPerChannel
+		    [ControllerInfo->NumberOfPhysicalChannelsPresent-1];
+  Controller->MemorySize = ControllerInfo->MemorySizeMB;
+  /*
+    Initialize the Controller Queue Depth, Driver Queue Depth, Logical Drive
+    Count, Maximum Blocks per Command, Controller Scatter/Gather Limit, and
+    Driver Scatter/Gather Limit.  The Driver Queue Depth must be at most one
+    less than the Controller Queue Depth to allow for an automatic drive
+    rebuild operation.
+  */
+  Controller->ControllerQueueDepth = ControllerInfo->MaximumParallelCommands;
+  Controller->DriverQueueDepth = Controller->ControllerQueueDepth - 1;
+  if (Controller->DriverQueueDepth > DAC960_MaxDriverQueueDepth)
+    Controller->DriverQueueDepth = DAC960_MaxDriverQueueDepth;
+  Controller->LogicalDriveCount = ControllerInfo->LogicalDevicesPresent;
+  Controller->MaxBlocksPerCommand =
+    ControllerInfo->MaximumDataTransferSizeInBlocks;
+  Controller->ControllerScatterGatherLimit =
+    ControllerInfo->MaximumScatterGatherEntries;
+  Controller->DriverScatterGatherLimit =
+    Controller->ControllerScatterGatherLimit;
+  if (Controller->DriverScatterGatherLimit > DAC960_V2_ScatterGatherLimit)
+    Controller->DriverScatterGatherLimit = DAC960_V2_ScatterGatherLimit;
+  /*
+    Initialize the Logical Device Information.
+  */
+  while (true)
+    {
+      DAC960_V2_LogicalDeviceInfo_T *NewLogicalDeviceInfo =
+	&Controller->V2.NewLogicalDeviceInformation;
+      DAC960_V2_LogicalDeviceInfo_T *LogicalDeviceInfo;
+      DAC960_V2_PhysicalDevice_T PhysicalDevice;
+      if (!DAC960_V2_LogicalDeviceInfo(Controller,
+				       DAC960_V2_GetLogicalDeviceInfoValid,
+				       LogicalDeviceNumber,
+				       NewLogicalDeviceInfo,
+				       sizeof(DAC960_V2_LogicalDeviceInfo_T)))
+	break;
+      LogicalDeviceNumber = NewLogicalDeviceInfo->LogicalDeviceNumber;
+      if (LogicalDeviceNumber > DAC960_MaxLogicalDrives)
+	panic("DAC960: Logical Drive Number %d not supported\n",
+		       LogicalDeviceNumber);
+      if (NewLogicalDeviceInfo->DeviceBlockSizeInBytes != DAC960_BlockSize)
+	panic("DAC960: Logical Drive Block Size %d not supported\n",
+	      NewLogicalDeviceInfo->DeviceBlockSizeInBytes);
+      PhysicalDevice.Controller = 0;
+      PhysicalDevice.Channel = NewLogicalDeviceInfo->Channel;
+      PhysicalDevice.TargetID = NewLogicalDeviceInfo->TargetID;
+      PhysicalDevice.LogicalUnit = NewLogicalDeviceInfo->LogicalUnit;
+      Controller->V2.LogicalDriveToVirtualDevice[LogicalDeviceNumber] =
+	PhysicalDevice;
+      if (NewLogicalDeviceInfo->LogicalDeviceState !=
+	  DAC960_V2_LogicalDevice_Offline)
+	Controller->LogicalDriveInitiallyAccessible[LogicalDeviceNumber] = true;
+      LogicalDeviceInfo = (DAC960_V2_LogicalDeviceInfo_T *)
+	kmalloc(sizeof(DAC960_V2_LogicalDeviceInfo_T), GFP_ATOMIC);
+      if (LogicalDeviceInfo == NULL)
+	return DAC960_Failure(Controller, "LOGICAL DEVICE ALLOCATION");
+      Controller->V2.LogicalDeviceInformation[LogicalDeviceNumber] =
+	LogicalDeviceInfo;
+      memcpy(LogicalDeviceInfo, NewLogicalDeviceInfo,
+	     sizeof(DAC960_V2_LogicalDeviceInfo_T));
+      LogicalDeviceNumber++;
+    }
+  return true;
+}
+
+
+/*
+  DAC960_ReportControllerConfiguration reports the Configuration Information
+  for Controller.
 */
 
 static boolean DAC960_ReportControllerConfiguration(DAC960_Controller_T
@@ -898,54 +1301,60 @@
 	      Controller, Controller->ControllerQueueDepth,
 	      Controller->MaxBlocksPerCommand);
   DAC960_Info("  Driver Queue Depth: %d, "
-	      "Maximum Scatter/Gather Segments: %d\n",
+	      "Scatter/Gather Limit: %d of %d Segments\n",
 	      Controller, Controller->DriverQueueDepth,
-	      Controller->MaxScatterGatherSegments);
-  DAC960_Info("  Stripe Size: %dKB, Segment Size: %dKB, "
-	      "BIOS Geometry: %d/%d\n", Controller,
-	      Controller->StripeSize,
-	      Controller->SegmentSize,
-	      Controller->GeometryTranslationHeads,
-	      Controller->GeometryTranslationSectors);
-  if (Controller->SAFTE_EnclosureManagementEnabled)
-    DAC960_Info("  SAF-TE Enclosure Management Enabled\n", Controller);
+	      Controller->DriverScatterGatherLimit,
+	      Controller->ControllerScatterGatherLimit);
+  if (Controller->FirmwareType == DAC960_V1_Controller)
+    {
+      DAC960_Info("  Stripe Size: %dKB, Segment Size: %dKB, "
+		  "BIOS Geometry: %d/%d\n", Controller,
+		  Controller->V1.StripeSize,
+		  Controller->V1.SegmentSize,
+		  Controller->V1.GeometryTranslationHeads,
+		  Controller->V1.GeometryTranslationSectors);
+      if (Controller->V1.SAFTE_EnclosureManagementEnabled)
+	DAC960_Info("  SAF-TE Enclosure Management Enabled\n", Controller);
+    }
   return true;
 }
 
 
 /*
-  DAC960_ReadDeviceConfiguration reads the Device Configuration Information by
-  requesting the SCSI Inquiry and SCSI Inquiry Unit Serial Number information
-  for each device connected to Controller.
+  DAC960_V1_ReadDeviceConfiguration reads the Device Configuration Information
+  for DAC960 V1 Firmware Controllers by requesting the SCSI Inquiry and SCSI
+  Inquiry Unit Serial Number information for each device connected to
+  Controller.
 */
 
-static boolean DAC960_ReadDeviceConfiguration(DAC960_Controller_T *Controller)
+static boolean DAC960_V1_ReadDeviceConfiguration(DAC960_Controller_T
+						 *Controller)
 {
-  DAC960_DCDB_T DCDBs[DAC960_MaxChannels], *DCDB;
-  Semaphore_T Semaphores[DAC960_MaxChannels], *Semaphore;
+  DAC960_V1_DCDB_T DCDBs[DAC960_V1_MaxChannels], *DCDB;
+  Semaphore_T Semaphores[DAC960_V1_MaxChannels], *Semaphore;
   unsigned long ProcessorFlags;
   int Channel, TargetID;
-  for (TargetID = 0; TargetID < DAC960_MaxTargets; TargetID++)
+  for (TargetID = 0; TargetID < Controller->Targets; TargetID++)
     {
       for (Channel = 0; Channel < Controller->Channels; Channel++)
 	{
-	  DAC960_Command_T *Command = &Controller->Commands[Channel];
+	  DAC960_Command_T *Command = Controller->Commands[Channel];
 	  DAC960_SCSI_Inquiry_T *InquiryStandardData =
-	    &Controller->InquiryStandardData[Channel][TargetID];
+	    &Controller->V1.InquiryStandardData[Channel][TargetID];
 	  InquiryStandardData->PeripheralDeviceType = 0x1F;
 	  Semaphore = &Semaphores[Channel];
 	  *Semaphore = MUTEX_LOCKED;
 	  DCDB = &DCDBs[Channel];
-	  DAC960_ClearCommand(Command);
+	  DAC960_V1_ClearCommand(Command);
 	  Command->CommandType = DAC960_ImmediateCommand;
 	  Command->Semaphore = Semaphore;
-	  Command->CommandMailbox.Type3.CommandOpcode = DAC960_DCDB;
-	  Command->CommandMailbox.Type3.BusAddress = Virtual_to_Bus(DCDB);
+	  Command->V1.CommandMailbox.Type3.CommandOpcode = DAC960_V1_DCDB;
+	  Command->V1.CommandMailbox.Type3.BusAddress = Virtual_to_Bus(DCDB);
 	  DCDB->Channel = Channel;
 	  DCDB->TargetID = TargetID;
-	  DCDB->Direction = DAC960_DCDB_DataTransferDeviceToSystem;
+	  DCDB->Direction = DAC960_V1_DCDB_DataTransferDeviceToSystem;
 	  DCDB->EarlyStatus = false;
-	  DCDB->Timeout = DAC960_DCDB_Timeout_10_seconds;
+	  DCDB->Timeout = DAC960_V1_DCDB_Timeout_10_seconds;
 	  DCDB->NoAutomaticRequestSense = false;
 	  DCDB->DisconnectPermitted = true;
 	  DCDB->TransferLength = sizeof(DAC960_SCSI_Inquiry_T);
@@ -965,13 +1374,14 @@
 	}
       for (Channel = 0; Channel < Controller->Channels; Channel++)
 	{
-	  DAC960_Command_T *Command = &Controller->Commands[Channel];
+	  DAC960_Command_T *Command = Controller->Commands[Channel];
 	  DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber =
-	    &Controller->InquiryUnitSerialNumber[Channel][TargetID];
+	    &Controller->V1.InquiryUnitSerialNumber[Channel][TargetID];
 	  InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F;
 	  Semaphore = &Semaphores[Channel];
 	  down(Semaphore);
-	  if (Command->CommandStatus != DAC960_NormalCompletion) continue;
+	  if (Command->V1.CommandStatus != DAC960_V1_NormalCompletion)
+	    continue;
 	  Command->Semaphore = Semaphore;
 	  DCDB = &DCDBs[Channel];
 	  DCDB->TransferLength = sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T);
@@ -989,107 +1399,215 @@
 	  down(Semaphore);
 	}
     }
-  return true; 
+  return true;
+}
+
+
+/*
+  DAC960_V2_ReadDeviceConfiguration reads the Device Configuration Information
+  for DAC960 V2 Firmware Controllers by requesting the Physical Device
+  Information and SCSI Inquiry Unit Serial Number information for each
+  device connected to Controller.
+*/
+
+static boolean DAC960_V2_ReadDeviceConfiguration(DAC960_Controller_T
+						 *Controller)
+{
+  unsigned char Channel = 0, TargetID = 0, LogicalUnit = 0;
+  unsigned short PhysicalDeviceIndex = 0;
+  while (true)
+    {
+      DAC960_V2_PhysicalDeviceInfo_T *NewPhysicalDeviceInfo =
+	&Controller->V2.NewPhysicalDeviceInformation;
+      DAC960_V2_PhysicalDeviceInfo_T *PhysicalDeviceInfo;
+      DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber;
+      DAC960_Command_T *Command;
+      DAC960_V2_CommandMailbox_T *CommandMailbox;
+      if (!DAC960_V2_PhysicalDeviceInfo(Controller,
+					DAC960_V2_GetPhysicalDeviceInfoValid,
+					Channel,
+					TargetID,
+					LogicalUnit,
+					NewPhysicalDeviceInfo,
+					sizeof(DAC960_V2_PhysicalDeviceInfo_T)))
+	  break;
+      Channel = NewPhysicalDeviceInfo->Channel;
+      TargetID = NewPhysicalDeviceInfo->TargetID;
+      LogicalUnit = NewPhysicalDeviceInfo->LogicalUnit;
+      PhysicalDeviceInfo = (DAC960_V2_PhysicalDeviceInfo_T *)
+	kmalloc(sizeof(DAC960_V2_PhysicalDeviceInfo_T), GFP_ATOMIC);
+      if (PhysicalDeviceInfo == NULL)
+	return DAC960_Failure(Controller, "PHYSICAL DEVICE ALLOCATION");
+      Controller->V2.PhysicalDeviceInformation[PhysicalDeviceIndex] =
+	PhysicalDeviceInfo;
+      memcpy(PhysicalDeviceInfo, NewPhysicalDeviceInfo,
+	     sizeof(DAC960_V2_PhysicalDeviceInfo_T));
+      InquiryUnitSerialNumber = (DAC960_SCSI_Inquiry_UnitSerialNumber_T *)
+	kmalloc(sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T), GFP_ATOMIC);
+      if (InquiryUnitSerialNumber == NULL)
+	return DAC960_Failure(Controller, "SERIAL NUMBER ALLOCATION");
+      Controller->V2.InquiryUnitSerialNumber[PhysicalDeviceIndex] =
+	InquiryUnitSerialNumber;
+      memset(InquiryUnitSerialNumber, 0,
+	     sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T));
+      InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F;
+      Command = DAC960_AllocateCommand(Controller);
+      CommandMailbox = &Command->V2.CommandMailbox;
+      DAC960_V2_ClearCommand(Command);
+      Command->CommandType = DAC960_ImmediateCommand;
+      CommandMailbox->SCSI_10.CommandOpcode = DAC960_V2_SCSI_10_Passthru;
+      CommandMailbox->SCSI_10.CommandControlBits
+			     .DataTransferControllerToHost = true;
+      CommandMailbox->SCSI_10.CommandControlBits
+			     .NoAutoRequestSense = true;
+      CommandMailbox->SCSI_10.DataTransferSize =
+	sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T);
+      CommandMailbox->SCSI_10.PhysicalDevice.LogicalUnit = LogicalUnit;
+      CommandMailbox->SCSI_10.PhysicalDevice.TargetID = TargetID;
+      CommandMailbox->SCSI_10.PhysicalDevice.Channel = Channel;
+      CommandMailbox->SCSI_10.CDBLength = 6;
+      CommandMailbox->SCSI_10.SCSI_CDB[0] = 0x12; /* INQUIRY */
+      CommandMailbox->SCSI_10.SCSI_CDB[1] = 1; /* EVPD = 1 */
+      CommandMailbox->SCSI_10.SCSI_CDB[2] = 0x80; /* Page Code */
+      CommandMailbox->SCSI_10.SCSI_CDB[3] = 0; /* Reserved */
+      CommandMailbox->SCSI_10.SCSI_CDB[4] =
+	sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T);
+      CommandMailbox->SCSI_10.SCSI_CDB[5] = 0; /* Control */
+      CommandMailbox->SCSI_10.DataTransferMemoryAddress
+			     .ScatterGatherSegments[0]
+			     .SegmentDataPointer =
+	Virtual_to_Bus(InquiryUnitSerialNumber);
+      CommandMailbox->SCSI_10.DataTransferMemoryAddress
+			     .ScatterGatherSegments[0]
+			     .SegmentByteCount =
+	CommandMailbox->SCSI_10.DataTransferSize;
+      DAC960_ExecuteCommand(Command);
+      DAC960_DeallocateCommand(Command);
+      PhysicalDeviceIndex++;
+      LogicalUnit++;
+    }
+  return true;
+}
+
+
+/*
+  DAC960_SanitizeInquiryData sanitizes the Vendor, Model, Revision, and
+  Product Serial Number fields of the Inquiry Standard Data and Inquiry
+  Unit Serial Number structures.
+*/
+
+static void DAC960_SanitizeInquiryData(DAC960_SCSI_Inquiry_T
+					 *InquiryStandardData,
+				       DAC960_SCSI_Inquiry_UnitSerialNumber_T
+					 *InquiryUnitSerialNumber,
+				       unsigned char *Vendor,
+				       unsigned char *Model,
+				       unsigned char *Revision,
+				       unsigned char *SerialNumber)
+{
+  int SerialNumberLength, i;
+  if (InquiryStandardData->PeripheralDeviceType == 0x1F) return;
+  for (i = 0; i < sizeof(InquiryStandardData->VendorIdentification); i++)
+    {
+      unsigned char VendorCharacter =
+	InquiryStandardData->VendorIdentification[i];
+      Vendor[i] = (VendorCharacter >= ' ' && VendorCharacter <= '~'
+		   ? VendorCharacter : ' ');
+    }
+  Vendor[sizeof(InquiryStandardData->VendorIdentification)] = '\0';
+  for (i = 0; i < sizeof(InquiryStandardData->ProductIdentification); i++)
+    {
+      unsigned char ModelCharacter =
+	InquiryStandardData->ProductIdentification[i];
+      Model[i] = (ModelCharacter >= ' ' && ModelCharacter <= '~'
+		  ? ModelCharacter : ' ');
+    }
+  Model[sizeof(InquiryStandardData->ProductIdentification)] = '\0';
+  for (i = 0; i < sizeof(InquiryStandardData->ProductRevisionLevel); i++)
+    {
+      unsigned char RevisionCharacter =
+	InquiryStandardData->ProductRevisionLevel[i];
+      Revision[i] = (RevisionCharacter >= ' ' && RevisionCharacter <= '~'
+		     ? RevisionCharacter : ' ');
+    }
+  Revision[sizeof(InquiryStandardData->ProductRevisionLevel)] = '\0';
+  if (InquiryUnitSerialNumber->PeripheralDeviceType == 0x1F) return;
+  SerialNumberLength = InquiryUnitSerialNumber->PageLength;
+  if (SerialNumberLength >
+      sizeof(InquiryUnitSerialNumber->ProductSerialNumber))
+    SerialNumberLength = sizeof(InquiryUnitSerialNumber->ProductSerialNumber);
+  for (i = 0; i < SerialNumberLength; i++)
+    {
+      unsigned char SerialNumberCharacter =
+	InquiryUnitSerialNumber->ProductSerialNumber[i];
+      SerialNumber[i] =
+	(SerialNumberCharacter >= ' ' && SerialNumberCharacter <= '~'
+	 ? SerialNumberCharacter : ' ');
+    }
+  SerialNumber[SerialNumberLength] = '\0';
 }
 
 
 /*
-  DAC960_ReportDeviceConfiguration reports the Device Configuration Information
-  of Controller.
+  DAC960_V1_ReportDeviceConfiguration reports the Device Configuration
+  Information for DAC960 V1 Firmware Controllers.
 */
 
-static boolean DAC960_ReportDeviceConfiguration(DAC960_Controller_T *Controller)
+static boolean DAC960_V1_ReportDeviceConfiguration(DAC960_Controller_T
+						   *Controller)
 {
   int LogicalDriveNumber, Channel, TargetID;
   DAC960_Info("  Physical Devices:\n", Controller);
   for (Channel = 0; Channel < Controller->Channels; Channel++)
-    for (TargetID = 0; TargetID < DAC960_MaxTargets; TargetID++)
+    for (TargetID = 0; TargetID < Controller->Targets; TargetID++)
       {
 	DAC960_SCSI_Inquiry_T *InquiryStandardData =
-	  &Controller->InquiryStandardData[Channel][TargetID];
+	  &Controller->V1.InquiryStandardData[Channel][TargetID];
 	DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber =
-	  &Controller->InquiryUnitSerialNumber[Channel][TargetID];
-	DAC960_DeviceState_T *DeviceState =
-	  &Controller->DeviceState[Controller->DeviceStateIndex]
-				  [Channel][TargetID];
-	DAC960_ErrorTable_T *ErrorTable =
-	  &Controller->ErrorTable[Controller->ErrorTableIndex];
-	DAC960_ErrorTableEntry_T *ErrorEntry =
-	  &ErrorTable->ErrorTableEntries[Channel][TargetID];
+	  &Controller->V1.InquiryUnitSerialNumber[Channel][TargetID];
+	DAC960_V1_DeviceState_T *DeviceState =
+	  &Controller->V1.DeviceState[Channel][TargetID];
+	DAC960_V1_ErrorTableEntry_T *ErrorEntry =
+	  &Controller->V1.ErrorTable.ErrorTableEntries[Channel][TargetID];
 	char Vendor[1+sizeof(InquiryStandardData->VendorIdentification)];
 	char Model[1+sizeof(InquiryStandardData->ProductIdentification)];
 	char Revision[1+sizeof(InquiryStandardData->ProductRevisionLevel)];
 	char SerialNumber[1+sizeof(InquiryUnitSerialNumber
 				   ->ProductSerialNumber)];
-	int i;
 	if (InquiryStandardData->PeripheralDeviceType == 0x1F) continue;
-	for (i = 0; i < sizeof(Vendor)-1; i++)
-	  {
-	    unsigned char VendorCharacter =
-	      InquiryStandardData->VendorIdentification[i];
-	    Vendor[i] = (VendorCharacter >= ' ' && VendorCharacter <= '~'
-			 ? VendorCharacter : ' ');
-	  }
-	Vendor[sizeof(Vendor)-1] = '\0';
-	for (i = 0; i < sizeof(Model)-1; i++)
-	  {
-	    unsigned char ModelCharacter =
-	      InquiryStandardData->ProductIdentification[i];
-	    Model[i] = (ModelCharacter >= ' ' && ModelCharacter <= '~'
-			? ModelCharacter : ' ');
-	  }
-	Model[sizeof(Model)-1] = '\0';
-	for (i = 0; i < sizeof(Revision)-1; i++)
-	  {
-	    unsigned char RevisionCharacter =
-	      InquiryStandardData->ProductRevisionLevel[i];
-	    Revision[i] = (RevisionCharacter >= ' ' && RevisionCharacter <= '~'
-			   ? RevisionCharacter : ' ');
-	  }
-	Revision[sizeof(Revision)-1] = '\0';
+	DAC960_SanitizeInquiryData(InquiryStandardData, InquiryUnitSerialNumber,
+				   Vendor, Model, Revision, SerialNumber);
 	DAC960_Info("    %d:%d%s Vendor: %s  Model: %s  Revision: %s\n",
 		    Controller, Channel, TargetID, (TargetID < 10 ? " " : ""),
 		    Vendor, Model, Revision);
 	if (InquiryUnitSerialNumber->PeripheralDeviceType != 0x1F)
+	  DAC960_Info("         Serial Number: %s\n", Controller, SerialNumber);
+	if (DeviceState->Present &&
+	    DeviceState->DeviceType == DAC960_V1_DiskType)
 	  {
-	    int SerialNumberLength = InquiryUnitSerialNumber->PageLength;
-	    if (SerialNumberLength >
-		sizeof(InquiryUnitSerialNumber->ProductSerialNumber))
-	      SerialNumberLength =
-		sizeof(InquiryUnitSerialNumber->ProductSerialNumber);
-	    for (i = 0; i < SerialNumberLength; i++)
-	      {
-		unsigned char SerialNumberCharacter =
-		  InquiryUnitSerialNumber->ProductSerialNumber[i];
-		SerialNumber[i] =
-		  (SerialNumberCharacter >= ' ' && SerialNumberCharacter <= '~'
-		   ? SerialNumberCharacter : ' ');
-	      }
-	    SerialNumber[SerialNumberLength] = '\0';
-	    DAC960_Info("         Serial Number: %s\n",
-			Controller, SerialNumber);
-	  }
-	if (DeviceState->Present && DeviceState->DeviceType == DAC960_DiskType)
-	  {
-	    if (Controller->DeviceResetCount[Channel][TargetID] > 0)
+	    if (Controller->V1.DeviceResetCount[Channel][TargetID] > 0)
 	      DAC960_Info("         Disk Status: %s, %d blocks, %d resets\n",
 			  Controller,
-			  (DeviceState->DeviceState == DAC960_Device_Dead
+			  (DeviceState->DeviceState == DAC960_V1_Device_Dead
 			   ? "Dead"
-			   : DeviceState->DeviceState == DAC960_Device_WriteOnly
-			   ? "Write-Only"
-			   : DeviceState->DeviceState == DAC960_Device_Online
-			   ? "Online" : "Standby"),
+			   : DeviceState->DeviceState
+			     == DAC960_V1_Device_WriteOnly
+			     ? "Write-Only"
+			     : DeviceState->DeviceState
+			       == DAC960_V1_Device_Online
+			       ? "Online" : "Standby"),
 			  DeviceState->DiskSize,
-			  Controller->DeviceResetCount[Channel][TargetID]);
+			  Controller->V1.DeviceResetCount[Channel][TargetID]);
 	    else
 	      DAC960_Info("         Disk Status: %s, %d blocks\n", Controller,
-			  (DeviceState->DeviceState == DAC960_Device_Dead
+			  (DeviceState->DeviceState == DAC960_V1_Device_Dead
 			   ? "Dead"
-			   : DeviceState->DeviceState == DAC960_Device_WriteOnly
-			   ? "Write-Only"
-			   : DeviceState->DeviceState == DAC960_Device_Online
-			   ? "Online" : "Standby"),
+			   : DeviceState->DeviceState
+			     == DAC960_V1_Device_WriteOnly
+			     ? "Write-Only"
+			     : DeviceState->DeviceState
+			       == DAC960_V1_Device_Online
+			       ? "Online" : "Standby"),
 			  DeviceState->DiskSize);
 	  }
 	if (ErrorEntry->ParityErrorCount > 0 ||
@@ -1108,17 +1626,16 @@
        LogicalDriveNumber < Controller->LogicalDriveCount;
        LogicalDriveNumber++)
     {
-      DAC960_LogicalDriveInformation_T *LogicalDriveInformation =
-	&Controller->LogicalDriveInformation
-	   [Controller->LogicalDriveInformationIndex][LogicalDriveNumber];
+      DAC960_V1_LogicalDriveInformation_T *LogicalDriveInformation =
+	&Controller->V1.LogicalDriveInformation[LogicalDriveNumber];
       DAC960_Info("    /dev/rd/c%dd%d: RAID-%d, %s, %d blocks, %s\n",
 		  Controller, Controller->ControllerNumber, LogicalDriveNumber,
 		  LogicalDriveInformation->RAIDLevel,
-		  (LogicalDriveInformation->LogicalDriveState ==
-		     DAC960_LogicalDrive_Online
+		  (LogicalDriveInformation->LogicalDriveState
+		   == DAC960_V1_LogicalDrive_Online
 		   ? "Online"
-		   : LogicalDriveInformation->LogicalDriveState ==
-		     DAC960_LogicalDrive_Critical
+		   : LogicalDriveInformation->LogicalDriveState
+		     == DAC960_V1_LogicalDrive_Critical
 		     ? "Critical" : "Offline"),
 		  LogicalDriveInformation->LogicalDriveSize,
 		  (LogicalDriveInformation->WriteBack
@@ -1129,6 +1646,179 @@
 
 
 /*
+  DAC960_V2_ReportDeviceConfiguration reports the Device Configuration
+  Information for DAC960 V2 Firmware Controllers.
+*/
+
+static boolean DAC960_V2_ReportDeviceConfiguration(DAC960_Controller_T
+						   *Controller)
+{
+  int PhysicalDeviceIndex, LogicalDriveNumber;
+  DAC960_Info("  Physical Devices:\n", Controller);
+  for (PhysicalDeviceIndex = 0;
+       PhysicalDeviceIndex < DAC960_V2_MaxPhysicalDevices;
+       PhysicalDeviceIndex++)
+    {
+      DAC960_V2_PhysicalDeviceInfo_T *PhysicalDeviceInfo =
+	Controller->V2.PhysicalDeviceInformation[PhysicalDeviceIndex];
+      DAC960_SCSI_Inquiry_T *InquiryStandardData =
+	(DAC960_SCSI_Inquiry_T *) &PhysicalDeviceInfo->SCSI_InquiryData;
+      DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber =
+	Controller->V2.InquiryUnitSerialNumber[PhysicalDeviceIndex];
+      char Vendor[1+sizeof(InquiryStandardData->VendorIdentification)];
+      char Model[1+sizeof(InquiryStandardData->ProductIdentification)];
+      char Revision[1+sizeof(InquiryStandardData->ProductRevisionLevel)];
+      char SerialNumber[1+sizeof(InquiryUnitSerialNumber->ProductSerialNumber)];
+      if (PhysicalDeviceInfo == NULL) break;
+      DAC960_SanitizeInquiryData(InquiryStandardData, InquiryUnitSerialNumber,
+				 Vendor, Model, Revision, SerialNumber);
+      DAC960_Info("    %d:%d%s Vendor: %s  Model: %s  Revision: %s\n",
+		  Controller,
+		  PhysicalDeviceInfo->Channel,
+		  PhysicalDeviceInfo->TargetID,
+		  (PhysicalDeviceInfo->TargetID < 10 ? " " : ""),
+		  Vendor, Model, Revision);
+      if (PhysicalDeviceInfo->NegotiatedSynchronousMegaTransfers == 0)
+	DAC960_Info("         %sAsynchronous\n", Controller,
+		    (PhysicalDeviceInfo->NegotiatedDataWidthBits == 16
+		     ? "Wide " :""));
+      else
+	DAC960_Info("         %sSynchronous at %d MB/sec\n", Controller,
+		    (PhysicalDeviceInfo->NegotiatedDataWidthBits == 16
+		     ? "Wide " :""),
+		    (PhysicalDeviceInfo->NegotiatedSynchronousMegaTransfers
+		     * (PhysicalDeviceInfo->NegotiatedDataWidthBits == 16
+			? 2 : 1)));
+      if (InquiryUnitSerialNumber->PeripheralDeviceType != 0x1F)
+	DAC960_Info("         Serial Number: %s\n", Controller, SerialNumber);
+      if (PhysicalDeviceInfo->PhysicalDeviceState ==
+	  DAC960_V2_Device_Unconfigured)
+	continue;
+      DAC960_Info("         Disk Status: %s, %d blocks\n", Controller,
+		  (PhysicalDeviceInfo->PhysicalDeviceState
+		   == DAC960_V2_Device_Online
+		   ? "Online"
+		   : PhysicalDeviceInfo->PhysicalDeviceState
+		     == DAC960_V2_Device_WriteOnly
+		     ? "Write-Only"
+		     : PhysicalDeviceInfo->PhysicalDeviceState
+		       == DAC960_V2_Device_Dead
+		       ? "Dead" : "Standby"),
+		  PhysicalDeviceInfo
+		  ->ConfigurableDeviceSizeIn512ByteBlocksOrMB);
+      if (PhysicalDeviceInfo->ParityErrors == 0 &&
+	  PhysicalDeviceInfo->SoftErrors == 0 &&
+	  PhysicalDeviceInfo->HardErrors == 0 &&
+	  PhysicalDeviceInfo->MiscellaneousErrors == 0 &&
+	  PhysicalDeviceInfo->CommandTimeouts == 0 &&
+	  PhysicalDeviceInfo->Retries == 0 &&
+	  PhysicalDeviceInfo->Aborts == 0 &&
+	  PhysicalDeviceInfo->PredictedFailuresDetected == 0)
+	continue;
+      DAC960_Info("         Errors - Parity: %d, Soft: %d, "
+		  "Hard: %d, Misc: %d\n", Controller,
+		  PhysicalDeviceInfo->ParityErrors,
+		  PhysicalDeviceInfo->SoftErrors,
+		  PhysicalDeviceInfo->HardErrors,
+		  PhysicalDeviceInfo->MiscellaneousErrors);
+      DAC960_Info("                  Timeouts: %d, Retries: %d, "
+		  "Aborts: %d, Predicted: %d\n", Controller,
+		  PhysicalDeviceInfo->CommandTimeouts,
+		  PhysicalDeviceInfo->Retries,
+		  PhysicalDeviceInfo->Aborts,
+		  PhysicalDeviceInfo->PredictedFailuresDetected);
+    }
+  DAC960_Info("  Logical Drives:\n", Controller);
+  for (LogicalDriveNumber = 0;
+       LogicalDriveNumber < DAC960_MaxLogicalDrives;
+       LogicalDriveNumber++)
+    {
+      DAC960_V2_LogicalDeviceInfo_T *LogicalDeviceInfo =
+	Controller->V2.LogicalDeviceInformation[LogicalDriveNumber];
+      unsigned char *ReadCacheStatus[] = { "Read Cache Disabled",
+					   "Read Cache Enabled",
+					   "Read Ahead Enabled",
+					   "Intelligent Read Ahead Enabled",
+					   "-", "-", "-", "-" };
+      unsigned char *WriteCacheStatus[] = { "Write Cache Disabled",
+					    "Logical Device Read Only",
+					    "Write Cache Enabled",
+					    "Intelligent Write Cache Enabled",
+					    "-", "-", "-", "-" };
+      unsigned char *GeometryTranslation;
+      if (LogicalDeviceInfo == NULL) continue;
+      switch(LogicalDeviceInfo->DriveGeometry)
+	{
+	case DAC960_V2_Geometry_128_32:
+	  GeometryTranslation = "128/32";
+	  break;
+	case DAC960_V2_Geometry_255_63:
+	  GeometryTranslation = "255/63";
+	  break;
+	default:
+	  GeometryTranslation = "Invalid";
+	  DAC960_Error("Illegal Logical Device Geometry %d\n",
+		       Controller, LogicalDeviceInfo->DriveGeometry);
+	  break;
+	}
+      DAC960_Info("    /dev/rd/c%dd%d: RAID-%d, %s, %d blocks\n",
+		  Controller, Controller->ControllerNumber, LogicalDriveNumber,
+		  LogicalDeviceInfo->RAIDLevel,
+		  (LogicalDeviceInfo->LogicalDeviceState
+		   == DAC960_V2_LogicalDevice_Online
+		   ? "Online"
+		   : LogicalDeviceInfo->LogicalDeviceState
+		     == DAC960_V2_LogicalDevice_Critical
+		     ? "Critical" : "Offline"),
+		  LogicalDeviceInfo->ConfigurableDeviceSizeIn512ByteBlocksOrMB);
+      DAC960_Info("                  Logical Device %s, BIOS Geometry: %s\n",
+		  Controller,
+		  (LogicalDeviceInfo->LogicalDeviceControl
+				     .LogicalDeviceInitialized
+		   ? "Initialized" : "Uninitialized"),
+		  GeometryTranslation);
+      if (LogicalDeviceInfo->StripeSize == 0)
+	{
+	  if (LogicalDeviceInfo->CacheLineSize == 0)
+	    DAC960_Info("                  Stripe Size: N/A, "
+			"Segment Size: N/A\n", Controller);
+	  else
+	    DAC960_Info("                  Stripe Size: N/A, "
+			"Segment Size: %dKB\n", Controller,
+			1 << (LogicalDeviceInfo->CacheLineSize - 2));
+	}
+      else
+	{
+	  if (LogicalDeviceInfo->CacheLineSize == 0)
+	    DAC960_Info("                  Stripe Size: %dKB, "
+			"Segment Size: N/A\n", Controller,
+			1 << (LogicalDeviceInfo->StripeSize - 2));
+	  else
+	    DAC960_Info("                  Stripe Size: %dKB, "
+			"Segment Size: %dKB\n", Controller,
+			1 << (LogicalDeviceInfo->StripeSize - 2),
+			1 << (LogicalDeviceInfo->CacheLineSize - 2));
+	}
+      DAC960_Info("                  %s, %s\n", Controller,
+		  ReadCacheStatus[
+		    LogicalDeviceInfo->LogicalDeviceControl.ReadCache],
+		  WriteCacheStatus[
+		    LogicalDeviceInfo->LogicalDeviceControl.WriteCache]);
+      if (LogicalDeviceInfo->SoftErrors > 0 ||
+	  LogicalDeviceInfo->CommandsFailed > 0 ||
+	  LogicalDeviceInfo->DeferredWriteErrors)
+	DAC960_Info("                  Errors - Soft: %d, Failed: %d, "
+		    "Deferred Write: %d\n", Controller,
+		    LogicalDeviceInfo->SoftErrors,
+		    LogicalDeviceInfo->CommandsFailed,
+		    LogicalDeviceInfo->DeferredWriteErrors);
+
+    }
+  return true;
+}
+
+
+/*
   DAC960_RegisterBlockDevice registers the Block Device structures
   associated with Controller.
 */
@@ -1167,7 +1857,7 @@
       Controller->MaxSectorsPerRequest[MinorNumber] =
 	Controller->MaxBlocksPerCommand;
       Controller->MaxSegmentsPerRequest[MinorNumber] =
-	Controller->MaxScatterGatherSegments;
+	Controller->DriverScatterGatherLimit;
     }
   Controller->GenericDiskInfo.part = Controller->DiskPartitions;
   Controller->GenericDiskInfo.sizes = Controller->PartitionSizes;
@@ -1250,37 +1940,484 @@
 
 
 /*
-  DAC960_InitializeController initializes Controller.
+  DAC960_GenericDiskInit is the Generic Disk Information Initialization
+  Function for the DAC960 Driver.
 */
 
-static void DAC960_InitializeController(DAC960_Controller_T *Controller)
+static void DAC960_InitializeGenericDiskInfo(GenericDiskInfo_T *GenericDiskInfo)
 {
-  if (DAC960_ReadControllerConfiguration(Controller) &&
-      DAC960_ReportControllerConfiguration(Controller) &&
-      DAC960_ReadDeviceConfiguration(Controller) &&
-      DAC960_ReportDeviceConfiguration(Controller) &&
-      DAC960_RegisterBlockDevice(Controller))
-    {
-      /*
-	Initialize the Command structures.
-      */
-      DAC960_Command_T *Commands = Controller->Commands;
-      int CommandIdentifier;
-      Controller->FreeCommands = NULL;
-      for (CommandIdentifier = 0;
-	   CommandIdentifier < Controller->DriverQueueDepth;
-	   CommandIdentifier++)
-	{
-	  Commands[CommandIdentifier].Controller = Controller;
-	  Commands[CommandIdentifier].Next = Controller->FreeCommands;
-	  Controller->FreeCommands = &Commands[CommandIdentifier];
-	}
-      /*
-	Initialize the Monitoring Timer.
-      */
-      init_timer(&Controller->MonitoringTimer);
-      Controller->MonitoringTimer.expires =
-	jiffies + DAC960_MonitoringTimerInterval;
+  DAC960_Controller_T *Controller =
+    (DAC960_Controller_T *) GenericDiskInfo->real_devices;
+  int LogicalDriveNumber;
+  if (Controller->FirmwareType == DAC960_V1_Controller)
+    for (LogicalDriveNumber = 0;
+	 LogicalDriveNumber < Controller->LogicalDriveCount;
+	 LogicalDriveNumber++)
+      GenericDiskInfo->part[DAC960_MinorNumber(LogicalDriveNumber, 0)]
+		      .nr_sects =
+	Controller->V1.LogicalDriveInformation
+		       [LogicalDriveNumber].LogicalDriveSize;
+  else
+    for (LogicalDriveNumber = 0;
+	 LogicalDriveNumber < DAC960_MaxLogicalDrives;
+	 LogicalDriveNumber++)
+      {
+	DAC960_V2_LogicalDeviceInfo_T *LogicalDeviceInfo =
+	  Controller->V2.LogicalDeviceInformation[LogicalDriveNumber];
+	if (LogicalDeviceInfo != NULL)
+	  GenericDiskInfo->part[DAC960_MinorNumber(LogicalDriveNumber, 0)]
+			  .nr_sects =
+	    LogicalDeviceInfo->ConfigurableDeviceSizeIn512ByteBlocksOrMB;
+      }
+}
+
+
+/*
+  DAC960_ReportErrorStatus reports Controller BIOS Messages passed through
+  the Error Status Register when the driver performs the BIOS handshaking.
+  It returns true for fatal errors and false otherwise.
+*/
+
+static boolean DAC960_ReportErrorStatus(DAC960_Controller_T *Controller,
+					unsigned char ErrorStatus,
+					unsigned char Parameter0,
+					unsigned char Parameter1)
+{
+  switch (ErrorStatus)
+    {
+    case 0x00:
+      DAC960_Notice("Physical Device %d:%d Not Responding\n",
+		    Controller, Parameter1, Parameter0);
+      break;
+    case 0x08:
+      if (Controller->DriveSpinUpMessageDisplayed) break;
+      DAC960_Notice("Spinning Up Drives\n", Controller);
+      Controller->DriveSpinUpMessageDisplayed = true;
+      break;
+    case 0x30:
+      DAC960_Notice("Configuration Checksum Error\n", Controller);
+      break;
+    case 0x60:
+      DAC960_Notice("Mirror Race Recovery Failed\n", Controller);
+      break;
+    case 0x70:
+      DAC960_Notice("Mirror Race Recovery In Progress\n", Controller);
+      break;
+    case 0x90:
+      DAC960_Notice("Physical Device %d:%d COD Mismatch\n",
+		    Controller, Parameter1, Parameter0);
+      break;
+    case 0xA0:
+      DAC960_Notice("Logical Drive Installation Aborted\n", Controller);
+      break;
+    case 0xB0:
+      DAC960_Notice("Mirror Race On A Critical Logical Drive\n", Controller);
+      break;
+    case 0xD0:
+      DAC960_Notice("New Controller Configuration Found\n", Controller);
+      break;
+    case 0xF0:
+      DAC960_Error("Fatal Memory Parity Error for Controller at\n", Controller);
+      return true;
+    default:
+      DAC960_Error("Unknown Initialization Error %02X for Controller at\n",
+		   Controller, ErrorStatus);
+      return true;
+    }
+  return false;
+}
+
+
+/*
+  DAC960_DetectControllers detects Mylex DAC960/AcceleRAID/eXtremeRAID
+  PCI RAID Controllers by interrogating the PCI Configuration Space for
+  Controller Type.
+*/
+
+static void DAC960_DetectControllers(DAC960_HardwareType_T HardwareType)
+{
+  void (*InterruptHandler)(int, void *, Registers_T *) = NULL;
+  DAC960_FirmwareType_T FirmwareType = 0;
+  unsigned short VendorID = 0, DeviceID = 0;
+  unsigned int MemoryWindowSize = 0;
+  PCI_Device_T *PCI_Device = NULL;
+  switch (HardwareType)
+    {
+    case DAC960_BA_Controller:
+      VendorID = PCI_VENDOR_ID_MYLEX;
+      DeviceID = PCI_DEVICE_ID_MYLEX_DAC960_BA;
+      FirmwareType = DAC960_V2_Controller;
+      InterruptHandler = DAC960_BA_InterruptHandler;
+      MemoryWindowSize = DAC960_BA_RegisterWindowSize;
+      break;
+    case DAC960_LP_Controller:
+      VendorID = PCI_VENDOR_ID_MYLEX;
+      DeviceID = PCI_DEVICE_ID_MYLEX_DAC960_LP;
+      FirmwareType = DAC960_LP_Controller;
+      InterruptHandler = DAC960_LP_InterruptHandler;
+      MemoryWindowSize = DAC960_LP_RegisterWindowSize;
+      break;
+    case DAC960_LA_Controller:
+      VendorID = PCI_VENDOR_ID_DEC;
+      DeviceID = PCI_DEVICE_ID_DEC_21285;
+      FirmwareType = DAC960_V1_Controller;
+      InterruptHandler = DAC960_LA_InterruptHandler;
+      MemoryWindowSize = DAC960_LA_RegisterWindowSize;
+      break;
+    case DAC960_PG_Controller:
+      VendorID = PCI_VENDOR_ID_MYLEX;
+      DeviceID = PCI_DEVICE_ID_MYLEX_DAC960_PG;
+      FirmwareType = DAC960_V1_Controller;
+      InterruptHandler = DAC960_PG_InterruptHandler;
+      MemoryWindowSize = DAC960_PG_RegisterWindowSize;
+      break;
+    case DAC960_PD_Controller:
+      VendorID = PCI_VENDOR_ID_MYLEX;
+      DeviceID = PCI_DEVICE_ID_MYLEX_DAC960_PD;
+      FirmwareType = DAC960_V1_Controller;
+      InterruptHandler = DAC960_PD_InterruptHandler;
+      MemoryWindowSize = DAC960_PD_RegisterWindowSize;
+      break;
+    }
+  while ((PCI_Device = pci_find_device(VendorID, DeviceID, PCI_Device)) != NULL)
+    {
+      DAC960_Controller_T *Controller = NULL;
+      DAC960_IO_Address_T IO_Address = 0;
+      DAC960_PCI_Address_T PCI_Address = 0;
+      unsigned char Bus = PCI_Device->bus->number;
+      unsigned char DeviceFunction = PCI_Device->devfn;
+      unsigned char Device = DeviceFunction >> 3;
+      unsigned char Function = DeviceFunction & 0x7;
+      unsigned char ErrorStatus, Parameter0, Parameter1;
+      unsigned int IRQ_Channel = PCI_Device->irq;
+      unsigned long BaseAddress0 = PCI_Device->base_address[0];
+      unsigned long BaseAddress1 = PCI_Device->base_address[1];
+      unsigned short SubsystemVendorID, SubsystemDeviceID;
+      void *BaseAddress;
+      pci_read_config_word(PCI_Device, PCI_SUBSYSTEM_VENDOR_ID,
+			   &SubsystemVendorID);
+      pci_read_config_word(PCI_Device, PCI_SUBSYSTEM_ID,
+			   &SubsystemDeviceID);
+      switch (HardwareType)
+	{
+	case DAC960_BA_Controller:
+	  PCI_Address = BaseAddress0 & PCI_BASE_ADDRESS_MEM_MASK;
+	  break;
+	case DAC960_LP_Controller:
+	  PCI_Address = BaseAddress0 & PCI_BASE_ADDRESS_MEM_MASK;
+	  break;
+	case DAC960_LA_Controller:
+	  if (!(SubsystemVendorID == PCI_VENDOR_ID_MYLEX &&
+		SubsystemDeviceID == PCI_DEVICE_ID_MYLEX_DAC960_LA))
+	    continue;
+	  PCI_Address = BaseAddress0 & PCI_BASE_ADDRESS_MEM_MASK;
+	  break;
+	case DAC960_PG_Controller:
+	  PCI_Address = BaseAddress0 & PCI_BASE_ADDRESS_MEM_MASK;
+	  break;
+	case DAC960_PD_Controller:
+	  IO_Address = BaseAddress0 & PCI_BASE_ADDRESS_IO_MASK;
+	  PCI_Address = BaseAddress1 & PCI_BASE_ADDRESS_MEM_MASK;
+	  break;
+	}
+      if (DAC960_ControllerCount == DAC960_MaxControllers)
+	{
+	  DAC960_Error("More than %d DAC960 Controllers detected - "
+		       "ignoring from Controller at\n",
+		       NULL, DAC960_MaxControllers);
+	  goto Failure;
+	}
+      Controller = (DAC960_Controller_T *)
+	kmalloc(sizeof(DAC960_Controller_T), GFP_ATOMIC);
+      if (Controller == NULL)
+	{
+	  DAC960_Error("Unable to allocate Controller structure for "
+		       "Controller at\n", NULL);
+	  goto Failure;
+	}
+      memset(Controller, 0, sizeof(DAC960_Controller_T));
+      Controller->ControllerNumber = DAC960_ControllerCount;
+      DAC960_Controllers[DAC960_ControllerCount++] = Controller;
+      DAC960_AnnounceDriver(Controller);
+      Controller->FirmwareType = FirmwareType;
+      Controller->HardwareType = HardwareType;
+      Controller->IO_Address = IO_Address;
+      Controller->PCI_Address = PCI_Address;
+      Controller->Bus = Bus;
+      Controller->Device = Device;
+      Controller->Function = Function;
+      /*
+	Map the Controller Register Window.
+      */
+      if (MemoryWindowSize < PAGE_SIZE)
+	MemoryWindowSize = PAGE_SIZE;
+      Controller->MemoryMappedAddress =
+	ioremap_nocache(PCI_Address & PAGE_MASK, MemoryWindowSize);
+      Controller->BaseAddress =
+	Controller->MemoryMappedAddress + (PCI_Address & ~PAGE_MASK);
+      if (Controller->MemoryMappedAddress == NULL)
+	{
+	  DAC960_Error("Unable to map Controller Register Window for "
+		       "Controller at\n", Controller);
+	  goto Failure;
+	}
+      BaseAddress = Controller->BaseAddress;
+      switch (HardwareType)
+	{
+	case DAC960_BA_Controller:
+	  DAC960_BA_DisableInterrupts(Controller->BaseAddress);
+	  DAC960_BA_AcknowledgeHardwareMailboxStatus(BaseAddress);
+	  udelay(1000);
+	  while (DAC960_BA_InitializationInProgressP(BaseAddress))
+	    {
+	      if (DAC960_BA_ReadErrorStatus(BaseAddress, &ErrorStatus,
+					    &Parameter0, &Parameter1) &&
+		  DAC960_ReportErrorStatus(Controller, ErrorStatus,
+					   Parameter0, Parameter1))
+		goto Failure;
+	      udelay(10);
+	    }
+	  if (!DAC960_V2_EnableMemoryMailboxInterface(Controller))
+	    {
+	      DAC960_Error("Unable to Enable Memory Mailbox Interface "
+			   "for Controller at\n", Controller);
+	      goto Failure;
+	    }
+	  DAC960_BA_EnableInterrupts(Controller->BaseAddress);
+	  Controller->QueueCommand = DAC960_BA_QueueCommand;
+	  Controller->ReadControllerConfiguration =
+	    DAC960_V2_ReadControllerConfiguration;
+	  Controller->ReadDeviceConfiguration =
+	    DAC960_V2_ReadDeviceConfiguration;
+	  Controller->ReportDeviceConfiguration =
+	    DAC960_V2_ReportDeviceConfiguration;
+	  Controller->QueueReadWriteCommand =
+	    DAC960_V2_QueueReadWriteCommand;
+	  break;
+	case DAC960_LP_Controller:
+	  DAC960_LP_DisableInterrupts(Controller->BaseAddress);
+	  DAC960_LP_AcknowledgeHardwareMailboxStatus(BaseAddress);
+	  udelay(1000);
+	  while (DAC960_LP_InitializationInProgressP(BaseAddress))
+	    {
+	      if (DAC960_LP_ReadErrorStatus(BaseAddress, &ErrorStatus,
+					    &Parameter0, &Parameter1) &&
+		  DAC960_ReportErrorStatus(Controller, ErrorStatus,
+					   Parameter0, Parameter1))
+		goto Failure;
+	      udelay(10);
+	    }
+	  if (!DAC960_V2_EnableMemoryMailboxInterface(Controller))
+	    {
+	      DAC960_Error("Unable to Enable Memory Mailbox Interface "
+			   "for Controller at\n", Controller);
+	      goto Failure;
+	    }
+	  DAC960_LP_EnableInterrupts(Controller->BaseAddress);
+	  Controller->QueueCommand = DAC960_LP_QueueCommand;
+	  Controller->ReadControllerConfiguration =
+	    DAC960_V2_ReadControllerConfiguration;
+	  Controller->ReadDeviceConfiguration =
+	    DAC960_V2_ReadDeviceConfiguration;
+	  Controller->ReportDeviceConfiguration =
+	    DAC960_V2_ReportDeviceConfiguration;
+	  Controller->QueueReadWriteCommand =
+	    DAC960_V2_QueueReadWriteCommand;
+	  break;
+	case DAC960_LA_Controller:
+	  DAC960_LA_DisableInterrupts(Controller->BaseAddress);
+	  DAC960_LA_AcknowledgeHardwareMailboxStatus(BaseAddress);
+	  udelay(1000);
+	  while (DAC960_LA_InitializationInProgressP(BaseAddress))
+	    {
+	      if (DAC960_LA_ReadErrorStatus(BaseAddress, &ErrorStatus,
+					    &Parameter0, &Parameter1) &&
+		  DAC960_ReportErrorStatus(Controller, ErrorStatus,
+					   Parameter0, Parameter1))
+		goto Failure;
+	      udelay(10);
+	    }
+	  if (!DAC960_V1_EnableMemoryMailboxInterface(Controller))
+	    {
+	      DAC960_Error("Unable to Enable Memory Mailbox Interface "
+			   "for Controller at\n", Controller);
+	      goto Failure;
+	    }
+	  DAC960_LA_EnableInterrupts(Controller->BaseAddress);
+	  if (Controller->V1.DualModeMemoryMailboxInterface)
+	    Controller->QueueCommand = DAC960_LA_QueueCommandDualMode;
+	  else Controller->QueueCommand = DAC960_LA_QueueCommandSingleMode;
+	  Controller->ReadControllerConfiguration =
+	    DAC960_V1_ReadControllerConfiguration;
+	  Controller->ReadDeviceConfiguration =
+	    DAC960_V1_ReadDeviceConfiguration;
+	  Controller->ReportDeviceConfiguration =
+	    DAC960_V1_ReportDeviceConfiguration;
+	  Controller->QueueReadWriteCommand =
+	    DAC960_V1_QueueReadWriteCommand;
+	  break;
+	case DAC960_PG_Controller:
+	  DAC960_PG_DisableInterrupts(Controller->BaseAddress);
+	  DAC960_PG_AcknowledgeHardwareMailboxStatus(BaseAddress);
+	  udelay(1000);
+	  while (DAC960_PG_InitializationInProgressP(BaseAddress))
+	    {
+	      if (DAC960_PG_ReadErrorStatus(BaseAddress, &ErrorStatus,
+					    &Parameter0, &Parameter1) &&
+		  DAC960_ReportErrorStatus(Controller, ErrorStatus,
+					   Parameter0, Parameter1))
+		goto Failure;
+	      udelay(10);
+	    }
+	  if (!DAC960_V1_EnableMemoryMailboxInterface(Controller))
+	    {
+	      DAC960_Error("Unable to Enable Memory Mailbox Interface "
+			   "for Controller at\n", Controller);
+	      goto Failure;
+	    }
+	  DAC960_PG_EnableInterrupts(Controller->BaseAddress);
+	  if (Controller->V1.DualModeMemoryMailboxInterface)
+	    Controller->QueueCommand = DAC960_PG_QueueCommandDualMode;
+	  else Controller->QueueCommand = DAC960_PG_QueueCommandSingleMode;
+	  Controller->ReadControllerConfiguration =
+	    DAC960_V1_ReadControllerConfiguration;
+	  Controller->ReadDeviceConfiguration =
+	    DAC960_V1_ReadDeviceConfiguration;
+	  Controller->ReportDeviceConfiguration =
+	    DAC960_V1_ReportDeviceConfiguration;
+	  Controller->QueueReadWriteCommand =
+	    DAC960_V1_QueueReadWriteCommand;
+	  break;
+	case DAC960_PD_Controller:
+	  request_region(Controller->IO_Address, 0x80,
+			 Controller->FullModelName);
+	  DAC960_PD_DisableInterrupts(BaseAddress);
+	  DAC960_PD_AcknowledgeStatus(BaseAddress);
+	  udelay(1000);
+	  while (DAC960_PD_InitializationInProgressP(BaseAddress))
+	    {
+	      if (DAC960_PD_ReadErrorStatus(BaseAddress, &ErrorStatus,
+					    &Parameter0, &Parameter1) &&
+		  DAC960_ReportErrorStatus(Controller, ErrorStatus,
+					   Parameter0, Parameter1))
+		goto Failure;
+	      udelay(10);
+	    }
+	  DAC960_PD_EnableInterrupts(Controller->BaseAddress);
+	  Controller->QueueCommand = DAC960_PD_QueueCommand;
+	  Controller->ReadControllerConfiguration =
+	    DAC960_V1_ReadControllerConfiguration;
+	  Controller->ReadDeviceConfiguration =
+	    DAC960_V1_ReadDeviceConfiguration;
+	  Controller->ReportDeviceConfiguration =
+	    DAC960_V1_ReportDeviceConfiguration;
+	  Controller->QueueReadWriteCommand =
+	    DAC960_V1_QueueReadWriteCommand;
+	  break;
+	}
+      /*
+	Acquire shared access to the IRQ Channel.
+      */
+      if (IRQ_Channel == 0)
+	{
+	  DAC960_Error("IRQ Channel %d illegal for Controller at\n",
+		       Controller, IRQ_Channel);
+	  goto Failure;
+	}
+      strcpy(Controller->FullModelName, "DAC960");
+      if (request_irq(IRQ_Channel, InterruptHandler, SA_SHIRQ,
+		      Controller->FullModelName, Controller) < 0)
+	{
+	  DAC960_Error("Unable to acquire IRQ Channel %d for Controller at\n",
+		       Controller, IRQ_Channel);
+	  goto Failure;
+	}
+      Controller->IRQ_Channel = IRQ_Channel;
+      DAC960_ActiveControllerCount++;
+      Controller->InitialCommand.CommandIdentifier = 1;
+      Controller->InitialCommand.Controller = Controller;
+      Controller->Commands[0] = &Controller->InitialCommand;
+      Controller->FreeCommands = &Controller->InitialCommand;
+      Controller->ControllerDetectionSuccessful = true;
+      continue;
+    Failure:
+      if (IO_Address == 0)
+	DAC960_Error("PCI Bus %d Device %d Function %d I/O Address N/A "
+		     "PCI Address 0x%X\n", Controller,
+		     Bus, Device, Function, PCI_Address);
+      else DAC960_Error("PCI Bus %d Device %d Function %d I/O Address "
+			"0x%X PCI Address 0x%X\n", Controller,
+			Bus, Device, Function, IO_Address, PCI_Address);
+      if (Controller == NULL) break;
+      if (Controller->MemoryMappedAddress != NULL)
+	iounmap(Controller->MemoryMappedAddress);
+      if (Controller->IRQ_Channel > 0)
+	free_irq(IRQ_Channel, Controller);
+    }
+}
+
+
+/*
+  DAC960_SortControllers sorts the Controllers by PCI Bus and Device Number.
+*/
+
+static void DAC960_SortControllers(void)
+{
+  int ControllerNumber, LastInterchange, Bound, j;
+  LastInterchange = DAC960_ControllerCount-1;
+  while (LastInterchange > 0)
+    {
+      Bound = LastInterchange;
+      LastInterchange = 0;
+      for (j = 0; j < Bound; j++)
+	{
+	  DAC960_Controller_T *Controller1 = DAC960_Controllers[j];
+	  DAC960_Controller_T *Controller2 = DAC960_Controllers[j+1];
+	  if (Controller1->Bus > Controller2->Bus ||
+	      (Controller1->Bus == Controller2->Bus &&
+	       (Controller1->Device > Controller2->Device)))
+	    {
+	      Controller2->ControllerNumber = j;
+	      DAC960_Controllers[j] = Controller2;
+	      Controller1->ControllerNumber = j+1;
+	      DAC960_Controllers[j+1] = Controller1;
+	      LastInterchange = j;
+	    }
+	}
+    }
+  for (ControllerNumber = 0;
+       ControllerNumber < DAC960_ControllerCount;
+       ControllerNumber++)
+    {
+      DAC960_Controller_T *Controller = DAC960_Controllers[ControllerNumber];
+      if (!Controller->ControllerDetectionSuccessful)
+	{
+	  DAC960_Controllers[ControllerNumber] = NULL;
+	  kfree(Controller);
+	}
+    }
+}
+
+
+/*
+  DAC960_InitializeController initializes Controller.
+*/
+
+static void DAC960_InitializeController(DAC960_Controller_T *Controller)
+{
+  if (DAC960_ReadControllerConfiguration(Controller) &&
+      DAC960_ReportControllerConfiguration(Controller) &&
+      DAC960_CreateAuxiliaryStructures(Controller) &&
+      DAC960_ReadDeviceConfiguration(Controller) &&
+      DAC960_ReportDeviceConfiguration(Controller) &&
+      DAC960_RegisterBlockDevice(Controller))
+    {
+      /*
+	Initialize the Monitoring Timer.
+      */
+      init_timer(&Controller->MonitoringTimer);
+      Controller->MonitoringTimer.expires =
+	jiffies + DAC960_MonitoringTimerInterval;
       Controller->MonitoringTimer.data = (unsigned long) Controller;
       Controller->MonitoringTimer.function = DAC960_MonitoringTimerFunction;
       add_timer(&Controller->MonitoringTimer);
@@ -1299,28 +2436,46 @@
   if (Controller->ControllerInitialized)
     {
       del_timer(&Controller->MonitoringTimer);
-      DAC960_Notice("Flushing Cache...", Controller);
-      DAC960_ExecuteType3(Controller, DAC960_Flush, NULL);
-      DAC960_Notice("done\n", Controller);
-      switch (Controller->ControllerType)
-	{
-	case DAC960_V5_Controller:
-	  if (!Controller->DualModeMemoryMailboxInterface)
-	    DAC960_V5_SaveMemoryMailboxInfo(Controller);
-	  break;
-	case DAC960_V4_Controller:
-	  if (!Controller->DualModeMemoryMailboxInterface)
-	    DAC960_V4_SaveMemoryMailboxInfo(Controller);
-	  break;
-	case DAC960_V3_Controller:
-	  break;
+      if (Controller->FirmwareType == DAC960_V1_Controller)
+	{
+	  DAC960_Notice("Flushing Cache...", Controller);
+	  DAC960_V1_ExecuteType3(Controller, DAC960_V1_Flush, NULL);
+	  DAC960_Notice("done\n", Controller);
+	  switch (Controller->HardwareType)
+	    {
+	    case DAC960_LA_Controller:
+	      if (Controller->V1.DualModeMemoryMailboxInterface)
+		free_pages(Controller->MemoryMailboxPagesAddress,
+			   Controller->MemoryMailboxPagesOrder);
+	      else DAC960_LA_SaveMemoryMailboxInfo(Controller);
+	      break;
+	    case DAC960_PG_Controller:
+	      if (Controller->V1.DualModeMemoryMailboxInterface)
+		free_pages(Controller->MemoryMailboxPagesAddress,
+			   Controller->MemoryMailboxPagesOrder);
+	      else DAC960_PG_SaveMemoryMailboxInfo(Controller);
+	      break;
+	    case DAC960_PD_Controller:
+	      release_region(Controller->IO_Address, 0x80);
+	      break;
+	    default:
+	      break;
+	    }
+	}
+      else
+	{
+	  DAC960_Notice("Flushing Cache...", Controller);
+	  DAC960_V2_DeviceOperation(Controller, DAC960_V2_PauseDevice,
+				    DAC960_V2_RAID_Controller);
+	  DAC960_Notice("done\n", Controller);
+	  free_pages(Controller->MemoryMailboxPagesAddress,
+		     Controller->MemoryMailboxPagesOrder);
 	}
     }
   free_irq(Controller->IRQ_Channel, Controller);
   iounmap(Controller->MemoryMappedAddress);
-  if (Controller->IO_Address > 0)
-    release_region(Controller->IO_Address, 0x80);
   DAC960_UnregisterBlockDevice(Controller);
+  DAC960_DestroyAuxiliaryStructures(Controller);
   DAC960_Controllers[Controller->ControllerNumber] = NULL;
   kfree(Controller);
 }
@@ -1333,9 +2488,12 @@
 void DAC960_Initialize(void)
 {
   int ControllerNumber;
-  DAC960_DetectControllers(DAC960_V5_Controller);
-  DAC960_DetectControllers(DAC960_V4_Controller);
-  DAC960_DetectControllers(DAC960_V3_Controller);
+  DAC960_DetectControllers(DAC960_BA_Controller);
+  DAC960_DetectControllers(DAC960_LP_Controller);
+  DAC960_DetectControllers(DAC960_LA_Controller);
+  DAC960_DetectControllers(DAC960_PG_Controller);
+  DAC960_DetectControllers(DAC960_PD_Controller);
+  DAC960_SortControllers();
   if (DAC960_ActiveControllerCount == 0) return;
   for (ControllerNumber = 0;
        ControllerNumber < DAC960_ControllerCount;
@@ -1371,68 +2529,38 @@
 
 
 /*
-  DAC960_ProcessRequest attempts to remove one I/O Request from Controller's
-  I/O Request Queue and queues it to the Controller.  WaitForCommand is true if
-  this function should wait for a Command to become available if necessary.
-  This function returns true if an I/O Request was queued and false otherwise.
+  DAC960_V1_QueueReadWriteCommand prepares and queues a Read/Write Command for
+  DAC960 V1 Firmware Controllers.
 */
 
-static boolean DAC960_ProcessRequest(DAC960_Controller_T *Controller,
-				     boolean WaitForCommand)
+static void DAC960_V1_QueueReadWriteCommand(DAC960_Command_T *Command)
 {
-  IO_Request_T **RequestQueuePointer =
-    &blk_dev[DAC960_MAJOR + Controller->ControllerNumber].current_request;
-  IO_Request_T *Request;
-  DAC960_Command_T *Command;
-  char *RequestBuffer;
-  while (true)
-    {
-      Request = *RequestQueuePointer;
-      if (Request == NULL || Request->rq_status == RQ_INACTIVE) return false;
-      Command = DAC960_AllocateCommand(Controller);
-      if (Command != NULL) break;
-      if (!WaitForCommand) return false;
-      DAC960_WaitForCommand(Controller);
-    }
-  DAC960_ClearCommand(Command);
-  if (Request->cmd == READ)
-    Command->CommandType = DAC960_ReadCommand;
-  else Command->CommandType = DAC960_WriteCommand;
-  Command->Semaphore = Request->sem;
-  Command->LogicalDriveNumber = DAC960_LogicalDriveNumber(Request->rq_dev);
-  Command->BlockNumber =
-    Request->sector
-    + Controller->GenericDiskInfo.part[MINOR(Request->rq_dev)].start_sect;
-  Command->BlockCount = Request->nr_sectors;
-  Command->SegmentCount = Request->nr_segments;
-  Command->BufferHeader = Request->bh;
-  RequestBuffer = Request->buffer;
-  Request->rq_status = RQ_INACTIVE;
-  *RequestQueuePointer = Request->next;
-  wake_up(&wait_for_request);
+  DAC960_Controller_T *Controller = Command->Controller;
+  DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
+  DAC960_V1_ClearCommand(Command);
   if (Command->SegmentCount == 1)
     {
-      DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
       if (Command->CommandType == DAC960_ReadCommand)
-	CommandMailbox->Type5.CommandOpcode = DAC960_Read;
-      else CommandMailbox->Type5.CommandOpcode = DAC960_Write;
+	CommandMailbox->Type5.CommandOpcode = DAC960_V1_Read;
+      else CommandMailbox->Type5.CommandOpcode = DAC960_V1_Write;
       CommandMailbox->Type5.LD.TransferLength = Command->BlockCount;
       CommandMailbox->Type5.LD.LogicalDriveNumber = Command->LogicalDriveNumber;
       CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber;
-      CommandMailbox->Type5.BusAddress = Virtual_to_Bus(RequestBuffer);
+      CommandMailbox->Type5.BusAddress = Virtual_to_Bus(Command->RequestBuffer);
     }
   else
     {
-      DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
-      DAC960_ScatterGatherSegment_T
-	*ScatterGatherList = Command->ScatterGatherList;
+      DAC960_V1_ScatterGatherSegment_T
+	*ScatterGatherList = Command->V1.ScatterGatherList;
       BufferHeader_T *BufferHeader = Command->BufferHeader;
       char *LastDataEndPointer = NULL;
       int SegmentNumber = 0;
       if (Command->CommandType == DAC960_ReadCommand)
-	CommandMailbox->Type5.CommandOpcode = DAC960_ReadWithOldScatterGather;
+	CommandMailbox->Type5.CommandOpcode =
+	  DAC960_V1_ReadWithOldScatterGather;
       else
-	CommandMailbox->Type5.CommandOpcode = DAC960_WriteWithOldScatterGather;
+	CommandMailbox->Type5.CommandOpcode =
+	  DAC960_V1_WriteWithOldScatterGather;
       CommandMailbox->Type5.LD.TransferLength = Command->BlockCount;
       CommandMailbox->Type5.LD.LogicalDriveNumber = Command->LogicalDriveNumber;
       CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber;
@@ -1453,7 +2581,7 @@
 	      ScatterGatherList[SegmentNumber].SegmentByteCount =
 		BufferHeader->b_size;
 	      LastDataEndPointer = BufferHeader->b_data + BufferHeader->b_size;
-	      if (SegmentNumber++ > Controller->MaxScatterGatherSegments)
+	      if (SegmentNumber++ > Controller->DriverScatterGatherLimit)
 		panic("DAC960: Scatter/Gather Segment Overflow\n");
 	    }
 	  BufferHeader = BufferHeader->b_reqnext;
@@ -1462,6 +2590,138 @@
 	panic("DAC960: SegmentNumber != SegmentCount\n");
     }
   DAC960_QueueCommand(Command);
+}
+
+
+/*
+  DAC960_V2_QueueReadWriteCommand prepares and queues a Read/Write Command for
+  DAC960 V2 Firmware Controllers.
+*/
+
+static void DAC960_V2_QueueReadWriteCommand(DAC960_Command_T *Command)
+{
+  DAC960_Controller_T *Controller = Command->Controller;
+  DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
+  DAC960_V2_ClearCommand(Command);
+  CommandMailbox->SCSI_10.CommandOpcode = DAC960_V2_SCSI_10;
+  CommandMailbox->SCSI_10.CommandControlBits.DataTransferControllerToHost =
+    (Command->CommandType == DAC960_ReadCommand);
+  CommandMailbox->SCSI_10.DataTransferSize =
+    Command->BlockCount << DAC960_BlockSizeBits;
+  CommandMailbox->SCSI_10.RequestSenseBusAddress =
+    Virtual_to_Bus(&Command->V2.RequestSense);
+  CommandMailbox->SCSI_10.PhysicalDevice =
+    Controller->V2.LogicalDriveToVirtualDevice[Command->LogicalDriveNumber];
+  CommandMailbox->SCSI_10.RequestSenseSize =
+    sizeof(DAC960_SCSI_RequestSense_T);
+  CommandMailbox->SCSI_10.CDBLength = 10;
+  CommandMailbox->SCSI_10.SCSI_CDB[0] =
+    (Command->CommandType == DAC960_ReadCommand ? 0x28 : 0x2A);
+  CommandMailbox->SCSI_10.SCSI_CDB[2] = Command->BlockNumber >> 24;
+  CommandMailbox->SCSI_10.SCSI_CDB[3] = Command->BlockNumber >> 16;
+  CommandMailbox->SCSI_10.SCSI_CDB[4] = Command->BlockNumber >> 8;
+  CommandMailbox->SCSI_10.SCSI_CDB[5] = Command->BlockNumber;
+  CommandMailbox->SCSI_10.SCSI_CDB[7] = Command->BlockCount >> 8;
+  CommandMailbox->SCSI_10.SCSI_CDB[8] = Command->BlockCount;
+  if (Command->SegmentCount == 1)
+    {
+      CommandMailbox->SCSI_10.DataTransferMemoryAddress
+			     .ScatterGatherSegments[0]
+			     .SegmentDataPointer =
+	Virtual_to_Bus(Command->RequestBuffer);
+      CommandMailbox->SCSI_10.DataTransferMemoryAddress
+			     .ScatterGatherSegments[0]
+			     .SegmentByteCount =
+	CommandMailbox->SCSI_10.DataTransferSize;
+    }
+  else
+    {
+      DAC960_V2_ScatterGatherSegment_T
+	*ScatterGatherList = Command->V2.ScatterGatherList;
+      BufferHeader_T *BufferHeader = Command->BufferHeader;
+      char *LastDataEndPointer = NULL;
+      int SegmentNumber = 0;
+      if (Command->SegmentCount > 2)
+	{
+	  CommandMailbox->SCSI_10.CommandControlBits
+			 .AdditionalScatterGatherListMemory = true;
+	  CommandMailbox->SCSI_10.DataTransferMemoryAddress
+			 .ExtendedScatterGather.ScatterGatherList0Length =
+	    Command->SegmentCount;
+	  CommandMailbox->SCSI_10.DataTransferMemoryAddress
+			 .ExtendedScatterGather.ScatterGatherList0Address =
+	    Virtual_to_Bus(ScatterGatherList);
+	}
+      else
+	ScatterGatherList =
+	  CommandMailbox->SCSI_10.DataTransferMemoryAddress
+				 .ScatterGatherSegments;
+      while (BufferHeader != NULL)
+	{
+	  if (BufferHeader->b_data == LastDataEndPointer)
+	    {
+	      ScatterGatherList[SegmentNumber-1].SegmentByteCount +=
+		BufferHeader->b_size;
+	      LastDataEndPointer += BufferHeader->b_size;
+	    }
+	  else
+	    {
+	      ScatterGatherList[SegmentNumber].SegmentDataPointer =
+		Virtual_to_Bus(BufferHeader->b_data);
+	      ScatterGatherList[SegmentNumber].SegmentByteCount =
+		BufferHeader->b_size;
+	      LastDataEndPointer = BufferHeader->b_data + BufferHeader->b_size;
+	      if (SegmentNumber++ > Controller->DriverScatterGatherLimit)
+		panic("DAC960: Scatter/Gather Segment Overflow\n");
+	    }
+	  BufferHeader = BufferHeader->b_reqnext;
+	}
+      if (SegmentNumber != Command->SegmentCount)
+	panic("DAC960: SegmentNumber != SegmentCount\n");
+    }
+  DAC960_QueueCommand(Command);
+}
+
+
+/*
+  DAC960_ProcessRequest attempts to remove one I/O Request from Controller's
+  I/O Request Queue and queues it to the Controller.  WaitForCommand is true if
+  this function should wait for a Command to become available if necessary.
+  This function returns true if an I/O Request was queued and false otherwise.
+*/
+
+static boolean DAC960_ProcessRequest(DAC960_Controller_T *Controller,
+				     boolean WaitForCommand)
+{
+  IO_Request_T **RequestQueuePointer =
+    &blk_dev[DAC960_MAJOR + Controller->ControllerNumber].current_request;
+  IO_Request_T *Request;
+  DAC960_Command_T *Command;
+  while (true)
+    {
+      Request = *RequestQueuePointer;
+      if (Request == NULL || Request->rq_status == RQ_INACTIVE) return false;
+      Command = DAC960_AllocateCommand(Controller);
+      if (Command != NULL) break;
+      if (!WaitForCommand) return false;
+      DAC960_WaitForCommand(Controller);
+    }
+  if (Request->cmd == READ)
+    Command->CommandType = DAC960_ReadCommand;
+  else Command->CommandType = DAC960_WriteCommand;
+  Command->Semaphore = Request->sem;
+  Command->LogicalDriveNumber = DAC960_LogicalDriveNumber(Request->rq_dev);
+  Command->BlockNumber =
+    Request->sector
+    + Controller->GenericDiskInfo.part[MINOR(Request->rq_dev)].start_sect;
+  Command->BlockCount = Request->nr_sectors;
+  Command->SegmentCount = Request->nr_segments;
+  Command->BufferHeader = Request->bh;
+  Command->RequestBuffer = Request->buffer;
+  Request->rq_status = RQ_INACTIVE;
+  *RequestQueuePointer = Request->next;
+  DAC960_QueueReadWriteCommand(Command);
+  wake_up(&wait_for_request);
   return true;
 }
 
@@ -1663,14 +2923,26 @@
 
 
 /*
-  DAC960_ReadWriteError prints an appropriate error message for Command when
-  an error occurs on a Read or Write operation.
+  DAC960_ProcessCompletedBuffer performs completion processing for an
+  individual Buffer.
+*/
+
+static inline void DAC960_ProcessCompletedBuffer(BufferHeader_T *BufferHeader,
+						 boolean SuccessfulIO)
+{
+  BufferHeader->b_end_io(BufferHeader, SuccessfulIO);
+}
+
+
+/*
+  DAC960_V1_ReadWriteError prints an appropriate error message for Command
+  when an error occurs on a Read or Write operation.
 */
 
-static void DAC960_ReadWriteError(DAC960_Command_T *Command)
+static void DAC960_V1_ReadWriteError(DAC960_Command_T *Command)
 {
   DAC960_Controller_T *Controller = Command->Controller;
-  char *CommandName = "UNKNOWN";
+  unsigned char *CommandName = "UNKNOWN";
   switch (Command->CommandType)
     {
     case DAC960_ReadCommand:
@@ -1686,26 +2958,26 @@
     case DAC960_QueuedCommand:
       break;
     }
-  switch (Command->CommandStatus)
+  switch (Command->V1.CommandStatus)
     {
-    case DAC960_IrrecoverableDataError:
+    case DAC960_V1_IrrecoverableDataError:
       DAC960_Error("Irrecoverable Data Error on %s:\n",
 		   Controller, CommandName);
       break;
-    case DAC960_LogicalDriveNonexistentOrOffline:
+    case DAC960_V1_LogicalDriveNonexistentOrOffline:
       DAC960_Error("Logical Drive Nonexistent or Offline on %s:\n",
 		   Controller, CommandName);
       break;
-    case DAC960_AccessBeyondEndOfLogicalDrive:
+    case DAC960_V1_AccessBeyondEndOfLogicalDrive:
       DAC960_Error("Attempt to Access Beyond End of Logical Drive "
 		   "on %s:\n", Controller, CommandName);
       break;
-    case DAC960_BadDataEncountered:
+    case DAC960_V1_BadDataEncountered:
       DAC960_Error("Bad Data Encountered on %s:\n", Controller, CommandName);
       break;
     default:
       DAC960_Error("Unexpected Error Status %04X on %s:\n",
-		   Controller, Command->CommandStatus, CommandName);
+		   Controller, Command->V1.CommandStatus, CommandName);
       break;
     }
   DAC960_Error("  /dev/rd/c%dd%d:   absolute blocks %d..%d\n",
@@ -1723,33 +2995,22 @@
 
 
 /*
-  DAC960_ProcessCompletedBuffer performs completion processing for an
-  individual Buffer.
-*/
-
-static inline void DAC960_ProcessCompletedBuffer(BufferHeader_T *BufferHeader,
-						 boolean SuccessfulIO)
-{
-  BufferHeader->b_end_io(BufferHeader, SuccessfulIO);
-}
-
-
-/*
-  DAC960_ProcessCompletedCommand performs completion processing for Command.
+  DAC960_V1_ProcessCompletedCommand performs completion processing for Command
+  for DAC960 V1 Firmware Controllers.
 */
 
-static void DAC960_ProcessCompletedCommand(DAC960_Command_T *Command)
+static void DAC960_V1_ProcessCompletedCommand(DAC960_Command_T *Command)
 {
   DAC960_Controller_T *Controller = Command->Controller;
   DAC960_CommandType_T CommandType = Command->CommandType;
-  DAC960_CommandOpcode_T CommandOpcode =
-    Command->CommandMailbox.Common.CommandOpcode;
-  DAC960_CommandStatus_T CommandStatus = Command->CommandStatus;
+  DAC960_V1_CommandOpcode_T CommandOpcode =
+    Command->V1.CommandMailbox.Common.CommandOpcode;
+  DAC960_V1_CommandStatus_T CommandStatus = Command->V1.CommandStatus;
   BufferHeader_T *BufferHeader = Command->BufferHeader;
   if (CommandType == DAC960_ReadCommand ||
       CommandType == DAC960_WriteCommand)
     {
-      if (CommandStatus == DAC960_NormalCompletion)
+      if (CommandStatus == DAC960_V1_NormalCompletion)
 	{
 	  /*
 	    Perform completion processing for all buffers in this I/O Request.
@@ -1771,21 +3032,22 @@
 	    }
 	  add_blkdev_randomness(DAC960_MAJOR + Controller->ControllerNumber);
 	}
-      else if ((CommandStatus == DAC960_IrrecoverableDataError ||
-		CommandStatus == DAC960_BadDataEncountered) &&
+      else if ((CommandStatus == DAC960_V1_IrrecoverableDataError ||
+		CommandStatus == DAC960_V1_BadDataEncountered) &&
 	       BufferHeader != NULL &&
 	       BufferHeader->b_reqnext != NULL)
 	{
-	  DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
+	  DAC960_V1_CommandMailbox_T *CommandMailbox =
+	    &Command->V1.CommandMailbox;
 	  if (CommandType == DAC960_ReadCommand)
 	    {
 	      Command->CommandType = DAC960_ReadRetryCommand;
-	      CommandMailbox->Type5.CommandOpcode = DAC960_Read;
+	      CommandMailbox->Type5.CommandOpcode = DAC960_V1_Read;
 	    }
 	  else
 	    {
 	      Command->CommandType = DAC960_WriteRetryCommand;
-	      CommandMailbox->Type5.CommandOpcode = DAC960_Write;
+	      CommandMailbox->Type5.CommandOpcode = DAC960_V1_Write;
 	    }
 	  Command->BlockCount = BufferHeader->b_size >> DAC960_BlockSizeBits;
 	  CommandMailbox->Type5.LD.TransferLength = Command->BlockCount;
@@ -1796,8 +3058,8 @@
 	}
       else
 	{
-	  if (CommandStatus != DAC960_LogicalDriveNonexistentOrOffline)
-	    DAC960_ReadWriteError(Command);
+	  if (CommandStatus != DAC960_V1_LogicalDriveNonexistentOrOffline)
+	    DAC960_V1_ReadWriteError(Command);
 	  /*
 	    Perform completion processing for all buffers in this I/O Request.
 	  */
@@ -1826,17 +3088,18 @@
       /*
 	Perform completion processing for this single buffer.
       */
-      if (CommandStatus == DAC960_NormalCompletion)
+      if (CommandStatus == DAC960_V1_NormalCompletion)
 	DAC960_ProcessCompletedBuffer(BufferHeader, true);
       else
 	{
-	  if (CommandStatus != DAC960_LogicalDriveNonexistentOrOffline)
-	    DAC960_ReadWriteError(Command);
+	  if (CommandStatus != DAC960_V1_LogicalDriveNonexistentOrOffline)
+	    DAC960_V1_ReadWriteError(Command);
 	  DAC960_ProcessCompletedBuffer(BufferHeader, false);
 	}
       if (NextBufferHeader != NULL)
 	{
-	  DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
+	  DAC960_V1_CommandMailbox_T *CommandMailbox =
+	    &Command->V1.CommandMailbox;
 	  Command->BlockNumber +=
 	    BufferHeader->b_size >> DAC960_BlockSizeBits;
 	  Command->BlockCount =
@@ -1851,30 +3114,43 @@
 	}
     }
   else if (CommandType == DAC960_MonitoringCommand ||
-	   CommandOpcode == DAC960_Enquiry ||
-	   CommandOpcode == DAC960_GetRebuildProgress)
+	   CommandOpcode == DAC960_V1_Enquiry ||
+	   CommandOpcode == DAC960_V1_GetRebuildProgress)
     {
       if (CommandType != DAC960_MonitoringCommand)
 	{
-	  if (CommandOpcode == DAC960_Enquiry)
-	    memcpy(&Controller->Enquiry[Controller->EnquiryIndex ^ 1],
-		   Bus_to_Virtual(Command->CommandMailbox.Type3.BusAddress),
-		   sizeof(DAC960_Enquiry_T));
-	  else if (CommandOpcode == DAC960_GetRebuildProgress)
-	    memcpy(&Controller->RebuildProgress,
-		   Bus_to_Virtual(Command->CommandMailbox.Type3.BusAddress),
-		   sizeof(DAC960_RebuildProgress_T));
-	}
-      if (CommandOpcode == DAC960_Enquiry)
-	{
-	  DAC960_Enquiry_T *OldEnquiry =
-	    &Controller->Enquiry[Controller->EnquiryIndex];
-	  DAC960_Enquiry_T *NewEnquiry =
-	    &Controller->Enquiry[Controller->EnquiryIndex ^= 1];
+	  if (CommandOpcode == DAC960_V1_Enquiry)
+	    memcpy(&Controller->V1.NewEnquiry,
+		   Bus_to_Virtual(Command->V1.CommandMailbox.Type3.BusAddress),
+		   sizeof(DAC960_V1_Enquiry_T));
+	  else if (CommandOpcode == DAC960_V1_GetRebuildProgress)
+	    memcpy(&Controller->V1.RebuildProgress,
+		   Bus_to_Virtual(Command->V1.CommandMailbox.Type3.BusAddress),
+		   sizeof(DAC960_V1_RebuildProgress_T));
+	}
+      if (CommandOpcode == DAC960_V1_Enquiry &&
+	  Controller->ControllerInitialized)
+	{
+	  DAC960_V1_Enquiry_T *OldEnquiry = &Controller->V1.Enquiry;
+	  DAC960_V1_Enquiry_T *NewEnquiry = &Controller->V1.NewEnquiry;
 	  unsigned int OldCriticalLogicalDriveCount =
 	    OldEnquiry->CriticalLogicalDriveCount;
 	  unsigned int NewCriticalLogicalDriveCount =
 	    NewEnquiry->CriticalLogicalDriveCount;
+	  if (NewEnquiry->NumberOfLogicalDrives > Controller->LogicalDriveCount)
+	    {
+	      int LogicalDriveNumber = Controller->LogicalDriveCount;
+	      while (LogicalDriveNumber < NewEnquiry->NumberOfLogicalDrives)
+		{
+		  DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) "
+				  "Now Exists\n", Controller,
+				  LogicalDriveNumber,
+				  Controller->ControllerNumber,
+				  LogicalDriveNumber);
+		  LogicalDriveNumber++;
+		}
+	      Controller->LogicalDriveCount = LogicalDriveNumber;
+	    }
 	  if (NewEnquiry->StatusFlags.DeferredWriteError !=
 	      OldEnquiry->StatusFlags.DeferredWriteError)
 	    DAC960_Critical("Deferred Write Error Flag is now %s\n", Controller,
@@ -1894,72 +3170,86 @@
 	      (jiffies - Controller->SecondaryMonitoringTime
 	       >= DAC960_SecondaryMonitoringInterval))
 	    {
-	      Controller->NeedLogicalDriveInformation = true;
-	      Controller->NewEventLogSequenceNumber =
+	      Controller->V1.NeedLogicalDriveInformation = true;
+	      Controller->V1.NewEventLogSequenceNumber =
 		NewEnquiry->EventLogSequenceNumber;
-	      Controller->NeedErrorTableInformation = true;
-	      Controller->NeedDeviceStateInformation = true;
-	      Controller->DeviceStateChannel = 0;
-	      Controller->DeviceStateTargetID = -1;
+	      Controller->V1.NeedErrorTableInformation = true;
+	      Controller->V1.NeedDeviceStateInformation = true;
+	      Controller->V1.DeviceStateChannel = 0;
+	      Controller->V1.DeviceStateTargetID = -1;
 	      Controller->SecondaryMonitoringTime = jiffies;
 	    }
-	  if (NewEnquiry->RebuildFlag == DAC960_StandbyRebuildInProgress ||
-	      NewEnquiry->RebuildFlag == DAC960_BackgroundRebuildInProgress ||
-	      OldEnquiry->RebuildFlag == DAC960_StandbyRebuildInProgress ||
-	      OldEnquiry->RebuildFlag == DAC960_BackgroundRebuildInProgress)
-	    Controller->NeedRebuildProgress = true;
-	  if (OldEnquiry->RebuildFlag == DAC960_BackgroundCheckInProgress)
+	  if (NewEnquiry->RebuildFlag == DAC960_V1_StandbyRebuildInProgress ||
+	      NewEnquiry->RebuildFlag
+	      == DAC960_V1_BackgroundRebuildInProgress ||
+	      OldEnquiry->RebuildFlag == DAC960_V1_StandbyRebuildInProgress ||
+	      OldEnquiry->RebuildFlag == DAC960_V1_BackgroundRebuildInProgress)
+	    {
+	      Controller->V1.NeedRebuildProgress = true;
+	      Controller->V1.RebuildProgressFirst =
+		(NewEnquiry->CriticalLogicalDriveCount <
+		 OldEnquiry->CriticalLogicalDriveCount);
+	    }
+	  if (OldEnquiry->RebuildFlag == DAC960_V1_BackgroundCheckInProgress)
 	    switch (NewEnquiry->RebuildFlag)
 	      {
-	      case DAC960_NoStandbyRebuildOrCheckInProgress:
+	      case DAC960_V1_NoStandbyRebuildOrCheckInProgress:
 		DAC960_Progress("Consistency Check Completed Successfully\n",
 				Controller);
 		break;
-	      case DAC960_StandbyRebuildInProgress:
-	      case DAC960_BackgroundRebuildInProgress:
+	      case DAC960_V1_StandbyRebuildInProgress:
+	      case DAC960_V1_BackgroundRebuildInProgress:
 		break;
-	      case DAC960_BackgroundCheckInProgress:
-		Controller->NeedConsistencyCheckProgress = true;
+	      case DAC960_V1_BackgroundCheckInProgress:
+		Controller->V1.NeedConsistencyCheckProgress = true;
 		break;
-	      case DAC960_StandbyRebuildCompletedWithError:
+	      case DAC960_V1_StandbyRebuildCompletedWithError:
 		DAC960_Progress("Consistency Check Completed with Error\n",
 				Controller);
 		break;
-	      case DAC960_BackgroundRebuildOrCheckFailed_DriveFailed:
+	      case DAC960_V1_BackgroundRebuildOrCheckFailed_DriveFailed:
 		DAC960_Progress("Consistency Check Failed - "
-				"Physical Drive Failed\n", Controller);
+				"Physical Device Failed\n", Controller);
 		break;
-	      case DAC960_BackgroundRebuildOrCheckFailed_LogicalDriveFailed:
+	      case DAC960_V1_BackgroundRebuildOrCheckFailed_LogicalDriveFailed:
 		DAC960_Progress("Consistency Check Failed - "
 				"Logical Drive Failed\n", Controller);
 		break;
-	      case DAC960_BackgroundRebuildOrCheckFailed_OtherCauses:
+	      case DAC960_V1_BackgroundRebuildOrCheckFailed_OtherCauses:
 		DAC960_Progress("Consistency Check Failed - Other Causes\n",
 				Controller);
 		break;
-	      case DAC960_BackgroundRebuildOrCheckSuccessfullyTerminated:
+	      case DAC960_V1_BackgroundRebuildOrCheckSuccessfullyTerminated:
 		DAC960_Progress("Consistency Check Successfully Terminated\n",
 				Controller);
 		break;
 	      }
-	  else if (NewEnquiry->RebuildFlag == DAC960_BackgroundCheckInProgress)
-	    Controller->NeedConsistencyCheckProgress = true;
+	  else if (NewEnquiry->RebuildFlag
+		   == DAC960_V1_BackgroundCheckInProgress)
+	    Controller->V1.NeedConsistencyCheckProgress = true;
+	  Controller->MonitoringAlertMode =
+	    (NewEnquiry->CriticalLogicalDriveCount > 0 ||
+	     NewEnquiry->OfflineLogicalDriveCount > 0 ||
+	     NewEnquiry->DeadDriveCount > 0);
 	  if (CommandType != DAC960_MonitoringCommand &&
-	      Controller->RebuildFlagPending)
+	      Controller->V1.RebuildFlagPending)
 	    {
-	      DAC960_Enquiry_T *Enquiry = (DAC960_Enquiry_T *)
-		Bus_to_Virtual(Command->CommandMailbox.Type3.BusAddress);
-	      Enquiry->RebuildFlag = Controller->PendingRebuildFlag;
-	      Controller->RebuildFlagPending = false;
+	      DAC960_V1_Enquiry_T *Enquiry = (DAC960_V1_Enquiry_T *)
+		Bus_to_Virtual(Command->V1.CommandMailbox.Type3.BusAddress);
+	      Enquiry->RebuildFlag = Controller->V1.PendingRebuildFlag;
+	      Controller->V1.RebuildFlagPending = false;
 	    }
 	  else if (CommandType == DAC960_MonitoringCommand &&
-		   NewEnquiry->RebuildFlag > DAC960_BackgroundCheckInProgress)
+		   NewEnquiry->RebuildFlag >
+		   DAC960_V1_BackgroundCheckInProgress)
 	    {
-	      Controller->PendingRebuildFlag = NewEnquiry->RebuildFlag;
-	      Controller->RebuildFlagPending = true;
+	      Controller->V1.PendingRebuildFlag = NewEnquiry->RebuildFlag;
+	      Controller->V1.RebuildFlagPending = true;
 	    }
+	  memcpy(&Controller->V1.Enquiry, &Controller->V1.NewEnquiry,
+		 sizeof(DAC960_V1_Enquiry_T));
 	}
-      else if (CommandOpcode == DAC960_PerformEventLogOperation)
+      else if (CommandOpcode == DAC960_V1_PerformEventLogOperation)
 	{
 	  static char
 	    *DAC960_EventMessages[] =
@@ -1976,37 +3266,39 @@
 		 "killed because of selection timeout",
 		 "killed due to SCSI phase sequence error",
 		 "killed due to unknown status" };
-	  DAC960_EventLogEntry_T *EventLogEntry = &Controller->EventLogEntry;
+	  DAC960_V1_EventLogEntry_T *EventLogEntry =
+	    &Controller->V1.EventLogEntry;
 	  if (EventLogEntry->SequenceNumber ==
-	      Controller->OldEventLogSequenceNumber)
+	      Controller->V1.OldEventLogSequenceNumber)
 	    {
 	      unsigned char SenseKey = EventLogEntry->SenseKey;
 	      unsigned char AdditionalSenseCode =
 		EventLogEntry->AdditionalSenseCode;
 	      unsigned char AdditionalSenseCodeQualifier =
 		EventLogEntry->AdditionalSenseCodeQualifier;
-	      if (SenseKey == 9 &&
+	      if (SenseKey == DAC960_SenseKey_VendorSpecific &&
 		  AdditionalSenseCode == 0x80 &&
 		  AdditionalSenseCodeQualifier <
 		  sizeof(DAC960_EventMessages) / sizeof(char *))
-		DAC960_Critical("Physical Drive %d:%d %s\n", Controller,
+		DAC960_Critical("Physical Device %d:%d %s\n", Controller,
 				EventLogEntry->Channel,
 				EventLogEntry->TargetID,
 				DAC960_EventMessages[
 				  AdditionalSenseCodeQualifier]);
-	      else if (SenseKey == 6 && AdditionalSenseCode == 0x29)
+	      else if (SenseKey == DAC960_SenseKey_UnitAttention &&
+		       AdditionalSenseCode == 0x29)
 		{
 		  if (Controller->MonitoringTimerCount > 0)
-		    Controller->DeviceResetCount[EventLogEntry->Channel]
-						[EventLogEntry->TargetID]++;
+		    Controller->V1.DeviceResetCount[EventLogEntry->Channel]
+						   [EventLogEntry->TargetID]++;
 		}
-	      else if (!(SenseKey == 0 ||
-			 (SenseKey == 2 &&
+	      else if (!(SenseKey == DAC960_SenseKey_NoSense ||
+			 (SenseKey == DAC960_SenseKey_NotReady &&
 			  AdditionalSenseCode == 0x04 &&
 			  (AdditionalSenseCodeQualifier == 0x01 ||
 			   AdditionalSenseCodeQualifier == 0x02))))
 		{
-		  DAC960_Critical("Physical Drive %d:%d Error Log: "
+		  DAC960_Critical("Physical Device %d:%d Error Log: "
 				  "Sense Key = %d, ASC = %02X, ASCQ = %02X\n",
 				  Controller,
 				  EventLogEntry->Channel,
@@ -2014,7 +3306,7 @@
 				  SenseKey,
 				  AdditionalSenseCode,
 				  AdditionalSenseCodeQualifier);
-		  DAC960_Critical("Physical Drive %d:%d Error Log: "
+		  DAC960_Critical("Physical Device %d:%d Error Log: "
 				  "Information = %02X%02X%02X%02X "
 				  "%02X%02X%02X%02X\n",
 				  Controller,
@@ -2030,21 +3322,19 @@
 				  EventLogEntry->CommandSpecificInformation[3]);
 		}
 	    }
-	  Controller->OldEventLogSequenceNumber++;
+	  Controller->V1.OldEventLogSequenceNumber++;
 	}
-      else if (CommandOpcode == DAC960_GetErrorTable)
+      else if (CommandOpcode == DAC960_V1_GetErrorTable)
 	{
-	  DAC960_ErrorTable_T *OldErrorTable =
-	    &Controller->ErrorTable[Controller->ErrorTableIndex];
-	  DAC960_ErrorTable_T *NewErrorTable =
-	    &Controller->ErrorTable[Controller->ErrorTableIndex ^= 1];
+	  DAC960_V1_ErrorTable_T *OldErrorTable = &Controller->V1.ErrorTable;
+	  DAC960_V1_ErrorTable_T *NewErrorTable = &Controller->V1.NewErrorTable;
 	  int Channel, TargetID;
 	  for (Channel = 0; Channel < Controller->Channels; Channel++)
-	    for (TargetID = 0; TargetID < DAC960_MaxTargets; TargetID++)
+	    for (TargetID = 0; TargetID < Controller->Targets; TargetID++)
 	      {
-		DAC960_ErrorTableEntry_T *NewErrorEntry =
+		DAC960_V1_ErrorTableEntry_T *NewErrorEntry =
 		  &NewErrorTable->ErrorTableEntries[Channel][TargetID];
-		DAC960_ErrorTableEntry_T *OldErrorEntry =
+		DAC960_V1_ErrorTableEntry_T *OldErrorEntry =
 		  &OldErrorTable->ErrorTableEntries[Channel][TargetID];
 		if ((NewErrorEntry->ParityErrorCount !=
 		     OldErrorEntry->ParityErrorCount) ||
@@ -2054,7 +3344,7 @@
 		     OldErrorEntry->HardErrorCount) ||
 		    (NewErrorEntry->MiscErrorCount !=
 		     OldErrorEntry->MiscErrorCount))
-		  DAC960_Critical("Physical Drive %d:%d Errors: "
+		  DAC960_Critical("Physical Device %d:%d Errors: "
 				  "Parity = %d, Soft = %d, "
 				  "Hard = %d, Misc = %d\n",
 				  Controller, Channel, TargetID,
@@ -2063,51 +3353,49 @@
 				  NewErrorEntry->HardErrorCount,
 				  NewErrorEntry->MiscErrorCount);
 	      }
+	  memcpy(&Controller->V1.ErrorTable, &Controller->V1.NewErrorTable,
+		 sizeof(DAC960_V1_ErrorTable_T));
 	}
-      else if (CommandOpcode == DAC960_GetDeviceState)
+      else if (CommandOpcode == DAC960_V1_GetDeviceState)
 	{
-	  DAC960_DeviceState_T *OldDeviceState =
-	    &Controller->DeviceState[Controller->DeviceStateIndex]
-				    [Controller->DeviceStateChannel]
-				    [Controller->DeviceStateTargetID];
-	  DAC960_DeviceState_T *NewDeviceState =
-	    &Controller->DeviceState[Controller->DeviceStateIndex ^ 1]
-				    [Controller->DeviceStateChannel]
-				    [Controller->DeviceStateTargetID];
+	  DAC960_V1_DeviceState_T *OldDeviceState =
+	    &Controller->V1.DeviceState[Controller->V1.DeviceStateChannel]
+				       [Controller->V1.DeviceStateTargetID];
+	  DAC960_V1_DeviceState_T *NewDeviceState =
+	    &Controller->V1.NewDeviceState;
 	  if (NewDeviceState->DeviceState != OldDeviceState->DeviceState)
-	    DAC960_Critical("Physical Drive %d:%d is now %s\n", Controller,
-			    Controller->DeviceStateChannel,
-			    Controller->DeviceStateTargetID,
-			    (NewDeviceState->DeviceState == DAC960_Device_Dead
+	    DAC960_Critical("Physical Device %d:%d is now %s\n", Controller,
+			    Controller->V1.DeviceStateChannel,
+			    Controller->V1.DeviceStateTargetID,
+			    (NewDeviceState->DeviceState
+			     == DAC960_V1_Device_Dead
 			     ? "DEAD"
 			     : NewDeviceState->DeviceState
-			       == DAC960_Device_WriteOnly
+			       == DAC960_V1_Device_WriteOnly
 			       ? "WRITE-ONLY"
 			       : NewDeviceState->DeviceState
-				 == DAC960_Device_Online
+				 == DAC960_V1_Device_Online
 				 ? "ONLINE" : "STANDBY"));
-	  if (OldDeviceState->DeviceState == DAC960_Device_Dead &&
-	      NewDeviceState->DeviceState != DAC960_Device_Dead)
+	  if (OldDeviceState->DeviceState == DAC960_V1_Device_Dead &&
+	      NewDeviceState->DeviceState != DAC960_V1_Device_Dead)
 	    {
-	      Controller->NeedDeviceInquiryInformation = true;
-	      Controller->NeedDeviceSerialNumberInformation = true;
+	      Controller->V1.NeedDeviceInquiryInformation = true;
+	      Controller->V1.NeedDeviceSerialNumberInformation = true;
 	    }
+	  memcpy(OldDeviceState, NewDeviceState,
+		 sizeof(DAC960_V1_DeviceState_T));
 	}
-      else if (CommandOpcode == DAC960_GetLogicalDriveInformation)
+      else if (CommandOpcode == DAC960_V1_GetLogicalDriveInformation)
 	{
 	  int LogicalDriveNumber;
 	  for (LogicalDriveNumber = 0;
 	       LogicalDriveNumber < Controller->LogicalDriveCount;
 	       LogicalDriveNumber++)
 	    {
-	      DAC960_LogicalDriveInformation_T *OldLogicalDriveInformation =
-		&Controller->LogicalDriveInformation
-			     [Controller->LogicalDriveInformationIndex]
-			     [LogicalDriveNumber];
-	      DAC960_LogicalDriveInformation_T *NewLogicalDriveInformation =
-		&Controller->LogicalDriveInformation
-			     [Controller->LogicalDriveInformationIndex ^ 1]
-			     [LogicalDriveNumber];
+	      DAC960_V1_LogicalDriveInformation_T *OldLogicalDriveInformation =
+		&Controller->V1.LogicalDriveInformation[LogicalDriveNumber];
+	      DAC960_V1_LogicalDriveInformation_T *NewLogicalDriveInformation =
+		&Controller->V1.NewLogicalDriveInformation[LogicalDriveNumber];
 	      if (NewLogicalDriveInformation->LogicalDriveState !=
 		  OldLogicalDriveInformation->LogicalDriveState)
 		DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) "
@@ -2116,11 +3404,11 @@
 				Controller->ControllerNumber,
 				LogicalDriveNumber,
 				(NewLogicalDriveInformation->LogicalDriveState
-				 == DAC960_LogicalDrive_Online
+				 == DAC960_V1_LogicalDrive_Online
 				 ? "ONLINE"
 				 : NewLogicalDriveInformation->LogicalDriveState
-				 == DAC960_LogicalDrive_Critical
-				 ? "CRITICAL" : "OFFLINE"));
+				   == DAC960_V1_LogicalDrive_Critical
+				   ? "CRITICAL" : "OFFLINE"));
 	      if (NewLogicalDriveInformation->WriteBack !=
 		  OldLogicalDriveInformation->WriteBack)
 		DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) "
@@ -2131,22 +3419,24 @@
 				(NewLogicalDriveInformation->WriteBack
 				 ? "WRITE BACK" : "WRITE THRU"));
 	    }
-	  Controller->LogicalDriveInformationIndex ^= 1;
+	  memcpy(&Controller->V1.LogicalDriveInformation,
+		 &Controller->V1.NewLogicalDriveInformation,
+		 sizeof(DAC960_V1_LogicalDriveInformationArray_T));
 	}
-      else if (CommandOpcode == DAC960_GetRebuildProgress)
+      else if (CommandOpcode == DAC960_V1_GetRebuildProgress)
 	{
 	  unsigned int LogicalDriveNumber =
-	    Controller->RebuildProgress.LogicalDriveNumber;
+	    Controller->V1.RebuildProgress.LogicalDriveNumber;
 	  unsigned int LogicalDriveSize =
-	    Controller->RebuildProgress.LogicalDriveSize;
+	    Controller->V1.RebuildProgress.LogicalDriveSize;
 	  unsigned int BlocksCompleted =
-	    LogicalDriveSize - Controller->RebuildProgress.RemainingBlocks;
-	  if (CommandStatus == DAC960_NoRebuildOrCheckInProgress &&
-	      Controller->LastRebuildStatus == DAC960_NormalCompletion)
-	    CommandStatus = DAC960_RebuildSuccessful;
+	    LogicalDriveSize - Controller->V1.RebuildProgress.RemainingBlocks;
+	  if (CommandStatus == DAC960_V1_NoRebuildOrCheckInProgress &&
+	      Controller->V1.LastRebuildStatus == DAC960_V1_NormalCompletion)
+	    CommandStatus = DAC960_V1_RebuildSuccessful;
 	  switch (CommandStatus)
 	    {
-	    case DAC960_NormalCompletion:
+	    case DAC960_V1_NormalCompletion:
 	      Controller->EphemeralProgressMessage = true;
 	      DAC960_Progress("Rebuild in Progress: "
 			      "Logical Drive %d (/dev/rd/c%dd%d) "
@@ -2158,244 +3448,1068 @@
 			      / (LogicalDriveSize >> 7));
 	      Controller->EphemeralProgressMessage = false;
 	      break;
-	    case DAC960_RebuildFailed_LogicalDriveFailure:
+	    case DAC960_V1_RebuildFailed_LogicalDriveFailure:
 	      DAC960_Progress("Rebuild Failed due to "
 			      "Logical Drive Failure\n", Controller);
 	      break;
-	    case DAC960_RebuildFailed_BadBlocksOnOther:
+	    case DAC960_V1_RebuildFailed_BadBlocksOnOther:
 	      DAC960_Progress("Rebuild Failed due to "
 			      "Bad Blocks on Other Drives\n", Controller);
 	      break;
-	    case DAC960_RebuildFailed_NewDriveFailed:
+	    case DAC960_V1_RebuildFailed_NewDriveFailed:
 	      DAC960_Progress("Rebuild Failed due to "
 			      "Failure of Drive Being Rebuilt\n", Controller);
 	      break;
-	    case DAC960_NoRebuildOrCheckInProgress:
+	    case DAC960_V1_NoRebuildOrCheckInProgress:
 	      break;
-	    case DAC960_RebuildSuccessful:
+	    case DAC960_V1_RebuildSuccessful:
 	      DAC960_Progress("Rebuild Completed Successfully\n", Controller);
 	      break;
-	    case DAC960_RebuildSuccessfullyTerminated:
+	    case DAC960_V1_RebuildSuccessfullyTerminated:
 	      DAC960_Progress("Rebuild Successfully Terminated\n", Controller);
 	      break;
 	    }
-	  Controller->LastRebuildStatus = CommandStatus;
+	  Controller->V1.LastRebuildStatus = CommandStatus;
 	  if (CommandType != DAC960_MonitoringCommand &&
-	      Controller->RebuildStatusPending)
+	      Controller->V1.RebuildStatusPending)
 	    {
-	      Command->CommandStatus = Controller->PendingRebuildStatus;
-	      Controller->RebuildStatusPending = false;
+	      Command->V1.CommandStatus = Controller->V1.PendingRebuildStatus;
+	      Controller->V1.RebuildStatusPending = false;
 	    }
 	  else if (CommandType == DAC960_MonitoringCommand &&
-		   CommandStatus != DAC960_NormalCompletion &&
-		   CommandStatus != DAC960_NoRebuildOrCheckInProgress)
+		   CommandStatus != DAC960_V1_NormalCompletion &&
+		   CommandStatus != DAC960_V1_NoRebuildOrCheckInProgress)
+	    {
+	      Controller->V1.PendingRebuildStatus = CommandStatus;
+	      Controller->V1.RebuildStatusPending = true;
+	    }
+	}
+      else if (CommandOpcode == DAC960_V1_RebuildStat)
+	{
+	  unsigned int LogicalDriveNumber =
+	    Controller->V1.RebuildProgress.LogicalDriveNumber;
+	  unsigned int LogicalDriveSize =
+	    Controller->V1.RebuildProgress.LogicalDriveSize;
+	  unsigned int BlocksCompleted =
+	    LogicalDriveSize - Controller->V1.RebuildProgress.RemainingBlocks;
+	  if (CommandStatus == DAC960_V1_NormalCompletion)
+	    {
+	      Controller->EphemeralProgressMessage = true;
+	      DAC960_Progress("Consistency Check in Progress: "
+			      "Logical Drive %d (/dev/rd/c%dd%d) "
+			      "%d%% completed\n",
+			      Controller, LogicalDriveNumber,
+			      Controller->ControllerNumber,
+			      LogicalDriveNumber,
+			      (100 * (BlocksCompleted >> 7))
+			      / (LogicalDriveSize >> 7));
+	      Controller->EphemeralProgressMessage = false;
+	    }
+	}
+    }
+  if (CommandType == DAC960_MonitoringCommand)
+    {
+      if (Controller->V1.NewEventLogSequenceNumber
+	  - Controller->V1.OldEventLogSequenceNumber > 0)
+	{
+	  Command->V1.CommandMailbox.Type3E.CommandOpcode =
+	    DAC960_V1_PerformEventLogOperation;
+	  Command->V1.CommandMailbox.Type3E.OperationType =
+	    DAC960_V1_GetEventLogEntry;
+	  Command->V1.CommandMailbox.Type3E.OperationQualifier = 1;
+	  Command->V1.CommandMailbox.Type3E.SequenceNumber =
+	    Controller->V1.OldEventLogSequenceNumber;
+	  Command->V1.CommandMailbox.Type3E.BusAddress =
+	    Virtual_to_Bus(&Controller->V1.EventLogEntry);
+	  DAC960_QueueCommand(Command);
+	  return;
+	}
+      if (Controller->V1.NeedErrorTableInformation)
+	{
+	  Controller->V1.NeedErrorTableInformation = false;
+	  Command->V1.CommandMailbox.Type3.CommandOpcode =
+	    DAC960_V1_GetErrorTable;
+	  Command->V1.CommandMailbox.Type3.BusAddress =
+	    Virtual_to_Bus(&Controller->V1.NewErrorTable);
+	  DAC960_QueueCommand(Command);
+	  return;
+	}
+      if (Controller->V1.NeedRebuildProgress &&
+	  Controller->V1.RebuildProgressFirst)
+	{
+	  Controller->V1.NeedRebuildProgress = false;
+	  Command->V1.CommandMailbox.Type3.CommandOpcode =
+	    DAC960_V1_GetRebuildProgress;
+	  Command->V1.CommandMailbox.Type3.BusAddress =
+	    Virtual_to_Bus(&Controller->V1.RebuildProgress);
+	  DAC960_QueueCommand(Command);
+	  return;
+	}
+      if (Controller->V1.NeedDeviceStateInformation)
+	{
+	  if (Controller->V1.NeedDeviceInquiryInformation)
+	    {
+	      DAC960_V1_DCDB_T *DCDB = &Controller->V1.MonitoringDCDB;
+	      DAC960_SCSI_Inquiry_T *InquiryStandardData =
+		&Controller->V1.InquiryStandardData
+				[Controller->V1.DeviceStateChannel]
+				[Controller->V1.DeviceStateTargetID];
+	      InquiryStandardData->PeripheralDeviceType = 0x1F;
+	      Command->V1.CommandMailbox.Type3.CommandOpcode = DAC960_V1_DCDB;
+	      Command->V1.CommandMailbox.Type3.BusAddress =
+		Virtual_to_Bus(DCDB);
+	      DCDB->Channel = Controller->V1.DeviceStateChannel;
+	      DCDB->TargetID = Controller->V1.DeviceStateTargetID;
+	      DCDB->Direction = DAC960_V1_DCDB_DataTransferDeviceToSystem;
+	      DCDB->EarlyStatus = false;
+	      DCDB->Timeout = DAC960_V1_DCDB_Timeout_10_seconds;
+	      DCDB->NoAutomaticRequestSense = false;
+	      DCDB->DisconnectPermitted = true;
+	      DCDB->TransferLength = sizeof(DAC960_SCSI_Inquiry_T);
+	      DCDB->BusAddress = Virtual_to_Bus(InquiryStandardData);
+	      DCDB->CDBLength = 6;
+	      DCDB->TransferLengthHigh4 = 0;
+	      DCDB->SenseLength = sizeof(DCDB->SenseData);
+	      DCDB->CDB[0] = 0x12; /* INQUIRY */
+	      DCDB->CDB[1] = 0; /* EVPD = 0 */
+	      DCDB->CDB[2] = 0; /* Page Code */
+	      DCDB->CDB[3] = 0; /* Reserved */
+	      DCDB->CDB[4] = sizeof(DAC960_SCSI_Inquiry_T);
+	      DCDB->CDB[5] = 0; /* Control */
+	      DAC960_QueueCommand(Command);
+	      Controller->V1.NeedDeviceInquiryInformation = false;
+	      return;
+	    }
+	  if (Controller->V1.NeedDeviceSerialNumberInformation)
+	    {
+	      DAC960_V1_DCDB_T *DCDB = &Controller->V1.MonitoringDCDB;
+	      DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber =
+		&Controller->V1.InquiryUnitSerialNumber
+				[Controller->V1.DeviceStateChannel]
+				[Controller->V1.DeviceStateTargetID];
+	      InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F;
+	      Command->V1.CommandMailbox.Type3.CommandOpcode = DAC960_V1_DCDB;
+	      Command->V1.CommandMailbox.Type3.BusAddress =
+		Virtual_to_Bus(DCDB);
+	      DCDB->Channel = Controller->V1.DeviceStateChannel;
+	      DCDB->TargetID = Controller->V1.DeviceStateTargetID;
+	      DCDB->Direction = DAC960_V1_DCDB_DataTransferDeviceToSystem;
+	      DCDB->EarlyStatus = false;
+	      DCDB->Timeout = DAC960_V1_DCDB_Timeout_10_seconds;
+	      DCDB->NoAutomaticRequestSense = false;
+	      DCDB->DisconnectPermitted = true;
+	      DCDB->TransferLength =
+		sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T);
+	      DCDB->BusAddress = Virtual_to_Bus(InquiryUnitSerialNumber);
+	      DCDB->CDBLength = 6;
+	      DCDB->TransferLengthHigh4 = 0;
+	      DCDB->SenseLength = sizeof(DCDB->SenseData);
+	      DCDB->CDB[0] = 0x12; /* INQUIRY */
+	      DCDB->CDB[1] = 1; /* EVPD = 1 */
+	      DCDB->CDB[2] = 0x80; /* Page Code */
+	      DCDB->CDB[3] = 0; /* Reserved */
+	      DCDB->CDB[4] = sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T);
+	      DCDB->CDB[5] = 0; /* Control */
+	      DAC960_QueueCommand(Command);
+	      Controller->V1.NeedDeviceSerialNumberInformation = false;
+	      return;
+	    }
+	  if (++Controller->V1.DeviceStateTargetID == Controller->Targets)
+	    {
+	      Controller->V1.DeviceStateChannel++;
+	      Controller->V1.DeviceStateTargetID = 0;
+	    }
+	  while (Controller->V1.DeviceStateChannel < Controller->Channels)
+	    {
+	      DAC960_V1_DeviceState_T *OldDeviceState =
+		&Controller->V1.DeviceState[Controller->V1.DeviceStateChannel]
+					   [Controller->V1.DeviceStateTargetID];
+	      if (OldDeviceState->Present &&
+		  OldDeviceState->DeviceType == DAC960_V1_DiskType)
+		{
+		  Command->V1.CommandMailbox.Type3D.CommandOpcode =
+		    DAC960_V1_GetDeviceState;
+		  Command->V1.CommandMailbox.Type3D.Channel =
+		    Controller->V1.DeviceStateChannel;
+		  Command->V1.CommandMailbox.Type3D.TargetID =
+		    Controller->V1.DeviceStateTargetID;
+		  Command->V1.CommandMailbox.Type3D.BusAddress =
+		    Virtual_to_Bus(&Controller->V1.NewDeviceState);
+		  DAC960_QueueCommand(Command);
+		  return;
+		}
+	      if (++Controller->V1.DeviceStateTargetID == Controller->Targets)
+		{
+		  Controller->V1.DeviceStateChannel++;
+		  Controller->V1.DeviceStateTargetID = 0;
+		}
+	    }
+	  Controller->V1.NeedDeviceStateInformation = false;
+	}
+      if (Controller->V1.NeedLogicalDriveInformation)
+	{
+	  Controller->V1.NeedLogicalDriveInformation = false;
+	  Command->V1.CommandMailbox.Type3.CommandOpcode =
+	    DAC960_V1_GetLogicalDriveInformation;
+	  Command->V1.CommandMailbox.Type3.BusAddress =
+	    Virtual_to_Bus(&Controller->V1.NewLogicalDriveInformation);
+	  DAC960_QueueCommand(Command);
+	  return;
+	}
+      if (Controller->V1.NeedRebuildProgress)
+	{
+	  Controller->V1.NeedRebuildProgress = false;
+	  Command->V1.CommandMailbox.Type3.CommandOpcode =
+	    DAC960_V1_GetRebuildProgress;
+	  Command->V1.CommandMailbox.Type3.BusAddress =
+	    Virtual_to_Bus(&Controller->V1.RebuildProgress);
+	  DAC960_QueueCommand(Command);
+	  return;
+	}
+      if (Controller->V1.NeedConsistencyCheckProgress)
+	{
+	  Controller->V1.NeedConsistencyCheckProgress = false;
+	  Command->V1.CommandMailbox.Type3.CommandOpcode =
+	    DAC960_V1_RebuildStat;
+	  Command->V1.CommandMailbox.Type3.BusAddress =
+	    Virtual_to_Bus(&Controller->V1.RebuildProgress);
+	  DAC960_QueueCommand(Command);
+	  return;
+	}
+      Controller->MonitoringTimerCount++;
+      Controller->MonitoringTimer.expires =
+	jiffies + DAC960_MonitoringTimerInterval;
+      add_timer(&Controller->MonitoringTimer);
+    }
+  if (CommandType == DAC960_ImmediateCommand)
+    {
+      up(Command->Semaphore);
+      Command->Semaphore = NULL;
+      return;
+    }
+  if (CommandType == DAC960_QueuedCommand)
+    {
+      DAC960_V1_KernelCommand_T *KernelCommand = Command->V1.KernelCommand;
+      KernelCommand->CommandStatus = Command->V1.CommandStatus;
+      Command->V1.KernelCommand = NULL;
+      if (CommandOpcode == DAC960_V1_DCDB)
+	Controller->V1.DirectCommandActive[KernelCommand->DCDB->Channel]
+					  [KernelCommand->DCDB->TargetID] =
+	  false;
+      DAC960_DeallocateCommand(Command);
+      KernelCommand->CompletionFunction(KernelCommand);
+      return;
+    }
+  /*
+    Queue a Status Monitoring Command to the Controller using the just
+    completed Command if one was deferred previously due to lack of a
+    free Command when the Monitoring Timer Function was called.
+  */
+  if (Controller->MonitoringCommandDeferred)
+    {
+      Controller->MonitoringCommandDeferred = false;
+      DAC960_V1_QueueMonitoringCommand(Command);
+      return;
+    }
+  /*
+    Deallocate the Command.
+  */
+  DAC960_DeallocateCommand(Command);
+  /*
+    Wake up any processes waiting on a free Command.
+  */
+  wake_up(&Controller->CommandWaitQueue);
+}
+
+
+/*
+  DAC960_V2_ReadWriteError prints an appropriate error message for Command
+  when an error occurs on a Read or Write operation.
+*/
+
+static void DAC960_V2_ReadWriteError(DAC960_Command_T *Command)
+{
+  DAC960_Controller_T *Controller = Command->Controller;
+  unsigned char *SenseErrors[] = { "NO SENSE", "RECOVERED ERROR",
+				   "NOT READY", "MEDIUM ERROR",
+				   "HARDWARE ERROR", "ILLEGAL REQUEST",
+				   "UNIT ATTENTION", "DATA PROTECT",
+				   "BLANK CHECK", "VENDOR-SPECIFIC",
+				   "COPY ABORTED", "ABORTED COMMAND",
+				   "EQUAL", "VOLUME OVERFLOW",
+				   "MISCOMPARE", "RESERVED" };
+  unsigned char *CommandName = "UNKNOWN";
+  switch (Command->CommandType)
+    {
+    case DAC960_ReadCommand:
+    case DAC960_ReadRetryCommand:
+      CommandName = "READ";
+      break;
+    case DAC960_WriteCommand:
+    case DAC960_WriteRetryCommand:
+      CommandName = "WRITE";
+      break;
+    case DAC960_MonitoringCommand:
+    case DAC960_ImmediateCommand:
+    case DAC960_QueuedCommand:
+      break;
+    }
+  DAC960_Error("Error Condition %s on %s:\n", Controller,
+	       SenseErrors[Command->V2.RequestSense.SenseKey], CommandName);
+  DAC960_Error("  /dev/rd/c%dd%d:   absolute blocks %d..%d\n",
+	       Controller, Controller->ControllerNumber,
+	       Command->LogicalDriveNumber, Command->BlockNumber,
+	       Command->BlockNumber + Command->BlockCount - 1);
+  if (DAC960_PartitionNumber(Command->BufferHeader->b_rdev) > 0)
+    DAC960_Error("  /dev/rd/c%dd%dp%d: relative blocks %d..%d\n",
+		 Controller, Controller->ControllerNumber,
+		 Command->LogicalDriveNumber,
+		 DAC960_PartitionNumber(Command->BufferHeader->b_rdev),
+		 Command->BufferHeader->b_rsector,
+		 Command->BufferHeader->b_rsector + Command->BlockCount - 1);
+}
+
+
+/*
+  DAC960_V2_ReportEvent prints an appropriate message when a Controller Event
+  occurs.
+*/
+
+static void DAC960_V2_ReportEvent(DAC960_Controller_T *Controller,
+				  DAC960_V2_Event_T *Event)
+{
+  DAC960_SCSI_RequestSense_T *RequestSense =
+    (DAC960_SCSI_RequestSense_T *) &Event->RequestSenseData;
+  unsigned char MessageBuffer[DAC960_LineBufferSize];
+  static struct { int EventCode; unsigned char *EventMessage; } EventList[] =
+    { /* Physical Device Events (0x0000 - 0x007F) */
+      { 0x0001, "P Online" },
+      { 0x0002, "P Standby" },
+      { 0x0005, "P Automatic Rebuild Started" },
+      { 0x0006, "P Manual Rebuild Started" },
+      { 0x0007, "P Rebuild Completed" },
+      { 0x0008, "P Rebuild Cancelled" },
+      { 0x0009, "P Rebuild Failed for Unknown Reasons" },
+      { 0x000A, "P Rebuild Failed due to New Physical Device" },
+      { 0x000B, "P Rebuild Failed due to Logical Drive Failure" },
+      { 0x000C, "S Offline" },
+      { 0x000D, "P Found" },
+      { 0x000E, "P Gone" },
+      { 0x000F, "P Unconfigured" },
+      { 0x0010, "P Expand Capacity Started" },
+      { 0x0011, "P Expand Capacity Completed" },
+      { 0x0012, "P Expand Capacity Failed" },
+      { 0x0016, "P Parity Error" },
+      { 0x0017, "P Soft Error" },
+      { 0x0018, "P Miscellaneous Error" },
+      { 0x0019, "P Reset" },
+      { 0x001A, "P Active Spare Found" },
+      { 0x001B, "P Warm Spare Found" },
+      { 0x001C, "S Sense Data Received" },
+      { 0x001D, "P Initialization Started" },
+      { 0x001E, "P Initialization Completed" },
+      { 0x001F, "P Initialization Failed" },
+      { 0x0020, "P Initialization Cancelled" },
+      { 0x0021, "P Failed because Write Recovery Failed" },
+      { 0x0022, "P Failed because SCSI Bus Reset Failed" },
+      { 0x0023, "P Failed because of Double Check Condition" },
+      { 0x0024, "P Failed because Device Cannot Be Accessed" },
+      { 0x0025, "P Failed because of Gross Error on SCSI Processor" },
+      { 0x0026, "P Failed because of Bad Tag from Device" },
+      { 0x0027, "P Failed because of Command Timeout" },
+      { 0x0028, "P Failed because of System Reset" },
+      { 0x0029, "P Failed because of Busy Status or Parity Error" },
+      { 0x002A, "P Failed because Host Set Device to Failed State" },
+      { 0x002B, "P Failed because of Selection Timeout" },
+      { 0x002C, "P Failed because of SCSI Bus Phase Error" },
+      { 0x002D, "P Failed because Device Returned Unknown Status" },
+      { 0x002E, "P Failed because Device Not Ready" },
+      { 0x002F, "P Failed because Device Not Found at Startup" },
+      { 0x0030, "P Failed because COD Write Operation Failed" },
+      { 0x0031, "P Failed because BDT Write Operation Failed" },
+      { 0x0039, "P Missing at Startup" },
+      { 0x003A, "P Start Rebuild Failed due to Physical Drive Too Small" },
+      /* Logical Device Events (0x0080 - 0x00FF) */
+      { 0x0080, "M Consistency Check Started" },
+      { 0x0081, "M Consistency Check Completed" },
+      { 0x0082, "M Consistency Check Cancelled" },
+      { 0x0083, "M Consistency Check Completed With Errors" },
+      { 0x0084, "M Consistency Check Failed due to Logical Drive Failure" },
+      { 0x0085, "M Consistency Check Failed due to Physical Device Failure" },
+      { 0x0086, "L Offline" },
+      { 0x0087, "L Critical" },
+      { 0x0088, "L Online" },
+      { 0x0089, "M Automatic Rebuild Started" },
+      { 0x008A, "M Manual Rebuild Started" },
+      { 0x008B, "M Rebuild Completed" },
+      { 0x008C, "M Rebuild Cancelled" },
+      { 0x008D, "M Rebuild Failed for Unknown Reasons" },
+      { 0x008E, "M Rebuild Failed due to New Physical Device" },
+      { 0x008F, "M Rebuild Failed due to Logical Drive Failure" },
+      { 0x0090, "M Initialization Started" },
+      { 0x0091, "M Initialization Completed" },
+      { 0x0092, "M Initialization Cancelled" },
+      { 0x0093, "M Initialization Failed" },
+      { 0x0094, "L Found" },
+      { 0x0095, "L Gone" },
+      { 0x0096, "M Expand Capacity Started" },
+      { 0x0097, "M Expand Capacity Completed" },
+      { 0x0098, "M Expand Capacity Failed" },
+      { 0x0099, "L Bad Block Found" },
+      { 0x009A, "L Size Changed" },
+      { 0x009B, "L Type Changed" },
+      { 0x009C, "L Bad Data Block Found" },
+      { 0x009E, "L Read of Data Block in BDT" },
+      { 0x009F, "L Write Back Data for Disk Block Lost" },
+      /* Fault Management Events (0x0100 - 0x017F) */
+      { 0x0140, "E Fan %d Failed" },
+      { 0x0141, "E Fan %d OK" },
+      { 0x0142, "E Fan %d Not Present" },
+      { 0x0143, "E Power Supply %d Failed" },
+      { 0x0144, "E Power Supply %d OK" },
+      { 0x0145, "E Power Supply %d Not Present" },
+      { 0x0146, "E Temperature Sensor %d Failed" },
+      { 0x0147, "E Temperature Sensor %d Critical" },
+      { 0x0148, "E Temperature Sensor %d OK" },
+      { 0x0149, "E Temperature Sensor %d Not Present" },
+      { 0x014A, "E Unit %d Access Critical" },
+      { 0x014B, "E Unit %d Access OK" },
+      { 0x014C, "E Unit %d Access Offline" },
+      /* Controller Events (0x0180 - 0x01FF) */
+      { 0x0181, "C Cache Write Back Error" },
+      { 0x0188, "C Battery Backup Unit Found" },
+      { 0x0189, "C Battery Backup Unit Charge Level Low" },
+      { 0x018A, "C Battery Backup Unit Charge Level OK" },
+      { 0x0193, "C Installation Aborted" },
+      { 0x0195, "C Mirror Race Recovery In Progress" },
+      { 0x0196, "C Mirror Race on Critical Drive" },
+      { 0x019E, "C Memory Soft ECC Error" },
+      { 0x019F, "C Memory Hard ECC Error" },
+      { 0x01A2, "C Battery Backup Unit Failed" },
+      { 0, "" } };
+  int EventListIndex = 0, EventCode;
+  unsigned char EventType, *EventMessage;
+  if (Event->EventCode == 0x1C &&
+      RequestSense->SenseKey == DAC960_SenseKey_VendorSpecific &&
+      (RequestSense->AdditionalSenseCode == 0x80 ||
+       RequestSense->AdditionalSenseCode == 0x81))
+    Event->EventCode = ((RequestSense->AdditionalSenseCode - 0x80) << 8) |
+		       RequestSense->AdditionalSenseCodeQualifier;
+  while (true)
+    {
+      EventCode = EventList[EventListIndex].EventCode;
+      if (EventCode == Event->EventCode || EventCode == 0) break;
+      EventListIndex++;
+    }
+  EventType = EventList[EventListIndex].EventMessage[0];
+  EventMessage = &EventList[EventListIndex].EventMessage[2];
+  if (EventCode == 0)
+    {
+      DAC960_Critical("Unknown Controller Event Code %04X\n",
+		      Controller, Event->EventCode);
+      return;
+    }
+  switch (EventType)
+    {
+    case 'P':
+      DAC960_Critical("Physical Device %d:%d %s\n", Controller,
+		      Event->Channel, Event->TargetID, EventMessage);
+      break;
+    case 'L':
+      DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) %s\n", Controller,
+		      Event->LogicalUnit, Controller->ControllerNumber,
+		      Event->LogicalUnit, EventMessage);
+      break;
+    case 'M':
+      DAC960_Progress("Logical Drive %d (/dev/rd/c%dd%d) %s\n", Controller,
+		      Event->LogicalUnit, Controller->ControllerNumber,
+		      Event->LogicalUnit, EventMessage);
+      break;
+    case 'S':
+      if (RequestSense->SenseKey == DAC960_SenseKey_NoSense ||
+	  (RequestSense->SenseKey == DAC960_SenseKey_NotReady &&
+	   RequestSense->AdditionalSenseCode == 0x04 &&
+	   (RequestSense->AdditionalSenseCodeQualifier == 0x01 ||
+	    RequestSense->AdditionalSenseCodeQualifier == 0x02)))
+	break;
+      DAC960_Critical("Physical Device %d:%d %s\n", Controller,
+		      Event->Channel, Event->TargetID, EventMessage);
+      DAC960_Critical("Physical Device %d:%d Request Sense: "
+		      "Sense Key = %d, ASC = %02X, ASCQ = %02X\n",
+		      Controller,
+		      Event->Channel,
+		      Event->TargetID,
+		      RequestSense->SenseKey,
+		      RequestSense->AdditionalSenseCode,
+		      RequestSense->AdditionalSenseCodeQualifier);
+      DAC960_Critical("Physical Device %d:%d Request Sense: "
+		      "Information = %02X%02X%02X%02X "
+		      "%02X%02X%02X%02X\n",
+		      Controller,
+		      Event->Channel,
+		      Event->TargetID,
+		      RequestSense->Information[0],
+		      RequestSense->Information[1],
+		      RequestSense->Information[2],
+		      RequestSense->Information[3],
+		      RequestSense->CommandSpecificInformation[0],
+		      RequestSense->CommandSpecificInformation[1],
+		      RequestSense->CommandSpecificInformation[2],
+		      RequestSense->CommandSpecificInformation[3]);
+      break;
+    case 'E':
+      if (Controller->SuppressEnclosureMessages) break;
+      sprintf(MessageBuffer, EventMessage, Event->LogicalUnit);
+      DAC960_Critical("Enclosure %d %s\n", Controller,
+		      Event->TargetID, MessageBuffer);
+      break;
+    case 'C':
+      DAC960_Critical("Controller %s\n", Controller, EventMessage);
+      break;
+    default:
+      DAC960_Critical("Unknown Controller Event Code %04X\n",
+		      Controller, Event->EventCode);
+      break;
+    }
+}
+
+
+/*
+  DAC960_V2_ReportProgress prints an appropriate progress message for
+  Logical Device Long Operations.
+*/
+
+static void DAC960_V2_ReportProgress(DAC960_Controller_T *Controller,
+				     unsigned char *MessageString,
+				     unsigned int LogicalDeviceNumber,
+				     unsigned long BlocksCompleted,
+				     unsigned long LogicalDeviceSize)
+{
+  Controller->EphemeralProgressMessage = true;
+  DAC960_Progress("%s in Progress: Logical Drive %d (/dev/rd/c%dd%d) "
+		  "%d%% completed\n", Controller,
+		  MessageString,
+		  LogicalDeviceNumber,
+		  Controller->ControllerNumber,
+		  LogicalDeviceNumber,
+		  (100 * (BlocksCompleted >> 7)) / (LogicalDeviceSize >> 7));
+  Controller->EphemeralProgressMessage = false;
+}
+
+
+/*
+  DAC960_V2_ProcessCompletedCommand performs completion processing for Command
+  for DAC960 V2 Firmware Controllers.
+*/
+
+static void DAC960_V2_ProcessCompletedCommand(DAC960_Command_T *Command)
+{
+  DAC960_Controller_T *Controller = Command->Controller;
+  DAC960_CommandType_T CommandType = Command->CommandType;
+  DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
+  DAC960_V2_IOCTL_Opcode_T CommandOpcode = CommandMailbox->Common.IOCTL_Opcode;
+  DAC960_V2_CommandStatus_T CommandStatus = Command->V2.CommandStatus;
+  BufferHeader_T *BufferHeader = Command->BufferHeader;
+  if (CommandType == DAC960_ReadCommand ||
+      CommandType == DAC960_WriteCommand)
+    {
+      if (CommandStatus == DAC960_V2_NormalCompletion)
+	{
+	  /*
+	    Perform completion processing for all buffers in this I/O Request.
+	  */
+	  while (BufferHeader != NULL)
+	    {
+	      BufferHeader_T *NextBufferHeader = BufferHeader->b_reqnext;
+	      BufferHeader->b_reqnext = NULL;
+	      DAC960_ProcessCompletedBuffer(BufferHeader, true);
+	      BufferHeader = NextBufferHeader;
+	    }
+	  /*
+	    Wake up requestor for swap file paging requests.
+	  */
+	  if (Command->Semaphore != NULL)
 	    {
-	      Controller->PendingRebuildStatus = CommandStatus;
-	      Controller->RebuildStatusPending = true;
+	      up(Command->Semaphore);
+	      Command->Semaphore = NULL;
 	    }
+	  add_blkdev_randomness(DAC960_MAJOR + Controller->ControllerNumber);
 	}
-      else if (CommandOpcode == DAC960_RebuildStat)
+      else if (Command->V2.RequestSense.SenseKey
+	       == DAC960_SenseKey_MediumError &&
+	       BufferHeader != NULL &&
+	       BufferHeader->b_reqnext != NULL)
 	{
-	  unsigned int LogicalDriveNumber =
-	    Controller->RebuildProgress.LogicalDriveNumber;
-	  unsigned int LogicalDriveSize =
-	    Controller->RebuildProgress.LogicalDriveSize;
-	  unsigned int BlocksCompleted =
-	    LogicalDriveSize - Controller->RebuildProgress.RemainingBlocks;
-	  if (CommandStatus == DAC960_NormalCompletion)
+	  if (CommandType == DAC960_ReadCommand)
+	    Command->CommandType = DAC960_ReadRetryCommand;
+	  else Command->CommandType = DAC960_WriteRetryCommand;
+	  Command->BlockCount = BufferHeader->b_size >> DAC960_BlockSizeBits;
+	  CommandMailbox->SCSI_10.CommandControlBits
+				 .AdditionalScatterGatherListMemory = false;
+	  CommandMailbox->SCSI_10.DataTransferSize =
+	    Command->BlockCount << DAC960_BlockSizeBits;
+	  CommandMailbox->SCSI_10.DataTransferMemoryAddress
+				 .ScatterGatherSegments[0].SegmentDataPointer =
+	    Virtual_to_Bus(BufferHeader->b_data);
+	  CommandMailbox->SCSI_10.DataTransferMemoryAddress
+				 .ScatterGatherSegments[0].SegmentByteCount =
+	    CommandMailbox->SCSI_10.DataTransferSize;
+	  CommandMailbox->SCSI_10.SCSI_CDB[7] = Command->BlockCount >> 8;
+	  CommandMailbox->SCSI_10.SCSI_CDB[8] = Command->BlockCount;
+	  DAC960_QueueCommand(Command);
+	  return;
+	}
+      else
+	{
+	  if (Command->V2.RequestSense.SenseKey != DAC960_SenseKey_NotReady)
+	    DAC960_V2_ReadWriteError(Command);
+	  /*
+	    Perform completion processing for all buffers in this I/O Request.
+	  */
+	  while (BufferHeader != NULL)
 	    {
-	      Controller->EphemeralProgressMessage = true;
-	      DAC960_Progress("Consistency Check in Progress: "
-			      "Logical Drive %d (/dev/rd/c%dd%d) "
-			      "%d%% completed\n",
-			      Controller, LogicalDriveNumber,
-			      Controller->ControllerNumber,
-			      LogicalDriveNumber,
-			      (100 * (BlocksCompleted >> 7))
-			      / (LogicalDriveSize >> 7));
-	      Controller->EphemeralProgressMessage = false;
+	      BufferHeader_T *NextBufferHeader = BufferHeader->b_reqnext;
+	      BufferHeader->b_reqnext = NULL;
+	      DAC960_ProcessCompletedBuffer(BufferHeader, false);
+	      BufferHeader = NextBufferHeader;
+	    }
+	  /*
+	    Wake up requestor for swap file paging requests.
+	  */
+	  if (Command->Semaphore != NULL)
+	    {
+	      up(Command->Semaphore);
+	      Command->Semaphore = NULL;
 	    }
 	}
     }
-  if (CommandType == DAC960_MonitoringCommand)
+  else if (CommandType == DAC960_ReadRetryCommand ||
+	   CommandType == DAC960_WriteRetryCommand)
     {
-      if (Controller->NewEventLogSequenceNumber
-	  - Controller->OldEventLogSequenceNumber > 0)
+      BufferHeader_T *NextBufferHeader = BufferHeader->b_reqnext;
+      BufferHeader->b_reqnext = NULL;
+      /*
+	Perform completion processing for this single buffer.
+      */
+      if (CommandStatus == DAC960_V2_NormalCompletion)
+	DAC960_ProcessCompletedBuffer(BufferHeader, true);
+      else
 	{
-	  Command->CommandMailbox.Type3E.CommandOpcode =
-	    DAC960_PerformEventLogOperation;
-	  Command->CommandMailbox.Type3E.OperationType =
-	    DAC960_GetEventLogEntry;
-	  Command->CommandMailbox.Type3E.OperationQualifier = 1;
-	  Command->CommandMailbox.Type3E.SequenceNumber =
-	    Controller->OldEventLogSequenceNumber;
-	  Command->CommandMailbox.Type3E.BusAddress =
-	    Virtual_to_Bus(&Controller->EventLogEntry);
-	  DAC960_QueueCommand(Command);
-	  return;
+	  if (Command->V2.RequestSense.SenseKey != DAC960_SenseKey_NotReady)
+	    DAC960_V2_ReadWriteError(Command);
+	  DAC960_ProcessCompletedBuffer(BufferHeader, false);
 	}
-      if (Controller->NeedErrorTableInformation)
+      if (NextBufferHeader != NULL)
 	{
-	  Controller->NeedErrorTableInformation = false;
-	  Command->CommandMailbox.Type3.CommandOpcode = DAC960_GetErrorTable;
-	  Command->CommandMailbox.Type3.BusAddress =
-	    Virtual_to_Bus(
-	      &Controller->ErrorTable[Controller->ErrorTableIndex ^ 1]);
-	  DAC960_QueueCommand(Command);
-	  return;
-	}
-      if (Controller->NeedRebuildProgress && 
-	  Controller->Enquiry[Controller->EnquiryIndex]
-		      .CriticalLogicalDriveCount <
-	  Controller->Enquiry[Controller->EnquiryIndex ^ 1]
-		      .CriticalLogicalDriveCount)
-	{
-	  Controller->NeedRebuildProgress = false;
-	  Command->CommandMailbox.Type3.CommandOpcode =
-	    DAC960_GetRebuildProgress;
-	  Command->CommandMailbox.Type3.BusAddress =
-	    Virtual_to_Bus(&Controller->RebuildProgress);
+	  Command->BlockNumber +=
+	    BufferHeader->b_size >> DAC960_BlockSizeBits;
+	  Command->BlockCount =
+	    NextBufferHeader->b_size >> DAC960_BlockSizeBits;
+	  Command->BufferHeader = NextBufferHeader;
+	  CommandMailbox->SCSI_10.DataTransferSize =
+	    Command->BlockCount << DAC960_BlockSizeBits;
+	  CommandMailbox->SCSI_10.DataTransferMemoryAddress
+				 .ScatterGatherSegments[0]
+				 .SegmentDataPointer =
+	    Virtual_to_Bus(NextBufferHeader->b_data);
+	  CommandMailbox->SCSI_10.DataTransferMemoryAddress
+				 .ScatterGatherSegments[0]
+				 .SegmentByteCount =
+	    CommandMailbox->SCSI_10.DataTransferSize;
+	  CommandMailbox->SCSI_10.SCSI_CDB[2] = Command->BlockNumber >> 24;
+	  CommandMailbox->SCSI_10.SCSI_CDB[3] = Command->BlockNumber >> 16;
+	  CommandMailbox->SCSI_10.SCSI_CDB[4] = Command->BlockNumber >> 8;
+	  CommandMailbox->SCSI_10.SCSI_CDB[5] = Command->BlockNumber;
+	  CommandMailbox->SCSI_10.SCSI_CDB[7] = Command->BlockCount >> 8;
+	  CommandMailbox->SCSI_10.SCSI_CDB[8] = Command->BlockCount;
 	  DAC960_QueueCommand(Command);
 	  return;
 	}
-      if (Controller->NeedDeviceStateInformation)
+    }
+  else if (CommandType == DAC960_MonitoringCommand)
+    {
+      if (CommandOpcode == DAC960_V2_GetControllerInfo)
 	{
-	  if (Controller->NeedDeviceInquiryInformation)
+	  DAC960_V2_ControllerInfo_T *NewControllerInfo =
+	    &Controller->V2.NewControllerInformation;
+	  DAC960_V2_ControllerInfo_T *ControllerInfo =
+	    &Controller->V2.ControllerInformation;
+	  Controller->LogicalDriveCount =
+	    NewControllerInfo->LogicalDevicesPresent;
+	  Controller->V2.NeedLogicalDeviceInformation = true;
+	  Controller->V2.NewLogicalDeviceInformation.LogicalDeviceNumber = 0;
+	  Controller->V2.NeedPhysicalDeviceInformation = true;
+	  Controller->V2.PhysicalDeviceIndex = 0;
+	  Controller->V2.NewPhysicalDeviceInformation.Channel = 0;
+	  Controller->V2.NewPhysicalDeviceInformation.TargetID = 0;
+	  Controller->V2.NewPhysicalDeviceInformation.LogicalUnit = 0;
+	  Controller->MonitoringAlertMode =
+	    (NewControllerInfo->LogicalDevicesCritical > 0 ||
+	     NewControllerInfo->LogicalDevicesOffline > 0 ||
+	     NewControllerInfo->PhysicalDisksCritical > 0 ||
+	     NewControllerInfo->PhysicalDisksOffline > 0);
+	  memcpy(ControllerInfo, NewControllerInfo,
+		 sizeof(DAC960_V2_ControllerInfo_T));
+	}
+      else if (CommandOpcode == DAC960_V2_GetEvent)
+	{
+	  if (CommandStatus == DAC960_V2_NormalCompletion)
+	    DAC960_V2_ReportEvent(Controller, &Controller->V2.Event);
+	  Controller->V2.NextEventSequenceNumber++;
+	}
+      else if (CommandOpcode == DAC960_V2_GetPhysicalDeviceInfoValid &&
+	       CommandStatus == DAC960_V2_NormalCompletion)
+	{
+	  DAC960_V2_PhysicalDeviceInfo_T *NewPhysicalDeviceInfo =
+	    &Controller->V2.NewPhysicalDeviceInformation;
+	  unsigned int PhysicalDeviceIndex = Controller->V2.PhysicalDeviceIndex;
+	  DAC960_V2_PhysicalDeviceInfo_T *PhysicalDeviceInfo =
+	    Controller->V2.PhysicalDeviceInformation[PhysicalDeviceIndex];
+	  DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber;
+	  if (PhysicalDeviceInfo == NULL ||
+	      (NewPhysicalDeviceInfo->Channel !=
+	       PhysicalDeviceInfo->Channel) ||
+	      (NewPhysicalDeviceInfo->TargetID !=
+	       PhysicalDeviceInfo->TargetID) ||
+	      (NewPhysicalDeviceInfo->LogicalUnit !=
+	       PhysicalDeviceInfo->LogicalUnit))
 	    {
-	      DAC960_DCDB_T *DCDB = &Controller->MonitoringDCDB;
-	      DAC960_SCSI_Inquiry_T *InquiryStandardData =
-		&Controller->InquiryStandardData
-			       [Controller->DeviceStateChannel]
-			       [Controller->DeviceStateTargetID];
-	      InquiryStandardData->PeripheralDeviceType = 0x1F;
-	      Command->CommandMailbox.Type3.CommandOpcode = DAC960_DCDB;
-	      Command->CommandMailbox.Type3.BusAddress = Virtual_to_Bus(DCDB);
-	      DCDB->Channel = Controller->DeviceStateChannel;
-	      DCDB->TargetID = Controller->DeviceStateTargetID;
-	      DCDB->Direction = DAC960_DCDB_DataTransferDeviceToSystem;
-	      DCDB->EarlyStatus = false;
-	      DCDB->Timeout = DAC960_DCDB_Timeout_10_seconds;
-	      DCDB->NoAutomaticRequestSense = false;
-	      DCDB->DisconnectPermitted = true;
-	      DCDB->TransferLength = sizeof(DAC960_SCSI_Inquiry_T);
-	      DCDB->BusAddress = Virtual_to_Bus(InquiryStandardData);
-	      DCDB->CDBLength = 6;
-	      DCDB->TransferLengthHigh4 = 0;
-	      DCDB->SenseLength = sizeof(DCDB->SenseData);
-	      DCDB->CDB[0] = 0x12; /* INQUIRY */
-	      DCDB->CDB[1] = 0; /* EVPD = 0 */
-	      DCDB->CDB[2] = 0; /* Page Code */
-	      DCDB->CDB[3] = 0; /* Reserved */
-	      DCDB->CDB[4] = sizeof(DAC960_SCSI_Inquiry_T);
-	      DCDB->CDB[5] = 0; /* Control */
-	      DAC960_QueueCommand(Command);
-	      Controller->NeedDeviceInquiryInformation = false;
-	      return;
+	      unsigned int DeviceIndex;
+	      PhysicalDeviceInfo = (DAC960_V2_PhysicalDeviceInfo_T *)
+		kmalloc(sizeof(DAC960_V2_PhysicalDeviceInfo_T), GFP_ATOMIC);
+	      InquiryUnitSerialNumber =
+		(DAC960_SCSI_Inquiry_UnitSerialNumber_T *)
+		  kmalloc(sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T),
+			  GFP_ATOMIC);
+	      if (InquiryUnitSerialNumber == NULL)
+		{
+		  kfree(PhysicalDeviceInfo);
+		  PhysicalDeviceInfo = NULL;
+		}
+	      DAC960_Critical("Physical Device %d:%d Now Exists%s\n",
+			      Controller,
+			      NewPhysicalDeviceInfo->Channel,
+			      NewPhysicalDeviceInfo->TargetID,
+			      (PhysicalDeviceInfo != NULL
+			       ? "" : " - Allocation Failed"));
+	      if (PhysicalDeviceInfo != NULL)
+		{
+		  for (DeviceIndex = PhysicalDeviceIndex;
+		       DeviceIndex < DAC960_V2_MaxPhysicalDevices - 1;
+		       DeviceIndex++)
+		    {
+		      Controller->V2.PhysicalDeviceInformation[DeviceIndex+1] =
+			Controller->V2.PhysicalDeviceInformation[DeviceIndex];
+		      Controller->V2.InquiryUnitSerialNumber[DeviceIndex+1] =
+			Controller->V2.InquiryUnitSerialNumber[DeviceIndex];
+		      Controller->V2.PhysicalDeviceInformation
+				     [PhysicalDeviceIndex] =
+			PhysicalDeviceInfo;
+		      Controller->V2.InquiryUnitSerialNumber
+				     [PhysicalDeviceIndex] =
+			InquiryUnitSerialNumber;
+		    }
+		  memset(PhysicalDeviceInfo, 0,
+			 sizeof(DAC960_V2_PhysicalDeviceInfo_T));
+		  PhysicalDeviceInfo->PhysicalDeviceState =
+		    DAC960_V2_Device_InvalidState;
+		  memset(InquiryUnitSerialNumber, 0,
+			 sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T));
+		  InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F;
+		  Controller->V2.NeedDeviceSerialNumberInformation = true;
+		}
 	    }
-	  if (Controller->NeedDeviceSerialNumberInformation)
+	  if (PhysicalDeviceInfo != NULL)
 	    {
-	      DAC960_DCDB_T *DCDB = &Controller->MonitoringDCDB;
-	      DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber =
-		&Controller->InquiryUnitSerialNumber
-			       [Controller->DeviceStateChannel]
-			       [Controller->DeviceStateTargetID];
-	      InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F;
-	      Command->CommandMailbox.Type3.CommandOpcode = DAC960_DCDB;
-	      Command->CommandMailbox.Type3.BusAddress = Virtual_to_Bus(DCDB);
-	      DCDB->Channel = Controller->DeviceStateChannel;
-	      DCDB->TargetID = Controller->DeviceStateTargetID;
-	      DCDB->Direction = DAC960_DCDB_DataTransferDeviceToSystem;
-	      DCDB->EarlyStatus = false;
-	      DCDB->Timeout = DAC960_DCDB_Timeout_10_seconds;
-	      DCDB->NoAutomaticRequestSense = false;
-	      DCDB->DisconnectPermitted = true;
-	      DCDB->TransferLength =
-		sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T);
-	      DCDB->BusAddress = Virtual_to_Bus(InquiryUnitSerialNumber);
-	      DCDB->CDBLength = 6;
-	      DCDB->TransferLengthHigh4 = 0;
-	      DCDB->SenseLength = sizeof(DCDB->SenseData);
-	      DCDB->CDB[0] = 0x12; /* INQUIRY */
-	      DCDB->CDB[1] = 1; /* EVPD = 1 */
-	      DCDB->CDB[2] = 0x80; /* Page Code */
-	      DCDB->CDB[3] = 0; /* Reserved */
-	      DCDB->CDB[4] = sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T);
-	      DCDB->CDB[5] = 0; /* Control */
-	      DAC960_QueueCommand(Command);
-	      Controller->NeedDeviceSerialNumberInformation = false;
-	      return;
+	      if (NewPhysicalDeviceInfo->PhysicalDeviceState !=
+		  PhysicalDeviceInfo->PhysicalDeviceState)
+		DAC960_Critical("Physical Device %d:%d is now %s\n", Controller,
+				NewPhysicalDeviceInfo->Channel,
+				NewPhysicalDeviceInfo->TargetID,
+				(NewPhysicalDeviceInfo->PhysicalDeviceState
+				 == DAC960_V2_Device_Unconfigured
+				 ? "UNCONFIGURED"
+				 : NewPhysicalDeviceInfo->PhysicalDeviceState
+				   == DAC960_V2_Device_Online
+				   ? "ONLINE"
+				   : NewPhysicalDeviceInfo->PhysicalDeviceState
+				     == DAC960_V2_Device_WriteOnly
+				     ? "WRITE-ONLY"
+				     : NewPhysicalDeviceInfo
+				       ->PhysicalDeviceState
+				       == DAC960_V2_Device_Dead
+				       ? "DEAD" : "STANDBY"));
+	      if ((NewPhysicalDeviceInfo->ParityErrors !=
+		   PhysicalDeviceInfo->ParityErrors) ||
+		  (NewPhysicalDeviceInfo->SoftErrors !=
+		   PhysicalDeviceInfo->SoftErrors) ||
+		  (NewPhysicalDeviceInfo->HardErrors !=
+		   PhysicalDeviceInfo->HardErrors) ||
+		  (NewPhysicalDeviceInfo->MiscellaneousErrors !=
+		   PhysicalDeviceInfo->MiscellaneousErrors) ||
+		  (NewPhysicalDeviceInfo->CommandTimeouts !=
+		   PhysicalDeviceInfo->CommandTimeouts) ||
+		  (NewPhysicalDeviceInfo->Retries !=
+		   PhysicalDeviceInfo->Retries) ||
+		  (NewPhysicalDeviceInfo->Aborts !=
+		   PhysicalDeviceInfo->Aborts) ||
+		  (NewPhysicalDeviceInfo->PredictedFailuresDetected !=
+		   PhysicalDeviceInfo->PredictedFailuresDetected))
+		{
+		  DAC960_Critical("Physical Device %d:%d Errors: "
+				  "Parity = %d, Soft = %d, "
+				  "Hard = %d, Misc = %d\n",
+				  Controller,
+				  NewPhysicalDeviceInfo->Channel,
+				  NewPhysicalDeviceInfo->TargetID,
+				  NewPhysicalDeviceInfo->ParityErrors,
+				  NewPhysicalDeviceInfo->SoftErrors,
+				  NewPhysicalDeviceInfo->HardErrors,
+				  NewPhysicalDeviceInfo->MiscellaneousErrors);
+		  DAC960_Critical("Physical Device %d:%d Errors: "
+				  "Timeouts = %d, Retries = %d, "
+				  "Aborts = %d, Predicted = %d\n",
+				  Controller,
+				  NewPhysicalDeviceInfo->Channel,
+				  NewPhysicalDeviceInfo->TargetID,
+				  NewPhysicalDeviceInfo->CommandTimeouts,
+				  NewPhysicalDeviceInfo->Retries,
+				  NewPhysicalDeviceInfo->Aborts,
+				  NewPhysicalDeviceInfo
+				  ->PredictedFailuresDetected);
+		}
+	      if (PhysicalDeviceInfo->PhysicalDeviceState
+		  == DAC960_V2_Device_Dead &&
+		  NewPhysicalDeviceInfo->PhysicalDeviceState
+		  != DAC960_V2_Device_Dead)
+		Controller->V2.NeedDeviceSerialNumberInformation = true;
+	      memcpy(PhysicalDeviceInfo, NewPhysicalDeviceInfo,
+		     sizeof(DAC960_V2_PhysicalDeviceInfo_T));
 	    }
-	  if (++Controller->DeviceStateTargetID == DAC960_MaxTargets)
+	  NewPhysicalDeviceInfo->LogicalUnit++;
+	  Controller->V2.PhysicalDeviceIndex++;
+	}
+      else if (CommandOpcode == DAC960_V2_GetPhysicalDeviceInfoValid)
+	Controller->V2.NeedPhysicalDeviceInformation = false;
+      else if (CommandOpcode == DAC960_V2_GetLogicalDeviceInfoValid &&
+	       CommandStatus == DAC960_V2_NormalCompletion)
+	{
+	  DAC960_V2_LogicalDeviceInfo_T *NewLogicalDeviceInfo =
+	    &Controller->V2.NewLogicalDeviceInformation;
+	  unsigned short LogicalDeviceNumber =
+	    NewLogicalDeviceInfo->LogicalDeviceNumber;
+	  DAC960_V2_LogicalDeviceInfo_T *LogicalDeviceInfo =
+	    Controller->V2.LogicalDeviceInformation[LogicalDeviceNumber];
+	  if (LogicalDeviceInfo == NULL)
 	    {
-	      Controller->DeviceStateChannel++;
-	      Controller->DeviceStateTargetID = 0;
+	      DAC960_V2_PhysicalDevice_T PhysicalDevice;
+	      PhysicalDevice.Controller = 0;
+	      PhysicalDevice.Channel = NewLogicalDeviceInfo->Channel;
+	      PhysicalDevice.TargetID = NewLogicalDeviceInfo->TargetID;
+	      PhysicalDevice.LogicalUnit = NewLogicalDeviceInfo->LogicalUnit;
+	      Controller->V2.LogicalDriveToVirtualDevice[LogicalDeviceNumber] =
+		PhysicalDevice;
+	      LogicalDeviceInfo = (DAC960_V2_LogicalDeviceInfo_T *)
+		kmalloc(sizeof(DAC960_V2_LogicalDeviceInfo_T), GFP_ATOMIC);
+	      Controller->V2.LogicalDeviceInformation[LogicalDeviceNumber] =
+		LogicalDeviceInfo;
+	      DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) "
+			      "Now Exists%s\n", Controller,
+			      LogicalDeviceNumber,
+			      Controller->ControllerNumber,
+			      LogicalDeviceNumber,
+			      (LogicalDeviceInfo != NULL
+			       ? "" : " - Allocation Failed"));
+	      if (LogicalDeviceInfo != NULL)
+		memset(LogicalDeviceInfo, 0,
+		       sizeof(DAC960_V2_LogicalDeviceInfo_T));
 	    }
-	  while (Controller->DeviceStateChannel < Controller->Channels)
+	  if (LogicalDeviceInfo != NULL)
 	    {
-	      DAC960_DeviceState_T *OldDeviceState =
-		&Controller->DeviceState[Controller->DeviceStateIndex]
-					[Controller->DeviceStateChannel]
-					[Controller->DeviceStateTargetID];
-	      if (OldDeviceState->Present &&
-		  OldDeviceState->DeviceType == DAC960_DiskType)
-		{
-		  Command->CommandMailbox.Type3D.CommandOpcode =
-		    DAC960_GetDeviceState;
-		  Command->CommandMailbox.Type3D.Channel =
-		    Controller->DeviceStateChannel;
-		  Command->CommandMailbox.Type3D.TargetID =
-		    Controller->DeviceStateTargetID;
-		  Command->CommandMailbox.Type3D.BusAddress =
-		    Virtual_to_Bus(&Controller->DeviceState
-				      [Controller->DeviceStateIndex ^ 1]
-				      [Controller->DeviceStateChannel]
-				      [Controller->DeviceStateTargetID]);
-		  DAC960_QueueCommand(Command);
-		  return;
-		}
-	      if (++Controller->DeviceStateTargetID == DAC960_MaxTargets)
-		{
-		  Controller->DeviceStateChannel++;
-		  Controller->DeviceStateTargetID = 0;
-		}
+	      unsigned long LogicalDeviceSize =
+		NewLogicalDeviceInfo->ConfigurableDeviceSizeIn512ByteBlocksOrMB;
+	      if (NewLogicalDeviceInfo->LogicalDeviceState !=
+		  LogicalDeviceInfo->LogicalDeviceState)
+		DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) "
+				"is now %s\n", Controller,
+				LogicalDeviceNumber,
+				Controller->ControllerNumber,
+				LogicalDeviceNumber,
+				(NewLogicalDeviceInfo->LogicalDeviceState
+				 == DAC960_V2_LogicalDevice_Online
+				 ? "ONLINE"
+				 : NewLogicalDeviceInfo->LogicalDeviceState
+				   == DAC960_V2_LogicalDevice_Critical
+				   ? "CRITICAL" : "OFFLINE"));
+	      if ((NewLogicalDeviceInfo->SoftErrors !=
+		   LogicalDeviceInfo->SoftErrors) ||
+		  (NewLogicalDeviceInfo->CommandsFailed !=
+		   LogicalDeviceInfo->CommandsFailed) ||
+		  (NewLogicalDeviceInfo->DeferredWriteErrors !=
+		   LogicalDeviceInfo->DeferredWriteErrors))
+		DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) Errors: "
+				"Soft = %d, Failed = %d, Deferred Write = %d\n",
+				Controller, LogicalDeviceNumber,
+				Controller->ControllerNumber,
+				LogicalDeviceNumber,
+				NewLogicalDeviceInfo->SoftErrors,
+				NewLogicalDeviceInfo->CommandsFailed,
+				NewLogicalDeviceInfo->DeferredWriteErrors);
+	      if (NewLogicalDeviceInfo->ConsistencyCheckInProgress)
+		DAC960_V2_ReportProgress(Controller,
+					 "Consistency Check",
+					 LogicalDeviceNumber,
+					 NewLogicalDeviceInfo
+					 ->ConsistencyCheckBlockNumber,
+					 LogicalDeviceSize);
+	      else if (NewLogicalDeviceInfo->RebuildInProgress)
+		DAC960_V2_ReportProgress(Controller,
+					 "Rebuild",
+					 LogicalDeviceNumber,
+					 NewLogicalDeviceInfo
+					 ->RebuildBlockNumber,
+					 LogicalDeviceSize);
+	      else if (NewLogicalDeviceInfo->BackgroundInitializationInProgress)
+		DAC960_V2_ReportProgress(Controller,
+					 "Background Initialization",
+					 LogicalDeviceNumber,
+					 NewLogicalDeviceInfo
+					 ->BackgroundInitializationBlockNumber,
+					 LogicalDeviceSize);
+	      else if (NewLogicalDeviceInfo->ForegroundInitializationInProgress)
+		DAC960_V2_ReportProgress(Controller,
+					 "Foreground Initialization",
+					 LogicalDeviceNumber,
+					 NewLogicalDeviceInfo
+					 ->ForegroundInitializationBlockNumber,
+					 LogicalDeviceSize);
+	      else if (NewLogicalDeviceInfo->DataMigrationInProgress)
+		DAC960_V2_ReportProgress(Controller,
+					 "Data Migration",
+					 LogicalDeviceNumber,
+					 NewLogicalDeviceInfo
+					 ->DataMigrationBlockNumber,
+					 LogicalDeviceSize);
+	      else if (NewLogicalDeviceInfo->PatrolOperationInProgress)
+		DAC960_V2_ReportProgress(Controller,
+					 "Patrol Operation",
+					 LogicalDeviceNumber,
+					 NewLogicalDeviceInfo
+					 ->PatrolOperationBlockNumber,
+					 LogicalDeviceSize);
+	      memcpy(LogicalDeviceInfo, NewLogicalDeviceInfo,
+		     sizeof(DAC960_V2_LogicalDeviceInfo_T));
 	    }
-	  Controller->NeedDeviceStateInformation = false;
-	  Controller->DeviceStateIndex ^= 1;
+	  NewLogicalDeviceInfo->LogicalDeviceNumber++;
 	}
-      if (Controller->NeedLogicalDriveInformation)
-	{
-	  Controller->NeedLogicalDriveInformation = false;
-	  Command->CommandMailbox.Type3.CommandOpcode =
-	    DAC960_GetLogicalDriveInformation;
-	  Command->CommandMailbox.Type3.BusAddress =
-	    Virtual_to_Bus(
-	      &Controller->LogicalDriveInformation
-			   [Controller->LogicalDriveInformationIndex ^ 1]);
+      else if (CommandOpcode == DAC960_V2_GetLogicalDeviceInfoValid)
+	Controller->V2.NeedLogicalDeviceInformation = false;
+      if (Controller->V2.HealthStatusBuffer->NextEventSequenceNumber
+	  - Controller->V2.NextEventSequenceNumber > 0)
+	{
+	  CommandMailbox->GetEvent.CommandOpcode = DAC960_V2_IOCTL;
+	  CommandMailbox->GetEvent.DataTransferSize = sizeof(DAC960_V2_Event_T);
+	  CommandMailbox->GetEvent.EventSequenceNumberHigh16 =
+	    Controller->V2.NextEventSequenceNumber >> 16;
+	  CommandMailbox->GetEvent.ControllerNumber = 0;
+	  CommandMailbox->GetEvent.IOCTL_Opcode =
+	    DAC960_V2_GetEvent;
+	  CommandMailbox->GetEvent.EventSequenceNumberLow16 =
+	    Controller->V2.NextEventSequenceNumber & 0xFFFF;
+	  CommandMailbox->GetEvent.DataTransferMemoryAddress
+				  .ScatterGatherSegments[0]
+				  .SegmentDataPointer =
+	    Virtual_to_Bus(&Controller->V2.Event);
+	  CommandMailbox->GetEvent.DataTransferMemoryAddress
+				  .ScatterGatherSegments[0]
+				  .SegmentByteCount =
+	    CommandMailbox->GetEvent.DataTransferSize;
 	  DAC960_QueueCommand(Command);
 	  return;
 	}
-      if (Controller->NeedRebuildProgress)
+      if (Controller->V2.NeedPhysicalDeviceInformation)
 	{
-	  Controller->NeedRebuildProgress = false;
-	  Command->CommandMailbox.Type3.CommandOpcode =
-	    DAC960_GetRebuildProgress;
-	  Command->CommandMailbox.Type3.BusAddress =
-	    Virtual_to_Bus(&Controller->RebuildProgress);
+	  if (Controller->V2.NeedDeviceSerialNumberInformation)
+	    {
+	      DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber =
+		Controller->V2.InquiryUnitSerialNumber
+			       [Controller->V2.PhysicalDeviceIndex - 1];
+	      InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F;
+	      CommandMailbox->SCSI_10.CommandOpcode =
+		DAC960_V2_SCSI_10_Passthru;
+	      CommandMailbox->SCSI_10.DataTransferSize =
+		sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T);
+	      CommandMailbox->SCSI_10.PhysicalDevice.LogicalUnit =
+		Controller->V2.NewPhysicalDeviceInformation.LogicalUnit - 1;
+	      CommandMailbox->SCSI_10.PhysicalDevice.TargetID =
+		Controller->V2.NewPhysicalDeviceInformation.TargetID;
+	      CommandMailbox->SCSI_10.PhysicalDevice.Channel =
+		Controller->V2.NewPhysicalDeviceInformation.Channel;
+	      CommandMailbox->SCSI_10.CDBLength = 6;
+	      CommandMailbox->SCSI_10.SCSI_CDB[0] = 0x12; /* INQUIRY */
+	      CommandMailbox->SCSI_10.SCSI_CDB[1] = 1; /* EVPD = 1 */
+	      CommandMailbox->SCSI_10.SCSI_CDB[2] = 0x80; /* Page Code */
+	      CommandMailbox->SCSI_10.SCSI_CDB[3] = 0; /* Reserved */
+	      CommandMailbox->SCSI_10.SCSI_CDB[4] =
+		sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T);
+	      CommandMailbox->SCSI_10.SCSI_CDB[5] = 0; /* Control */
+	      CommandMailbox->SCSI_10.DataTransferMemoryAddress
+				     .ScatterGatherSegments[0]
+				     .SegmentDataPointer =
+		Virtual_to_Bus(InquiryUnitSerialNumber);
+	      CommandMailbox->SCSI_10.DataTransferMemoryAddress
+				     .ScatterGatherSegments[0]
+				     .SegmentByteCount =
+		CommandMailbox->SCSI_10.DataTransferSize;
+	      DAC960_QueueCommand(Command);
+	      Controller->V2.NeedDeviceSerialNumberInformation = false;
+	      return;
+	    }
+	  CommandMailbox->PhysicalDeviceInfo.CommandOpcode = DAC960_V2_IOCTL;
+	  CommandMailbox->PhysicalDeviceInfo.DataTransferSize =
+	    sizeof(DAC960_V2_PhysicalDeviceInfo_T);
+	  CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.LogicalUnit =
+	    Controller->V2.NewPhysicalDeviceInformation.LogicalUnit;
+	  CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.TargetID =
+	    Controller->V2.NewPhysicalDeviceInformation.TargetID;
+	  CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.Channel =
+	    Controller->V2.NewPhysicalDeviceInformation.Channel;
+	  CommandMailbox->PhysicalDeviceInfo.IOCTL_Opcode =
+	    DAC960_V2_GetPhysicalDeviceInfoValid;
+	  CommandMailbox->PhysicalDeviceInfo.DataTransferMemoryAddress
+					    .ScatterGatherSegments[0]
+					    .SegmentDataPointer =
+	    Virtual_to_Bus(&Controller->V2.NewPhysicalDeviceInformation);
+	  CommandMailbox->PhysicalDeviceInfo.DataTransferMemoryAddress
+					    .ScatterGatherSegments[0]
+					    .SegmentByteCount =
+	    CommandMailbox->PhysicalDeviceInfo.DataTransferSize;
 	  DAC960_QueueCommand(Command);
 	  return;
 	}
-      if (Controller->NeedConsistencyCheckProgress)
+      if (Controller->V2.NeedLogicalDeviceInformation)
 	{
-	  Controller->NeedConsistencyCheckProgress = false;
-	  Command->CommandMailbox.Type3.CommandOpcode = DAC960_RebuildStat;
-	  Command->CommandMailbox.Type3.BusAddress =
-	    Virtual_to_Bus(&Controller->RebuildProgress);
+	  CommandMailbox->LogicalDeviceInfo.CommandOpcode = DAC960_V2_IOCTL;
+	  CommandMailbox->LogicalDeviceInfo.DataTransferSize =
+	    sizeof(DAC960_V2_LogicalDeviceInfo_T);
+	  CommandMailbox->LogicalDeviceInfo.LogicalDevice.LogicalDeviceNumber =
+	    Controller->V2.NewLogicalDeviceInformation.LogicalDeviceNumber;
+	  CommandMailbox->LogicalDeviceInfo.IOCTL_Opcode =
+	    DAC960_V2_GetLogicalDeviceInfoValid;
+	  CommandMailbox->LogicalDeviceInfo.DataTransferMemoryAddress
+					   .ScatterGatherSegments[0]
+					   .SegmentDataPointer =
+	    Virtual_to_Bus(&Controller->V2.NewLogicalDeviceInformation);
+	  CommandMailbox->LogicalDeviceInfo.DataTransferMemoryAddress
+					   .ScatterGatherSegments[0]
+					   .SegmentByteCount =
+	    CommandMailbox->LogicalDeviceInfo.DataTransferSize;
 	  DAC960_QueueCommand(Command);
 	  return;
 	}
       Controller->MonitoringTimerCount++;
       Controller->MonitoringTimer.expires =
-	jiffies + DAC960_MonitoringTimerInterval;
+	jiffies + DAC960_HealthStatusMonitoringInterval;
       add_timer(&Controller->MonitoringTimer);
     }
   if (CommandType == DAC960_ImmediateCommand)
@@ -2406,12 +4520,11 @@
     }
   if (CommandType == DAC960_QueuedCommand)
     {
-      DAC960_KernelCommand_T *KernelCommand = Command->KernelCommand;
-      KernelCommand->CommandStatus = Command->CommandStatus;
-      Command->KernelCommand = NULL;
-      if (CommandOpcode == DAC960_DCDB)
-	Controller->DirectCommandActive[KernelCommand->DCDB->Channel]
-				       [KernelCommand->DCDB->TargetID] = false;
+      DAC960_V2_KernelCommand_T *KernelCommand = Command->V2.KernelCommand;
+      KernelCommand->CommandStatus = CommandStatus;
+      KernelCommand->RequestSenseLength = Command->V2.RequestSenseLength;
+      KernelCommand->DataTransferLength = Command->V2.DataTransferResidue;
+      Command->V2.KernelCommand = NULL;
       DAC960_DeallocateCommand(Command);
       KernelCommand->CompletionFunction(KernelCommand);
       return;
@@ -2424,7 +4537,7 @@
   if (Controller->MonitoringCommandDeferred)
     {
       Controller->MonitoringCommandDeferred = false;
-      DAC960_QueueMonitoringCommand(Command);
+      DAC960_V2_QueueMonitoringCommand(Command);
       return;
     }
   /*
@@ -2439,16 +4552,208 @@
 
 
 /*
-  DAC960_InterruptHandler handles hardware interrupts from DAC960 Controllers.
+  DAC960_BA_InterruptHandler handles hardware interrupts from DAC960 BA Series
+  Controllers.
+*/
+
+static void DAC960_BA_InterruptHandler(int IRQ_Channel,
+				       void *DeviceIdentifier,
+				       Registers_T *InterruptRegisters)
+{
+  DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier;
+  void *ControllerBaseAddress = Controller->BaseAddress;
+  DAC960_V2_StatusMailbox_T *NextStatusMailbox;
+  ProcessorFlags_T ProcessorFlags;
+  /*
+    Acquire exclusive access to Controller.
+  */
+  DAC960_AcquireControllerLockIH(Controller, &ProcessorFlags);
+  /*
+    Process Hardware Interrupts for Controller.
+  */
+  DAC960_BA_AcknowledgeInterrupt(ControllerBaseAddress);
+  NextStatusMailbox = Controller->V2.NextStatusMailbox;
+  while (NextStatusMailbox->Fields.CommandIdentifier > 0)
+    {
+      DAC960_V2_CommandIdentifier_T CommandIdentifier =
+	NextStatusMailbox->Fields.CommandIdentifier;
+      DAC960_Command_T *Command = Controller->Commands[CommandIdentifier-1];
+      Command->V2.CommandStatus = NextStatusMailbox->Fields.CommandStatus;
+      Command->V2.RequestSenseLength =
+	NextStatusMailbox->Fields.RequestSenseLength;
+      Command->V2.DataTransferResidue =
+	NextStatusMailbox->Fields.DataTransferResidue;
+      NextStatusMailbox->Words[0] = 0;
+      if (++NextStatusMailbox > Controller->V2.LastStatusMailbox)
+	NextStatusMailbox = Controller->V2.FirstStatusMailbox;
+      DAC960_V2_ProcessCompletedCommand(Command);
+    }
+  Controller->V2.NextStatusMailbox = NextStatusMailbox;
+  /*
+    Attempt to remove additional I/O Requests from the Controller's
+    I/O Request Queue and queue them to the Controller.
+  */
+  while (DAC960_ProcessRequest(Controller, false)) ;
+  /*
+    Release exclusive access to Controller.
+  */
+  DAC960_ReleaseControllerLockIH(Controller, &ProcessorFlags);
+}
+
+
+/*
+  DAC960_LP_InterruptHandler handles hardware interrupts from DAC960 LP Series
+  Controllers.
+*/
+
+static void DAC960_LP_InterruptHandler(int IRQ_Channel,
+				       void *DeviceIdentifier,
+				       Registers_T *InterruptRegisters)
+{
+  DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier;
+  void *ControllerBaseAddress = Controller->BaseAddress;
+  DAC960_V2_StatusMailbox_T *NextStatusMailbox;
+  ProcessorFlags_T ProcessorFlags;
+  /*
+    Acquire exclusive access to Controller.
+  */
+  DAC960_AcquireControllerLockIH(Controller, &ProcessorFlags);
+  /*
+    Process Hardware Interrupts for Controller.
+  */
+  DAC960_LP_AcknowledgeInterrupt(ControllerBaseAddress);
+  NextStatusMailbox = Controller->V2.NextStatusMailbox;
+  while (NextStatusMailbox->Fields.CommandIdentifier > 0)
+    {
+      DAC960_V2_CommandIdentifier_T CommandIdentifier =
+	NextStatusMailbox->Fields.CommandIdentifier;
+      DAC960_Command_T *Command = Controller->Commands[CommandIdentifier-1];
+      Command->V2.CommandStatus = NextStatusMailbox->Fields.CommandStatus;
+      Command->V2.RequestSenseLength =
+	NextStatusMailbox->Fields.RequestSenseLength;
+      Command->V2.DataTransferResidue =
+	NextStatusMailbox->Fields.DataTransferResidue;
+      NextStatusMailbox->Words[0] = 0;
+      if (++NextStatusMailbox > Controller->V2.LastStatusMailbox)
+	NextStatusMailbox = Controller->V2.FirstStatusMailbox;
+      DAC960_V2_ProcessCompletedCommand(Command);
+    }
+  Controller->V2.NextStatusMailbox = NextStatusMailbox;
+  /*
+    Attempt to remove additional I/O Requests from the Controller's
+    I/O Request Queue and queue them to the Controller.
+  */
+  while (DAC960_ProcessRequest(Controller, false)) ;
+  /*
+    Release exclusive access to Controller.
+  */
+  DAC960_ReleaseControllerLockIH(Controller, &ProcessorFlags);
+}
+
+
+/*
+  DAC960_LA_InterruptHandler handles hardware interrupts from DAC960 LA Series
+  Controllers.
+*/
+
+static void DAC960_LA_InterruptHandler(int IRQ_Channel,
+				       void *DeviceIdentifier,
+				       Registers_T *InterruptRegisters)
+{
+  DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier;
+  void *ControllerBaseAddress = Controller->BaseAddress;
+  DAC960_V1_StatusMailbox_T *NextStatusMailbox;
+  ProcessorFlags_T ProcessorFlags;
+  /*
+    Acquire exclusive access to Controller.
+  */
+  DAC960_AcquireControllerLockIH(Controller, &ProcessorFlags);
+  /*
+    Process Hardware Interrupts for Controller.
+  */
+  DAC960_LA_AcknowledgeInterrupt(ControllerBaseAddress);
+  NextStatusMailbox = Controller->V1.NextStatusMailbox;
+  while (NextStatusMailbox->Fields.Valid)
+    {
+      DAC960_V1_CommandIdentifier_T CommandIdentifier =
+	NextStatusMailbox->Fields.CommandIdentifier;
+      DAC960_Command_T *Command = Controller->Commands[CommandIdentifier-1];
+      Command->V1.CommandStatus = NextStatusMailbox->Fields.CommandStatus;
+      NextStatusMailbox->Word = 0;
+      if (++NextStatusMailbox > Controller->V1.LastStatusMailbox)
+	NextStatusMailbox = Controller->V1.FirstStatusMailbox;
+      DAC960_V1_ProcessCompletedCommand(Command);
+    }
+  Controller->V1.NextStatusMailbox = NextStatusMailbox;
+  /*
+    Attempt to remove additional I/O Requests from the Controller's
+    I/O Request Queue and queue them to the Controller.
+  */
+  while (DAC960_ProcessRequest(Controller, false)) ;
+  /*
+    Release exclusive access to Controller.
+  */
+  DAC960_ReleaseControllerLockIH(Controller, &ProcessorFlags);
+}
+
+
+/*
+  DAC960_PG_InterruptHandler handles hardware interrupts from DAC960 PG Series
+  Controllers.
+*/
+
+static void DAC960_PG_InterruptHandler(int IRQ_Channel,
+				       void *DeviceIdentifier,
+				       Registers_T *InterruptRegisters)
+{
+  DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier;
+  void *ControllerBaseAddress = Controller->BaseAddress;
+  DAC960_V1_StatusMailbox_T *NextStatusMailbox;
+  ProcessorFlags_T ProcessorFlags;
+  /*
+    Acquire exclusive access to Controller.
+  */
+  DAC960_AcquireControllerLockIH(Controller, &ProcessorFlags);
+  /*
+    Process Hardware Interrupts for Controller.
+  */
+  DAC960_PG_AcknowledgeInterrupt(ControllerBaseAddress);
+  NextStatusMailbox = Controller->V1.NextStatusMailbox;
+  while (NextStatusMailbox->Fields.Valid)
+    {
+      DAC960_V1_CommandIdentifier_T CommandIdentifier =
+	NextStatusMailbox->Fields.CommandIdentifier;
+      DAC960_Command_T *Command = Controller->Commands[CommandIdentifier-1];
+      Command->V1.CommandStatus = NextStatusMailbox->Fields.CommandStatus;
+      NextStatusMailbox->Word = 0;
+      if (++NextStatusMailbox > Controller->V1.LastStatusMailbox)
+	NextStatusMailbox = Controller->V1.FirstStatusMailbox;
+      DAC960_V1_ProcessCompletedCommand(Command);
+    }
+  Controller->V1.NextStatusMailbox = NextStatusMailbox;
+  /*
+    Attempt to remove additional I/O Requests from the Controller's
+    I/O Request Queue and queue them to the Controller.
+  */
+  while (DAC960_ProcessRequest(Controller, false)) ;
+  /*
+    Release exclusive access to Controller.
+  */
+  DAC960_ReleaseControllerLockIH(Controller, &ProcessorFlags);
+}
+
+
+/*
+  DAC960_PD_InterruptHandler handles hardware interrupts from DAC960 PD Series
+  Controllers.
 */
 
-static void DAC960_InterruptHandler(int IRQ_Channel,
-				    void *DeviceIdentifier,
-				    Registers_T *InterruptRegisters)
+static void DAC960_PD_InterruptHandler(int IRQ_Channel,
+				       void *DeviceIdentifier,
+				       Registers_T *InterruptRegisters)
 {
   DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier;
   void *ControllerBaseAddress = Controller->BaseAddress;
-  DAC960_StatusMailbox_T *NextStatusMailbox;
   ProcessorFlags_T ProcessorFlags;
   /*
     Acquire exclusive access to Controller.
@@ -2457,53 +4762,16 @@
   /*
     Process Hardware Interrupts for Controller.
   */
-  switch (Controller->ControllerType)
+  while (DAC960_PD_StatusAvailableP(ControllerBaseAddress))
     {
-    case DAC960_V5_Controller:
-      DAC960_V5_AcknowledgeInterrupt(ControllerBaseAddress);
-      NextStatusMailbox = Controller->NextStatusMailbox;
-      while (NextStatusMailbox->Fields.Valid)
-	{
-	  DAC960_CommandIdentifier_T CommandIdentifier =
-	    NextStatusMailbox->Fields.CommandIdentifier;
-	  DAC960_Command_T *Command = &Controller->Commands[CommandIdentifier];
-	  Command->CommandStatus = NextStatusMailbox->Fields.CommandStatus;
-	  NextStatusMailbox->Word = 0;
-	  if (++NextStatusMailbox > Controller->LastStatusMailbox)
-	    NextStatusMailbox = Controller->FirstStatusMailbox;
-	  DAC960_ProcessCompletedCommand(Command);
-	}
-      Controller->NextStatusMailbox = NextStatusMailbox;
-      break;
-    case DAC960_V4_Controller:
-      DAC960_V4_AcknowledgeInterrupt(ControllerBaseAddress);
-      NextStatusMailbox = Controller->NextStatusMailbox;
-      while (NextStatusMailbox->Fields.Valid)
-	{
-	  DAC960_CommandIdentifier_T CommandIdentifier =
-	    NextStatusMailbox->Fields.CommandIdentifier;
-	  DAC960_Command_T *Command = &Controller->Commands[CommandIdentifier];
-	  Command->CommandStatus = NextStatusMailbox->Fields.CommandStatus;
-	  NextStatusMailbox->Word = 0;
-	  if (++NextStatusMailbox > Controller->LastStatusMailbox)
-	    NextStatusMailbox = Controller->FirstStatusMailbox;
-	  DAC960_ProcessCompletedCommand(Command);
-	}
-      Controller->NextStatusMailbox = NextStatusMailbox;
-      break;
-    case DAC960_V3_Controller:
-      while (DAC960_V3_StatusAvailableP(ControllerBaseAddress))
-	{
-	  DAC960_CommandIdentifier_T CommandIdentifier =
-	    DAC960_V3_ReadStatusCommandIdentifier(ControllerBaseAddress);
-	  DAC960_Command_T *Command = &Controller->Commands[CommandIdentifier];
-	  Command->CommandStatus =
-	    DAC960_V3_ReadStatusRegister(ControllerBaseAddress);
-	  DAC960_V3_AcknowledgeInterrupt(ControllerBaseAddress);
-	  DAC960_V3_AcknowledgeStatus(ControllerBaseAddress);
-	  DAC960_ProcessCompletedCommand(Command);
-	}
-      break;
+      DAC960_V1_CommandIdentifier_T CommandIdentifier =
+	DAC960_PD_ReadStatusCommandIdentifier(ControllerBaseAddress);
+      DAC960_Command_T *Command = Controller->Commands[CommandIdentifier-1];
+      Command->V1.CommandStatus =
+	DAC960_PD_ReadStatusRegister(ControllerBaseAddress);
+      DAC960_PD_AcknowledgeInterrupt(ControllerBaseAddress);
+      DAC960_PD_AcknowledgeStatus(ControllerBaseAddress);
+      DAC960_V1_ProcessCompletedCommand(Command);
     }
   /*
     Attempt to remove additional I/O Requests from the Controller's
@@ -2518,18 +4786,50 @@
 
 
 /*
-  DAC960_QueueMonitoringCommand queues a Monitoring Command to Controller.
+  DAC960_V1_QueueMonitoringCommand queues a Monitoring Command to DAC960 V1
+  Firmware Controllers.
+*/
+
+static void DAC960_V1_QueueMonitoringCommand(DAC960_Command_T *Command)
+{
+  DAC960_Controller_T *Controller = Command->Controller;
+  DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
+  DAC960_V1_ClearCommand(Command);
+  Command->CommandType = DAC960_MonitoringCommand;
+  CommandMailbox->Type3.CommandOpcode = DAC960_V1_Enquiry;
+  CommandMailbox->Type3.BusAddress = Virtual_to_Bus(&Controller->V1.NewEnquiry);
+  DAC960_QueueCommand(Command);
+}
+
+
+/*
+  DAC960_V2_QueueMonitoringCommand queues a Monitoring Command to DAC960 V2
+  Firmware Controllers.
 */
 
-static void DAC960_QueueMonitoringCommand(DAC960_Command_T *Command)
+static void DAC960_V2_QueueMonitoringCommand(DAC960_Command_T *Command)
 {
   DAC960_Controller_T *Controller = Command->Controller;
-  DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
-  DAC960_ClearCommand(Command);
+  DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
+  DAC960_V2_ClearCommand(Command);
   Command->CommandType = DAC960_MonitoringCommand;
-  CommandMailbox->Type3.CommandOpcode = DAC960_Enquiry;
-  CommandMailbox->Type3.BusAddress =
-    Virtual_to_Bus(&Controller->Enquiry[Controller->EnquiryIndex ^ 1]);
+  CommandMailbox->ControllerInfo.CommandOpcode = DAC960_V2_IOCTL;
+  CommandMailbox->ControllerInfo.CommandControlBits
+				.DataTransferControllerToHost = true;
+  CommandMailbox->ControllerInfo.CommandControlBits
+				.NoAutoRequestSense = true;
+  CommandMailbox->ControllerInfo.DataTransferSize =
+    sizeof(DAC960_V2_ControllerInfo_T);
+  CommandMailbox->ControllerInfo.ControllerNumber = 0;
+  CommandMailbox->ControllerInfo.IOCTL_Opcode = DAC960_V2_GetControllerInfo;
+  CommandMailbox->ControllerInfo.DataTransferMemoryAddress
+				.ScatterGatherSegments[0]
+				.SegmentDataPointer =
+    Virtual_to_Bus(&Controller->V2.NewControllerInformation);
+  CommandMailbox->ControllerInfo.DataTransferMemoryAddress
+				.ScatterGatherSegments[0]
+				.SegmentByteCount =
+    CommandMailbox->ControllerInfo.DataTransferSize;
   DAC960_QueueCommand(Command);
 }
 
@@ -2544,21 +4844,69 @@
   DAC960_Controller_T *Controller = (DAC960_Controller_T *) TimerData;
   DAC960_Command_T *Command;
   ProcessorFlags_T ProcessorFlags;
-  /*
-    Acquire exclusive access to Controller.
-  */
-  DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
-  /*
-    Queue a Status Monitoring Command to Controller.
-  */
-  Command = DAC960_AllocateCommand(Controller);
-  if (Command != NULL)
-    DAC960_QueueMonitoringCommand(Command);
-  else Controller->MonitoringCommandDeferred = true;
-  /*
-    Release exclusive access to Controller.
-  */
-  DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
+  if (Controller->FirmwareType == DAC960_V1_Controller)
+    {
+      /*
+	Acquire exclusive access to Controller.
+      */
+      DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
+      /*
+	Queue a Status Monitoring Command to Controller.
+      */
+      Command = DAC960_AllocateCommand(Controller);
+      if (Command != NULL)
+	DAC960_V1_QueueMonitoringCommand(Command);
+      else Controller->MonitoringCommandDeferred = true;
+      /*
+	Release exclusive access to Controller.
+      */
+      DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
+    }
+  else
+    {
+      DAC960_V2_ControllerInfo_T *ControllerInfo =
+	&Controller->V2.ControllerInformation;
+      unsigned int StatusChangeCounter =
+	Controller->V2.HealthStatusBuffer->StatusChangeCounter;
+      if (StatusChangeCounter == Controller->V2.StatusChangeCounter &&
+	  Controller->V2.HealthStatusBuffer->NextEventSequenceNumber
+	  == Controller->V2.NextEventSequenceNumber &&
+	  (ControllerInfo->BackgroundInitializationsActive +
+	   ControllerInfo->LogicalDeviceInitializationsActive +
+	   ControllerInfo->PhysicalDeviceInitializationsActive +
+	   ControllerInfo->ConsistencyChecksActive +
+	   ControllerInfo->RebuildsActive +
+	   ControllerInfo->OnlineExpansionsActive == 0 ||
+	   jiffies - Controller->PrimaryMonitoringTime
+	   < DAC960_MonitoringTimerInterval))
+	{
+	  Controller->MonitoringTimer.expires =
+	    jiffies + DAC960_HealthStatusMonitoringInterval;
+	  add_timer(&Controller->MonitoringTimer);
+	  return;
+	}
+      Controller->V2.StatusChangeCounter = StatusChangeCounter;
+      Controller->PrimaryMonitoringTime = jiffies;
+      /*
+	Acquire exclusive access to Controller.
+      */
+      DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
+      /*
+	Queue a Status Monitoring Command to Controller.
+      */
+      Command = DAC960_AllocateCommand(Controller);
+      if (Command != NULL)
+	DAC960_V2_QueueMonitoringCommand(Command);
+      else Controller->MonitoringCommandDeferred = true;
+      /*
+	Release exclusive access to Controller.
+      */
+      DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
+      /*
+	Wake up any processes waiting on a Health Status Buffer change.
+      */
+      wake_up(&Controller->HealthStatusWaitQueue);
+    }
 }
 
 
@@ -2577,19 +4925,28 @@
   if (ControllerNumber < 0 || ControllerNumber > DAC960_ControllerCount - 1)
     return -ENXIO;
   Controller = DAC960_Controllers[ControllerNumber];
-  if (Controller == NULL ||
-      LogicalDriveNumber > Controller->LogicalDriveCount - 1)
-    return -ENXIO;
-  if (Controller->LogicalDriveInformation
-		  [Controller->LogicalDriveInformationIndex]
-		  [LogicalDriveNumber].LogicalDriveState
-      == DAC960_LogicalDrive_Offline)
-    return -ENXIO;
-  if (Controller->LogicalDriveInitialState[LogicalDriveNumber]
-      == DAC960_LogicalDrive_Offline)
+  if (Controller == NULL) return -ENXIO;
+  if (Controller->FirmwareType == DAC960_V1_Controller)
+    {
+      if (LogicalDriveNumber > Controller->LogicalDriveCount - 1)
+	return -ENXIO;
+      if (Controller->V1.LogicalDriveInformation
+			 [LogicalDriveNumber].LogicalDriveState
+	  == DAC960_V1_LogicalDrive_Offline)
+	return -ENXIO;
+    }
+  else
     {
-      Controller->LogicalDriveInitialState[LogicalDriveNumber] =
-	DAC960_LogicalDrive_Online;
+      DAC960_V2_LogicalDeviceInfo_T *LogicalDeviceInfo =
+	Controller->V2.LogicalDeviceInformation[LogicalDriveNumber];
+      if (LogicalDeviceInfo == NULL ||
+	  LogicalDeviceInfo->LogicalDeviceState
+	  == DAC960_V2_LogicalDevice_Offline)
+	return -ENXIO;
+    }
+  if (!Controller->LogicalDriveInitiallyAccessible[LogicalDriveNumber])
+    {
+      Controller->LogicalDriveInitiallyAccessible[LogicalDriveNumber] = true;
       DAC960_InitializeGenericDiskInfo(&Controller->GenericDiskInfo);
       resetup_one_dev(&Controller->GenericDiskInfo, LogicalDriveNumber);
     }
@@ -2645,30 +5002,57 @@
   DiskGeometry_T Geometry, *UserGeometry;
   DAC960_Controller_T *Controller;
   int PartitionNumber;
+  if (File == NULL) return -EINVAL;
   if (File->f_flags & O_NONBLOCK)
     return DAC960_UserIOCTL(Inode, File, Request, Argument);
   if (ControllerNumber < 0 || ControllerNumber > DAC960_ControllerCount - 1)
     return -ENXIO;
   Controller = DAC960_Controllers[ControllerNumber];
-  if (Controller == NULL ||
-      LogicalDriveNumber > Controller->LogicalDriveCount - 1)
-    return -ENXIO;
+  if (Controller == NULL) return -ENXIO;
   switch (Request)
     {
     case HDIO_GETGEO:
       /* Get BIOS Disk Geometry. */
       UserGeometry = (DiskGeometry_T *) Argument;
       if (UserGeometry == NULL) return -EINVAL;
-      Geometry.heads = Controller->GeometryTranslationHeads;
-      Geometry.sectors = Controller->GeometryTranslationSectors;
-      Geometry.cylinders =
-	Controller->LogicalDriveInformation
-		    [Controller->LogicalDriveInformationIndex]
-		    [LogicalDriveNumber].LogicalDriveSize
-	/ (Controller->GeometryTranslationHeads *
-	   Controller->GeometryTranslationSectors);
-      Geometry.start = Controller->GenericDiskInfo.part[MINOR(Inode->i_rdev)]
-						  .start_sect;
+      if (Controller->FirmwareType == DAC960_V1_Controller)
+	{
+	  if (LogicalDriveNumber > Controller->LogicalDriveCount - 1)
+	    return -ENXIO;
+	  Geometry.heads = Controller->V1.GeometryTranslationHeads;
+	  Geometry.sectors = Controller->V1.GeometryTranslationSectors;
+	  Geometry.cylinders =
+	    Controller->V1.LogicalDriveInformation[LogicalDriveNumber]
+						  .LogicalDriveSize
+	    / (Geometry.heads * Geometry.sectors);
+	}
+      else
+	{
+	  DAC960_V2_LogicalDeviceInfo_T *LogicalDeviceInfo =
+	    Controller->V2.LogicalDeviceInformation[LogicalDriveNumber];
+	  if (LogicalDeviceInfo == NULL)
+	    return -EINVAL;
+	  switch(LogicalDeviceInfo->DriveGeometry)
+	    {
+	    case DAC960_V2_Geometry_128_32:
+	      Geometry.heads = 128;
+	      Geometry.sectors = 32;
+	      break;
+	    case DAC960_V2_Geometry_255_63:
+	      Geometry.heads = 255;
+	      Geometry.sectors = 63;
+	      break;
+	    default:
+	      DAC960_Error("Illegal Logical Device Geometry %d\n",
+			   Controller, LogicalDeviceInfo->DriveGeometry);
+	      return -EINVAL;
+	    }
+	  Geometry.cylinders =
+	    LogicalDeviceInfo->ConfigurableDeviceSizeIn512ByteBlocksOrMB
+	    / (Geometry.heads * Geometry.sectors);
+	}
+      Geometry.start =
+	Controller->GenericDiskInfo.part[MINOR(Inode->i_rdev)].start_sect;
       return copy_to_user(UserGeometry, &Geometry, sizeof(DiskGeometry_T));
     case BLKGETSIZE:
       /* Get Device Size. */
@@ -2764,59 +5148,64 @@
 	    ControllerNumber > DAC960_ControllerCount - 1)
 	  return -ENXIO;
 	Controller = DAC960_Controllers[ControllerNumber];
-	if (Controller == NULL)
-	  return -ENXIO;
+	if (Controller == NULL) return -ENXIO;
 	memset(&ControllerInfo, 0, sizeof(DAC960_ControllerInfo_T));
 	ControllerInfo.ControllerNumber = ControllerNumber;
+	ControllerInfo.FirmwareType = Controller->FirmwareType;
+	ControllerInfo.Channels = Controller->Channels;
+	ControllerInfo.Targets = Controller->Targets;
 	ControllerInfo.PCI_Bus = Controller->Bus;
 	ControllerInfo.PCI_Device = Controller->Device;
 	ControllerInfo.PCI_Function = Controller->Function;
 	ControllerInfo.IRQ_Channel = Controller->IRQ_Channel;
-	ControllerInfo.Channels = Controller->Channels;
 	ControllerInfo.PCI_Address = Controller->PCI_Address;
 	strcpy(ControllerInfo.ModelName, Controller->ModelName);
 	strcpy(ControllerInfo.FirmwareVersion, Controller->FirmwareVersion);
 	return copy_to_user(UserSpaceControllerInfo, &ControllerInfo,
 			    sizeof(DAC960_ControllerInfo_T));
       }
-    case DAC960_IOCTL_EXECUTE_COMMAND:
+    case DAC960_IOCTL_V1_EXECUTE_COMMAND:
       {
-	DAC960_UserCommand_T *UserSpaceUserCommand =
-	  (DAC960_UserCommand_T *) Argument;
-	DAC960_UserCommand_T UserCommand;
+	DAC960_V1_UserCommand_T *UserSpaceUserCommand =
+	  (DAC960_V1_UserCommand_T *) Argument;
+	DAC960_V1_UserCommand_T UserCommand;
 	DAC960_Controller_T *Controller;
 	DAC960_Command_T *Command = NULL;
-	DAC960_CommandOpcode_T CommandOpcode;
-	DAC960_CommandStatus_T CommandStatus;
-	DAC960_DCDB_T DCDB;
+	DAC960_V1_CommandOpcode_T CommandOpcode;
+	DAC960_V1_CommandStatus_T CommandStatus;
+	DAC960_V1_DCDB_T DCDB;
 	ProcessorFlags_T ProcessorFlags;
 	int ControllerNumber, DataTransferLength;
 	unsigned char *DataTransferBuffer = NULL;
 	if (UserSpaceUserCommand == NULL) return -EINVAL;
 	ErrorCode = copy_from_user(&UserCommand, UserSpaceUserCommand,
-				   sizeof(DAC960_UserCommand_T));
-	if (ErrorCode != 0) goto Failure;
+				   sizeof(DAC960_V1_UserCommand_T));
+	if (ErrorCode != 0) goto Failure1;
 	ControllerNumber = UserCommand.ControllerNumber;
 	if (ControllerNumber < 0 ||
 	    ControllerNumber > DAC960_ControllerCount - 1)
 	  return -ENXIO;
 	Controller = DAC960_Controllers[ControllerNumber];
-	if (Controller == NULL)
-	  return -ENXIO;
+	if (Controller == NULL) return -ENXIO;
+	if (Controller->FirmwareType != DAC960_V1_Controller) return -EINVAL;
 	CommandOpcode = UserCommand.CommandMailbox.Common.CommandOpcode;
 	DataTransferLength = UserCommand.DataTransferLength;
 	if (CommandOpcode & 0x80) return -EINVAL;
-	if (CommandOpcode == DAC960_DCDB)
+	if (CommandOpcode == DAC960_V1_DCDB)
 	  {
 	    ErrorCode =
-	      copy_from_user(&DCDB, UserCommand.DCDB, sizeof(DAC960_DCDB_T));
-	    if (ErrorCode != 0) goto Failure;
+	      copy_from_user(&DCDB, UserCommand.DCDB, sizeof(DAC960_V1_DCDB_T));
+	    if (ErrorCode != 0) goto Failure1;
+	    if (DCDB.Channel >= DAC960_V1_MaxChannels) return -EINVAL;
 	    if (!((DataTransferLength == 0 &&
-		   DCDB.Direction == DAC960_DCDB_NoDataTransfer) ||
+		   DCDB.Direction
+		   == DAC960_V1_DCDB_NoDataTransfer) ||
 		  (DataTransferLength > 0 &&
-		   DCDB.Direction == DAC960_DCDB_DataTransferDeviceToSystem) ||
+		   DCDB.Direction
+		   == DAC960_V1_DCDB_DataTransferDeviceToSystem) ||
 		  (DataTransferLength < 0 &&
-		   DCDB.Direction == DAC960_DCDB_DataTransferSystemToDevice)))
+		   DCDB.Direction
+		   == DAC960_V1_DCDB_DataTransferSystemToDevice)))
 	      return -EINVAL;
 	    if (((DCDB.TransferLengthHigh4 << 16) | DCDB.TransferLength)
 		!= abs(DataTransferLength))
@@ -2835,23 +5224,24 @@
 	    ErrorCode = copy_from_user(DataTransferBuffer,
 				       UserCommand.DataTransferBuffer,
 				       -DataTransferLength);
-	    if (ErrorCode != 0) goto Failure;
+	    if (ErrorCode != 0) goto Failure1;
 	  }
-	if (CommandOpcode == DAC960_DCDB)
+	if (CommandOpcode == DAC960_V1_DCDB)
 	  {
 	    DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
-	    while (Controller->DirectCommandActive[DCDB.Channel]
-						  [DCDB.TargetID] ||
+	    while (Controller->V1.DirectCommandActive[DCDB.Channel]
+						     [DCDB.TargetID] ||
 		   (Command = DAC960_AllocateCommand(Controller)) == NULL)
 	      DAC960_WaitForCommand(Controller);
-	    Controller->DirectCommandActive[DCDB.Channel]
-					   [DCDB.TargetID] = true;
+	    Controller->V1.DirectCommandActive[DCDB.Channel]
+					      [DCDB.TargetID] = true;
 	    DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
-	    DAC960_ClearCommand(Command);
+	    DAC960_V1_ClearCommand(Command);
 	    Command->CommandType = DAC960_ImmediateCommand;
-	    memcpy(&Command->CommandMailbox, &UserCommand.CommandMailbox,
-		   sizeof(DAC960_CommandMailbox_T));
-	    Command->CommandMailbox.Type3.BusAddress = Virtual_to_Bus(&DCDB);
+	    memcpy(&Command->V1.CommandMailbox, &UserCommand.CommandMailbox,
+		   sizeof(DAC960_V1_CommandMailbox_T));
+	    Command->V1.CommandMailbox.Type3.BusAddress =
+	      Virtual_to_Bus(&DCDB);
 	    DCDB.BusAddress = Virtual_to_Bus(DataTransferBuffer);
 	  }
 	else
@@ -2860,38 +5250,211 @@
 	    while ((Command = DAC960_AllocateCommand(Controller)) == NULL)
 	      DAC960_WaitForCommand(Controller);
 	    DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
-	    DAC960_ClearCommand(Command);
+	    DAC960_V1_ClearCommand(Command);
 	    Command->CommandType = DAC960_ImmediateCommand;
-	    memcpy(&Command->CommandMailbox, &UserCommand.CommandMailbox,
-		   sizeof(DAC960_CommandMailbox_T));
+	    memcpy(&Command->V1.CommandMailbox, &UserCommand.CommandMailbox,
+		   sizeof(DAC960_V1_CommandMailbox_T));
 	    if (DataTransferBuffer != NULL)
-	      Command->CommandMailbox.Type3.BusAddress =
+	      Command->V1.CommandMailbox.Type3.BusAddress =
 		Virtual_to_Bus(DataTransferBuffer);
 	  }
 	DAC960_ExecuteCommand(Command);
-	CommandStatus = Command->CommandStatus;
+	CommandStatus = Command->V1.CommandStatus;
 	DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
 	DAC960_DeallocateCommand(Command);
 	DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
-	if (CommandStatus == DAC960_NormalCompletion &&
-	    DataTransferLength > 0)
+	if (DataTransferLength > 0)
 	  {
 	    ErrorCode = copy_to_user(UserCommand.DataTransferBuffer,
 				     DataTransferBuffer, DataTransferLength);
-	    if (ErrorCode != 0) goto Failure;
+	    if (ErrorCode != 0) goto Failure1;
 	  }
-	if (CommandOpcode == DAC960_DCDB)
+	if (CommandOpcode == DAC960_V1_DCDB)
 	  {
-	    Controller->DirectCommandActive[DCDB.Channel]
-					   [DCDB.TargetID] = false;
+	    Controller->V1.DirectCommandActive[DCDB.Channel]
+					      [DCDB.TargetID] = false;
 	    ErrorCode =
-	      copy_to_user(UserCommand.DCDB, &DCDB, sizeof(DAC960_DCDB_T));
-	    if (ErrorCode != 0) goto Failure;
+	      copy_to_user(UserCommand.DCDB, &DCDB, sizeof(DAC960_V1_DCDB_T));
+	    if (ErrorCode != 0) goto Failure1;
+	  }
+	ErrorCode = CommandStatus;
+      Failure1:
+	if (DataTransferBuffer != NULL)
+	  kfree(DataTransferBuffer);
+	return ErrorCode;
+      }
+    case DAC960_IOCTL_V2_EXECUTE_COMMAND:
+      {
+	DAC960_V2_UserCommand_T *UserSpaceUserCommand =
+	  (DAC960_V2_UserCommand_T *) Argument;
+	DAC960_V2_UserCommand_T UserCommand;
+	DAC960_Controller_T *Controller;
+	DAC960_Command_T *Command = NULL;
+	DAC960_V2_CommandMailbox_T *CommandMailbox;
+	DAC960_V2_CommandStatus_T CommandStatus;
+	ProcessorFlags_T ProcessorFlags;
+	int ControllerNumber, DataTransferLength;
+	int DataTransferResidue, RequestSenseLength;
+	unsigned char *DataTransferBuffer = NULL;
+	unsigned char *RequestSenseBuffer = NULL;
+	if (UserSpaceUserCommand == NULL) return -EINVAL;
+	ErrorCode = copy_from_user(&UserCommand, UserSpaceUserCommand,
+				   sizeof(DAC960_V2_UserCommand_T));
+	if (ErrorCode != 0) goto Failure2;
+	ControllerNumber = UserCommand.ControllerNumber;
+	if (ControllerNumber < 0 ||
+	    ControllerNumber > DAC960_ControllerCount - 1)
+	  return -ENXIO;
+	Controller = DAC960_Controllers[ControllerNumber];
+	if (Controller == NULL) return -ENXIO;
+	if (Controller->FirmwareType != DAC960_V2_Controller) return -EINVAL;
+	DataTransferLength = UserCommand.DataTransferLength;
+	if (DataTransferLength > 0)
+	  {
+	    DataTransferBuffer = kmalloc(DataTransferLength, GFP_KERNEL);
+	    if (DataTransferBuffer == NULL) return -ENOMEM;
+	    memset(DataTransferBuffer, 0, DataTransferLength);
+	  }
+	else if (DataTransferLength < 0)
+	  {
+	    DataTransferBuffer = kmalloc(-DataTransferLength, GFP_KERNEL);
+	    if (DataTransferBuffer == NULL) return -ENOMEM;
+	    ErrorCode = copy_from_user(DataTransferBuffer,
+				       UserCommand.DataTransferBuffer,
+				       -DataTransferLength);
+	    if (ErrorCode != 0) goto Failure2;
+	  }
+	RequestSenseLength = UserCommand.RequestSenseLength;
+	if (RequestSenseLength > 0)
+	  {
+	    RequestSenseBuffer = kmalloc(RequestSenseLength, GFP_KERNEL);
+	    if (RequestSenseBuffer == NULL)
+	      {
+		ErrorCode = -ENOMEM;
+		goto Failure2;
+	      }
+	    memset(RequestSenseBuffer, 0, RequestSenseLength);
+	  }
+	DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
+	while ((Command = DAC960_AllocateCommand(Controller)) == NULL)
+	  DAC960_WaitForCommand(Controller);
+	DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
+	DAC960_V2_ClearCommand(Command);
+	Command->CommandType = DAC960_ImmediateCommand;
+	CommandMailbox = &Command->V2.CommandMailbox;
+	memcpy(CommandMailbox, &UserCommand.CommandMailbox,
+	       sizeof(DAC960_V2_CommandMailbox_T));
+	CommandMailbox->Common.CommandControlBits
+			      .AdditionalScatterGatherListMemory = false;
+	CommandMailbox->Common.CommandControlBits
+			      .NoAutoRequestSense = true;
+	CommandMailbox->Common.DataTransferSize = 0;
+	CommandMailbox->Common.DataTransferPageNumber = 0;
+	memset(&CommandMailbox->Common.DataTransferMemoryAddress, 0,
+	       sizeof(DAC960_V2_DataTransferMemoryAddress_T));
+	if (DataTransferLength != 0)
+	  {
+	    if (DataTransferLength > 0)
+	      {
+		CommandMailbox->Common.CommandControlBits
+				      .DataTransferControllerToHost = true;
+		CommandMailbox->Common.DataTransferSize = DataTransferLength;
+	      }
+	    else
+	      {
+		CommandMailbox->Common.CommandControlBits
+				      .DataTransferControllerToHost = false;
+		CommandMailbox->Common.DataTransferSize = -DataTransferLength;
+	      }
+	    CommandMailbox->Common.DataTransferMemoryAddress
+				  .ScatterGatherSegments[0]
+				  .SegmentDataPointer =
+	      Virtual_to_Bus(DataTransferBuffer);
+	    CommandMailbox->Common.DataTransferMemoryAddress
+				  .ScatterGatherSegments[0]
+				  .SegmentByteCount =
+	      CommandMailbox->Common.DataTransferSize;
+	  }
+	if (RequestSenseLength > 0)
+	  {
+	    CommandMailbox->Common.CommandControlBits
+				  .NoAutoRequestSense = false;
+	    CommandMailbox->Common.RequestSenseSize = RequestSenseLength;
+	    CommandMailbox->Common.RequestSenseBusAddress =
+	      Virtual_to_Bus(RequestSenseBuffer);
+	  }
+	DAC960_ExecuteCommand(Command);
+	CommandStatus = Command->V2.CommandStatus;
+	RequestSenseLength = Command->V2.RequestSenseLength;
+	DataTransferResidue = Command->V2.DataTransferResidue;
+	DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
+	DAC960_DeallocateCommand(Command);
+	DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
+	if (RequestSenseLength > UserCommand.RequestSenseLength)
+	  RequestSenseLength = UserCommand.RequestSenseLength;
+	ErrorCode = copy_to_user(&UserSpaceUserCommand->DataTransferLength,
+				 &DataTransferResidue,
+				 sizeof(DataTransferResidue));
+	if (ErrorCode != 0) goto Failure2;
+	ErrorCode = copy_to_user(&UserSpaceUserCommand->RequestSenseLength,
+				 &RequestSenseLength,
+				 sizeof(RequestSenseLength));
+	if (ErrorCode != 0) goto Failure2;
+	if (DataTransferLength > 0)
+	  {
+	    ErrorCode = copy_to_user(UserCommand.DataTransferBuffer,
+				     DataTransferBuffer, DataTransferLength);
+	    if (ErrorCode != 0) goto Failure2;
+	  }
+	if (RequestSenseLength > 0)
+	  {
+	    ErrorCode = copy_to_user(UserCommand.RequestSenseBuffer,
+				     RequestSenseBuffer, RequestSenseLength);
+	    if (ErrorCode != 0) goto Failure2;
 	  }
 	ErrorCode = CommandStatus;
-      Failure:
+      Failure2:
 	if (DataTransferBuffer != NULL)
 	  kfree(DataTransferBuffer);
+	if (RequestSenseBuffer != NULL)
+	  kfree(RequestSenseBuffer);
+	return ErrorCode;
+      }
+    case DAC960_IOCTL_V2_GET_HEALTH_STATUS:
+      {
+	DAC960_V2_GetHealthStatus_T *UserSpaceGetHealthStatus =
+	  (DAC960_V2_GetHealthStatus_T *) Argument;
+	DAC960_V2_GetHealthStatus_T GetHealthStatus;
+	DAC960_V2_HealthStatusBuffer_T HealthStatusBuffer;
+	DAC960_Controller_T *Controller;
+	int ControllerNumber;
+	if (UserSpaceGetHealthStatus == NULL) return -EINVAL;
+	ErrorCode = copy_from_user(&GetHealthStatus, UserSpaceGetHealthStatus,
+				   sizeof(DAC960_V2_GetHealthStatus_T));
+	if (ErrorCode != 0) return ErrorCode;
+	ControllerNumber = GetHealthStatus.ControllerNumber;
+	if (ControllerNumber < 0 ||
+	    ControllerNumber > DAC960_ControllerCount - 1)
+	  return -ENXIO;
+	Controller = DAC960_Controllers[ControllerNumber];
+	if (Controller == NULL) return -ENXIO;
+	if (Controller->FirmwareType != DAC960_V2_Controller) return -EINVAL;
+	ErrorCode = copy_from_user(&HealthStatusBuffer,
+				   GetHealthStatus.HealthStatusBuffer,
+				   sizeof(DAC960_V2_HealthStatusBuffer_T));
+	if (ErrorCode != 0) return ErrorCode;
+	while (Controller->V2.HealthStatusBuffer->StatusChangeCounter
+	       == HealthStatusBuffer.StatusChangeCounter &&
+	       Controller->V2.HealthStatusBuffer->NextEventSequenceNumber
+	       == HealthStatusBuffer.NextEventSequenceNumber)
+	  {
+	    interruptible_sleep_on_timeout(&Controller->HealthStatusWaitQueue,
+					   DAC960_MonitoringTimerInterval);
+	    if (signal_pending(current)) return -EINTR;
+	  }
+	ErrorCode = copy_to_user(GetHealthStatus.HealthStatusBuffer,
+				 Controller->V2.HealthStatusBuffer,
+				 sizeof(DAC960_V2_HealthStatusBuffer_T));
 	return ErrorCode;
       }
     }
@@ -2921,28 +5484,29 @@
 	    ControllerNumber > DAC960_ControllerCount - 1)
 	  return -ENXIO;
 	Controller = DAC960_Controllers[ControllerNumber];
-	if (Controller == NULL)
-	  return -ENXIO;
+	if (Controller == NULL) return -ENXIO;
 	memset(ControllerInfo, 0, sizeof(DAC960_ControllerInfo_T));
 	ControllerInfo->ControllerNumber = ControllerNumber;
+	ControllerInfo->FirmwareType = Controller->FirmwareType;
+	ControllerInfo->Channels = Controller->Channels;
+	ControllerInfo->Targets = Controller->Targets;
 	ControllerInfo->PCI_Bus = Controller->Bus;
 	ControllerInfo->PCI_Device = Controller->Device;
 	ControllerInfo->PCI_Function = Controller->Function;
 	ControllerInfo->IRQ_Channel = Controller->IRQ_Channel;
-	ControllerInfo->Channels = Controller->Channels;
 	ControllerInfo->PCI_Address = Controller->PCI_Address;
 	strcpy(ControllerInfo->ModelName, Controller->ModelName);
 	strcpy(ControllerInfo->FirmwareVersion, Controller->FirmwareVersion);
 	return 0;
       }
-    case DAC960_IOCTL_EXECUTE_COMMAND:
+    case DAC960_IOCTL_V1_EXECUTE_COMMAND:
       {
-	DAC960_KernelCommand_T *KernelCommand =
-	  (DAC960_KernelCommand_T *) Argument;
+	DAC960_V1_KernelCommand_T *KernelCommand =
+	  (DAC960_V1_KernelCommand_T *) Argument;
 	DAC960_Controller_T *Controller;
 	DAC960_Command_T *Command = NULL;
-	DAC960_CommandOpcode_T CommandOpcode;
-	DAC960_DCDB_T *DCDB = NULL;
+	DAC960_V1_CommandOpcode_T CommandOpcode;
+	DAC960_V1_DCDB_T *DCDB = NULL;
 	ProcessorFlags_T ProcessorFlags;
 	int ControllerNumber, DataTransferLength;
 	unsigned char *DataTransferBuffer = NULL;
@@ -2952,21 +5516,24 @@
 	    ControllerNumber > DAC960_ControllerCount - 1)
 	  return -ENXIO;
 	Controller = DAC960_Controllers[ControllerNumber];
-	if (Controller == NULL)
-	  return -ENXIO;
+	if (Controller == NULL) return -ENXIO;
+	if (Controller->FirmwareType != DAC960_V1_Controller) return -EINVAL;
 	CommandOpcode = KernelCommand->CommandMailbox.Common.CommandOpcode;
 	DataTransferLength = KernelCommand->DataTransferLength;
 	DataTransferBuffer = KernelCommand->DataTransferBuffer;
 	if (CommandOpcode & 0x80) return -EINVAL;
-	if (CommandOpcode == DAC960_DCDB)
+	if (CommandOpcode == DAC960_V1_DCDB)
 	  {
 	    DCDB = KernelCommand->DCDB;
+	    if (DCDB->Channel >= DAC960_V1_MaxChannels) return -EINVAL;
 	    if (!((DataTransferLength == 0 &&
-		   DCDB->Direction == DAC960_DCDB_NoDataTransfer) ||
+		   DCDB->Direction == DAC960_V1_DCDB_NoDataTransfer) ||
 		  (DataTransferLength > 0 &&
-		   DCDB->Direction == DAC960_DCDB_DataTransferDeviceToSystem) ||
+		   DCDB->Direction
+		   == DAC960_V1_DCDB_DataTransferDeviceToSystem) ||
 		  (DataTransferLength < 0 &&
-		   DCDB->Direction == DAC960_DCDB_DataTransferSystemToDevice)))
+		   DCDB->Direction
+		   == DAC960_V1_DCDB_DataTransferSystemToDevice)))
 	      return -EINVAL;
 	    if (((DCDB->TransferLengthHigh4 << 16) | DCDB->TransferLength)
 		!= abs(DataTransferLength))
@@ -2976,25 +5543,26 @@
 	  return -EINVAL;
 	if (DataTransferLength > 0)
 	  memset(DataTransferBuffer, 0, DataTransferLength);
-	if (CommandOpcode == DAC960_DCDB)
+	if (CommandOpcode == DAC960_V1_DCDB)
 	  {
 	    DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
-	    if (!Controller->DirectCommandActive[DCDB->Channel]
-						[DCDB->TargetID])
+	    if (!Controller->V1.DirectCommandActive[DCDB->Channel]
+						   [DCDB->TargetID])
 	      Command = DAC960_AllocateCommand(Controller);
 	    if (Command == NULL)
 	      {
 		DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
 		return -EBUSY;
 	      }
-	    else Controller->DirectCommandActive[DCDB->Channel]
-						[DCDB->TargetID] = true;
-	    DAC960_ClearCommand(Command);
+	    else Controller->V1.DirectCommandActive[DCDB->Channel]
+						   [DCDB->TargetID] = true;
+	    DAC960_V1_ClearCommand(Command);
 	    Command->CommandType = DAC960_QueuedCommand;
-	    memcpy(&Command->CommandMailbox, &KernelCommand->CommandMailbox,
-		   sizeof(DAC960_CommandMailbox_T));
-	    Command->CommandMailbox.Type3.BusAddress = Virtual_to_Bus(DCDB);
-	    Command->KernelCommand = KernelCommand;
+	    memcpy(&Command->V1.CommandMailbox, &KernelCommand->CommandMailbox,
+		   sizeof(DAC960_V1_CommandMailbox_T));
+	    Command->V1.CommandMailbox.Type3.BusAddress =
+	      Virtual_to_Bus(DCDB);
+	    Command->V1.KernelCommand = KernelCommand;
 	    DCDB->BusAddress = Virtual_to_Bus(DataTransferBuffer);
 	    DAC960_QueueCommand(Command);
 	    DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
@@ -3008,42 +5576,153 @@
 		DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
 		return -EBUSY;
 	      }
-	    DAC960_ClearCommand(Command);
+	    DAC960_V1_ClearCommand(Command);
 	    Command->CommandType = DAC960_QueuedCommand;
-	    memcpy(&Command->CommandMailbox, &KernelCommand->CommandMailbox,
-		   sizeof(DAC960_CommandMailbox_T));
+	    memcpy(&Command->V1.CommandMailbox, &KernelCommand->CommandMailbox,
+		   sizeof(DAC960_V1_CommandMailbox_T));
 	    if (DataTransferBuffer != NULL)
-	      Command->CommandMailbox.Type3.BusAddress =
+	      Command->V1.CommandMailbox.Type3.BusAddress =
 		Virtual_to_Bus(DataTransferBuffer);
-	    Command->KernelCommand = KernelCommand;
+	    Command->V1.KernelCommand = KernelCommand;
 	    DAC960_QueueCommand(Command);
 	    DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
 	  }
 	return 0;
       }
+    case DAC960_IOCTL_V2_EXECUTE_COMMAND:
+      {
+	DAC960_V2_KernelCommand_T *KernelCommand =
+	  (DAC960_V2_KernelCommand_T *) Argument;
+	DAC960_Controller_T *Controller;
+	DAC960_Command_T *Command = NULL;
+	DAC960_V2_CommandMailbox_T *CommandMailbox;
+	ProcessorFlags_T ProcessorFlags;
+	int ControllerNumber, DataTransferLength, RequestSenseLength;
+	unsigned char *DataTransferBuffer = NULL;
+	unsigned char *RequestSenseBuffer = NULL;
+	if (KernelCommand == NULL) return -EINVAL;
+	ControllerNumber = KernelCommand->ControllerNumber;
+	if (ControllerNumber < 0 ||
+	    ControllerNumber > DAC960_ControllerCount - 1)
+	  return -ENXIO;
+	Controller = DAC960_Controllers[ControllerNumber];
+	if (Controller == NULL) return -ENXIO;
+	if (Controller->FirmwareType != DAC960_V2_Controller) return -EINVAL;
+	DataTransferLength = KernelCommand->DataTransferLength;
+	RequestSenseLength = KernelCommand->RequestSenseLength;
+	DataTransferBuffer = KernelCommand->DataTransferBuffer;
+	RequestSenseBuffer = KernelCommand->RequestSenseBuffer;
+	if (DataTransferLength != 0 && DataTransferBuffer == NULL)
+	  return -EINVAL;
+	if (RequestSenseLength < 0)
+	  return -EINVAL;
+	if (RequestSenseLength > 0 && RequestSenseBuffer == NULL)
+	  return -EINVAL;
+	if (DataTransferLength > 0)
+	  memset(DataTransferBuffer, 0, DataTransferLength);
+	if (RequestSenseLength > 0)
+	  memset(RequestSenseBuffer, 0, RequestSenseLength);
+	DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
+	Command = DAC960_AllocateCommand(Controller);
+	if (Command == NULL)
+	  {
+	    DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
+	    return -EBUSY;
+	  }
+	DAC960_V2_ClearCommand(Command);
+	Command->CommandType = DAC960_QueuedCommand;
+	CommandMailbox = &Command->V2.CommandMailbox;
+	memcpy(CommandMailbox, &KernelCommand->CommandMailbox,
+	       sizeof(DAC960_V2_CommandMailbox_T));
+	CommandMailbox->Common.CommandControlBits
+			      .AdditionalScatterGatherListMemory = false;
+	CommandMailbox->Common.CommandControlBits
+			      .NoAutoRequestSense = true;
+	CommandMailbox->Common.DataTransferSize = 0;
+	CommandMailbox->Common.DataTransferPageNumber = 0;
+	memset(&CommandMailbox->Common.DataTransferMemoryAddress, 0,
+	       sizeof(DAC960_V2_DataTransferMemoryAddress_T));
+	if (DataTransferLength != 0)
+	  {
+	    if (DataTransferLength > 0)
+	      {
+		CommandMailbox->Common.CommandControlBits
+				      .DataTransferControllerToHost = true;
+		CommandMailbox->Common.DataTransferSize = DataTransferLength;
+	      }
+	    else
+	      {
+		CommandMailbox->Common.CommandControlBits
+				      .DataTransferControllerToHost = false;
+		CommandMailbox->Common.DataTransferSize = -DataTransferLength;
+	      }
+	    CommandMailbox->Common.DataTransferMemoryAddress
+				  .ScatterGatherSegments[0]
+				  .SegmentDataPointer =
+	      Virtual_to_Bus(DataTransferBuffer);
+	    CommandMailbox->Common.DataTransferMemoryAddress
+				  .ScatterGatherSegments[0]
+				  .SegmentByteCount =
+	      CommandMailbox->Common.DataTransferSize;
+	  }
+	if (RequestSenseLength > 0)
+	  {
+	    CommandMailbox->Common.CommandControlBits
+				  .NoAutoRequestSense = false;
+	    CommandMailbox->Common.RequestSenseBusAddress =
+	      Virtual_to_Bus(RequestSenseBuffer);
+	  }
+	Command->V2.KernelCommand = KernelCommand;
+	DAC960_QueueCommand(Command);
+	DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
+	return 0;
+      }
     }
   return -EINVAL;
 }
 
 
 /*
-  DAC960_GenericDiskInit is the Generic Disk Information Initialization
-  Function for the DAC960 Driver.
-*/
-
-static void DAC960_InitializeGenericDiskInfo(GenericDiskInfo_T *GenericDiskInfo)
-{
-  DAC960_Controller_T *Controller =
-    (DAC960_Controller_T *) GenericDiskInfo->real_devices;
-  DAC960_LogicalDriveInformation_T *LogicalDriveInformation =
-    Controller->LogicalDriveInformation
-		[Controller->LogicalDriveInformationIndex];
-  int LogicalDriveNumber;
-  for (LogicalDriveNumber = 0;
-       LogicalDriveNumber < Controller->LogicalDriveCount;
-       LogicalDriveNumber++)
-    GenericDiskInfo->part[DAC960_MinorNumber(LogicalDriveNumber, 0)].nr_sects =
-      LogicalDriveInformation[LogicalDriveNumber].LogicalDriveSize;
+  DAC960_CheckStatusBuffer verifies that there is room to hold ByteCount
+  additional bytes in the Combined Status Buffer and grows the buffer if
+  necessary.  It returns true if there is enough room and false otherwise.
+*/
+
+static boolean DAC960_CheckStatusBuffer(DAC960_Controller_T *Controller,
+					unsigned int ByteCount)
+{
+  unsigned char *NewStatusBuffer;
+  if (Controller->InitialStatusLength + 1 +
+      Controller->CurrentStatusLength + ByteCount + 1 <=
+      Controller->CombinedStatusBufferLength)
+    return true;
+  if (Controller->CombinedStatusBufferLength == 0)
+    {
+      unsigned int NewStatusBufferLength = DAC960_InitialStatusBufferSize;
+      while (NewStatusBufferLength < ByteCount)
+	NewStatusBufferLength *= 2;
+      Controller->CombinedStatusBuffer =
+	(unsigned char *) kmalloc(NewStatusBufferLength, GFP_ATOMIC);
+      if (Controller->CombinedStatusBuffer == NULL) return false;
+      Controller->CombinedStatusBufferLength = NewStatusBufferLength;
+      return true;
+    }
+  NewStatusBuffer = (unsigned char *)
+    kmalloc(2 * Controller->CombinedStatusBufferLength, GFP_ATOMIC);
+  if (NewStatusBuffer == NULL)
+    {
+      DAC960_Warning("Unable to expand Combined Status Buffer - Truncating\n",
+		     Controller);
+      return false;
+    }
+  memcpy(NewStatusBuffer, Controller->CombinedStatusBuffer,
+	 Controller->CombinedStatusBufferLength);
+  kfree(Controller->CombinedStatusBuffer);
+  Controller->CombinedStatusBuffer = NewStatusBuffer;
+  Controller->CombinedStatusBufferLength *= 2;
+  Controller->CurrentStatusBuffer =
+    &NewStatusBuffer[Controller->InitialStatusLength + 1];
+  return true;
 }
 
 
@@ -3052,11 +5731,11 @@
 */
 
 static void DAC960_Message(DAC960_MessageLevel_T MessageLevel,
-			   char *Format,
+			   unsigned char *Format,
 			   DAC960_Controller_T *Controller,
 			   ...)
 {
-  static char Buffer[DAC960_LineBufferSize];
+  static unsigned char Buffer[DAC960_LineBufferSize];
   static boolean BeginningOfLine = true;
   va_list Arguments;
   int Length = 0;
@@ -3071,9 +5750,16 @@
     {
       if (!Controller->ControllerInitialized)
 	{
-	  strcpy(&Controller->InitialStatusBuffer[
-		    Controller->InitialStatusLength], Buffer);
-	  Controller->InitialStatusLength += Length;
+	  if (DAC960_CheckStatusBuffer(Controller, Length))
+	    {
+	      strcpy(&Controller->CombinedStatusBuffer
+				  [Controller->InitialStatusLength],
+		     Buffer);
+	      Controller->InitialStatusLength += Length;
+	      Controller->CurrentStatusBuffer =
+		&Controller->CombinedStatusBuffer
+			     [Controller->InitialStatusLength + 1];
+	    }
 	  if (MessageLevel == DAC960_AnnounceLevel)
 	    {
 	      static int AnnouncementLines = 0;
@@ -3093,7 +5779,7 @@
 	      else printk("%s", Buffer);
 	    }
 	}
-      else
+      else if (DAC960_CheckStatusBuffer(Controller, Length))
 	{
 	  strcpy(&Controller->CurrentStatusBuffer[
 		    Controller->CurrentStatusLength], Buffer);
@@ -3102,8 +5788,8 @@
     }
   else if (MessageLevel == DAC960_ProgressLevel)
     {
-      strcpy(Controller->RebuildProgressBuffer, Buffer);
-      Controller->RebuildProgressLength = Length;
+      strcpy(Controller->ProgressBuffer, Buffer);
+      Controller->ProgressBufferLength = Length;
       if (Controller->EphemeralProgressMessage)
 	{
 	  if (jiffies - Controller->LastProgressReportTime
@@ -3138,15 +5824,15 @@
 
 
 /*
-  DAC960_ParsePhysicalDrive parses spaces followed by a Physical Drive
+  DAC960_ParsePhysicalDevice parses spaces followed by a Physical Device
   Channel:TargetID specification from a User Command string.  It updates
-  Channel and TargetID and returns true on success and returns false otherwise.
+  Channel and TargetID and returns true on success and false on failure.
 */
 
-static boolean DAC960_ParsePhysicalDrive(DAC960_Controller_T *Controller,
-					 char *UserCommandString,
-					 unsigned char *Channel,
-					 unsigned char *TargetID)
+static boolean DAC960_ParsePhysicalDevice(DAC960_Controller_T *Controller,
+					  char *UserCommandString,
+					  unsigned char *Channel,
+					  unsigned char *TargetID)
 {
   char *NewUserCommandString = UserCommandString;
   unsigned long XChannel, XTargetID;
@@ -3162,7 +5848,7 @@
   XTargetID = simple_strtoul(UserCommandString, &NewUserCommandString, 10);
   if (NewUserCommandString == UserCommandString ||
       *NewUserCommandString != '\0' ||
-      XTargetID >= DAC960_MaxTargets)
+      XTargetID >= Controller->Targets)
     return false;
   *Channel = XChannel;
   *TargetID = XTargetID;
@@ -3173,7 +5859,7 @@
 /*
   DAC960_ParseLogicalDrive parses spaces followed by a Logical Drive Number
   specification from a User Command string.  It updates LogicalDriveNumber and
-  returns true on success and returns false otherwise.
+  returns true on success and false on failure.
 */
 
 static boolean DAC960_ParseLogicalDrive(DAC960_Controller_T *Controller,
@@ -3189,7 +5875,7 @@
     simple_strtoul(UserCommandString, &NewUserCommandString, 10);
   if (NewUserCommandString == UserCommandString ||
       *NewUserCommandString != '\0' ||
-      XLogicalDriveNumber >= Controller->LogicalDriveCount)
+      XLogicalDriveNumber > DAC960_MaxLogicalDrives - 1)
     return false;
   *LogicalDriveNumber = XLogicalDriveNumber;
   return true;
@@ -3197,68 +5883,71 @@
 
 
 /*
-  DAC960_SetDeviceState sets the Device State for a Physical Drive.
+  DAC960_V1_SetDeviceState sets the Device State for a Physical Device for
+  DAC960 V1 Firmware Controllers.
 */
 
-static void DAC960_SetDeviceState(DAC960_Controller_T *Controller,
-				  DAC960_Command_T *Command,
-				  unsigned char Channel,
-				  unsigned char TargetID,
-				  DAC960_PhysicalDeviceState_T DeviceState,
-				  const char *DeviceStateString)
+static void DAC960_V1_SetDeviceState(DAC960_Controller_T *Controller,
+				     DAC960_Command_T *Command,
+				     unsigned char Channel,
+				     unsigned char TargetID,
+				     DAC960_V1_PhysicalDeviceState_T
+				       DeviceState,
+				     const unsigned char *DeviceStateString)
 {
-  DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
-  CommandMailbox->Type3D.CommandOpcode = DAC960_StartDevice;
+  DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
+  CommandMailbox->Type3D.CommandOpcode = DAC960_V1_StartDevice;
   CommandMailbox->Type3D.Channel = Channel;
   CommandMailbox->Type3D.TargetID = TargetID;
   CommandMailbox->Type3D.DeviceState = DeviceState;
   CommandMailbox->Type3D.Modifier = 0;
   DAC960_ExecuteCommand(Command);
-  switch (Command->CommandStatus)
+  switch (Command->V1.CommandStatus)
     {
-    case DAC960_NormalCompletion:
-      DAC960_UserCritical("%s of Physical Drive %d:%d Succeeded\n", Controller,
+    case DAC960_V1_NormalCompletion:
+      DAC960_UserCritical("%s of Physical Device %d:%d Succeeded\n", Controller,
 			  DeviceStateString, Channel, TargetID);
       break;
-    case DAC960_UnableToStartDevice:
-      DAC960_UserCritical("%s of Physical Drive %d:%d Failed - "
+    case DAC960_V1_UnableToStartDevice:
+      DAC960_UserCritical("%s of Physical Device %d:%d Failed - "
 			  "Unable to Start Device\n", Controller,
 			  DeviceStateString, Channel, TargetID);
       break;
-    case DAC960_NoDeviceAtAddress:
-      DAC960_UserCritical("%s of Physical Drive %d:%d Failed - "
+    case DAC960_V1_NoDeviceAtAddress:
+      DAC960_UserCritical("%s of Physical Device %d:%d Failed - "
 			  "No Device at Address\n", Controller,
 			  DeviceStateString, Channel, TargetID);
       break;
-    case DAC960_InvalidChannelOrTargetOrModifier:
-      DAC960_UserCritical("%s of Physical Drive %d:%d Failed - "
+    case DAC960_V1_InvalidChannelOrTargetOrModifier:
+      DAC960_UserCritical("%s of Physical Device %d:%d Failed - "
 			  "Invalid Channel or Target or Modifier\n",
 			  Controller, DeviceStateString, Channel, TargetID);
       break;
-    case DAC960_ChannelBusy:
-      DAC960_UserCritical("%s of Physical Drive %d:%d Failed - "
+    case DAC960_V1_ChannelBusy:
+      DAC960_UserCritical("%s of Physical Device %d:%d Failed - "
 			  "Channel Busy\n", Controller,
 			  DeviceStateString, Channel, TargetID);
       break;
     default:
-      DAC960_UserCritical("%s of Physical Drive %d:%d Failed - "
+      DAC960_UserCritical("%s of Physical Device %d:%d Failed - "
 			  "Unexpected Status %04X\n", Controller,
 			  DeviceStateString, Channel, TargetID,
-			  Command->CommandStatus);
+			  Command->V1.CommandStatus);
       break;
     }
 }
 
 
 /*
-  DAC960_ExecuteUserCommand executes a User Command.
+  DAC960_V1_ExecuteUserCommand executes a User Command for DAC960 V1 Firmware
+  Controllers.
 */
 
-static boolean DAC960_ExecuteUserCommand(DAC960_Controller_T *Controller,
-					 char *UserCommand)
+static boolean DAC960_V1_ExecuteUserCommand(DAC960_Controller_T *Controller,
+					    unsigned char *UserCommand)
 {
   DAC960_Command_T *Command;
-  DAC960_CommandMailbox_T *CommandMailbox;
+  DAC960_V1_CommandMailbox_T *CommandMailbox;
   ProcessorFlags_T ProcessorFlags;
   unsigned char Channel, TargetID, LogicalDriveNumber;
   DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
@@ -3266,100 +5955,98 @@
     DAC960_WaitForCommand(Controller);
   DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
   Controller->UserStatusLength = 0;
-  DAC960_ClearCommand(Command);
+  DAC960_V1_ClearCommand(Command);
   Command->CommandType = DAC960_ImmediateCommand;
-  CommandMailbox = &Command->CommandMailbox;
+  CommandMailbox = &Command->V1.CommandMailbox;
   if (strcmp(UserCommand, "flush-cache") == 0)
     {
-      CommandMailbox->Type3.CommandOpcode = DAC960_Flush;
+      CommandMailbox->Type3.CommandOpcode = DAC960_V1_Flush;
       DAC960_ExecuteCommand(Command);
       DAC960_UserCritical("Cache Flush Completed\n", Controller);
     }
   else if (strncmp(UserCommand, "kill", 4) == 0 &&
-	   DAC960_ParsePhysicalDrive(Controller, &UserCommand[4],
-				     &Channel, &TargetID))
+	   DAC960_ParsePhysicalDevice(Controller, &UserCommand[4],
+				      &Channel, &TargetID))
     {
-      DAC960_DeviceState_T *DeviceState =
-	&Controller->DeviceState[Controller->DeviceStateIndex]
-				[Channel][TargetID];
+      DAC960_V1_DeviceState_T *DeviceState =
+	&Controller->V1.DeviceState[Channel][TargetID];
       if (DeviceState->Present &&
-	  DeviceState->DeviceType == DAC960_DiskType &&
-	  DeviceState->DeviceState != DAC960_Device_Dead)
-	DAC960_SetDeviceState(Controller, Command, Channel, TargetID,
-			      DAC960_Device_Dead, "Kill");
-      else DAC960_UserCritical("Kill of Physical Drive %d:%d Illegal\n",
+	  DeviceState->DeviceType == DAC960_V1_DiskType &&
+	  DeviceState->DeviceState != DAC960_V1_Device_Dead)
+	DAC960_V1_SetDeviceState(Controller, Command, Channel, TargetID,
+				 DAC960_V1_Device_Dead, "Kill");
+      else DAC960_UserCritical("Kill of Physical Device %d:%d Illegal\n",
 			       Controller, Channel, TargetID);
     }
   else if (strncmp(UserCommand, "make-online", 11) == 0 &&
-	   DAC960_ParsePhysicalDrive(Controller, &UserCommand[11],
-				     &Channel, &TargetID))
+	   DAC960_ParsePhysicalDevice(Controller, &UserCommand[11],
+				      &Channel, &TargetID))
     {
-      DAC960_DeviceState_T *DeviceState =
-	&Controller->DeviceState[Controller->DeviceStateIndex]
-				[Channel][TargetID];
+      DAC960_V1_DeviceState_T *DeviceState =
+	&Controller->V1.DeviceState[Channel][TargetID];
       if (DeviceState->Present &&
-	  DeviceState->DeviceType == DAC960_DiskType &&
-	  DeviceState->DeviceState == DAC960_Device_Dead)
-	DAC960_SetDeviceState(Controller, Command, Channel, TargetID,
-			      DAC960_Device_Online, "Make Online");
-      else DAC960_UserCritical("Make Online of Physical Drive %d:%d Illegal\n",
+	  DeviceState->DeviceType == DAC960_V1_DiskType &&
+	  DeviceState->DeviceState == DAC960_V1_Device_Dead)
+	DAC960_V1_SetDeviceState(Controller, Command, Channel, TargetID,
+				 DAC960_V1_Device_Online, "Make Online");
+      else DAC960_UserCritical("Make Online of Physical Device %d:%d Illegal\n",
 			       Controller, Channel, TargetID);
 
     }
   else if (strncmp(UserCommand, "make-standby", 12) == 0 &&
-	   DAC960_ParsePhysicalDrive(Controller, &UserCommand[12],
-				     &Channel, &TargetID))
+	   DAC960_ParsePhysicalDevice(Controller, &UserCommand[12],
+				      &Channel, &TargetID))
     {
-      DAC960_DeviceState_T *DeviceState =
-	&Controller->DeviceState[Controller->DeviceStateIndex]
-				[Channel][TargetID];
+      DAC960_V1_DeviceState_T *DeviceState =
+	&Controller->V1.DeviceState[Channel][TargetID];
       if (DeviceState->Present &&
-	  DeviceState->DeviceType == DAC960_DiskType &&
-	  DeviceState->DeviceState == DAC960_Device_Dead)
-	DAC960_SetDeviceState(Controller, Command, Channel, TargetID,
-			      DAC960_Device_Standby, "Make Standby");
-      else DAC960_UserCritical("Make Standby of Physical Drive %d:%d Illegal\n",
+	  DeviceState->DeviceType == DAC960_V1_DiskType &&
+	  DeviceState->DeviceState == DAC960_V1_Device_Dead)
+	DAC960_V1_SetDeviceState(Controller, Command, Channel, TargetID,
+				 DAC960_V1_Device_Standby, "Make Standby");
+      else DAC960_UserCritical("Make Standby of Physical "
+			       "Device %d:%d Illegal\n",
 			       Controller, Channel, TargetID);
     }
   else if (strncmp(UserCommand, "rebuild", 7) == 0 &&
-	   DAC960_ParsePhysicalDrive(Controller, &UserCommand[7],
-				     &Channel, &TargetID))
+	   DAC960_ParsePhysicalDevice(Controller, &UserCommand[7],
+				      &Channel, &TargetID))
     {
-      CommandMailbox->Type3D.CommandOpcode = DAC960_RebuildAsync;
+      CommandMailbox->Type3D.CommandOpcode = DAC960_V1_RebuildAsync;
       CommandMailbox->Type3D.Channel = Channel;
       CommandMailbox->Type3D.TargetID = TargetID;
       DAC960_ExecuteCommand(Command);
-      switch (Command->CommandStatus)
+      switch (Command->V1.CommandStatus)
 	{
-	case DAC960_NormalCompletion:
-	  DAC960_UserCritical("Rebuild of Physical Drive %d:%d Initiated\n",
+	case DAC960_V1_NormalCompletion:
+	  DAC960_UserCritical("Rebuild of Physical Device %d:%d Initiated\n",
 			      Controller, Channel, TargetID);
 	  break;
-	case DAC960_AttemptToRebuildOnlineDrive:
-	  DAC960_UserCritical("Rebuild of Physical Drive %d:%d Failed - "
+	case DAC960_V1_AttemptToRebuildOnlineDrive:
+	  DAC960_UserCritical("Rebuild of Physical Device %d:%d Failed - "
 			      "Attempt to Rebuild Online or "
 			      "Unresponsive Drive\n",
 			      Controller, Channel, TargetID);
 	  break;
-	case DAC960_NewDiskFailedDuringRebuild:
-	  DAC960_UserCritical("Rebuild of Physical Drive %d:%d Failed - "
+	case DAC960_V1_NewDiskFailedDuringRebuild:
+	  DAC960_UserCritical("Rebuild of Physical Device %d:%d Failed - "
 			      "New Disk Failed During Rebuild\n",
 			      Controller, Channel, TargetID);
 	  break;
-	case DAC960_InvalidDeviceAddress:
-	  DAC960_UserCritical("Rebuild of Physical Drive %d:%d Failed - "
+	case DAC960_V1_InvalidDeviceAddress:
+	  DAC960_UserCritical("Rebuild of Physical Device %d:%d Failed - "
 			      "Invalid Device Address\n",
 			      Controller, Channel, TargetID);
 	  break;
-	case DAC960_RebuildOrCheckAlreadyInProgress:
-	  DAC960_UserCritical("Rebuild of Physical Drive %d:%d Failed - "
+	case DAC960_V1_RebuildOrCheckAlreadyInProgress:
+	  DAC960_UserCritical("Rebuild of Physical Device %d:%d Failed - "
 			      "Rebuild or Consistency Check Already "
 			      "in Progress\n", Controller, Channel, TargetID);
 	  break;
 	default:
-	  DAC960_UserCritical("Rebuild of Physical Drive %d:%d Failed - "
+	  DAC960_UserCritical("Rebuild of Physical Device %d:%d Failed - "
 			      "Unexpected Status %04X\n", Controller,
-			      Channel, TargetID, Command->CommandStatus);
+			      Channel, TargetID, Command->V1.CommandStatus);
 	  break;
 	}
     }
@@ -3367,28 +6054,28 @@
 	   DAC960_ParseLogicalDrive(Controller, &UserCommand[17],
 				    &LogicalDriveNumber))
     {
-      CommandMailbox->Type3C.CommandOpcode = DAC960_CheckConsistencyAsync;
+      CommandMailbox->Type3C.CommandOpcode = DAC960_V1_CheckConsistencyAsync;
       CommandMailbox->Type3C.LogicalDriveNumber = LogicalDriveNumber;
       CommandMailbox->Type3C.AutoRestore = true;
       DAC960_ExecuteCommand(Command);
-      switch (Command->CommandStatus)
+      switch (Command->V1.CommandStatus)
 	{
-	case DAC960_NormalCompletion:
+	case DAC960_V1_NormalCompletion:
 	  DAC960_UserCritical("Consistency Check of Logical Drive %d "
 			      "(/dev/rd/c%dd%d) Initiated\n",
 			      Controller, LogicalDriveNumber,
 			      Controller->ControllerNumber,
 			      LogicalDriveNumber);
 	  break;
-	case DAC960_DependentDiskIsDead:
+	case DAC960_V1_DependentDiskIsDead:
 	  DAC960_UserCritical("Consistency Check of Logical Drive %d "
 			      "(/dev/rd/c%dd%d) Failed - "
-			      "Dependent Physical Drive is DEAD\n",
+			      "Dependent Physical Device is DEAD\n",
 			      Controller, LogicalDriveNumber,
 			      Controller->ControllerNumber,
 			      LogicalDriveNumber);
 	  break;
-	case DAC960_InvalidOrNonredundantLogicalDrive:
+	case DAC960_V1_InvalidOrNonredundantLogicalDrive:
 	  DAC960_UserCritical("Consistency Check of Logical Drive %d "
 			      "(/dev/rd/c%dd%d) Failed - "
 			      "Invalid or Nonredundant Logical Drive\n",
@@ -3396,7 +6083,7 @@
 			      Controller->ControllerNumber,
 			      LogicalDriveNumber);
 	  break;
-	case DAC960_RebuildOrCheckAlreadyInProgress:
+	case DAC960_V1_RebuildOrCheckAlreadyInProgress:
 	  DAC960_UserCritical("Consistency Check of Logical Drive %d "
 			      "(/dev/rd/c%dd%d) Failed - Rebuild or "
 			      "Consistency Check Already in Progress\n",
@@ -3410,7 +6097,7 @@
 			      "Unexpected Status %04X\n",
 			      Controller, LogicalDriveNumber,
 			      Controller->ControllerNumber,
-			      LogicalDriveNumber, Command->CommandStatus);
+			      LogicalDriveNumber, Command->V1.CommandStatus);
 	  break;
 	}
     }
@@ -3418,14 +6105,14 @@
 	   strcmp(UserCommand, "cancel-consistency-check") == 0)
     {
       unsigned char OldRebuildRateConstant;
-      CommandMailbox->Type3R.CommandOpcode = DAC960_RebuildControl;
+      CommandMailbox->Type3R.CommandOpcode = DAC960_V1_RebuildControl;
       CommandMailbox->Type3R.RebuildRateConstant = 0xFF;
       CommandMailbox->Type3R.BusAddress =
 	Virtual_to_Bus(&OldRebuildRateConstant);
       DAC960_ExecuteCommand(Command);
-      switch (Command->CommandStatus)
+      switch (Command->V1.CommandStatus)
 	{
-	case DAC960_NormalCompletion:
+	case DAC960_V1_NormalCompletion:
 	  DAC960_UserCritical("Rebuild or Consistency Check Cancelled\n",
 			      Controller);
 	  break;
@@ -3433,7 +6120,7 @@
 	  DAC960_UserCritical("Cancellation of Rebuild or "
 			      "Consistency Check Failed - "
 			      "Unexpected Status %04X\n",
-			      Controller, Command->CommandStatus);
+			      Controller, Command->V1.CommandStatus);
 	  break;
 	}
     }
@@ -3447,25 +6134,237 @@
 
 
 /*
+  DAC960_V2_TranslatePhysicalDevice translates a Physical Device Channel and
+  TargetID into a Logical Device.  It returns true on success and false
+  on failure.
+*/
+
+static boolean DAC960_V2_TranslatePhysicalDevice(DAC960_Command_T *Command,
+						 unsigned char Channel,
+						 unsigned char TargetID,
+						 unsigned short
+						   *LogicalDeviceNumber)
+{
+  DAC960_V2_CommandMailbox_T SavedCommandMailbox, *CommandMailbox;
+  DAC960_V2_PhysicalToLogicalDevice_T PhysicalToLogicalDevice;
+  CommandMailbox = &Command->V2.CommandMailbox;
+  memcpy(&SavedCommandMailbox, CommandMailbox,
+	 sizeof(DAC960_V2_CommandMailbox_T));
+  CommandMailbox->PhysicalDeviceInfo.CommandOpcode = DAC960_V2_IOCTL;
+  CommandMailbox->PhysicalDeviceInfo.CommandControlBits
+				    .DataTransferControllerToHost = true;
+  CommandMailbox->PhysicalDeviceInfo.CommandControlBits
+				    .NoAutoRequestSense = true;
+  CommandMailbox->PhysicalDeviceInfo.DataTransferSize =
+    sizeof(DAC960_V2_PhysicalToLogicalDevice_T);
+  CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.TargetID = TargetID;
+  CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.Channel = Channel;
+  CommandMailbox->PhysicalDeviceInfo.IOCTL_Opcode =
+    DAC960_V2_TranslatePhysicalToLogicalDevice;
+  CommandMailbox->Common.DataTransferMemoryAddress
+			.ScatterGatherSegments[0]
+			.SegmentDataPointer =
+    Virtual_to_Bus(&PhysicalToLogicalDevice);
+  CommandMailbox->Common.DataTransferMemoryAddress
+			.ScatterGatherSegments[0]
+			.SegmentByteCount =
+    CommandMailbox->Common.DataTransferSize;
+  DAC960_ExecuteCommand(Command);
+  memcpy(CommandMailbox, &SavedCommandMailbox,
+	 sizeof(DAC960_V2_CommandMailbox_T));
+  *LogicalDeviceNumber = PhysicalToLogicalDevice.LogicalDeviceNumber;
+  return (Command->V2.CommandStatus == DAC960_V2_NormalCompletion);
+}
+
+
+/*
+  DAC960_V2_ExecuteUserCommand executes a User Command for DAC960 V2 Firmware
+  Controllers.
+*/
+
+static boolean DAC960_V2_ExecuteUserCommand(DAC960_Controller_T *Controller,
+					    unsigned char *UserCommand)
+{
+  DAC960_Command_T *Command;
+  DAC960_V2_CommandMailbox_T *CommandMailbox;
+  ProcessorFlags_T ProcessorFlags;
+  unsigned char Channel, TargetID, LogicalDriveNumber;
+  unsigned short LogicalDeviceNumber;
+  DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
+  while ((Command = DAC960_AllocateCommand(Controller)) == NULL)
+    DAC960_WaitForCommand(Controller);
+  DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
+  Controller->UserStatusLength = 0;
+  DAC960_V2_ClearCommand(Command);
+  Command->CommandType = DAC960_ImmediateCommand;
+  CommandMailbox = &Command->V2.CommandMailbox;
+  CommandMailbox->Common.CommandOpcode = DAC960_V2_IOCTL;
+  CommandMailbox->Common.CommandControlBits.DataTransferControllerToHost = true;
+  CommandMailbox->Common.CommandControlBits.NoAutoRequestSense = true;
+  if (strcmp(UserCommand, "flush-cache") == 0)
+    {
+      CommandMailbox->DeviceOperation.IOCTL_Opcode = DAC960_V2_PauseDevice;
+      CommandMailbox->DeviceOperation.OperationDevice =
+	DAC960_V2_RAID_Controller;
+      DAC960_ExecuteCommand(Command);
+      DAC960_UserCritical("Cache Flush Completed\n", Controller);
+    }
+  else if (strncmp(UserCommand, "kill", 4) == 0 &&
+	   DAC960_ParsePhysicalDevice(Controller, &UserCommand[4],
+				      &Channel, &TargetID) &&
+	   DAC960_V2_TranslatePhysicalDevice(Command, Channel, TargetID,
+					     &LogicalDeviceNumber))
+    {
+      CommandMailbox->SetDeviceState.LogicalDevice.LogicalDeviceNumber =
+	LogicalDeviceNumber;
+      CommandMailbox->SetDeviceState.IOCTL_Opcode =
+	DAC960_V2_SetDeviceState;
+      CommandMailbox->SetDeviceState.DeviceState.PhysicalDeviceState =
+	DAC960_V2_Device_Dead;
+      DAC960_ExecuteCommand(Command);
+      DAC960_UserCritical("Kill of Physical Device %d:%d %s\n",
+			  Controller, Channel, TargetID,
+			  (Command->V2.CommandStatus
+			   == DAC960_V2_NormalCompletion
+			   ? "Succeeded" : "Failed"));
+    }
+  else if (strncmp(UserCommand, "make-online", 11) == 0 &&
+	   DAC960_ParsePhysicalDevice(Controller, &UserCommand[11],
+				      &Channel, &TargetID) &&
+	   DAC960_V2_TranslatePhysicalDevice(Command, Channel, TargetID,
+					     &LogicalDeviceNumber))
+    {
+      CommandMailbox->SetDeviceState.LogicalDevice.LogicalDeviceNumber =
+	LogicalDeviceNumber;
+      CommandMailbox->SetDeviceState.IOCTL_Opcode =
+	DAC960_V2_SetDeviceState;
+      CommandMailbox->SetDeviceState.DeviceState.PhysicalDeviceState =
+	DAC960_V2_Device_Online;
+      DAC960_ExecuteCommand(Command);
+      DAC960_UserCritical("Make Online of Physical Device %d:%d %s\n",
+			  Controller, Channel, TargetID,
+			  (Command->V2.CommandStatus
+			   == DAC960_V2_NormalCompletion
+			   ? "Succeeded" : "Failed"));
+    }
+  else if (strncmp(UserCommand, "make-standby", 12) == 0 &&
+	   DAC960_ParsePhysicalDevice(Controller, &UserCommand[12],
+				      &Channel, &TargetID) &&
+	   DAC960_V2_TranslatePhysicalDevice(Command, Channel, TargetID,
+					     &LogicalDeviceNumber))
+    {
+      CommandMailbox->SetDeviceState.LogicalDevice.LogicalDeviceNumber =
+	LogicalDeviceNumber;
+      CommandMailbox->SetDeviceState.IOCTL_Opcode =
+	DAC960_V2_SetDeviceState;
+      CommandMailbox->SetDeviceState.DeviceState.PhysicalDeviceState =
+	DAC960_V2_Device_Standby;
+      DAC960_ExecuteCommand(Command);
+      DAC960_UserCritical("Make Standby of Physical Device %d:%d %s\n",
+			  Controller, Channel, TargetID,
+			  (Command->V2.CommandStatus
+			   == DAC960_V2_NormalCompletion
+			   ? "Succeeded" : "Failed"));
+    }
+  else if (strncmp(UserCommand, "rebuild", 7) == 0 &&
+	   DAC960_ParsePhysicalDevice(Controller, &UserCommand[7],
+				      &Channel, &TargetID) &&
+	   DAC960_V2_TranslatePhysicalDevice(Command, Channel, TargetID,
+					     &LogicalDeviceNumber))
+    {
+      CommandMailbox->LogicalDeviceInfo.LogicalDevice.LogicalDeviceNumber =
+	LogicalDeviceNumber;
+      CommandMailbox->LogicalDeviceInfo.IOCTL_Opcode =
+	DAC960_V2_RebuildDeviceStart;
+      DAC960_ExecuteCommand(Command);
+      DAC960_UserCritical("Rebuild of Physical Device %d:%d %s\n",
+			  Controller, Channel, TargetID,
+			  (Command->V2.CommandStatus
+			   == DAC960_V2_NormalCompletion
+			   ? "Initiated" : "Not Initiated"));
+    }
+  else if (strncmp(UserCommand, "cancel-rebuild", 14) == 0 &&
+	   DAC960_ParsePhysicalDevice(Controller, &UserCommand[14],
+				      &Channel, &TargetID) &&
+	   DAC960_V2_TranslatePhysicalDevice(Command, Channel, TargetID,
+					     &LogicalDeviceNumber))
+    {
+      CommandMailbox->LogicalDeviceInfo.LogicalDevice.LogicalDeviceNumber =
+	LogicalDeviceNumber;
+      CommandMailbox->LogicalDeviceInfo.IOCTL_Opcode =
+	DAC960_V2_RebuildDeviceStop;
+      DAC960_ExecuteCommand(Command);
+      DAC960_UserCritical("Rebuild of Physical Device %d:%d %s\n",
+			  Controller, Channel, TargetID,
+			  (Command->V2.CommandStatus
+			   == DAC960_V2_NormalCompletion
+			   ? "Cancelled" : "Not Cancelled"));
+    }
+  else if (strncmp(UserCommand, "check-consistency", 17) == 0 &&
+	   DAC960_ParseLogicalDrive(Controller, &UserCommand[17],
+				    &LogicalDriveNumber))
+    {
+      CommandMailbox->ConsistencyCheck.LogicalDevice.LogicalDeviceNumber =
+	LogicalDriveNumber;
+      CommandMailbox->ConsistencyCheck.IOCTL_Opcode =
+	DAC960_V2_ConsistencyCheckStart;
+      CommandMailbox->ConsistencyCheck.RestoreConsistency = true;
+      CommandMailbox->ConsistencyCheck.InitializedAreaOnly = false;
+      DAC960_ExecuteCommand(Command);
+      DAC960_UserCritical("Consistency Check of Logical Drive %d "
+			  "(/dev/rd/c%dd%d) %s\n",
+			  Controller, LogicalDriveNumber,
+			  Controller->ControllerNumber,
+			  LogicalDriveNumber,
+			  (Command->V2.CommandStatus
+			   == DAC960_V2_NormalCompletion
+			   ? "Initiated" : "Not Initiated"));
+    }
+  else if (strncmp(UserCommand, "cancel-consistency-check", 24) == 0 &&
+	   DAC960_ParseLogicalDrive(Controller, &UserCommand[24],
+				    &LogicalDriveNumber))
+    {
+      CommandMailbox->ConsistencyCheck.LogicalDevice.LogicalDeviceNumber =
+	LogicalDriveNumber;
+      CommandMailbox->ConsistencyCheck.IOCTL_Opcode =
+	DAC960_V2_ConsistencyCheckStop;
+      DAC960_ExecuteCommand(Command);
+      DAC960_UserCritical("Consistency Check of Logical Drive %d "
+			  "(/dev/rd/c%dd%d) %s\n",
+			  Controller, LogicalDriveNumber,
+			  Controller->ControllerNumber,
+			  LogicalDriveNumber,
+			  (Command->V2.CommandStatus
+			   == DAC960_V2_NormalCompletion
+			   ? "Cancelled" : "Not Cancelled"));
+    }
+  else if (strcmp(UserCommand, "suppress-enclosure-messages") == 0)
+    Controller->SuppressEnclosureMessages = true;
+  else DAC960_UserCritical("Illegal User Command: '%s'\n",
+			   Controller, UserCommand);
+  DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
+  DAC960_DeallocateCommand(Command);
+  DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
+  return true;
+}
+
+
+/*
   DAC960_ProcReadStatus implements reading /proc/rd/status.
 */
 
 static int DAC960_ProcReadStatus(char *Page, char **Start, off_t Offset,
 				 int Count, int *EOF, void *Data)
 {
-  char *StatusMessage = "OK\n";
+  unsigned char *StatusMessage = "OK\n";
   int ControllerNumber, BytesAvailable;
   for (ControllerNumber = 0;
        ControllerNumber < DAC960_ControllerCount;
        ControllerNumber++)
     {
       DAC960_Controller_T *Controller = DAC960_Controllers[ControllerNumber];
-      DAC960_Enquiry_T *Enquiry;
       if (Controller == NULL) continue;
-      Enquiry = &Controller->Enquiry[Controller->EnquiryIndex];
-      if (Enquiry->CriticalLogicalDriveCount > 0 ||
-	  Enquiry->OfflineLogicalDriveCount > 0 ||
-	  Enquiry->DeadDriveCount > 0)
+      if (Controller->MonitoringAlertMode)
 	{
 	  StatusMessage = "ALERT\n";
 	  break;
@@ -3500,7 +6399,7 @@
     }
   if (Count <= 0) return 0;
   *Start = Page;
-  memcpy(Page, &Controller->InitialStatusBuffer[Offset], Count);
+  memcpy(Page, &Controller->CombinedStatusBuffer[Offset], Count);
   return Count;
 }
 
@@ -3513,6 +6412,9 @@
 					int Count, int *EOF, void *Data)
 {
   DAC960_Controller_T *Controller = (DAC960_Controller_T *) Data;
+  unsigned char *StatusMessage =
+    "No Rebuild or Consistency Check in Progress\n";
+  int ProgressMessageLength = strlen(StatusMessage);
   int BytesAvailable;
   if (jiffies != Controller->LastCurrentStatusTime)
     {
@@ -3520,22 +6422,20 @@
       DAC960_AnnounceDriver(Controller);
       DAC960_ReportControllerConfiguration(Controller);
       DAC960_ReportDeviceConfiguration(Controller);
-      Controller->CurrentStatusBuffer[Controller->CurrentStatusLength++] = ' ';
-      Controller->CurrentStatusBuffer[Controller->CurrentStatusLength++] = ' ';
-      if (Controller->RebuildProgressLength > 0)
-	{
-	  strcpy(&Controller->CurrentStatusBuffer
-			      [Controller->CurrentStatusLength],
-		 Controller->RebuildProgressBuffer);
-	  Controller->CurrentStatusLength += Controller->RebuildProgressLength;
-	}
-      else
-	{
-	  char *StatusMessage = "No Rebuild or Consistency Check in Progress\n";
-	  strcpy(&Controller->CurrentStatusBuffer
-			      [Controller->CurrentStatusLength],
-		 StatusMessage);
-	  Controller->CurrentStatusLength += strlen(StatusMessage);
+      if (Controller->ProgressBufferLength > 0)
+	ProgressMessageLength = Controller->ProgressBufferLength;
+      if (DAC960_CheckStatusBuffer(Controller, 2 + ProgressMessageLength))
+	{
+	  unsigned char *CurrentStatusBuffer = Controller->CurrentStatusBuffer;
+	  CurrentStatusBuffer[Controller->CurrentStatusLength++] = ' ';
+	  CurrentStatusBuffer[Controller->CurrentStatusLength++] = ' ';
+	  if (Controller->ProgressBufferLength > 0)
+	    strcpy(&CurrentStatusBuffer[Controller->CurrentStatusLength],
+		   Controller->ProgressBuffer);
+	  else
+	    strcpy(&CurrentStatusBuffer[Controller->CurrentStatusLength],
+		   StatusMessage);
+	  Controller->CurrentStatusLength += ProgressMessageLength;
 	}
       Controller->LastCurrentStatusTime = jiffies;
     }
@@ -3581,7 +6481,7 @@
 				       unsigned long Count, void *Data)
 {
   DAC960_Controller_T *Controller = (DAC960_Controller_T *) Data;
-  char CommandBuffer[80];
+  unsigned char CommandBuffer[80];
   int Length;
   if (Count > sizeof(CommandBuffer)-1) return -EINVAL;
   copy_from_user(CommandBuffer, Buffer, Count);
@@ -3589,8 +6489,12 @@
   Length = strlen(CommandBuffer);
   if (CommandBuffer[Length-1] == '\n')
     CommandBuffer[--Length] = '\0';
-  return (DAC960_ExecuteUserCommand(Controller, CommandBuffer)
-	  ? Count : -EBUSY);
+  if (Controller->FirmwareType == DAC960_V1_Controller)
+    return (DAC960_V1_ExecuteUserCommand(Controller, CommandBuffer)
+	    ? Count : -EBUSY);
+  else
+    return (DAC960_V2_ExecuteUserCommand(Controller, CommandBuffer)
+	    ? Count : -EBUSY);
 }
 
 
@@ -3620,6 +6524,7 @@
       PROC_DirectoryEntry_T *ControllerProcEntry, *InitialStatusProcEntry;
       PROC_DirectoryEntry_T *CurrentStatusProcEntry, *UserCommandProcEntry;
       if (Controller == NULL) continue;
+      sprintf(Controller->ControllerName, "c%d", Controller->ControllerNumber);
       ControllerProcEntry = &Controller->ControllerProcEntry;
       ControllerProcEntry->name = Controller->ControllerName;
       ControllerProcEntry->namelen = strlen(ControllerProcEntry->name);

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