blob: e462a3cd33669bc8242c089a47203727c616f912 [file] [log] [blame]
/*
Linux Driver for Mylex DAC960/AcceleRAID/eXtremeRAID PCI RAID Controllers
Copyright 1998-2001 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
Free Software Foundation.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for complete details.
The author respectfully requests that any modifications to this software be
sent directly to him for evaluation and testing.
*/
#define DAC960_DriverVersion "2.4.11"
#define DAC960_DriverDate "11 October 2001"
#include <linux/version.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/blk.h>
#include <linux/blkdev.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/hdreg.h>
#include <linux/blkpg.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/locks.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/proc_fs.h>
#include <linux/reboot.h>
#include <linux/spinlock.h>
#include <linux/timer.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <asm/io.h>
#include <asm/segment.h>
#include <asm/uaccess.h>
#include "DAC960.h"
/*
DAC960_ControllerCount is the number of DAC960 Controllers detected.
*/
static int
DAC960_ControllerCount = 0;
/*
DAC960_ActiveControllerCount is the number of active DAC960 Controllers
detected.
*/
static int
DAC960_ActiveControllerCount = 0;
/*
DAC960_Controllers is an array of pointers to the DAC960 Controller
structures.
*/
static DAC960_Controller_T
*DAC960_Controllers[DAC960_MaxControllers] = { NULL };
/*
DAC960_BlockDeviceOperations is the Block Device Operations structure for
DAC960 Logical Disk Devices.
*/
static BlockDeviceOperations_T
DAC960_BlockDeviceOperations =
{ owner: THIS_MODULE,
open: DAC960_Open,
release: DAC960_Release,
ioctl: DAC960_IOCTL };
/*
DAC960_ProcDirectoryEntry is the DAC960 /proc/rd directory entry.
*/
static PROC_DirectoryEntry_T
*DAC960_ProcDirectoryEntry;
/*
DAC960_NotifierBlock is the Notifier Block structure for DAC960 Driver.
*/
static NotifierBlock_T
DAC960_NotifierBlock = { DAC960_Notifier, NULL, 0 };
/*
DAC960_AnnounceDriver announces the Driver Version and Date, Author's Name,
Copyright Notice, and Electronic Mail Address.
*/
static void DAC960_AnnounceDriver(DAC960_Controller_T *Controller)
{
DAC960_Announce("***** DAC960 RAID Driver Version "
DAC960_DriverVersion " of "
DAC960_DriverDate " *****\n", Controller);
DAC960_Announce("Copyright 1998-2001 by Leonard N. Zubkoff "
"<lnz@dandelion.com>\n", Controller);
}
/*
DAC960_Failure prints a standardized error message, and then returns false.
*/
static boolean DAC960_Failure(DAC960_Controller_T *Controller,
unsigned char *ErrorMessage)
{
DAC960_Error("While configuring DAC960 PCI RAID Controller at\n",
Controller);
if (Controller->IO_Address == 0)
DAC960_Error("PCI Bus %d Device %d Function %d I/O Address N/A "
"PCI Address 0x%X\n", Controller,
Controller->Bus, Controller->Device,
Controller->Function, Controller->PCI_Address);
else DAC960_Error("PCI Bus %d Device %d Function %d I/O Address "
"0x%X PCI Address 0x%X\n", Controller,
Controller->Bus, Controller->Device,
Controller->Function, Controller->IO_Address,
Controller->PCI_Address);
DAC960_Error("%s FAILED - DETACHING\n", Controller, ErrorMessage);
return false;
}
/*
DAC960_CreateAuxiliaryStructures allocates and initializes the auxiliary
data structures for Controller. It returns true on success and false on
failure.
*/
static boolean DAC960_CreateAuxiliaryStructures(DAC960_Controller_T *Controller)
{
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;
}
/*
DAC960_AllocateCommand allocates a Command structure from Controller's
free list. During driver initialization, a special initialization command
has been placed on the free list to guarantee that command allocation can
never fail.
*/
static inline DAC960_Command_T *DAC960_AllocateCommand(DAC960_Controller_T
*Controller)
{
DAC960_Command_T *Command = Controller->FreeCommands;
if (Command == NULL) return NULL;
Controller->FreeCommands = Command->Next;
Command->Next = NULL;
return Command;
}
/*
DAC960_DeallocateCommand deallocates Command, returning it to Controller's
free list.
*/
static inline void DAC960_DeallocateCommand(DAC960_Command_T *Command)
{
DAC960_Controller_T *Controller = Command->Controller;
Command->Next = Controller->FreeCommands;
Controller->FreeCommands = Command;
}
/*
DAC960_WaitForCommand waits for a wake_up on Controller's Command Wait Queue.
*/
static void DAC960_WaitForCommand(DAC960_Controller_T *Controller)
{
spin_unlock_irq(&io_request_lock);
__wait_event(Controller->CommandWaitQueue, Controller->FreeCommands);
spin_lock_irq(&io_request_lock);
}
/*
DAC960_BA_QueueCommand queues Command for DAC960 BA Series Controllers.
*/
static void DAC960_BA_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_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_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_P_QueueCommand queues Command for DAC960 P Series Controllers.
*/
static void DAC960_P_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;
switch (CommandMailbox->Common.CommandOpcode)
{
case DAC960_V1_Enquiry:
CommandMailbox->Common.CommandOpcode = DAC960_V1_Enquiry_Old;
break;
case DAC960_V1_GetDeviceState:
CommandMailbox->Common.CommandOpcode = DAC960_V1_GetDeviceState_Old;
break;
case DAC960_V1_Read:
CommandMailbox->Common.CommandOpcode = DAC960_V1_Read_Old;
DAC960_PD_To_P_TranslateReadWriteCommand(CommandMailbox);
break;
case DAC960_V1_Write:
CommandMailbox->Common.CommandOpcode = DAC960_V1_Write_Old;
DAC960_PD_To_P_TranslateReadWriteCommand(CommandMailbox);
break;
case DAC960_V1_ReadWithScatterGather:
CommandMailbox->Common.CommandOpcode =
DAC960_V1_ReadWithScatterGather_Old;
DAC960_PD_To_P_TranslateReadWriteCommand(CommandMailbox);
break;
case DAC960_V1_WriteWithScatterGather:
CommandMailbox->Common.CommandOpcode =
DAC960_V1_WriteWithScatterGather_Old;
DAC960_PD_To_P_TranslateReadWriteCommand(CommandMailbox);
break;
default:
break;
}
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 void DAC960_ExecuteCommand(DAC960_Command_T *Command)
{
DAC960_Controller_T *Controller = Command->Controller;
DECLARE_COMPLETION(Completion);
unsigned long ProcessorFlags;
Command->Completion = &Completion;
DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
DAC960_QueueCommand(Command);
DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
if (in_interrupt()) return;
wait_for_completion(&Completion);
}
/*
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_V1_ExecuteType3(DAC960_Controller_T *Controller,
DAC960_V1_CommandOpcode_T CommandOpcode,
void *DataPointer)
{
DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
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_Bus32(DataPointer);
DAC960_ExecuteCommand(Command);
CommandStatus = Command->V1.CommandStatus;
DAC960_DeallocateCommand(Command);
return (CommandStatus == DAC960_V1_NormalCompletion);
}
/*
DAC960_V1_ExecuteTypeB executes a DAC960 V1 Firmware Controller Type 3B
Command and waits for completion. It returns true on success and false
on failure.
*/
static boolean DAC960_V1_ExecuteType3B(DAC960_Controller_T *Controller,
DAC960_V1_CommandOpcode_T CommandOpcode,
unsigned char CommandOpcode2,
void *DataPointer)
{
DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
DAC960_V1_CommandStatus_T CommandStatus;
DAC960_V1_ClearCommand(Command);
Command->CommandType = DAC960_ImmediateCommand;
CommandMailbox->Type3B.CommandOpcode = CommandOpcode;
CommandMailbox->Type3B.CommandOpcode2 = CommandOpcode2;
CommandMailbox->Type3B.BusAddress = Virtual_to_Bus32(DataPointer);
DAC960_ExecuteCommand(Command);
CommandStatus = Command->V1.CommandStatus;
DAC960_DeallocateCommand(Command);
return (CommandStatus == DAC960_V1_NormalCompletion);
}
/*
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_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_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_Bus32(DataPointer);
DAC960_ExecuteCommand(Command);
CommandStatus = Command->V1.CommandStatus;
DAC960_DeallocateCommand(Command);
return (CommandStatus == DAC960_V1_NormalCompletion);
}
/*
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_V2_GeneralInfo(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->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_Bus64(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_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_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_Bus64(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_Bus64(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_Bus64(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_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;
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_PG_RestoreMemoryMailboxInfo(Controller,
&SavedMemoryMailboxesAddress,
&NextCommandMailboxIndex,
&NextStatusMailboxIndex);
if (SavedMemoryMailboxesAddress == NULL)
{
MemoryMailboxPagesAddress =
__get_free_pages(GFP_KERNEL, MemoryMailboxPagesOrder);
Controller->MemoryMailboxPagesAddress = MemoryMailboxPagesAddress;
CommandMailboxesMemory =
(DAC960_V1_CommandMailbox_T *) MemoryMailboxPagesAddress;
}
else CommandMailboxesMemory = SavedMemoryMailboxesAddress;
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_V1_CommandMailboxCount - 1;
Controller->V1.PreviousCommandMailbox1 =
&Controller->V1.FirstCommandMailbox[NextCommandMailboxIndex];
if (--NextCommandMailboxIndex < 0)
NextCommandMailboxIndex = DAC960_V1_CommandMailboxCount - 1;
Controller->V1.PreviousCommandMailbox2 =
&Controller->V1.FirstCommandMailbox[NextCommandMailboxIndex];
StatusMailboxesMemory =
(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->V1.DualModeMemoryMailboxInterface = true;
CommandMailbox.TypeX.CommandOpcode = 0x2B;
CommandMailbox.TypeX.CommandIdentifier = 0;
CommandMailbox.TypeX.CommandOpcode2 = 0x14;
CommandMailbox.TypeX.CommandMailboxesBusAddress =
Virtual_to_Bus32(Controller->V1.FirstCommandMailbox);
CommandMailbox.TypeX.StatusMailboxesBusAddress =
Virtual_to_Bus32(Controller->V1.FirstStatusMailbox);
for (i = 0; i < 2; i++)
switch (Controller->HardwareType)
{
case DAC960_LA_Controller:
while (--TimeoutCounter >= 0)
{
if (!DAC960_LA_HardwareMailboxFullP(ControllerBaseAddress))
break;
udelay(10);
}
if (TimeoutCounter < 0) return false;
DAC960_LA_WriteHardwareMailbox(ControllerBaseAddress, &CommandMailbox);
DAC960_LA_HardwareMailboxNewCommand(ControllerBaseAddress);
while (--TimeoutCounter >= 0)
{
if (DAC960_LA_HardwareMailboxStatusAvailableP(
ControllerBaseAddress))
break;
udelay(10);
}
if (TimeoutCounter < 0) return 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_PG_Controller:
while (--TimeoutCounter >= 0)
{
if (!DAC960_PG_HardwareMailboxFullP(ControllerBaseAddress))
break;
udelay(10);
}
if (TimeoutCounter < 0) return false;
DAC960_PG_WriteHardwareMailbox(ControllerBaseAddress, &CommandMailbox);
DAC960_PG_HardwareMailboxNewCommand(ControllerBaseAddress);
while (--TimeoutCounter >= 0)
{
if (DAC960_PG_HardwareMailboxStatusAvailableP(
ControllerBaseAddress))
break;
udelay(10);
}
if (TimeoutCounter < 0) return 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:
break;
}
return false;
}
/*
DAC960_V2_EnableMemoryMailboxInterface enables the Memory Mailbox Interface
for DAC960 V2 Firmware Controllers.
*/
static boolean DAC960_V2_EnableMemoryMailboxInterface(DAC960_Controller_T
*Controller)
{
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_Bus64(Controller->V2.HealthStatusBuffer);
CommandMailbox.SetMemoryMailbox.FirstCommandMailboxBusAddress =
Virtual_to_Bus64(Controller->V2.FirstCommandMailbox);
CommandMailbox.SetMemoryMailbox.FirstStatusMailboxBusAddress =
Virtual_to_Bus64(Controller->V2.FirstStatusMailbox);
switch (Controller->HardwareType)
{
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_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;
default:
break;
}
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)
{
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_V1_PL:
strcpy(Controller->ModelName, "DAC960PL");
break;
case DAC960_V1_PG:
strcpy(Controller->ModelName, "DAC960PG");
break;
case DAC960_V1_PJ:
strcpy(Controller->ModelName, "DAC960PJ");
break;
case DAC960_V1_PR:
strcpy(Controller->ModelName, "DAC960PR");
break;
case DAC960_V1_PT:
strcpy(Controller->ModelName, "DAC960PT");
break;
case DAC960_V1_PTL0:
strcpy(Controller->ModelName, "DAC960PTL0");
break;
case DAC960_V1_PRL:
strcpy(Controller->ModelName, "DAC960PRL");
break;
case DAC960_V1_PTL1:
strcpy(Controller->ModelName, "DAC960PTL1");
break;
case DAC960_V1_1164P:
strcpy(Controller->ModelName, "DAC1164P");
break;
default:
return DAC960_Failure(Controller, "MODEL VERIFICATION");
}
strcpy(Controller->FullModelName, "Mylex ");
strcat(Controller->FullModelName, Controller->ModelName);
/*
Initialize the Controller Firmware Version field and verify that it
is a supported firmware version. The supported firmware versions are:
DAC1164P 5.06 and above
DAC960PTL/PRL/PJ/PG 4.06 and above
DAC960PU/PD/PL 3.51 and above
DAC960PU/PD/PL/P 2.73 and above
*/
#if defined(__alpha__)
/*
DEC Alpha machines were often equipped with DAC960 cards that were
OEMed from Mylex, and had their own custom firmware. Version 2.70,
the last custom FW revision to be released by DEC for these older
controllers, appears to work quite well with this driver.
Cards tested successfully were several versions each of the PD and
PU, called by DEC the KZPSC and KZPAC, respectively, and having
the Manufacturer Numbers (from Mylex), usually on a sticker on the
back of the board, of:
KZPSC D040347 (1ch) or D040348 (2ch) or D040349 (3ch)
KZPAC D040395 (1ch) or D040396 (2ch) or D040397 (3ch)
*/
# define FIRMWARE_27x "2.70"
#else
# define FIRMWARE_27x "2.73"
#endif
if (Enquiry2.FirmwareID.MajorVersion == 0)
{
Enquiry2.FirmwareID.MajorVersion =
Controller->V1.Enquiry.MajorFirmwareVersion;
Enquiry2.FirmwareID.MinorVersion =
Controller->V1.Enquiry.MinorFirmwareVersion;
Enquiry2.FirmwareID.FirmwareType = '0';
Enquiry2.FirmwareID.TurnID = 0;
}
sprintf(Controller->FirmwareVersion, "%d.%02d-%c-%02d",
Enquiry2.FirmwareID.MajorVersion, Enquiry2.FirmwareID.MinorVersion,
Enquiry2.FirmwareID.FirmwareType, Enquiry2.FirmwareID.TurnID);
if (!((Controller->FirmwareVersion[0] == '5' &&
strcmp(Controller->FirmwareVersion, "5.06") >= 0) ||
(Controller->FirmwareVersion[0] == '4' &&
strcmp(Controller->FirmwareVersion, "4.06") >= 0) ||
(Controller->FirmwareVersion[0] == '3' &&
strcmp(Controller->FirmwareVersion, "3.51") >= 0) ||
(Controller->FirmwareVersion[0] == '2' &&
strcmp(Controller->FirmwareVersion, FIRMWARE_27x) >= 0)))
{
DAC960_Failure(Controller, "FIRMWARE VERSION VERIFICATION");
DAC960_Error("Firmware Version = '%s'\n", Controller,
Controller->FirmwareVersion);
return false;
}
/*
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->V1.SAFTE_EnclosureManagementEnabled =
(Enquiry2.FaultManagementType == DAC960_V1_SAFTE);
/*
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 = Controller->V1.Enquiry.MaxCommands;
Controller->DriverQueueDepth = Controller->ControllerQueueDepth - 1;
if (Controller->DriverQueueDepth > DAC960_MaxDriverQueueDepth)
Controller->DriverQueueDepth = DAC960_MaxDriverQueueDepth;
Controller->LogicalDriveCount =
Controller->V1.Enquiry.NumberOfLogicalDrives;
Controller->MaxBlocksPerCommand = Enquiry2.MaxBlocksPerCommand;
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->V1.StripeSize = Config2.BlocksPerStripe * Config2.BlockFactor
>> (10 - DAC960_BlockSizeBits);
Controller->V1.SegmentSize = Config2.BlocksPerCacheLine * Config2.BlockFactor
>> (10 - DAC960_BlockSizeBits);
switch (Config2.DriveGeometry)
{
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 Background Initialization Status.
*/
if ((Controller->FirmwareVersion[0] == '4' &&
strcmp(Controller->FirmwareVersion, "4.08") >= 0) ||
(Controller->FirmwareVersion[0] == '5' &&
strcmp(Controller->FirmwareVersion, "5.08") >= 0))
{
Controller->V1.BackgroundInitializationStatusSupported = true;
DAC960_V1_ExecuteType3B(Controller,
DAC960_V1_BackgroundInitializationControl, 0x20,
&Controller->
V1.LastBackgroundInitializationStatus);
}
/*
Initialize the Logical Drive Initially Accessible flag.
*/
for (LogicalDriveNumber = 0;
LogicalDriveNumber < Controller->LogicalDriveCount;
LogicalDriveNumber++)
if (Controller->V1.LogicalDriveInformation
[LogicalDriveNumber].LogicalDriveState !=
DAC960_V1_LogicalDrive_Offline)
Controller->LogicalDriveInitiallyAccessible[LogicalDriveNumber] = true;
Controller->V1.LastRebuildStatus = DAC960_V1_NoRebuildOrCheckInProgress;
return true;
}
/*
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
*Controller)
{
DAC960_Info("Configuring Mylex %s PCI RAID Controller\n",
Controller, Controller->ModelName);
DAC960_Info(" Firmware Version: %s, Channels: %d, Memory Size: %dMB\n",
Controller, Controller->FirmwareVersion,
Controller->Channels, Controller->MemorySize);
DAC960_Info(" PCI Bus: %d, Device: %d, Function: %d, I/O Address: ",
Controller, Controller->Bus,
Controller->Device, Controller->Function);
if (Controller->IO_Address == 0)
DAC960_Info("Unassigned\n", Controller);
else DAC960_Info("0x%X\n", Controller, Controller->IO_Address);
DAC960_Info(" PCI Address: 0x%X mapped at 0x%lX, IRQ Channel: %d\n",
Controller, Controller->PCI_Address,
(unsigned long) Controller->BaseAddress,
Controller->IRQ_Channel);
DAC960_Info(" Controller Queue Depth: %d, "
"Maximum Blocks per Command: %d\n",
Controller, Controller->ControllerQueueDepth,
Controller->MaxBlocksPerCommand);
DAC960_Info(" Driver Queue Depth: %d, "
"Scatter/Gather Limit: %d of %d Segments\n",
Controller, Controller->DriverQueueDepth,
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_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_V1_ReadDeviceConfiguration(DAC960_Controller_T
*Controller)
{
DAC960_V1_DCDB_T DCDBs[DAC960_V1_MaxChannels], *DCDB;
Completion_T Completions[DAC960_V1_MaxChannels], *Completion;
unsigned long ProcessorFlags;
int Channel, TargetID;
for (TargetID = 0; TargetID < Controller->Targets; TargetID++)
{
for (Channel = 0; Channel < Controller->Channels; Channel++)
{
DAC960_Command_T *Command = Controller->Commands[Channel];
DAC960_SCSI_Inquiry_T *InquiryStandardData =
&Controller->V1.InquiryStandardData[Channel][TargetID];
InquiryStandardData->PeripheralDeviceType = 0x1F;
Completion = &Completions[Channel];
init_completion(Completion);
DCDB = &DCDBs[Channel];
DAC960_V1_ClearCommand(Command);
Command->CommandType = DAC960_ImmediateCommand;
Command->Completion = Completion;
Command->V1.CommandMailbox.Type3.CommandOpcode = DAC960_V1_DCDB;
Command->V1.CommandMailbox.Type3.BusAddress = Virtual_to_Bus32(DCDB);
DCDB->Channel = Channel;
DCDB->TargetID = TargetID;
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_Bus32(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_AcquireControllerLock(Controller, &ProcessorFlags);
DAC960_QueueCommand(Command);
DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
}
for (Channel = 0; Channel < Controller->Channels; Channel++)
{
DAC960_Command_T *Command = Controller->Commands[Channel];
DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber =
&Controller->V1.InquiryUnitSerialNumber[Channel][TargetID];
InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F;
Completion = &Completions[Channel];
wait_for_completion(Completion);
if (Command->V1.CommandStatus != DAC960_V1_NormalCompletion)
continue;
Command->Completion = Completion;
DCDB = &DCDBs[Channel];
DCDB->TransferLength = sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T);
DCDB->BusAddress = Virtual_to_Bus32(InquiryUnitSerialNumber);
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_AcquireControllerLock(Controller, &ProcessorFlags);
DAC960_QueueCommand(Command);
DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
wait_for_completion(Completion);
}
}
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_Bus64(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_V1_ReportDeviceConfiguration reports the Device Configuration
Information for DAC960 V1 Firmware Controllers.
*/
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 < Controller->Targets; TargetID++)
{
DAC960_SCSI_Inquiry_T *InquiryStandardData =
&Controller->V1.InquiryStandardData[Channel][TargetID];
DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber =
&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)];
if (InquiryStandardData->PeripheralDeviceType == 0x1F) continue;
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)
{
if (Controller->V1.DeviceResetCount[Channel][TargetID] > 0)
DAC960_Info(" Disk Status: %s, %u blocks, %d resets\n",
Controller,
(DeviceState->DeviceState == DAC960_V1_Device_Dead
? "Dead"
: DeviceState->DeviceState
== DAC960_V1_Device_WriteOnly
? "Write-Only"
: DeviceState->DeviceState
== DAC960_V1_Device_Online
? "Online" : "Standby"),
DeviceState->DiskSize,
Controller->V1.DeviceResetCount[Channel][TargetID]);
else
DAC960_Info(" Disk Status: %s, %u blocks\n", Controller,
(DeviceState->DeviceState == DAC960_V1_Device_Dead
? "Dead"
: DeviceState->DeviceState
== DAC960_V1_Device_WriteOnly
? "Write-Only"
: DeviceState->DeviceState
== DAC960_V1_Device_Online
? "Online" : "Standby"),
DeviceState->DiskSize);
}
if (ErrorEntry->ParityErrorCount > 0 ||
ErrorEntry->SoftErrorCount > 0 ||
ErrorEntry->HardErrorCount > 0 ||
ErrorEntry->MiscErrorCount > 0)
DAC960_Info(" Errors - Parity: %d, Soft: %d, "
"Hard: %d, Misc: %d\n", Controller,
ErrorEntry->ParityErrorCount,
ErrorEntry->SoftErrorCount,
ErrorEntry->HardErrorCount,
ErrorEntry->MiscErrorCount);
}
DAC960_Info(" Logical Drives:\n", Controller);
for (LogicalDriveNumber = 0;
LogicalDriveNumber < Controller->LogicalDriveCount;
LogicalDriveNumber++)
{
DAC960_V1_LogicalDriveInformation_T *LogicalDriveInformation =
&Controller->V1.LogicalDriveInformation[LogicalDriveNumber];
DAC960_Info(" /dev/rd/c%dd%d: RAID-%d, %s, %u blocks, %s\n",
Controller, Controller->ControllerNumber, LogicalDriveNumber,
LogicalDriveInformation->RAIDLevel,
(LogicalDriveInformation->LogicalDriveState
== DAC960_V1_LogicalDrive_Online
? "Online"
: LogicalDriveInformation->LogicalDriveState
== DAC960_V1_LogicalDrive_Critical
? "Critical" : "Offline"),
LogicalDriveInformation->LogicalDriveSize,
(LogicalDriveInformation->WriteBack
? "Write Back" : "Write Thru"));
}
return true;
}
/*
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, %u blocks\n", Controller,
(PhysicalDeviceInfo->PhysicalDeviceState
== DAC960_V2_Device_Online
? "Online"
: PhysicalDeviceInfo->PhysicalDeviceState
== DAC960_V2_Device_Rebuild
? "Rebuild"
: PhysicalDeviceInfo->PhysicalDeviceState
== DAC960_V2_Device_Missing
? "Missing"
: PhysicalDeviceInfo->PhysicalDeviceState
== DAC960_V2_Device_Critical
? "Critical"
: PhysicalDeviceInfo->PhysicalDeviceState
== DAC960_V2_Device_Dead
? "Dead"
: PhysicalDeviceInfo->PhysicalDeviceState
== DAC960_V2_Device_SuspectedDead
? "Suspected-Dead"
: PhysicalDeviceInfo->PhysicalDeviceState
== DAC960_V2_Device_CommandedOffline
? "Commanded-Offline"
: PhysicalDeviceInfo->PhysicalDeviceState
== DAC960_V2_Device_Standby
? "Standby" : "Unknown"),
PhysicalDeviceInfo->ConfigurableDeviceSize);
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, %u blocks\n",
Controller, Controller->ControllerNumber, LogicalDriveNumber,
LogicalDeviceInfo->RAIDLevel,
(LogicalDeviceInfo->LogicalDeviceState
== DAC960_V2_LogicalDevice_Online
? "Online"
: LogicalDeviceInfo->LogicalDeviceState
== DAC960_V2_LogicalDevice_Critical
? "Critical" : "Offline"),
LogicalDeviceInfo->ConfigurableDeviceSize);
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_BackMergeFunction is the Back Merge Function for the DAC960 driver.
*/
static int DAC960_BackMergeFunction(RequestQueue_T *RequestQueue,
IO_Request_T *Request,
BufferHeader_T *BufferHeader,
int MaxSegments)
{
DAC960_Controller_T *Controller =
(DAC960_Controller_T *) RequestQueue->queuedata;
if (Request->bhtail->b_data + Request->bhtail->b_size == BufferHeader->b_data)
return true;
if (Request->nr_segments < MaxSegments &&
Request->nr_segments < Controller->DriverScatterGatherLimit)
{
Request->nr_segments++;
return true;
}
return false;
}
/*
DAC960_FrontMergeFunction is the Front Merge Function for the DAC960 driver.
*/
static int DAC960_FrontMergeFunction(RequestQueue_T *RequestQueue,
IO_Request_T *Request,
BufferHeader_T *BufferHeader,
int MaxSegments)
{
DAC960_Controller_T *Controller =
(DAC960_Controller_T *) RequestQueue->queuedata;
if (BufferHeader->b_data + BufferHeader->b_size == Request->bh->b_data)
return true;
if (Request->nr_segments < MaxSegments &&
Request->nr_segments < Controller->DriverScatterGatherLimit)
{
Request->nr_segments++;
return true;
}
return false;
}
/*
DAC960_MergeRequestsFunction is the Merge Requests Function for the
DAC960 driver.
*/
static int DAC960_MergeRequestsFunction(RequestQueue_T *RequestQueue,
IO_Request_T *Request,
IO_Request_T *NextRequest,
int MaxSegments)
{
DAC960_Controller_T *Controller =
(DAC960_Controller_T *) RequestQueue->queuedata;
int TotalSegments = Request->nr_segments + NextRequest->nr_segments;
if (Request->bhtail->b_data + Request->bhtail->b_size
== NextRequest->bh->b_data)
TotalSegments--;
if (TotalSegments > MaxSegments ||
TotalSegments > Controller->DriverScatterGatherLimit)
return false;
Request->nr_segments = TotalSegments;
return true;
}
/*
DAC960_RegisterBlockDevice registers the Block Device structures
associated with Controller.
*/
static boolean DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller)
{
int MajorNumber = DAC960_MAJOR + Controller->ControllerNumber;
RequestQueue_T *RequestQueue;
int MinorNumber;
/*
Register the Block Device Major Number for this DAC960 Controller.
*/
if (devfs_register_blkdev(MajorNumber, "dac960",
&DAC960_BlockDeviceOperations) < 0)
{
DAC960_Error("UNABLE TO ACQUIRE MAJOR NUMBER %d - DETACHING\n",
Controller, MajorNumber);
return false;
}
/*
Initialize the I/O Request Queue.
*/
RequestQueue = BLK_DEFAULT_QUEUE(MajorNumber);
blk_init_queue(RequestQueue, DAC960_RequestFunction);
blk_queue_headactive(RequestQueue, 0);
RequestQueue->back_merge_fn = DAC960_BackMergeFunction;
RequestQueue->front_merge_fn = DAC960_FrontMergeFunction;
RequestQueue->merge_requests_fn = DAC960_MergeRequestsFunction;
RequestQueue->queuedata = Controller;
Controller->RequestQueue = RequestQueue;
/*
Initialize the Max Sectors per Request array.
*/
for (MinorNumber = 0; MinorNumber < DAC960_MinorCount; MinorNumber++)
Controller->MaxSectorsPerRequest[MinorNumber] =
Controller->MaxBlocksPerCommand;
Controller->GenericDiskInfo.part = Controller->DiskPartitions;
Controller->GenericDiskInfo.sizes = Controller->PartitionSizes;
blksize_size[MajorNumber] = Controller->BlockSizes;
max_sectors[MajorNumber] = Controller->MaxSectorsPerRequest;
/*
Initialize Read Ahead to 128 sectors.
*/
read_ahead[MajorNumber] = 128;
/*
Complete initialization of the Generic Disk Information structure.
*/
Controller->GenericDiskInfo.major = MajorNumber;
Controller->GenericDiskInfo.major_name = "rd";
Controller->GenericDiskInfo.minor_shift = DAC960_MaxPartitionsBits;
Controller->GenericDiskInfo.max_p = DAC960_MaxPartitions;
Controller->GenericDiskInfo.nr_real = DAC960_MaxLogicalDrives;
Controller->GenericDiskInfo.real_devices = Controller;
Controller->GenericDiskInfo.next = NULL;
Controller->GenericDiskInfo.fops = &DAC960_BlockDeviceOperations;
/*
Install the Generic Disk Information structure at the end of the list.
*/
add_gendisk(&Controller->GenericDiskInfo);
/*
Indicate the Block Device Registration completed successfully,
*/
return true;
}
/*
DAC960_UnregisterBlockDevice unregisters the Block Device structures
associated with Controller.
*/
static void DAC960_UnregisterBlockDevice(DAC960_Controller_T *Controller)
{
int MajorNumber = DAC960_MAJOR + Controller->ControllerNumber;
/*
Unregister the Block Device Major Number for this DAC960 Controller.
*/
devfs_unregister_blkdev(MajorNumber, "dac960");
/*
Remove the I/O Request Queue.
*/
blk_cleanup_queue(BLK_DEFAULT_QUEUE(MajorNumber));
/*
Remove the Disk Partitions array, Partition Sizes array, Block Sizes
array, Max Sectors per Request array, and Max Segments per Request array.
*/
Controller->GenericDiskInfo.part = NULL;
Controller->GenericDiskInfo.sizes = NULL;
blk_size[MajorNumber] = NULL;
blksize_size[MajorNumber] = NULL;
max_sectors[MajorNumber] = NULL;
/*
Remove the Generic Disk Information structure from the list.
*/
del_gendisk(&Controller->GenericDiskInfo);
}
/*
DAC960_ComputeGenericDiskInfo computes the values for the Generic Disk
Information Partition Sector Counts and Block Sizes.
*/
static void DAC960_ComputeGenericDiskInfo(GenericDiskInfo_T *GenericDiskInfo)
{
DAC960_Controller_T *Controller =
(DAC960_Controller_T *) GenericDiskInfo->real_devices;
int LogicalDriveNumber, i;
for (LogicalDriveNumber = 0;
LogicalDriveNumber < DAC960_MaxLogicalDrives;
LogicalDriveNumber++)
{
int MinorNumber = DAC960_MinorNumber(LogicalDriveNumber, 0);
if (Controller->FirmwareType == DAC960_V1_Controller)
{
if (LogicalDriveNumber < Controller->LogicalDriveCount)
GenericDiskInfo->part[MinorNumber].nr_sects =
Controller->V1.LogicalDriveInformation
[LogicalDriveNumber].LogicalDriveSize;
else GenericDiskInfo->part[MinorNumber].nr_sects = 0;
}
else
{
DAC960_V2_LogicalDeviceInfo_T *LogicalDeviceInfo =
Controller->V2.LogicalDeviceInformation[LogicalDriveNumber];
if (LogicalDeviceInfo != NULL)
GenericDiskInfo->part[MinorNumber].nr_sects =
LogicalDeviceInfo->ConfigurableDeviceSize;
else GenericDiskInfo->part[MinorNumber].nr_sects = 0;
}
for (i = 0; i < DAC960_MaxPartitions; i++)
if (GenericDiskInfo->part[MinorNumber].nr_sects > 0)
Controller->BlockSizes[MinorNumber + i] = BLOCK_SIZE;
else Controller->BlockSizes[MinorNumber + i] = 0;
}
}
/*
DAC960_RegisterDisk registers the DAC960 Logical Disk Device for Logical
Drive Number if it exists.
*/
static void DAC960_RegisterDisk(DAC960_Controller_T *Controller,
int LogicalDriveNumber)
{
if (Controller->FirmwareType == DAC960_V1_Controller)
{
if (LogicalDriveNumber > Controller->LogicalDriveCount - 1) return;
register_disk(&Controller->GenericDiskInfo,
DAC960_KernelDevice(Controller->ControllerNumber,
LogicalDriveNumber, 0),
DAC960_MaxPartitions,
&DAC960_BlockDeviceOperations,
Controller->V1.LogicalDriveInformation
[LogicalDriveNumber].LogicalDriveSize);
}
else
{
DAC960_V2_LogicalDeviceInfo_T *LogicalDeviceInfo =
Controller->V2.LogicalDeviceInformation[LogicalDriveNumber];
if (LogicalDeviceInfo == NULL) return;
register_disk(&Controller->GenericDiskInfo,
DAC960_KernelDevice(Controller->ControllerNumber,
LogicalDriveNumber, 0),
DAC960_MaxPartitions,
&DAC960_BlockDeviceOperations,
LogicalDeviceInfo->ConfigurableDeviceSize);
}
}
/*
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;
case DAC960_P_Controller:
VendorID = PCI_VENDOR_ID_MYLEX;
DeviceID = PCI_DEVICE_ID_MYLEX_DAC960_P;
FirmwareType = DAC960_V1_Controller;
InterruptHandler = DAC960_P_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;
void *BaseAddress;
if (pci_enable_device(PCI_Device) != 0) continue;
switch (HardwareType)
{
case DAC960_BA_Controller:
PCI_Address = pci_resource_start(PCI_Device, 0);
break;
case DAC960_LP_Controller:
PCI_Address = pci_resource_start(PCI_Device, 0);
break;
case DAC960_LA_Controller:
if (!(PCI_Device->subsystem_vendor == PCI_VENDOR_ID_MYLEX &&
PCI_Device->subsystem_device == PCI_DEVICE_ID_MYLEX_DAC960_LA))
continue;
PCI_Address = pci_resource_start(PCI_Device, 0);
break;
case DAC960_PG_Controller:
PCI_Address = pci_resource_start(PCI_Device, 0);
break;
case DAC960_PD_Controller:
IO_Address = pci_resource_start(PCI_Device, 0);
PCI_Address = pci_resource_start(PCI_Device, 1);
break;
case DAC960_P_Controller:
IO_Address = pci_resource_start(PCI_Device, 0);
PCI_Address = pci_resource_start(PCI_Device, 1);
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;
init_waitqueue_head(&Controller->CommandWaitQueue);
init_waitqueue_head(&Controller->HealthStatusWaitQueue);
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:
if (!request_region(Controller->IO_Address, 0x80,
Controller->FullModelName)) {
DAC960_Error("IO port 0x%d busy for Controller at\n",
Controller, Controller->IO_Address);
goto Failure;
}
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 Failure1;
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;
case DAC960_P_Controller:
if (!request_region(Controller->IO_Address, 0x80,
Controller->FullModelName)){
DAC960_Error("IO port 0x%d busy for Controller at\n",
Controller, Controller->IO_Address);
goto Failure;
}
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 Failure1;
udelay(10);
}
DAC960_PD_EnableInterrupts(Controller->BaseAddress);
Controller->QueueCommand = DAC960_P_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 Failure1;
}
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 Failure1;
}
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;
Failure1:
if (Controller->IO_Address) release_region(Controller->IO_Address, 0x80);
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);
Controller->ControllerInitialized = true;
}
else DAC960_FinalizeController(Controller);
}
/*
DAC960_FinalizeController finalizes Controller.
*/
static void DAC960_FinalizeController(DAC960_Controller_T *Controller)
{
if (Controller->ControllerInitialized)
{
del_timer(&Controller->MonitoringTimer);
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);
DAC960_UnregisterBlockDevice(Controller);
DAC960_DestroyAuxiliaryStructures(Controller);
DAC960_Controllers[Controller->ControllerNumber] = NULL;
kfree(Controller);
}
/*
DAC960_Initialize initializes the DAC960 Driver.
*/
static int DAC960_Initialize(void)
{
int ControllerNumber;
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_DetectControllers(DAC960_P_Controller);
DAC960_SortControllers();
if (DAC960_ActiveControllerCount == 0) return -ENODEV;
for (ControllerNumber = 0;
ControllerNumber < DAC960_ControllerCount;
ControllerNumber++)
{
DAC960_Controller_T *Controller = DAC960_Controllers[ControllerNumber];
int LogicalDriveNumber;
if (Controller == NULL) continue;
DAC960_InitializeController(Controller);
DAC960_ComputeGenericDiskInfo(&Controller->GenericDiskInfo);
for (LogicalDriveNumber = 0;
LogicalDriveNumber < DAC960_MaxLogicalDrives;
LogicalDriveNumber++)
DAC960_RegisterDisk(Controller, LogicalDriveNumber);
}
DAC960_CreateProcEntries();
register_reboot_notifier(&DAC960_NotifierBlock);
return 0;
}
/*
DAC960_Finalize finalizes the DAC960 Driver.
*/
static void DAC960_Finalize(void)
{
int ControllerNumber;
if (DAC960_ActiveControllerCount == 0) return;
for (ControllerNumber = 0;
ControllerNumber < DAC960_ControllerCount;
ControllerNumber++)
if (DAC960_Controllers[ControllerNumber] != NULL)
DAC960_FinalizeController(DAC960_Controllers[ControllerNumber]);
DAC960_DestroyProcEntries();
unregister_reboot_notifier(&DAC960_NotifierBlock);
}
/*
DAC960_Notifier is the notifier for the DAC960 Driver.
*/
static int DAC960_Notifier(NotifierBlock_T *NotifierBlock,
unsigned long Event,
void *Buffer)
{
if (!(Event == SYS_RESTART || Event == SYS_HALT || Event == SYS_POWER_OFF))
return NOTIFY_DONE;
DAC960_Finalize();
return NOTIFY_OK;
}
/*
DAC960_V1_QueueReadWriteCommand prepares and queues a Read/Write Command for
DAC960 V1 Firmware Controllers.
*/
static void DAC960_V1_QueueReadWriteCommand(DAC960_Command_T *Command)
{
DAC960_Controller_T *Controller = Command->Controller;
DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
DAC960_V1_ClearCommand(Command);
if (Command->SegmentCount == 1)
{
if (Command->CommandType == DAC960_ReadCommand)
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_Bus32(Command->RequestBuffer);
}
else
{
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_V1_ReadWithScatterGather;
else
CommandMailbox->Type5.CommandOpcode = DAC960_V1_WriteWithScatterGather;
CommandMailbox->Type5.LD.TransferLength = Command->BlockCount;
CommandMailbox->Type5