Commit bbf41765 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] move DAC960 GAM IOCTLs into a new device

From: Dave Olien <dmo@osdl.org>

The DAC960 driver uses an ugly overloading of the O_NONBLOCK flag to
support the controller's RAID configuration features.

Opening "/dev/rd/c0d0" with the O_NONBLOCK flag set returns a file
descriptor that can be used to do RAID control operations using ioctl().
The normal ioctl operations are not availabe with that file descriptor.

This patch removes that O_NONBLOCK overloading from DAC960_open() and
DAC960_ioctl() functions.  It introduces a new "miscellaneous" device
named /dev/dac960_gam.  It uses minor device number 252 of the miscellaneous
character devices.

The currently distrubted "Global Array Manager" server distrubted by
LSIlogic on their web page page works only on RH7.3 or earlier.  It doesn't
work under RH9.  There are probably some library incompatabilities.
So, I don't view this patch as breaking anything that currently works.
If this software package is ever brought up to date (which I doubt),
then it can be modified to use this new device at that time.
parent 7909c355
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/version.h> #include <linux/version.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/miscdevice.h>
#include <linux/blkdev.h> #include <linux/blkdev.h>
#include <linux/bio.h> #include <linux/bio.h>
#include <linux/completion.h> #include <linux/completion.h>
...@@ -44,6 +45,8 @@ ...@@ -44,6 +45,8 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include "DAC960.h" #include "DAC960.h"
#define DAC960_GAM_MINOR 252
static DAC960_Controller_T *DAC960_Controllers[DAC960_MaxControllers]; static DAC960_Controller_T *DAC960_Controllers[DAC960_MaxControllers];
static int DAC960_ControllerCount; static int DAC960_ControllerCount;
...@@ -71,10 +74,6 @@ static int DAC960_open(struct inode *inode, struct file *file) ...@@ -71,10 +74,6 @@ static int DAC960_open(struct inode *inode, struct file *file)
DAC960_Controller_T *p = disk->queue->queuedata; DAC960_Controller_T *p = disk->queue->queuedata;
int drive_nr = (int)disk->private_data; int drive_nr = (int)disk->private_data;
/* bad hack for the "user" ioctls */
if (!p->ControllerNumber && !drive_nr && (file->f_flags & O_NONBLOCK))
return 0;
if (p->FirmwareType == DAC960_V1_Controller) { if (p->FirmwareType == DAC960_V1_Controller) {
if (p->V1.LogicalDriveInformation[drive_nr]. if (p->V1.LogicalDriveInformation[drive_nr].
LogicalDriveState == DAC960_V1_LogicalDrive_Offline) LogicalDriveState == DAC960_V1_LogicalDrive_Offline)
...@@ -101,9 +100,6 @@ static int DAC960_ioctl(struct inode *inode, struct file *file, ...@@ -101,9 +100,6 @@ static int DAC960_ioctl(struct inode *inode, struct file *file,
int drive_nr = (int)disk->private_data; int drive_nr = (int)disk->private_data;
struct hd_geometry g, *loc = (struct hd_geometry *)arg; struct hd_geometry g, *loc = (struct hd_geometry *)arg;
if (file && (file->f_flags & O_NONBLOCK))
return DAC960_UserIOCTL(inode, file, cmd, arg);
if (cmd != HDIO_GETGEO || !loc) if (cmd != HDIO_GETGEO || !loc)
return -EINVAL; return -EINVAL;
...@@ -5569,866 +5565,728 @@ static void DAC960_MonitoringTimerFunction(unsigned long TimerData) ...@@ -5569,866 +5565,728 @@ static void DAC960_MonitoringTimerFunction(unsigned long TimerData)
} }
/* /*
DAC960_UserIOCTL is the User IOCTL Function for the DAC960 Driver. DAC960_CheckStatusBuffer verifies that there is room to hold ByteCount
additional bytes in the Combined Status Buffer and grows the buffer if
necessary. It returns true if there is enough room and false otherwise.
*/ */
static int DAC960_UserIOCTL(struct inode *inode, struct file *file, static boolean DAC960_CheckStatusBuffer(DAC960_Controller_T *Controller,
unsigned int Request, unsigned long Argument) unsigned int ByteCount)
{ {
int ErrorCode = 0; unsigned char *NewStatusBuffer;
if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (Controller->InitialStatusLength + 1 +
switch (Request) Controller->CurrentStatusLength + ByteCount + 1 <=
{ Controller->CombinedStatusBufferLength)
case DAC960_IOCTL_GET_CONTROLLER_COUNT: return true;
return DAC960_ControllerCount; if (Controller->CombinedStatusBufferLength == 0)
case DAC960_IOCTL_GET_CONTROLLER_INFO:
{ {
DAC960_ControllerInfo_T *UserSpaceControllerInfo = unsigned int NewStatusBufferLength = DAC960_InitialStatusBufferSize;
(DAC960_ControllerInfo_T *) Argument; while (NewStatusBufferLength < ByteCount)
DAC960_ControllerInfo_T ControllerInfo; NewStatusBufferLength *= 2;
DAC960_Controller_T *Controller; Controller->CombinedStatusBuffer =
int ControllerNumber; (unsigned char *) kmalloc(NewStatusBufferLength, GFP_ATOMIC);
if (UserSpaceControllerInfo == NULL) return -EINVAL; if (Controller->CombinedStatusBuffer == NULL) return false;
ErrorCode = get_user(ControllerNumber, Controller->CombinedStatusBufferLength = NewStatusBufferLength;
&UserSpaceControllerInfo->ControllerNumber); return true;
if (ErrorCode != 0) return ErrorCode;
if (ControllerNumber < 0 ||
ControllerNumber > DAC960_ControllerCount - 1)
return -ENXIO;
Controller = DAC960_Controllers[ControllerNumber];
if (Controller == NULL) return -ENXIO;
memset(&ControllerInfo, 0, sizeof(DAC960_ControllerInfo_T));
ControllerInfo.ControllerNumber = ControllerNumber;
ControllerInfo.FirmwareType = Controller->FirmwareType;
ControllerInfo.Channels = Controller->Channels;
ControllerInfo.Targets = Controller->Targets;
ControllerInfo.PCI_Bus = Controller->Bus;
ControllerInfo.PCI_Device = Controller->Device;
ControllerInfo.PCI_Function = Controller->Function;
ControllerInfo.IRQ_Channel = Controller->IRQ_Channel;
ControllerInfo.PCI_Address = Controller->PCI_Address;
strcpy(ControllerInfo.ModelName, Controller->ModelName);
strcpy(ControllerInfo.FirmwareVersion, Controller->FirmwareVersion);
return (copy_to_user(UserSpaceControllerInfo, &ControllerInfo,
sizeof(DAC960_ControllerInfo_T)) ? -EFAULT : 0);
} }
case DAC960_IOCTL_V1_EXECUTE_COMMAND: NewStatusBuffer = (unsigned char *)
kmalloc(2 * Controller->CombinedStatusBufferLength, GFP_ATOMIC);
if (NewStatusBuffer == NULL)
{ {
DAC960_V1_UserCommand_T *UserSpaceUserCommand = DAC960_Warning("Unable to expand Combined Status Buffer - Truncating\n",
(DAC960_V1_UserCommand_T *) Argument; Controller);
DAC960_V1_UserCommand_T UserCommand; return false;
DAC960_Controller_T *Controller;
DAC960_Command_T *Command = NULL;
DAC960_V1_CommandOpcode_T CommandOpcode;
DAC960_V1_CommandStatus_T CommandStatus;
DAC960_V1_DCDB_T DCDB;
DAC960_V1_DCDB_T *DCDB_IOBUF = NULL;
dma_addr_t DCDB_IOBUFDMA;
unsigned long flags;
int ControllerNumber, DataTransferLength;
unsigned char *DataTransferBuffer = NULL;
dma_addr_t DataTransferBufferDMA;
if (UserSpaceUserCommand == NULL) return -EINVAL;
if (copy_from_user(&UserCommand, UserSpaceUserCommand,
sizeof(DAC960_V1_UserCommand_T))) {
ErrorCode = -EFAULT;
goto Failure1a;
} }
ControllerNumber = UserCommand.ControllerNumber; memcpy(NewStatusBuffer, Controller->CombinedStatusBuffer,
if (ControllerNumber < 0 || Controller->CombinedStatusBufferLength);
ControllerNumber > DAC960_ControllerCount - 1) kfree(Controller->CombinedStatusBuffer);
return -ENXIO; Controller->CombinedStatusBuffer = NewStatusBuffer;
Controller = DAC960_Controllers[ControllerNumber]; Controller->CombinedStatusBufferLength *= 2;
if (Controller == NULL) return -ENXIO; Controller->CurrentStatusBuffer =
if (Controller->FirmwareType != DAC960_V1_Controller) return -EINVAL; &NewStatusBuffer[Controller->InitialStatusLength + 1];
CommandOpcode = UserCommand.CommandMailbox.Common.CommandOpcode; return true;
DataTransferLength = UserCommand.DataTransferLength; }
if (CommandOpcode & 0x80) return -EINVAL;
if (CommandOpcode == DAC960_V1_DCDB)
/*
DAC960_Message prints Driver Messages.
*/
static void DAC960_Message(DAC960_MessageLevel_T MessageLevel,
unsigned char *Format,
DAC960_Controller_T *Controller,
...)
{
static unsigned char Buffer[DAC960_LineBufferSize];
static boolean BeginningOfLine = true;
va_list Arguments;
int Length = 0;
va_start(Arguments, Controller);
Length = vsprintf(Buffer, Format, Arguments);
va_end(Arguments);
if (Controller == NULL)
printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel],
DAC960_ControllerCount, Buffer);
else if (MessageLevel == DAC960_AnnounceLevel ||
MessageLevel == DAC960_InfoLevel)
{ {
if (copy_from_user(&DCDB, UserCommand.DCDB, if (!Controller->ControllerInitialized)
sizeof(DAC960_V1_DCDB_T))) {
ErrorCode = -EFAULT;
goto Failure1a;
}
if (DCDB.Channel >= DAC960_V1_MaxChannels) return -EINVAL;
if (!((DataTransferLength == 0 &&
DCDB.Direction
== DAC960_V1_DCDB_NoDataTransfer) ||
(DataTransferLength > 0 &&
DCDB.Direction
== DAC960_V1_DCDB_DataTransferDeviceToSystem) ||
(DataTransferLength < 0 &&
DCDB.Direction
== DAC960_V1_DCDB_DataTransferSystemToDevice)))
return -EINVAL;
if (((DCDB.TransferLengthHigh4 << 16) | DCDB.TransferLength)
!= abs(DataTransferLength))
return -EINVAL;
DCDB_IOBUF = pci_alloc_consistent(Controller->PCIDevice,
sizeof(DAC960_V1_DCDB_T), &DCDB_IOBUFDMA);
if (DCDB_IOBUF == NULL)
return -ENOMEM;
}
if (DataTransferLength > 0)
{ {
DataTransferBuffer = pci_alloc_consistent(Controller->PCIDevice, if (DAC960_CheckStatusBuffer(Controller, Length))
DataTransferLength, &DataTransferBufferDMA); {
if (DataTransferBuffer == NULL) { strcpy(&Controller->CombinedStatusBuffer
ErrorCode = -ENOMEM; [Controller->InitialStatusLength],
goto Failure1; Buffer);
Controller->InitialStatusLength += Length;
Controller->CurrentStatusBuffer =
&Controller->CombinedStatusBuffer
[Controller->InitialStatusLength + 1];
} }
memset(DataTransferBuffer, 0, DataTransferLength); if (MessageLevel == DAC960_AnnounceLevel)
{
static int AnnouncementLines = 0;
if (++AnnouncementLines <= 2)
printk("%sDAC960: %s", DAC960_MessageLevelMap[MessageLevel],
Buffer);
} }
else if (DataTransferLength < 0) else
{ {
DataTransferBuffer = pci_alloc_consistent(Controller->PCIDevice, if (BeginningOfLine)
-DataTransferLength, &DataTransferBufferDMA); {
if (DataTransferBuffer == NULL) { if (Buffer[0] != '\n' || Length > 1)
ErrorCode = -ENOMEM; printk("%sDAC960#%d: %s",
goto Failure1; DAC960_MessageLevelMap[MessageLevel],
Controller->ControllerNumber, Buffer);
} }
if (copy_from_user(DataTransferBuffer, else printk("%s", Buffer);
UserCommand.DataTransferBuffer,
-DataTransferLength)) {
ErrorCode = -EFAULT;
goto Failure1;
} }
} }
if (CommandOpcode == DAC960_V1_DCDB) else if (DAC960_CheckStatusBuffer(Controller, Length))
{
spin_lock_irqsave(&Controller->queue_lock, flags);
while ((Command = DAC960_AllocateCommand(Controller)) == NULL)
DAC960_WaitForCommand(Controller);
while (Controller->V1.DirectCommandActive[DCDB.Channel]
[DCDB.TargetID])
{ {
spin_unlock_irq(&Controller->queue_lock); strcpy(&Controller->CurrentStatusBuffer[
__wait_event(Controller->CommandWaitQueue, Controller->CurrentStatusLength], Buffer);
!Controller->V1.DirectCommandActive Controller->CurrentStatusLength += Length;
[DCDB.Channel][DCDB.TargetID]);
spin_lock_irq(&Controller->queue_lock);
} }
Controller->V1.DirectCommandActive[DCDB.Channel]
[DCDB.TargetID] = true;
spin_unlock_irqrestore(&Controller->queue_lock, flags);
DAC960_V1_ClearCommand(Command);
Command->CommandType = DAC960_ImmediateCommand;
memcpy(&Command->V1.CommandMailbox, &UserCommand.CommandMailbox,
sizeof(DAC960_V1_CommandMailbox_T));
Command->V1.CommandMailbox.Type3.BusAddress = DCDB_IOBUFDMA;
DCDB.BusAddress = DataTransferBufferDMA;
memcpy(DCDB_IOBUF, &DCDB, sizeof(DAC960_V1_DCDB_T));
} }
else else if (MessageLevel == DAC960_ProgressLevel)
{ {
spin_lock_irqsave(&Controller->queue_lock, flags); strcpy(Controller->ProgressBuffer, Buffer);
while ((Command = DAC960_AllocateCommand(Controller)) == NULL) Controller->ProgressBufferLength = Length;
DAC960_WaitForCommand(Controller); if (Controller->EphemeralProgressMessage)
spin_unlock_irqrestore(&Controller->queue_lock, flags);
DAC960_V1_ClearCommand(Command);
Command->CommandType = DAC960_ImmediateCommand;
memcpy(&Command->V1.CommandMailbox, &UserCommand.CommandMailbox,
sizeof(DAC960_V1_CommandMailbox_T));
if (DataTransferBuffer != NULL)
Command->V1.CommandMailbox.Type3.BusAddress =
DataTransferBufferDMA;
}
DAC960_ExecuteCommand(Command);
CommandStatus = Command->V1.CommandStatus;
spin_lock_irqsave(&Controller->queue_lock, flags);
DAC960_DeallocateCommand(Command);
spin_unlock_irqrestore(&Controller->queue_lock, flags);
if (DataTransferLength > 0)
{ {
if (copy_to_user(UserCommand.DataTransferBuffer, if (jiffies - Controller->LastProgressReportTime
DataTransferBuffer, DataTransferLength)) { >= DAC960_ProgressReportingInterval)
ErrorCode = -EFAULT; {
goto Failure1; printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel],
Controller->ControllerNumber, Buffer);
Controller->LastProgressReportTime = jiffies;
} }
} }
if (CommandOpcode == DAC960_V1_DCDB) else printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel],
{ Controller->ControllerNumber, Buffer);
/*
I don't believe Target or Channel in the DCDB_IOBUF
should be any different from the contents of DCDB.
*/
Controller->V1.DirectCommandActive[DCDB.Channel]
[DCDB.TargetID] = false;
if (copy_to_user(UserCommand.DCDB, DCDB_IOBUF,
sizeof(DAC960_V1_DCDB_T))) {
ErrorCode = -EFAULT;
goto Failure1;
}
}
ErrorCode = CommandStatus;
Failure1:
if (DataTransferBuffer != NULL)
pci_free_consistent(Controller->PCIDevice, abs(DataTransferLength),
DataTransferBuffer, DataTransferBufferDMA);
if (DCDB_IOBUF != NULL)
pci_free_consistent(Controller->PCIDevice, sizeof(DAC960_V1_DCDB_T),
DCDB_IOBUF, DCDB_IOBUFDMA);
Failure1a:
return ErrorCode;
}
case DAC960_IOCTL_V2_EXECUTE_COMMAND:
{
DAC960_V2_UserCommand_T *UserSpaceUserCommand =
(DAC960_V2_UserCommand_T *) Argument;
DAC960_V2_UserCommand_T UserCommand;
DAC960_Controller_T *Controller;
DAC960_Command_T *Command = NULL;
DAC960_V2_CommandMailbox_T *CommandMailbox;
DAC960_V2_CommandStatus_T CommandStatus;
unsigned long flags;
int ControllerNumber, DataTransferLength;
int DataTransferResidue, RequestSenseLength;
unsigned char *DataTransferBuffer = NULL;
dma_addr_t DataTransferBufferDMA;
unsigned char *RequestSenseBuffer = NULL;
dma_addr_t RequestSenseBufferDMA;
if (UserSpaceUserCommand == NULL) return -EINVAL;
if (copy_from_user(&UserCommand, UserSpaceUserCommand,
sizeof(DAC960_V2_UserCommand_T))) {
ErrorCode = -EFAULT;
goto Failure2a;
}
ControllerNumber = UserCommand.ControllerNumber;
if (ControllerNumber < 0 ||
ControllerNumber > DAC960_ControllerCount - 1)
return -ENXIO;
Controller = DAC960_Controllers[ControllerNumber];
if (Controller == NULL) return -ENXIO;
if (Controller->FirmwareType != DAC960_V2_Controller) return -EINVAL;
DataTransferLength = UserCommand.DataTransferLength;
if (DataTransferLength > 0)
{
DataTransferBuffer = pci_alloc_consistent(Controller->PCIDevice,
DataTransferLength, &DataTransferBufferDMA);
if (DataTransferBuffer == NULL) return -ENOMEM;
memset(DataTransferBuffer, 0, DataTransferLength);
}
else if (DataTransferLength < 0)
{
DataTransferBuffer = pci_alloc_consistent(Controller->PCIDevice,
-DataTransferLength, &DataTransferBufferDMA);
if (DataTransferBuffer == NULL) return -ENOMEM;
if (copy_from_user(DataTransferBuffer,
UserCommand.DataTransferBuffer,
-DataTransferLength)) {
ErrorCode = -EFAULT;
goto Failure2;
}
}
RequestSenseLength = UserCommand.RequestSenseLength;
if (RequestSenseLength > 0)
{
RequestSenseBuffer = pci_alloc_consistent(Controller->PCIDevice,
RequestSenseLength, &RequestSenseBufferDMA);
if (RequestSenseBuffer == NULL)
{
ErrorCode = -ENOMEM;
goto Failure2;
}
memset(RequestSenseBuffer, 0, RequestSenseLength);
} }
spin_lock_irqsave(&Controller->queue_lock, flags); else if (MessageLevel == DAC960_UserCriticalLevel)
while ((Command = DAC960_AllocateCommand(Controller)) == NULL)
DAC960_WaitForCommand(Controller);
spin_unlock_irqrestore(&Controller->queue_lock, flags);
DAC960_V2_ClearCommand(Command);
Command->CommandType = DAC960_ImmediateCommand;
CommandMailbox = &Command->V2.CommandMailbox;
memcpy(CommandMailbox, &UserCommand.CommandMailbox,
sizeof(DAC960_V2_CommandMailbox_T));
CommandMailbox->Common.CommandControlBits
.AdditionalScatterGatherListMemory = false;
CommandMailbox->Common.CommandControlBits
.NoAutoRequestSense = true;
CommandMailbox->Common.DataTransferSize = 0;
CommandMailbox->Common.DataTransferPageNumber = 0;
memset(&CommandMailbox->Common.DataTransferMemoryAddress, 0,
sizeof(DAC960_V2_DataTransferMemoryAddress_T));
if (DataTransferLength != 0)
{
if (DataTransferLength > 0)
{ {
CommandMailbox->Common.CommandControlBits strcpy(&Controller->UserStatusBuffer[Controller->UserStatusLength],
.DataTransferControllerToHost = true; Buffer);
CommandMailbox->Common.DataTransferSize = DataTransferLength; Controller->UserStatusLength += Length;
if (Buffer[0] != '\n' || Length > 1)
printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel],
Controller->ControllerNumber, Buffer);
} }
else else
{ {
CommandMailbox->Common.CommandControlBits if (BeginningOfLine)
.DataTransferControllerToHost = false; printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel],
CommandMailbox->Common.DataTransferSize = -DataTransferLength; Controller->ControllerNumber, Buffer);
} else printk("%s", Buffer);
CommandMailbox->Common.DataTransferMemoryAddress
.ScatterGatherSegments[0]
.SegmentDataPointer = DataTransferBufferDMA;
CommandMailbox->Common.DataTransferMemoryAddress
.ScatterGatherSegments[0]
.SegmentByteCount =
CommandMailbox->Common.DataTransferSize;
}
if (RequestSenseLength > 0)
{
CommandMailbox->Common.CommandControlBits
.NoAutoRequestSense = false;
CommandMailbox->Common.RequestSenseSize = RequestSenseLength;
CommandMailbox->Common.RequestSenseBusAddress =
RequestSenseBufferDMA;
}
DAC960_ExecuteCommand(Command);
CommandStatus = Command->V2.CommandStatus;
RequestSenseLength = Command->V2.RequestSenseLength;
DataTransferResidue = Command->V2.DataTransferResidue;
spin_lock_irqsave(&Controller->queue_lock, flags);
DAC960_DeallocateCommand(Command);
spin_unlock_irqrestore(&Controller->queue_lock, flags);
if (RequestSenseLength > UserCommand.RequestSenseLength)
RequestSenseLength = UserCommand.RequestSenseLength;
if (copy_to_user(&UserSpaceUserCommand->DataTransferLength,
&DataTransferResidue,
sizeof(DataTransferResidue))) {
ErrorCode = -EFAULT;
goto Failure2;
}
if (copy_to_user(&UserSpaceUserCommand->RequestSenseLength,
&RequestSenseLength, sizeof(RequestSenseLength))) {
ErrorCode = -EFAULT;
goto Failure2;
}
if (DataTransferLength > 0)
{
if (copy_to_user(UserCommand.DataTransferBuffer,
DataTransferBuffer, DataTransferLength)) {
ErrorCode = -EFAULT;
goto Failure2;
}
}
if (RequestSenseLength > 0)
{
if (copy_to_user(UserCommand.RequestSenseBuffer,
RequestSenseBuffer, RequestSenseLength)) {
ErrorCode = -EFAULT;
goto Failure2;
}
}
ErrorCode = CommandStatus;
Failure2:
pci_free_consistent(Controller->PCIDevice, abs(DataTransferLength),
DataTransferBuffer, DataTransferBufferDMA);
if (RequestSenseBuffer != NULL)
pci_free_consistent(Controller->PCIDevice, RequestSenseLength,
RequestSenseBuffer, RequestSenseBufferDMA);
Failure2a:
return ErrorCode;
}
case DAC960_IOCTL_V2_GET_HEALTH_STATUS:
{
DAC960_V2_GetHealthStatus_T *UserSpaceGetHealthStatus =
(DAC960_V2_GetHealthStatus_T *) Argument;
DAC960_V2_GetHealthStatus_T GetHealthStatus;
DAC960_V2_HealthStatusBuffer_T HealthStatusBuffer;
DAC960_Controller_T *Controller;
int ControllerNumber;
if (UserSpaceGetHealthStatus == NULL) return -EINVAL;
if (copy_from_user(&GetHealthStatus, UserSpaceGetHealthStatus,
sizeof(DAC960_V2_GetHealthStatus_T)))
return -EFAULT;
ControllerNumber = GetHealthStatus.ControllerNumber;
if (ControllerNumber < 0 ||
ControllerNumber > DAC960_ControllerCount - 1)
return -ENXIO;
Controller = DAC960_Controllers[ControllerNumber];
if (Controller == NULL) return -ENXIO;
if (Controller->FirmwareType != DAC960_V2_Controller) return -EINVAL;
if (copy_from_user(&HealthStatusBuffer,
GetHealthStatus.HealthStatusBuffer,
sizeof(DAC960_V2_HealthStatusBuffer_T)))
return -EFAULT;
while (Controller->V2.HealthStatusBuffer->StatusChangeCounter
== HealthStatusBuffer.StatusChangeCounter &&
Controller->V2.HealthStatusBuffer->NextEventSequenceNumber
== HealthStatusBuffer.NextEventSequenceNumber)
{
interruptible_sleep_on_timeout(&Controller->HealthStatusWaitQueue,
DAC960_MonitoringTimerInterval);
if (signal_pending(current)) return -EINTR;
}
if (copy_to_user(GetHealthStatus.HealthStatusBuffer,
Controller->V2.HealthStatusBuffer,
sizeof(DAC960_V2_HealthStatusBuffer_T)))
return -EFAULT;
return 0;
}
} }
return -EINVAL; BeginningOfLine = (Buffer[Length-1] == '\n');
} }
/* /*
DAC960_CheckStatusBuffer verifies that there is room to hold ByteCount DAC960_ParsePhysicalDevice parses spaces followed by a Physical Device
additional bytes in the Combined Status Buffer and grows the buffer if Channel:TargetID specification from a User Command string. It updates
necessary. It returns true if there is enough room and false otherwise. Channel and TargetID and returns true on success and false on failure.
*/ */
static boolean DAC960_CheckStatusBuffer(DAC960_Controller_T *Controller, static boolean DAC960_ParsePhysicalDevice(DAC960_Controller_T *Controller,
unsigned int ByteCount) char *UserCommandString,
unsigned char *Channel,
unsigned char *TargetID)
{ {
unsigned char *NewStatusBuffer; char *NewUserCommandString = UserCommandString;
if (Controller->InitialStatusLength + 1 + unsigned long XChannel, XTargetID;
Controller->CurrentStatusLength + ByteCount + 1 <= while (*UserCommandString == ' ') UserCommandString++;
Controller->CombinedStatusBufferLength) if (UserCommandString == NewUserCommandString)
return true; return false;
if (Controller->CombinedStatusBufferLength == 0) XChannel = simple_strtoul(UserCommandString, &NewUserCommandString, 10);
{ if (NewUserCommandString == UserCommandString ||
unsigned int NewStatusBufferLength = DAC960_InitialStatusBufferSize; *NewUserCommandString != ':' ||
while (NewStatusBufferLength < ByteCount) XChannel >= Controller->Channels)
NewStatusBufferLength *= 2; return false;
Controller->CombinedStatusBuffer = UserCommandString = ++NewUserCommandString;
(unsigned char *) kmalloc(NewStatusBufferLength, GFP_ATOMIC); XTargetID = simple_strtoul(UserCommandString, &NewUserCommandString, 10);
if (Controller->CombinedStatusBuffer == NULL) return false; if (NewUserCommandString == UserCommandString ||
Controller->CombinedStatusBufferLength = NewStatusBufferLength; *NewUserCommandString != '\0' ||
XTargetID >= Controller->Targets)
return false;
*Channel = XChannel;
*TargetID = XTargetID;
return true; return true;
} }
NewStatusBuffer = (unsigned char *)
kmalloc(2 * Controller->CombinedStatusBufferLength, GFP_ATOMIC);
if (NewStatusBuffer == NULL) /*
{ DAC960_ParseLogicalDrive parses spaces followed by a Logical Drive Number
DAC960_Warning("Unable to expand Combined Status Buffer - Truncating\n", specification from a User Command string. It updates LogicalDriveNumber and
Controller); returns true on success and false on failure.
*/
static boolean DAC960_ParseLogicalDrive(DAC960_Controller_T *Controller,
char *UserCommandString,
unsigned char *LogicalDriveNumber)
{
char *NewUserCommandString = UserCommandString;
unsigned long XLogicalDriveNumber;
while (*UserCommandString == ' ') UserCommandString++;
if (UserCommandString == NewUserCommandString)
return false; return false;
} XLogicalDriveNumber =
memcpy(NewStatusBuffer, Controller->CombinedStatusBuffer, simple_strtoul(UserCommandString, &NewUserCommandString, 10);
Controller->CombinedStatusBufferLength); if (NewUserCommandString == UserCommandString ||
kfree(Controller->CombinedStatusBuffer); *NewUserCommandString != '\0' ||
Controller->CombinedStatusBuffer = NewStatusBuffer; XLogicalDriveNumber > DAC960_MaxLogicalDrives - 1)
Controller->CombinedStatusBufferLength *= 2; return false;
Controller->CurrentStatusBuffer = *LogicalDriveNumber = XLogicalDriveNumber;
&NewStatusBuffer[Controller->InitialStatusLength + 1];
return true; return true;
} }
/* /*
DAC960_Message prints Driver Messages. DAC960_V1_SetDeviceState sets the Device State for a Physical Device for
DAC960 V1 Firmware Controllers.
*/ */
static void DAC960_Message(DAC960_MessageLevel_T MessageLevel, static void DAC960_V1_SetDeviceState(DAC960_Controller_T *Controller,
unsigned char *Format, DAC960_Command_T *Command,
DAC960_Controller_T *Controller, unsigned char Channel,
...) unsigned char TargetID,
DAC960_V1_PhysicalDeviceState_T
DeviceState,
const unsigned char *DeviceStateString)
{ {
static unsigned char Buffer[DAC960_LineBufferSize]; DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
static boolean BeginningOfLine = true; CommandMailbox->Type3D.CommandOpcode = DAC960_V1_StartDevice;
va_list Arguments; CommandMailbox->Type3D.Channel = Channel;
int Length = 0; CommandMailbox->Type3D.TargetID = TargetID;
va_start(Arguments, Controller); CommandMailbox->Type3D.DeviceState = DeviceState;
Length = vsprintf(Buffer, Format, Arguments); CommandMailbox->Type3D.Modifier = 0;
va_end(Arguments); DAC960_ExecuteCommand(Command);
if (Controller == NULL) switch (Command->V1.CommandStatus)
printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel],
DAC960_ControllerCount, Buffer);
else if (MessageLevel == DAC960_AnnounceLevel ||
MessageLevel == DAC960_InfoLevel)
{
if (!Controller->ControllerInitialized)
{
if (DAC960_CheckStatusBuffer(Controller, Length))
{ {
strcpy(&Controller->CombinedStatusBuffer case DAC960_V1_NormalCompletion:
[Controller->InitialStatusLength], DAC960_UserCritical("%s of Physical Device %d:%d Succeeded\n", Controller,
Buffer); DeviceStateString, Channel, TargetID);
Controller->InitialStatusLength += Length; break;
Controller->CurrentStatusBuffer = case DAC960_V1_UnableToStartDevice:
&Controller->CombinedStatusBuffer DAC960_UserCritical("%s of Physical Device %d:%d Failed - "
[Controller->InitialStatusLength + 1]; "Unable to Start Device\n", Controller,
DeviceStateString, Channel, TargetID);
break;
case DAC960_V1_NoDeviceAtAddress:
DAC960_UserCritical("%s of Physical Device %d:%d Failed - "
"No Device at Address\n", Controller,
DeviceStateString, Channel, TargetID);
break;
case DAC960_V1_InvalidChannelOrTargetOrModifier:
DAC960_UserCritical("%s of Physical Device %d:%d Failed - "
"Invalid Channel or Target or Modifier\n",
Controller, DeviceStateString, Channel, TargetID);
break;
case DAC960_V1_ChannelBusy:
DAC960_UserCritical("%s of Physical Device %d:%d Failed - "
"Channel Busy\n", Controller,
DeviceStateString, Channel, TargetID);
break;
default:
DAC960_UserCritical("%s of Physical Device %d:%d Failed - "
"Unexpected Status %04X\n", Controller,
DeviceStateString, Channel, TargetID,
Command->V1.CommandStatus);
break;
} }
if (MessageLevel == DAC960_AnnounceLevel) }
/*
DAC960_V1_ExecuteUserCommand executes a User Command for DAC960 V1 Firmware
Controllers.
*/
static boolean DAC960_V1_ExecuteUserCommand(DAC960_Controller_T *Controller,
unsigned char *UserCommand)
{
DAC960_Command_T *Command;
DAC960_V1_CommandMailbox_T *CommandMailbox;
unsigned long flags;
unsigned char Channel, TargetID, LogicalDriveNumber;
spin_lock_irqsave(&Controller->queue_lock, flags);
while ((Command = DAC960_AllocateCommand(Controller)) == NULL)
DAC960_WaitForCommand(Controller);
spin_unlock_irqrestore(&Controller->queue_lock, flags);
Controller->UserStatusLength = 0;
DAC960_V1_ClearCommand(Command);
Command->CommandType = DAC960_ImmediateCommand;
CommandMailbox = &Command->V1.CommandMailbox;
if (strcmp(UserCommand, "flush-cache") == 0)
{ {
static int AnnouncementLines = 0; CommandMailbox->Type3.CommandOpcode = DAC960_V1_Flush;
if (++AnnouncementLines <= 2) DAC960_ExecuteCommand(Command);
printk("%sDAC960: %s", DAC960_MessageLevelMap[MessageLevel], DAC960_UserCritical("Cache Flush Completed\n", Controller);
Buffer);
} }
else else if (strncmp(UserCommand, "kill", 4) == 0 &&
{ DAC960_ParsePhysicalDevice(Controller, &UserCommand[4],
if (BeginningOfLine) &Channel, &TargetID))
{ {
if (Buffer[0] != '\n' || Length > 1) DAC960_V1_DeviceState_T *DeviceState =
printk("%sDAC960#%d: %s", &Controller->V1.DeviceState[Channel][TargetID];
DAC960_MessageLevelMap[MessageLevel], if (DeviceState->Present &&
Controller->ControllerNumber, Buffer); DeviceState->DeviceType == DAC960_V1_DiskType &&
DeviceState->DeviceState != DAC960_V1_Device_Dead)
DAC960_V1_SetDeviceState(Controller, Command, Channel, TargetID,
DAC960_V1_Device_Dead, "Kill");
else DAC960_UserCritical("Kill of Physical Device %d:%d Illegal\n",
Controller, Channel, TargetID);
} }
else printk("%s", Buffer); else if (strncmp(UserCommand, "make-online", 11) == 0 &&
DAC960_ParsePhysicalDevice(Controller, &UserCommand[11],
&Channel, &TargetID))
{
DAC960_V1_DeviceState_T *DeviceState =
&Controller->V1.DeviceState[Channel][TargetID];
if (DeviceState->Present &&
DeviceState->DeviceType == DAC960_V1_DiskType &&
DeviceState->DeviceState == DAC960_V1_Device_Dead)
DAC960_V1_SetDeviceState(Controller, Command, Channel, TargetID,
DAC960_V1_Device_Online, "Make Online");
else DAC960_UserCritical("Make Online of Physical Device %d:%d Illegal\n",
Controller, Channel, TargetID);
} }
else if (strncmp(UserCommand, "make-standby", 12) == 0 &&
DAC960_ParsePhysicalDevice(Controller, &UserCommand[12],
&Channel, &TargetID))
{
DAC960_V1_DeviceState_T *DeviceState =
&Controller->V1.DeviceState[Channel][TargetID];
if (DeviceState->Present &&
DeviceState->DeviceType == DAC960_V1_DiskType &&
DeviceState->DeviceState == DAC960_V1_Device_Dead)
DAC960_V1_SetDeviceState(Controller, Command, Channel, TargetID,
DAC960_V1_Device_Standby, "Make Standby");
else DAC960_UserCritical("Make Standby of Physical "
"Device %d:%d Illegal\n",
Controller, Channel, TargetID);
} }
else if (DAC960_CheckStatusBuffer(Controller, Length)) else if (strncmp(UserCommand, "rebuild", 7) == 0 &&
DAC960_ParsePhysicalDevice(Controller, &UserCommand[7],
&Channel, &TargetID))
{ {
strcpy(&Controller->CurrentStatusBuffer[ CommandMailbox->Type3D.CommandOpcode = DAC960_V1_RebuildAsync;
Controller->CurrentStatusLength], Buffer); CommandMailbox->Type3D.Channel = Channel;
Controller->CurrentStatusLength += Length; CommandMailbox->Type3D.TargetID = TargetID;
DAC960_ExecuteCommand(Command);
switch (Command->V1.CommandStatus)
{
case DAC960_V1_NormalCompletion:
DAC960_UserCritical("Rebuild of Physical Device %d:%d Initiated\n",
Controller, Channel, TargetID);
break;
case DAC960_V1_AttemptToRebuildOnlineDrive:
DAC960_UserCritical("Rebuild of Physical Device %d:%d Failed - "
"Attempt to Rebuild Online or "
"Unresponsive Drive\n",
Controller, Channel, TargetID);
break;
case DAC960_V1_NewDiskFailedDuringRebuild:
DAC960_UserCritical("Rebuild of Physical Device %d:%d Failed - "
"New Disk Failed During Rebuild\n",
Controller, Channel, TargetID);
break;
case DAC960_V1_InvalidDeviceAddress:
DAC960_UserCritical("Rebuild of Physical Device %d:%d Failed - "
"Invalid Device Address\n",
Controller, Channel, TargetID);
break;
case DAC960_V1_RebuildOrCheckAlreadyInProgress:
DAC960_UserCritical("Rebuild of Physical Device %d:%d Failed - "
"Rebuild or Consistency Check Already "
"in Progress\n", Controller, Channel, TargetID);
break;
default:
DAC960_UserCritical("Rebuild of Physical Device %d:%d Failed - "
"Unexpected Status %04X\n", Controller,
Channel, TargetID, Command->V1.CommandStatus);
break;
} }
} }
else if (MessageLevel == DAC960_ProgressLevel) else if (strncmp(UserCommand, "check-consistency", 17) == 0 &&
{ DAC960_ParseLogicalDrive(Controller, &UserCommand[17],
strcpy(Controller->ProgressBuffer, Buffer); &LogicalDriveNumber))
Controller->ProgressBufferLength = Length;
if (Controller->EphemeralProgressMessage)
{ {
if (jiffies - Controller->LastProgressReportTime CommandMailbox->Type3C.CommandOpcode = DAC960_V1_CheckConsistencyAsync;
>= DAC960_ProgressReportingInterval) CommandMailbox->Type3C.LogicalDriveNumber = LogicalDriveNumber;
CommandMailbox->Type3C.AutoRestore = true;
DAC960_ExecuteCommand(Command);
switch (Command->V1.CommandStatus)
{ {
printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel], case DAC960_V1_NormalCompletion:
Controller->ControllerNumber, Buffer); DAC960_UserCritical("Consistency Check of Logical Drive %d "
Controller->LastProgressReportTime = jiffies; "(/dev/rd/c%dd%d) Initiated\n",
} Controller, LogicalDriveNumber,
Controller->ControllerNumber,
LogicalDriveNumber);
break;
case DAC960_V1_DependentDiskIsDead:
DAC960_UserCritical("Consistency Check of Logical Drive %d "
"(/dev/rd/c%dd%d) Failed - "
"Dependent Physical Device is DEAD\n",
Controller, LogicalDriveNumber,
Controller->ControllerNumber,
LogicalDriveNumber);
break;
case DAC960_V1_InvalidOrNonredundantLogicalDrive:
DAC960_UserCritical("Consistency Check of Logical Drive %d "
"(/dev/rd/c%dd%d) Failed - "
"Invalid or Nonredundant Logical Drive\n",
Controller, LogicalDriveNumber,
Controller->ControllerNumber,
LogicalDriveNumber);
break;
case DAC960_V1_RebuildOrCheckAlreadyInProgress:
DAC960_UserCritical("Consistency Check of Logical Drive %d "
"(/dev/rd/c%dd%d) Failed - Rebuild or "
"Consistency Check Already in Progress\n",
Controller, LogicalDriveNumber,
Controller->ControllerNumber,
LogicalDriveNumber);
break;
default:
DAC960_UserCritical("Consistency Check of Logical Drive %d "
"(/dev/rd/c%dd%d) Failed - "
"Unexpected Status %04X\n",
Controller, LogicalDriveNumber,
Controller->ControllerNumber,
LogicalDriveNumber, Command->V1.CommandStatus);
break;
} }
else printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel],
Controller->ControllerNumber, Buffer);
} }
else if (MessageLevel == DAC960_UserCriticalLevel) else if (strcmp(UserCommand, "cancel-rebuild") == 0 ||
strcmp(UserCommand, "cancel-consistency-check") == 0)
{ {
strcpy(&Controller->UserStatusBuffer[Controller->UserStatusLength], /*
Buffer); the OldRebuildRateConstant is never actually used
Controller->UserStatusLength += Length; once its value is retrieved from the controller.
if (Buffer[0] != '\n' || Length > 1) */
printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel], unsigned char *OldRebuildRateConstant;
Controller->ControllerNumber, Buffer); dma_addr_t OldRebuildRateConstantDMA;
OldRebuildRateConstant = pci_alloc_consistent( Controller->PCIDevice,
sizeof(char), &OldRebuildRateConstantDMA);
if (OldRebuildRateConstant == NULL) {
DAC960_UserCritical("Cancellation of Rebuild or "
"Consistency Check Failed - "
"Out of Memory",
Controller);
goto failure;
} }
else CommandMailbox->Type3R.CommandOpcode = DAC960_V1_RebuildControl;
CommandMailbox->Type3R.RebuildRateConstant = 0xFF;
CommandMailbox->Type3R.BusAddress = OldRebuildRateConstantDMA;
DAC960_ExecuteCommand(Command);
switch (Command->V1.CommandStatus)
{ {
if (BeginningOfLine) case DAC960_V1_NormalCompletion:
printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel], DAC960_UserCritical("Rebuild or Consistency Check Cancelled\n",
Controller->ControllerNumber, Buffer); Controller);
else printk("%s", Buffer); break;
default:
DAC960_UserCritical("Cancellation of Rebuild or "
"Consistency Check Failed - "
"Unexpected Status %04X\n",
Controller, Command->V1.CommandStatus);
break;
} }
BeginningOfLine = (Buffer[Length-1] == '\n'); failure:
} pci_free_consistent(Controller->PCIDevice, sizeof(char),
OldRebuildRateConstant, OldRebuildRateConstantDMA);
}
/* else DAC960_UserCritical("Illegal User Command: '%s'\n",
DAC960_ParsePhysicalDevice parses spaces followed by a Physical Device Controller, UserCommand);
Channel:TargetID specification from a User Command string. It updates
Channel and TargetID and returns true on success and false on failure.
*/
static boolean DAC960_ParsePhysicalDevice(DAC960_Controller_T *Controller,
char *UserCommandString,
unsigned char *Channel,
unsigned char *TargetID)
{
char *NewUserCommandString = UserCommandString;
unsigned long XChannel, XTargetID;
while (*UserCommandString == ' ') UserCommandString++;
if (UserCommandString == NewUserCommandString)
return false;
XChannel = simple_strtoul(UserCommandString, &NewUserCommandString, 10);
if (NewUserCommandString == UserCommandString ||
*NewUserCommandString != ':' ||
XChannel >= Controller->Channels)
return false;
UserCommandString = ++NewUserCommandString;
XTargetID = simple_strtoul(UserCommandString, &NewUserCommandString, 10);
if (NewUserCommandString == UserCommandString ||
*NewUserCommandString != '\0' ||
XTargetID >= Controller->Targets)
return false;
*Channel = XChannel;
*TargetID = XTargetID;
return true;
}
/*
DAC960_ParseLogicalDrive parses spaces followed by a Logical Drive Number
specification from a User Command string. It updates LogicalDriveNumber and
returns true on success and false on failure.
*/
static boolean DAC960_ParseLogicalDrive(DAC960_Controller_T *Controller, spin_lock_irqsave(&Controller->queue_lock, flags);
char *UserCommandString, DAC960_DeallocateCommand(Command);
unsigned char *LogicalDriveNumber) spin_unlock_irqrestore(&Controller->queue_lock, flags);
{
char *NewUserCommandString = UserCommandString;
unsigned long XLogicalDriveNumber;
while (*UserCommandString == ' ') UserCommandString++;
if (UserCommandString == NewUserCommandString)
return false;
XLogicalDriveNumber =
simple_strtoul(UserCommandString, &NewUserCommandString, 10);
if (NewUserCommandString == UserCommandString ||
*NewUserCommandString != '\0' ||
XLogicalDriveNumber > DAC960_MaxLogicalDrives - 1)
return false;
*LogicalDriveNumber = XLogicalDriveNumber;
return true; return true;
} }
/* /*
DAC960_V1_SetDeviceState sets the Device State for a Physical Device for DAC960_V2_TranslatePhysicalDevice translates a Physical Device Channel and
DAC960 V1 Firmware Controllers. TargetID into a Logical Device. It returns true on success and false
on failure.
*/ */
static void DAC960_V1_SetDeviceState(DAC960_Controller_T *Controller, static boolean DAC960_V2_TranslatePhysicalDevice(DAC960_Command_T *Command,
DAC960_Command_T *Command,
unsigned char Channel, unsigned char Channel,
unsigned char TargetID, unsigned char TargetID,
DAC960_V1_PhysicalDeviceState_T unsigned short
DeviceState, *LogicalDeviceNumber)
const unsigned char *DeviceStateString)
{ {
DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox; DAC960_V2_CommandMailbox_T SavedCommandMailbox, *CommandMailbox;
CommandMailbox->Type3D.CommandOpcode = DAC960_V1_StartDevice; DAC960_Controller_T *Controller = Command->Controller;
CommandMailbox->Type3D.Channel = Channel;
CommandMailbox->Type3D.TargetID = TargetID; CommandMailbox = &Command->V2.CommandMailbox;
CommandMailbox->Type3D.DeviceState = DeviceState; memcpy(&SavedCommandMailbox, CommandMailbox,
CommandMailbox->Type3D.Modifier = 0; sizeof(DAC960_V2_CommandMailbox_T));
CommandMailbox->PhysicalDeviceInfo.CommandOpcode = DAC960_V2_IOCTL;
CommandMailbox->PhysicalDeviceInfo.CommandControlBits
.DataTransferControllerToHost = true;
CommandMailbox->PhysicalDeviceInfo.CommandControlBits
.NoAutoRequestSense = true;
CommandMailbox->PhysicalDeviceInfo.DataTransferSize =
sizeof(DAC960_V2_PhysicalToLogicalDevice_T);
CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.TargetID = TargetID;
CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.Channel = Channel;
CommandMailbox->PhysicalDeviceInfo.IOCTL_Opcode =
DAC960_V2_TranslatePhysicalToLogicalDevice;
CommandMailbox->Common.DataTransferMemoryAddress
.ScatterGatherSegments[0]
.SegmentDataPointer =
Controller->V2.PhysicalToLogicalDeviceDMA;
CommandMailbox->Common.DataTransferMemoryAddress
.ScatterGatherSegments[0]
.SegmentByteCount =
CommandMailbox->Common.DataTransferSize;
DAC960_ExecuteCommand(Command); DAC960_ExecuteCommand(Command);
switch (Command->V1.CommandStatus) *LogicalDeviceNumber = Controller->V2.PhysicalToLogicalDevice->LogicalDeviceNumber;
{
case DAC960_V1_NormalCompletion: memcpy(CommandMailbox, &SavedCommandMailbox,
DAC960_UserCritical("%s of Physical Device %d:%d Succeeded\n", Controller, sizeof(DAC960_V2_CommandMailbox_T));
DeviceStateString, Channel, TargetID); return (Command->V2.CommandStatus == DAC960_V2_NormalCompletion);
break;
case DAC960_V1_UnableToStartDevice:
DAC960_UserCritical("%s of Physical Device %d:%d Failed - "
"Unable to Start Device\n", Controller,
DeviceStateString, Channel, TargetID);
break;
case DAC960_V1_NoDeviceAtAddress:
DAC960_UserCritical("%s of Physical Device %d:%d Failed - "
"No Device at Address\n", Controller,
DeviceStateString, Channel, TargetID);
break;
case DAC960_V1_InvalidChannelOrTargetOrModifier:
DAC960_UserCritical("%s of Physical Device %d:%d Failed - "
"Invalid Channel or Target or Modifier\n",
Controller, DeviceStateString, Channel, TargetID);
break;
case DAC960_V1_ChannelBusy:
DAC960_UserCritical("%s of Physical Device %d:%d Failed - "
"Channel Busy\n", Controller,
DeviceStateString, Channel, TargetID);
break;
default:
DAC960_UserCritical("%s of Physical Device %d:%d Failed - "
"Unexpected Status %04X\n", Controller,
DeviceStateString, Channel, TargetID,
Command->V1.CommandStatus);
break;
}
} }
/* /*
DAC960_V1_ExecuteUserCommand executes a User Command for DAC960 V1 Firmware DAC960_V2_ExecuteUserCommand executes a User Command for DAC960 V2 Firmware
Controllers. Controllers.
*/ */
static boolean DAC960_V1_ExecuteUserCommand(DAC960_Controller_T *Controller, static boolean DAC960_V2_ExecuteUserCommand(DAC960_Controller_T *Controller,
unsigned char *UserCommand) unsigned char *UserCommand)
{ {
DAC960_Command_T *Command; DAC960_Command_T *Command;
DAC960_V1_CommandMailbox_T *CommandMailbox; DAC960_V2_CommandMailbox_T *CommandMailbox;
unsigned long flags; unsigned long flags;
unsigned char Channel, TargetID, LogicalDriveNumber; unsigned char Channel, TargetID, LogicalDriveNumber;
unsigned short LogicalDeviceNumber;
spin_lock_irqsave(&Controller->queue_lock, flags); spin_lock_irqsave(&Controller->queue_lock, flags);
while ((Command = DAC960_AllocateCommand(Controller)) == NULL) while ((Command = DAC960_AllocateCommand(Controller)) == NULL)
DAC960_WaitForCommand(Controller); DAC960_WaitForCommand(Controller);
spin_unlock_irqrestore(&Controller->queue_lock, flags); spin_unlock_irqrestore(&Controller->queue_lock, flags);
Controller->UserStatusLength = 0; Controller->UserStatusLength = 0;
DAC960_V1_ClearCommand(Command); DAC960_V2_ClearCommand(Command);
Command->CommandType = DAC960_ImmediateCommand; Command->CommandType = DAC960_ImmediateCommand;
CommandMailbox = &Command->V1.CommandMailbox; CommandMailbox = &Command->V2.CommandMailbox;
CommandMailbox->Common.CommandOpcode = DAC960_V2_IOCTL;
CommandMailbox->Common.CommandControlBits.DataTransferControllerToHost = true;
CommandMailbox->Common.CommandControlBits.NoAutoRequestSense = true;
if (strcmp(UserCommand, "flush-cache") == 0) if (strcmp(UserCommand, "flush-cache") == 0)
{ {
CommandMailbox->Type3.CommandOpcode = DAC960_V1_Flush; CommandMailbox->DeviceOperation.IOCTL_Opcode = DAC960_V2_PauseDevice;
CommandMailbox->DeviceOperation.OperationDevice =
DAC960_V2_RAID_Controller;
DAC960_ExecuteCommand(Command); DAC960_ExecuteCommand(Command);
DAC960_UserCritical("Cache Flush Completed\n", Controller); DAC960_UserCritical("Cache Flush Completed\n", Controller);
} }
else if (strncmp(UserCommand, "kill", 4) == 0 && else if (strncmp(UserCommand, "kill", 4) == 0 &&
DAC960_ParsePhysicalDevice(Controller, &UserCommand[4], DAC960_ParsePhysicalDevice(Controller, &UserCommand[4],
&Channel, &TargetID)) &Channel, &TargetID) &&
DAC960_V2_TranslatePhysicalDevice(Command, Channel, TargetID,
&LogicalDeviceNumber))
{ {
DAC960_V1_DeviceState_T *DeviceState = CommandMailbox->SetDeviceState.LogicalDevice.LogicalDeviceNumber =
&Controller->V1.DeviceState[Channel][TargetID]; LogicalDeviceNumber;
if (DeviceState->Present && CommandMailbox->SetDeviceState.IOCTL_Opcode =
DeviceState->DeviceType == DAC960_V1_DiskType && DAC960_V2_SetDeviceState;
DeviceState->DeviceState != DAC960_V1_Device_Dead) CommandMailbox->SetDeviceState.DeviceState.PhysicalDeviceState =
DAC960_V1_SetDeviceState(Controller, Command, Channel, TargetID, DAC960_V2_Device_Dead;
DAC960_V1_Device_Dead, "Kill"); DAC960_ExecuteCommand(Command);
else DAC960_UserCritical("Kill of Physical Device %d:%d Illegal\n", DAC960_UserCritical("Kill of Physical Device %d:%d %s\n",
Controller, Channel, TargetID); Controller, Channel, TargetID,
(Command->V2.CommandStatus
== DAC960_V2_NormalCompletion
? "Succeeded" : "Failed"));
} }
else if (strncmp(UserCommand, "make-online", 11) == 0 && else if (strncmp(UserCommand, "make-online", 11) == 0 &&
DAC960_ParsePhysicalDevice(Controller, &UserCommand[11], DAC960_ParsePhysicalDevice(Controller, &UserCommand[11],
&Channel, &TargetID)) &Channel, &TargetID) &&
DAC960_V2_TranslatePhysicalDevice(Command, Channel, TargetID,
&LogicalDeviceNumber))
{ {
DAC960_V1_DeviceState_T *DeviceState = CommandMailbox->SetDeviceState.LogicalDevice.LogicalDeviceNumber =
&Controller->V1.DeviceState[Channel][TargetID]; LogicalDeviceNumber;
if (DeviceState->Present && CommandMailbox->SetDeviceState.IOCTL_Opcode =
DeviceState->DeviceType == DAC960_V1_DiskType && DAC960_V2_SetDeviceState;
DeviceState->DeviceState == DAC960_V1_Device_Dead) CommandMailbox->SetDeviceState.DeviceState.PhysicalDeviceState =
DAC960_V1_SetDeviceState(Controller, Command, Channel, TargetID, DAC960_V2_Device_Online;
DAC960_V1_Device_Online, "Make Online"); DAC960_ExecuteCommand(Command);
else DAC960_UserCritical("Make Online of Physical Device %d:%d Illegal\n", DAC960_UserCritical("Make Online of Physical Device %d:%d %s\n",
Controller, Channel, TargetID); Controller, Channel, TargetID,
(Command->V2.CommandStatus
== DAC960_V2_NormalCompletion
? "Succeeded" : "Failed"));
} }
else if (strncmp(UserCommand, "make-standby", 12) == 0 && else if (strncmp(UserCommand, "make-standby", 12) == 0 &&
DAC960_ParsePhysicalDevice(Controller, &UserCommand[12], DAC960_ParsePhysicalDevice(Controller, &UserCommand[12],
&Channel, &TargetID)) &Channel, &TargetID) &&
DAC960_V2_TranslatePhysicalDevice(Command, Channel, TargetID,
&LogicalDeviceNumber))
{ {
DAC960_V1_DeviceState_T *DeviceState = CommandMailbox->SetDeviceState.LogicalDevice.LogicalDeviceNumber =
&Controller->V1.DeviceState[Channel][TargetID]; LogicalDeviceNumber;
if (DeviceState->Present && CommandMailbox->SetDeviceState.IOCTL_Opcode =
DeviceState->DeviceType == DAC960_V1_DiskType && DAC960_V2_SetDeviceState;
DeviceState->DeviceState == DAC960_V1_Device_Dead) CommandMailbox->SetDeviceState.DeviceState.PhysicalDeviceState =
DAC960_V1_SetDeviceState(Controller, Command, Channel, TargetID, DAC960_V2_Device_Standby;
DAC960_V1_Device_Standby, "Make Standby"); DAC960_ExecuteCommand(Command);
else DAC960_UserCritical("Make Standby of Physical " DAC960_UserCritical("Make Standby of Physical Device %d:%d %s\n",
"Device %d:%d Illegal\n", Controller, Channel, TargetID,
Controller, Channel, TargetID); (Command->V2.CommandStatus
== DAC960_V2_NormalCompletion
? "Succeeded" : "Failed"));
} }
else if (strncmp(UserCommand, "rebuild", 7) == 0 && else if (strncmp(UserCommand, "rebuild", 7) == 0 &&
DAC960_ParsePhysicalDevice(Controller, &UserCommand[7], DAC960_ParsePhysicalDevice(Controller, &UserCommand[7],
&Channel, &TargetID)) &Channel, &TargetID) &&
DAC960_V2_TranslatePhysicalDevice(Command, Channel, TargetID,
&LogicalDeviceNumber))
{ {
CommandMailbox->Type3D.CommandOpcode = DAC960_V1_RebuildAsync; CommandMailbox->LogicalDeviceInfo.LogicalDevice.LogicalDeviceNumber =
CommandMailbox->Type3D.Channel = Channel; LogicalDeviceNumber;
CommandMailbox->Type3D.TargetID = TargetID; CommandMailbox->LogicalDeviceInfo.IOCTL_Opcode =
DAC960_V2_RebuildDeviceStart;
DAC960_ExecuteCommand(Command); DAC960_ExecuteCommand(Command);
switch (Command->V1.CommandStatus) DAC960_UserCritical("Rebuild of Physical Device %d:%d %s\n",
{ Controller, Channel, TargetID,
case DAC960_V1_NormalCompletion: (Command->V2.CommandStatus
DAC960_UserCritical("Rebuild of Physical Device %d:%d Initiated\n", == DAC960_V2_NormalCompletion
Controller, Channel, TargetID); ? "Initiated" : "Not Initiated"));
break;
case DAC960_V1_AttemptToRebuildOnlineDrive:
DAC960_UserCritical("Rebuild of Physical Device %d:%d Failed - "
"Attempt to Rebuild Online or "
"Unresponsive Drive\n",
Controller, Channel, TargetID);
break;
case DAC960_V1_NewDiskFailedDuringRebuild:
DAC960_UserCritical("Rebuild of Physical Device %d:%d Failed - "
"New Disk Failed During Rebuild\n",
Controller, Channel, TargetID);
break;
case DAC960_V1_InvalidDeviceAddress:
DAC960_UserCritical("Rebuild of Physical Device %d:%d Failed - "
"Invalid Device Address\n",
Controller, Channel, TargetID);
break;
case DAC960_V1_RebuildOrCheckAlreadyInProgress:
DAC960_UserCritical("Rebuild of Physical Device %d:%d Failed - "
"Rebuild or Consistency Check Already "
"in Progress\n", Controller, Channel, TargetID);
break;
default:
DAC960_UserCritical("Rebuild of Physical Device %d:%d Failed - "
"Unexpected Status %04X\n", Controller,
Channel, TargetID, Command->V1.CommandStatus);
break;
} }
else if (strncmp(UserCommand, "cancel-rebuild", 14) == 0 &&
DAC960_ParsePhysicalDevice(Controller, &UserCommand[14],
&Channel, &TargetID) &&
DAC960_V2_TranslatePhysicalDevice(Command, Channel, TargetID,
&LogicalDeviceNumber))
{
CommandMailbox->LogicalDeviceInfo.LogicalDevice.LogicalDeviceNumber =
LogicalDeviceNumber;
CommandMailbox->LogicalDeviceInfo.IOCTL_Opcode =
DAC960_V2_RebuildDeviceStop;
DAC960_ExecuteCommand(Command);
DAC960_UserCritical("Rebuild of Physical Device %d:%d %s\n",
Controller, Channel, TargetID,
(Command->V2.CommandStatus
== DAC960_V2_NormalCompletion
? "Cancelled" : "Not Cancelled"));
} }
else if (strncmp(UserCommand, "check-consistency", 17) == 0 && else if (strncmp(UserCommand, "check-consistency", 17) == 0 &&
DAC960_ParseLogicalDrive(Controller, &UserCommand[17], DAC960_ParseLogicalDrive(Controller, &UserCommand[17],
&LogicalDriveNumber)) &LogicalDriveNumber))
{ {
CommandMailbox->Type3C.CommandOpcode = DAC960_V1_CheckConsistencyAsync; CommandMailbox->ConsistencyCheck.LogicalDevice.LogicalDeviceNumber =
CommandMailbox->Type3C.LogicalDriveNumber = LogicalDriveNumber; LogicalDriveNumber;
CommandMailbox->Type3C.AutoRestore = true; CommandMailbox->ConsistencyCheck.IOCTL_Opcode =
DAC960_V2_ConsistencyCheckStart;
CommandMailbox->ConsistencyCheck.RestoreConsistency = true;
CommandMailbox->ConsistencyCheck.InitializedAreaOnly = false;
DAC960_ExecuteCommand(Command); DAC960_ExecuteCommand(Command);
switch (Command->V1.CommandStatus)
{
case DAC960_V1_NormalCompletion:
DAC960_UserCritical("Consistency Check of Logical Drive %d "
"(/dev/rd/c%dd%d) Initiated\n",
Controller, LogicalDriveNumber,
Controller->ControllerNumber,
LogicalDriveNumber);
break;
case DAC960_V1_DependentDiskIsDead:
DAC960_UserCritical("Consistency Check of Logical Drive %d "
"(/dev/rd/c%dd%d) Failed - "
"Dependent Physical Device is DEAD\n",
Controller, LogicalDriveNumber,
Controller->ControllerNumber,
LogicalDriveNumber);
break;
case DAC960_V1_InvalidOrNonredundantLogicalDrive:
DAC960_UserCritical("Consistency Check of Logical Drive %d "
"(/dev/rd/c%dd%d) Failed - "
"Invalid or Nonredundant Logical Drive\n",
Controller, LogicalDriveNumber,
Controller->ControllerNumber,
LogicalDriveNumber);
break;
case DAC960_V1_RebuildOrCheckAlreadyInProgress:
DAC960_UserCritical("Consistency Check of Logical Drive %d " DAC960_UserCritical("Consistency Check of Logical Drive %d "
"(/dev/rd/c%dd%d) Failed - Rebuild or " "(/dev/rd/c%dd%d) %s\n",
"Consistency Check Already in Progress\n",
Controller, LogicalDriveNumber, Controller, LogicalDriveNumber,
Controller->ControllerNumber, Controller->ControllerNumber,
LogicalDriveNumber); LogicalDriveNumber,
break; (Command->V2.CommandStatus
default: == DAC960_V2_NormalCompletion
? "Initiated" : "Not Initiated"));
}
else if (strncmp(UserCommand, "cancel-consistency-check", 24) == 0 &&
DAC960_ParseLogicalDrive(Controller, &UserCommand[24],
&LogicalDriveNumber))
{
CommandMailbox->ConsistencyCheck.LogicalDevice.LogicalDeviceNumber =
LogicalDriveNumber;
CommandMailbox->ConsistencyCheck.IOCTL_Opcode =
DAC960_V2_ConsistencyCheckStop;
DAC960_ExecuteCommand(Command);
DAC960_UserCritical("Consistency Check of Logical Drive %d " DAC960_UserCritical("Consistency Check of Logical Drive %d "
"(/dev/rd/c%dd%d) Failed - " "(/dev/rd/c%dd%d) %s\n",
"Unexpected Status %04X\n",
Controller, LogicalDriveNumber, Controller, LogicalDriveNumber,
Controller->ControllerNumber, Controller->ControllerNumber,
LogicalDriveNumber, Command->V1.CommandStatus); LogicalDriveNumber,
break; (Command->V2.CommandStatus
} == DAC960_V2_NormalCompletion
? "Cancelled" : "Not Cancelled"));
} }
else if (strcmp(UserCommand, "cancel-rebuild") == 0 || else if (strcmp(UserCommand, "perform-discovery") == 0)
strcmp(UserCommand, "cancel-consistency-check") == 0) {
CommandMailbox->Common.IOCTL_Opcode = DAC960_V2_StartDiscovery;
DAC960_ExecuteCommand(Command);
DAC960_UserCritical("Discovery %s\n", Controller,
(Command->V2.CommandStatus
== DAC960_V2_NormalCompletion
? "Initiated" : "Not Initiated"));
if (Command->V2.CommandStatus == DAC960_V2_NormalCompletion)
{ {
CommandMailbox->ControllerInfo.CommandOpcode = DAC960_V2_IOCTL;
CommandMailbox->ControllerInfo.CommandControlBits
.DataTransferControllerToHost = true;
CommandMailbox->ControllerInfo.CommandControlBits
.NoAutoRequestSense = true;
CommandMailbox->ControllerInfo.DataTransferSize =
sizeof(DAC960_V2_ControllerInfo_T);
CommandMailbox->ControllerInfo.ControllerNumber = 0;
CommandMailbox->ControllerInfo.IOCTL_Opcode =
DAC960_V2_GetControllerInfo;
/* /*
the OldRebuildRateConstant is never actually used * How does this NOT race with the queued Monitoring
once its value is retrieved from the controller. * usage of this structure?
*/ */
unsigned char *OldRebuildRateConstant; CommandMailbox->ControllerInfo.DataTransferMemoryAddress
dma_addr_t OldRebuildRateConstantDMA; .ScatterGatherSegments[0]
.SegmentDataPointer =
OldRebuildRateConstant = pci_alloc_consistent( Controller->PCIDevice, Controller->V2.NewControllerInformationDMA;
sizeof(char), &OldRebuildRateConstantDMA); CommandMailbox->ControllerInfo.DataTransferMemoryAddress
if (OldRebuildRateConstant == NULL) { .ScatterGatherSegments[0]
DAC960_UserCritical("Cancellation of Rebuild or " .SegmentByteCount =
"Consistency Check Failed - " CommandMailbox->ControllerInfo.DataTransferSize;
"Out of Memory",
Controller);
goto failure;
}
CommandMailbox->Type3R.CommandOpcode = DAC960_V1_RebuildControl;
CommandMailbox->Type3R.RebuildRateConstant = 0xFF;
CommandMailbox->Type3R.BusAddress = OldRebuildRateConstantDMA;
DAC960_ExecuteCommand(Command); DAC960_ExecuteCommand(Command);
switch (Command->V1.CommandStatus) while (Controller->V2.NewControllerInformation->PhysicalScanActive)
{ {
case DAC960_V1_NormalCompletion: DAC960_ExecuteCommand(Command);
DAC960_UserCritical("Rebuild or Consistency Check Cancelled\n", sleep_on_timeout(&Controller->CommandWaitQueue, HZ);
Controller);
break;
default:
DAC960_UserCritical("Cancellation of Rebuild or "
"Consistency Check Failed - "
"Unexpected Status %04X\n",
Controller, Command->V1.CommandStatus);
break;
} }
failure: DAC960_UserCritical("Discovery Completed\n", Controller);
pci_free_consistent(Controller->PCIDevice, sizeof(char),
OldRebuildRateConstant, OldRebuildRateConstantDMA);
} }
}
else if (strcmp(UserCommand, "suppress-enclosure-messages") == 0)
Controller->SuppressEnclosureMessages = true;
else DAC960_UserCritical("Illegal User Command: '%s'\n", else DAC960_UserCritical("Illegal User Command: '%s'\n",
Controller, UserCommand); Controller, UserCommand);
...@@ -6440,466 +6298,633 @@ static boolean DAC960_V1_ExecuteUserCommand(DAC960_Controller_T *Controller, ...@@ -6440,466 +6298,633 @@ static boolean DAC960_V1_ExecuteUserCommand(DAC960_Controller_T *Controller,
/* /*
DAC960_V2_TranslatePhysicalDevice translates a Physical Device Channel and DAC960_ProcReadStatus implements reading /proc/rd/status.
TargetID into a Logical Device. It returns true on success and false */
on failure.
static int DAC960_ProcReadStatus(char *Page, char **Start, off_t Offset,
int Count, int *EOF, void *Data)
{
unsigned char *StatusMessage = "OK\n";
int ControllerNumber, BytesAvailable;
for (ControllerNumber = 0;
ControllerNumber < DAC960_ControllerCount;
ControllerNumber++)
{
DAC960_Controller_T *Controller = DAC960_Controllers[ControllerNumber];
if (Controller == NULL) continue;
if (Controller->MonitoringAlertMode)
{
StatusMessage = "ALERT\n";
break;
}
}
BytesAvailable = strlen(StatusMessage) - Offset;
if (Count >= BytesAvailable)
{
Count = BytesAvailable;
*EOF = true;
}
if (Count <= 0) return 0;
*Start = Page;
memcpy(Page, &StatusMessage[Offset], Count);
return Count;
}
/*
DAC960_ProcReadInitialStatus implements reading /proc/rd/cN/initial_status.
*/
static int DAC960_ProcReadInitialStatus(char *Page, char **Start, off_t Offset,
int Count, int *EOF, void *Data)
{
DAC960_Controller_T *Controller = (DAC960_Controller_T *) Data;
int BytesAvailable = Controller->InitialStatusLength - Offset;
if (Count >= BytesAvailable)
{
Count = BytesAvailable;
*EOF = true;
}
if (Count <= 0) return 0;
*Start = Page;
memcpy(Page, &Controller->CombinedStatusBuffer[Offset], Count);
return Count;
}
/*
DAC960_ProcReadCurrentStatus implements reading /proc/rd/cN/current_status.
*/
static int DAC960_ProcReadCurrentStatus(char *Page, char **Start, off_t Offset,
int Count, int *EOF, void *Data)
{
DAC960_Controller_T *Controller = (DAC960_Controller_T *) Data;
unsigned char *StatusMessage =
"No Rebuild or Consistency Check in Progress\n";
int ProgressMessageLength = strlen(StatusMessage);
int BytesAvailable;
if (jiffies != Controller->LastCurrentStatusTime)
{
Controller->CurrentStatusLength = 0;
DAC960_AnnounceDriver(Controller);
DAC960_ReportControllerConfiguration(Controller);
DAC960_ReportDeviceConfiguration(Controller);
if (Controller->ProgressBufferLength > 0)
ProgressMessageLength = Controller->ProgressBufferLength;
if (DAC960_CheckStatusBuffer(Controller, 2 + ProgressMessageLength))
{
unsigned char *CurrentStatusBuffer = Controller->CurrentStatusBuffer;
CurrentStatusBuffer[Controller->CurrentStatusLength++] = ' ';
CurrentStatusBuffer[Controller->CurrentStatusLength++] = ' ';
if (Controller->ProgressBufferLength > 0)
strcpy(&CurrentStatusBuffer[Controller->CurrentStatusLength],
Controller->ProgressBuffer);
else
strcpy(&CurrentStatusBuffer[Controller->CurrentStatusLength],
StatusMessage);
Controller->CurrentStatusLength += ProgressMessageLength;
}
Controller->LastCurrentStatusTime = jiffies;
}
BytesAvailable = Controller->CurrentStatusLength - Offset;
if (Count >= BytesAvailable)
{
Count = BytesAvailable;
*EOF = true;
}
if (Count <= 0) return 0;
*Start = Page;
memcpy(Page, &Controller->CurrentStatusBuffer[Offset], Count);
return Count;
}
/*
DAC960_ProcReadUserCommand implements reading /proc/rd/cN/user_command.
*/
static int DAC960_ProcReadUserCommand(char *Page, char **Start, off_t Offset,
int Count, int *EOF, void *Data)
{
DAC960_Controller_T *Controller = (DAC960_Controller_T *) Data;
int BytesAvailable = Controller->UserStatusLength - Offset;
if (Count >= BytesAvailable)
{
Count = BytesAvailable;
*EOF = true;
}
if (Count <= 0) return 0;
*Start = Page;
memcpy(Page, &Controller->UserStatusBuffer[Offset], Count);
return Count;
}
/*
DAC960_ProcWriteUserCommand implements writing /proc/rd/cN/user_command.
*/
static int DAC960_ProcWriteUserCommand(struct file *file, const char *Buffer,
unsigned long Count, void *Data)
{
DAC960_Controller_T *Controller = (DAC960_Controller_T *) Data;
unsigned char CommandBuffer[80];
int Length;
if (Count > sizeof(CommandBuffer)-1) return -EINVAL;
if (copy_from_user(CommandBuffer, Buffer, Count)) return -EFAULT;
CommandBuffer[Count] = '\0';
Length = strlen(CommandBuffer);
if (CommandBuffer[Length-1] == '\n')
CommandBuffer[--Length] = '\0';
if (Controller->FirmwareType == DAC960_V1_Controller)
return (DAC960_V1_ExecuteUserCommand(Controller, CommandBuffer)
? Count : -EBUSY);
else
return (DAC960_V2_ExecuteUserCommand(Controller, CommandBuffer)
? Count : -EBUSY);
}
/*
DAC960_CreateProcEntries creates the /proc/rd/... entries for the
DAC960 Driver.
*/
static void DAC960_CreateProcEntries(DAC960_Controller_T *Controller)
{
struct proc_dir_entry *StatusProcEntry;
struct proc_dir_entry *ControllerProcEntry;
struct proc_dir_entry *UserCommandProcEntry;
if (DAC960_ProcDirectoryEntry == NULL) {
DAC960_ProcDirectoryEntry = proc_mkdir("rd", NULL);
StatusProcEntry = create_proc_read_entry("status", 0,
DAC960_ProcDirectoryEntry,
DAC960_ProcReadStatus, NULL);
}
sprintf(Controller->ControllerName, "c%d", Controller->ControllerNumber);
ControllerProcEntry = proc_mkdir(Controller->ControllerName,
DAC960_ProcDirectoryEntry);
create_proc_read_entry("initial_status", 0, ControllerProcEntry,
DAC960_ProcReadInitialStatus, Controller);
create_proc_read_entry("current_status", 0, ControllerProcEntry,
DAC960_ProcReadCurrentStatus, Controller);
UserCommandProcEntry =
create_proc_read_entry("user_command", S_IWUSR | S_IRUSR,
ControllerProcEntry, DAC960_ProcReadUserCommand,
Controller);
UserCommandProcEntry->write_proc = DAC960_ProcWriteUserCommand;
Controller->ControllerProcEntry = ControllerProcEntry;
}
/*
DAC960_DestroyProcEntries destroys the /proc/rd/... entries for the
DAC960 Driver.
*/ */
static boolean DAC960_V2_TranslatePhysicalDevice(DAC960_Command_T *Command, static void DAC960_DestroyProcEntries(DAC960_Controller_T *Controller)
unsigned char Channel,
unsigned char TargetID,
unsigned short
*LogicalDeviceNumber)
{ {
DAC960_V2_CommandMailbox_T SavedCommandMailbox, *CommandMailbox; if (Controller->ControllerProcEntry == NULL)
DAC960_Controller_T *Controller = Command->Controller; return;
remove_proc_entry("initial_status", Controller->ControllerProcEntry);
CommandMailbox = &Command->V2.CommandMailbox; remove_proc_entry("current_status", Controller->ControllerProcEntry);
memcpy(&SavedCommandMailbox, CommandMailbox, remove_proc_entry("user_command", Controller->ControllerProcEntry);
sizeof(DAC960_V2_CommandMailbox_T)); remove_proc_entry(Controller->ControllerName, DAC960_ProcDirectoryEntry);
Controller->ControllerProcEntry = NULL;
CommandMailbox->PhysicalDeviceInfo.CommandOpcode = DAC960_V2_IOCTL;
CommandMailbox->PhysicalDeviceInfo.CommandControlBits
.DataTransferControllerToHost = true;
CommandMailbox->PhysicalDeviceInfo.CommandControlBits
.NoAutoRequestSense = true;
CommandMailbox->PhysicalDeviceInfo.DataTransferSize =
sizeof(DAC960_V2_PhysicalToLogicalDevice_T);
CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.TargetID = TargetID;
CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.Channel = Channel;
CommandMailbox->PhysicalDeviceInfo.IOCTL_Opcode =
DAC960_V2_TranslatePhysicalToLogicalDevice;
CommandMailbox->Common.DataTransferMemoryAddress
.ScatterGatherSegments[0]
.SegmentDataPointer =
Controller->V2.PhysicalToLogicalDeviceDMA;
CommandMailbox->Common.DataTransferMemoryAddress
.ScatterGatherSegments[0]
.SegmentByteCount =
CommandMailbox->Common.DataTransferSize;
DAC960_ExecuteCommand(Command);
*LogicalDeviceNumber = Controller->V2.PhysicalToLogicalDevice->LogicalDeviceNumber;
memcpy(CommandMailbox, &SavedCommandMailbox,
sizeof(DAC960_V2_CommandMailbox_T));
return (Command->V2.CommandStatus == DAC960_V2_NormalCompletion);
} }
#ifdef DAC960_GAM_MINOR
/* /*
DAC960_V2_ExecuteUserCommand executes a User Command for DAC960 V2 Firmware * DAC960_gam_ioctl is the ioctl function for performing RAID operations.
Controllers.
*/ */
static boolean DAC960_V2_ExecuteUserCommand(DAC960_Controller_T *Controller, static int DAC960_gam_ioctl(struct inode *inode, struct file *file,
unsigned char *UserCommand) unsigned int Request, unsigned long Argument)
{ {
DAC960_Command_T *Command; int ErrorCode = 0;
DAC960_V2_CommandMailbox_T *CommandMailbox; if (!capable(CAP_SYS_ADMIN)) return -EACCES;
switch (Request)
{
case DAC960_IOCTL_GET_CONTROLLER_COUNT:
return DAC960_ControllerCount;
case DAC960_IOCTL_GET_CONTROLLER_INFO:
{
DAC960_ControllerInfo_T *UserSpaceControllerInfo =
(DAC960_ControllerInfo_T *) Argument;
DAC960_ControllerInfo_T ControllerInfo;
DAC960_Controller_T *Controller;
int ControllerNumber;
if (UserSpaceControllerInfo == NULL) return -EINVAL;
ErrorCode = get_user(ControllerNumber,
&UserSpaceControllerInfo->ControllerNumber);
if (ErrorCode != 0) return ErrorCode;
if (ControllerNumber < 0 ||
ControllerNumber > DAC960_ControllerCount - 1)
return -ENXIO;
Controller = DAC960_Controllers[ControllerNumber];
if (Controller == NULL) return -ENXIO;
memset(&ControllerInfo, 0, sizeof(DAC960_ControllerInfo_T));
ControllerInfo.ControllerNumber = ControllerNumber;
ControllerInfo.FirmwareType = Controller->FirmwareType;
ControllerInfo.Channels = Controller->Channels;
ControllerInfo.Targets = Controller->Targets;
ControllerInfo.PCI_Bus = Controller->Bus;
ControllerInfo.PCI_Device = Controller->Device;
ControllerInfo.PCI_Function = Controller->Function;
ControllerInfo.IRQ_Channel = Controller->IRQ_Channel;
ControllerInfo.PCI_Address = Controller->PCI_Address;
strcpy(ControllerInfo.ModelName, Controller->ModelName);
strcpy(ControllerInfo.FirmwareVersion, Controller->FirmwareVersion);
return (copy_to_user(UserSpaceControllerInfo, &ControllerInfo,
sizeof(DAC960_ControllerInfo_T)) ? -EFAULT : 0);
}
case DAC960_IOCTL_V1_EXECUTE_COMMAND:
{
DAC960_V1_UserCommand_T *UserSpaceUserCommand =
(DAC960_V1_UserCommand_T *) Argument;
DAC960_V1_UserCommand_T UserCommand;
DAC960_Controller_T *Controller;
DAC960_Command_T *Command = NULL;
DAC960_V1_CommandOpcode_T CommandOpcode;
DAC960_V1_CommandStatus_T CommandStatus;
DAC960_V1_DCDB_T DCDB;
DAC960_V1_DCDB_T *DCDB_IOBUF = NULL;
dma_addr_t DCDB_IOBUFDMA;
unsigned long flags; unsigned long flags;
unsigned char Channel, TargetID, LogicalDriveNumber; int ControllerNumber, DataTransferLength;
unsigned short LogicalDeviceNumber; unsigned char *DataTransferBuffer = NULL;
dma_addr_t DataTransferBufferDMA;
if (UserSpaceUserCommand == NULL) return -EINVAL;
if (copy_from_user(&UserCommand, UserSpaceUserCommand,
sizeof(DAC960_V1_UserCommand_T))) {
ErrorCode = -EFAULT;
goto Failure1a;
}
ControllerNumber = UserCommand.ControllerNumber;
if (ControllerNumber < 0 ||
ControllerNumber > DAC960_ControllerCount - 1)
return -ENXIO;
Controller = DAC960_Controllers[ControllerNumber];
if (Controller == NULL) return -ENXIO;
if (Controller->FirmwareType != DAC960_V1_Controller) return -EINVAL;
CommandOpcode = UserCommand.CommandMailbox.Common.CommandOpcode;
DataTransferLength = UserCommand.DataTransferLength;
if (CommandOpcode & 0x80) return -EINVAL;
if (CommandOpcode == DAC960_V1_DCDB)
{
if (copy_from_user(&DCDB, UserCommand.DCDB,
sizeof(DAC960_V1_DCDB_T))) {
ErrorCode = -EFAULT;
goto Failure1a;
}
if (DCDB.Channel >= DAC960_V1_MaxChannels) return -EINVAL;
if (!((DataTransferLength == 0 &&
DCDB.Direction
== DAC960_V1_DCDB_NoDataTransfer) ||
(DataTransferLength > 0 &&
DCDB.Direction
== DAC960_V1_DCDB_DataTransferDeviceToSystem) ||
(DataTransferLength < 0 &&
DCDB.Direction
== DAC960_V1_DCDB_DataTransferSystemToDevice)))
return -EINVAL;
if (((DCDB.TransferLengthHigh4 << 16) | DCDB.TransferLength)
!= abs(DataTransferLength))
return -EINVAL;
DCDB_IOBUF = pci_alloc_consistent(Controller->PCIDevice,
sizeof(DAC960_V1_DCDB_T), &DCDB_IOBUFDMA);
if (DCDB_IOBUF == NULL)
return -ENOMEM;
}
if (DataTransferLength > 0)
{
DataTransferBuffer = pci_alloc_consistent(Controller->PCIDevice,
DataTransferLength, &DataTransferBufferDMA);
if (DataTransferBuffer == NULL) {
ErrorCode = -ENOMEM;
goto Failure1;
}
memset(DataTransferBuffer, 0, DataTransferLength);
}
else if (DataTransferLength < 0)
{
DataTransferBuffer = pci_alloc_consistent(Controller->PCIDevice,
-DataTransferLength, &DataTransferBufferDMA);
if (DataTransferBuffer == NULL) {
ErrorCode = -ENOMEM;
goto Failure1;
}
if (copy_from_user(DataTransferBuffer,
UserCommand.DataTransferBuffer,
-DataTransferLength)) {
ErrorCode = -EFAULT;
goto Failure1;
}
}
if (CommandOpcode == DAC960_V1_DCDB)
{
spin_lock_irqsave(&Controller->queue_lock, flags); spin_lock_irqsave(&Controller->queue_lock, flags);
while ((Command = DAC960_AllocateCommand(Controller)) == NULL) while ((Command = DAC960_AllocateCommand(Controller)) == NULL)
DAC960_WaitForCommand(Controller); DAC960_WaitForCommand(Controller);
spin_unlock_irqrestore(&Controller->queue_lock, flags); while (Controller->V1.DirectCommandActive[DCDB.Channel]
Controller->UserStatusLength = 0; [DCDB.TargetID])
DAC960_V2_ClearCommand(Command);
Command->CommandType = DAC960_ImmediateCommand;
CommandMailbox = &Command->V2.CommandMailbox;
CommandMailbox->Common.CommandOpcode = DAC960_V2_IOCTL;
CommandMailbox->Common.CommandControlBits.DataTransferControllerToHost = true;
CommandMailbox->Common.CommandControlBits.NoAutoRequestSense = true;
if (strcmp(UserCommand, "flush-cache") == 0)
{ {
CommandMailbox->DeviceOperation.IOCTL_Opcode = DAC960_V2_PauseDevice; spin_unlock_irq(&Controller->queue_lock);
CommandMailbox->DeviceOperation.OperationDevice = __wait_event(Controller->CommandWaitQueue,
DAC960_V2_RAID_Controller; !Controller->V1.DirectCommandActive
DAC960_ExecuteCommand(Command); [DCDB.Channel][DCDB.TargetID]);
DAC960_UserCritical("Cache Flush Completed\n", Controller); spin_lock_irq(&Controller->queue_lock);
} }
else if (strncmp(UserCommand, "kill", 4) == 0 && Controller->V1.DirectCommandActive[DCDB.Channel]
DAC960_ParsePhysicalDevice(Controller, &UserCommand[4], [DCDB.TargetID] = true;
&Channel, &TargetID) && spin_unlock_irqrestore(&Controller->queue_lock, flags);
DAC960_V2_TranslatePhysicalDevice(Command, Channel, TargetID, DAC960_V1_ClearCommand(Command);
&LogicalDeviceNumber)) Command->CommandType = DAC960_ImmediateCommand;
{ memcpy(&Command->V1.CommandMailbox, &UserCommand.CommandMailbox,
CommandMailbox->SetDeviceState.LogicalDevice.LogicalDeviceNumber = sizeof(DAC960_V1_CommandMailbox_T));
LogicalDeviceNumber; Command->V1.CommandMailbox.Type3.BusAddress = DCDB_IOBUFDMA;
CommandMailbox->SetDeviceState.IOCTL_Opcode = DCDB.BusAddress = DataTransferBufferDMA;
DAC960_V2_SetDeviceState; memcpy(DCDB_IOBUF, &DCDB, sizeof(DAC960_V1_DCDB_T));
CommandMailbox->SetDeviceState.DeviceState.PhysicalDeviceState =
DAC960_V2_Device_Dead;
DAC960_ExecuteCommand(Command);
DAC960_UserCritical("Kill of Physical Device %d:%d %s\n",
Controller, Channel, TargetID,
(Command->V2.CommandStatus
== DAC960_V2_NormalCompletion
? "Succeeded" : "Failed"));
} }
else if (strncmp(UserCommand, "make-online", 11) == 0 && else
DAC960_ParsePhysicalDevice(Controller, &UserCommand[11],
&Channel, &TargetID) &&
DAC960_V2_TranslatePhysicalDevice(Command, Channel, TargetID,
&LogicalDeviceNumber))
{ {
CommandMailbox->SetDeviceState.LogicalDevice.LogicalDeviceNumber = spin_lock_irqsave(&Controller->queue_lock, flags);
LogicalDeviceNumber; while ((Command = DAC960_AllocateCommand(Controller)) == NULL)
CommandMailbox->SetDeviceState.IOCTL_Opcode = DAC960_WaitForCommand(Controller);
DAC960_V2_SetDeviceState; spin_unlock_irqrestore(&Controller->queue_lock, flags);
CommandMailbox->SetDeviceState.DeviceState.PhysicalDeviceState = DAC960_V1_ClearCommand(Command);
DAC960_V2_Device_Online; Command->CommandType = DAC960_ImmediateCommand;
memcpy(&Command->V1.CommandMailbox, &UserCommand.CommandMailbox,
sizeof(DAC960_V1_CommandMailbox_T));
if (DataTransferBuffer != NULL)
Command->V1.CommandMailbox.Type3.BusAddress =
DataTransferBufferDMA;
}
DAC960_ExecuteCommand(Command); DAC960_ExecuteCommand(Command);
DAC960_UserCritical("Make Online of Physical Device %d:%d %s\n", CommandStatus = Command->V1.CommandStatus;
Controller, Channel, TargetID, spin_lock_irqsave(&Controller->queue_lock, flags);
(Command->V2.CommandStatus DAC960_DeallocateCommand(Command);
== DAC960_V2_NormalCompletion spin_unlock_irqrestore(&Controller->queue_lock, flags);
? "Succeeded" : "Failed")); if (DataTransferLength > 0)
{
if (copy_to_user(UserCommand.DataTransferBuffer,
DataTransferBuffer, DataTransferLength)) {
ErrorCode = -EFAULT;
goto Failure1;
} }
else if (strncmp(UserCommand, "make-standby", 12) == 0 && }
DAC960_ParsePhysicalDevice(Controller, &UserCommand[12], if (CommandOpcode == DAC960_V1_DCDB)
&Channel, &TargetID) &&
DAC960_V2_TranslatePhysicalDevice(Command, Channel, TargetID,
&LogicalDeviceNumber))
{ {
CommandMailbox->SetDeviceState.LogicalDevice.LogicalDeviceNumber = /*
LogicalDeviceNumber; I don't believe Target or Channel in the DCDB_IOBUF
CommandMailbox->SetDeviceState.IOCTL_Opcode = should be any different from the contents of DCDB.
DAC960_V2_SetDeviceState; */
CommandMailbox->SetDeviceState.DeviceState.PhysicalDeviceState = Controller->V1.DirectCommandActive[DCDB.Channel]
DAC960_V2_Device_Standby; [DCDB.TargetID] = false;
DAC960_ExecuteCommand(Command); if (copy_to_user(UserCommand.DCDB, DCDB_IOBUF,
DAC960_UserCritical("Make Standby of Physical Device %d:%d %s\n", sizeof(DAC960_V1_DCDB_T))) {
Controller, Channel, TargetID, ErrorCode = -EFAULT;
(Command->V2.CommandStatus goto Failure1;
== DAC960_V2_NormalCompletion
? "Succeeded" : "Failed"));
} }
else if (strncmp(UserCommand, "rebuild", 7) == 0 && }
DAC960_ParsePhysicalDevice(Controller, &UserCommand[7], ErrorCode = CommandStatus;
&Channel, &TargetID) && Failure1:
DAC960_V2_TranslatePhysicalDevice(Command, Channel, TargetID, if (DataTransferBuffer != NULL)
&LogicalDeviceNumber)) pci_free_consistent(Controller->PCIDevice, abs(DataTransferLength),
DataTransferBuffer, DataTransferBufferDMA);
if (DCDB_IOBUF != NULL)
pci_free_consistent(Controller->PCIDevice, sizeof(DAC960_V1_DCDB_T),
DCDB_IOBUF, DCDB_IOBUFDMA);
Failure1a:
return ErrorCode;
}
case DAC960_IOCTL_V2_EXECUTE_COMMAND:
{ {
CommandMailbox->LogicalDeviceInfo.LogicalDevice.LogicalDeviceNumber = DAC960_V2_UserCommand_T *UserSpaceUserCommand =
LogicalDeviceNumber; (DAC960_V2_UserCommand_T *) Argument;
CommandMailbox->LogicalDeviceInfo.IOCTL_Opcode = DAC960_V2_UserCommand_T UserCommand;
DAC960_V2_RebuildDeviceStart; DAC960_Controller_T *Controller;
DAC960_ExecuteCommand(Command); DAC960_Command_T *Command = NULL;
DAC960_UserCritical("Rebuild of Physical Device %d:%d %s\n", DAC960_V2_CommandMailbox_T *CommandMailbox;
Controller, Channel, TargetID, DAC960_V2_CommandStatus_T CommandStatus;
(Command->V2.CommandStatus unsigned long flags;
== DAC960_V2_NormalCompletion int ControllerNumber, DataTransferLength;
? "Initiated" : "Not Initiated")); int DataTransferResidue, RequestSenseLength;
unsigned char *DataTransferBuffer = NULL;
dma_addr_t DataTransferBufferDMA;
unsigned char *RequestSenseBuffer = NULL;
dma_addr_t RequestSenseBufferDMA;
if (UserSpaceUserCommand == NULL) return -EINVAL;
if (copy_from_user(&UserCommand, UserSpaceUserCommand,
sizeof(DAC960_V2_UserCommand_T))) {
ErrorCode = -EFAULT;
goto Failure2a;
} }
else if (strncmp(UserCommand, "cancel-rebuild", 14) == 0 && ControllerNumber = UserCommand.ControllerNumber;
DAC960_ParsePhysicalDevice(Controller, &UserCommand[14], if (ControllerNumber < 0 ||
&Channel, &TargetID) && ControllerNumber > DAC960_ControllerCount - 1)
DAC960_V2_TranslatePhysicalDevice(Command, Channel, TargetID, return -ENXIO;
&LogicalDeviceNumber)) Controller = DAC960_Controllers[ControllerNumber];
if (Controller == NULL) return -ENXIO;
if (Controller->FirmwareType != DAC960_V2_Controller) return -EINVAL;
DataTransferLength = UserCommand.DataTransferLength;
if (DataTransferLength > 0)
{ {
CommandMailbox->LogicalDeviceInfo.LogicalDevice.LogicalDeviceNumber = DataTransferBuffer = pci_alloc_consistent(Controller->PCIDevice,
LogicalDeviceNumber; DataTransferLength, &DataTransferBufferDMA);
CommandMailbox->LogicalDeviceInfo.IOCTL_Opcode = if (DataTransferBuffer == NULL) return -ENOMEM;
DAC960_V2_RebuildDeviceStop; memset(DataTransferBuffer, 0, DataTransferLength);
DAC960_ExecuteCommand(Command);
DAC960_UserCritical("Rebuild of Physical Device %d:%d %s\n",
Controller, Channel, TargetID,
(Command->V2.CommandStatus
== DAC960_V2_NormalCompletion
? "Cancelled" : "Not Cancelled"));
} }
else if (strncmp(UserCommand, "check-consistency", 17) == 0 && else if (DataTransferLength < 0)
DAC960_ParseLogicalDrive(Controller, &UserCommand[17],
&LogicalDriveNumber))
{ {
CommandMailbox->ConsistencyCheck.LogicalDevice.LogicalDeviceNumber = DataTransferBuffer = pci_alloc_consistent(Controller->PCIDevice,
LogicalDriveNumber; -DataTransferLength, &DataTransferBufferDMA);
CommandMailbox->ConsistencyCheck.IOCTL_Opcode = if (DataTransferBuffer == NULL) return -ENOMEM;
DAC960_V2_ConsistencyCheckStart; if (copy_from_user(DataTransferBuffer,
CommandMailbox->ConsistencyCheck.RestoreConsistency = true; UserCommand.DataTransferBuffer,
CommandMailbox->ConsistencyCheck.InitializedAreaOnly = false; -DataTransferLength)) {
DAC960_ExecuteCommand(Command); ErrorCode = -EFAULT;
DAC960_UserCritical("Consistency Check of Logical Drive %d " goto Failure2;
"(/dev/rd/c%dd%d) %s\n",
Controller, LogicalDriveNumber,
Controller->ControllerNumber,
LogicalDriveNumber,
(Command->V2.CommandStatus
== DAC960_V2_NormalCompletion
? "Initiated" : "Not Initiated"));
} }
else if (strncmp(UserCommand, "cancel-consistency-check", 24) == 0 && }
DAC960_ParseLogicalDrive(Controller, &UserCommand[24], RequestSenseLength = UserCommand.RequestSenseLength;
&LogicalDriveNumber)) if (RequestSenseLength > 0)
{ {
CommandMailbox->ConsistencyCheck.LogicalDevice.LogicalDeviceNumber = RequestSenseBuffer = pci_alloc_consistent(Controller->PCIDevice,
LogicalDriveNumber; RequestSenseLength, &RequestSenseBufferDMA);
CommandMailbox->ConsistencyCheck.IOCTL_Opcode = if (RequestSenseBuffer == NULL)
DAC960_V2_ConsistencyCheckStop; {
DAC960_ExecuteCommand(Command); ErrorCode = -ENOMEM;
DAC960_UserCritical("Consistency Check of Logical Drive %d " goto Failure2;
"(/dev/rd/c%dd%d) %s\n",
Controller, LogicalDriveNumber,
Controller->ControllerNumber,
LogicalDriveNumber,
(Command->V2.CommandStatus
== DAC960_V2_NormalCompletion
? "Cancelled" : "Not Cancelled"));
} }
else if (strcmp(UserCommand, "perform-discovery") == 0) memset(RequestSenseBuffer, 0, RequestSenseLength);
}
spin_lock_irqsave(&Controller->queue_lock, flags);
while ((Command = DAC960_AllocateCommand(Controller)) == NULL)
DAC960_WaitForCommand(Controller);
spin_unlock_irqrestore(&Controller->queue_lock, flags);
DAC960_V2_ClearCommand(Command);
Command->CommandType = DAC960_ImmediateCommand;
CommandMailbox = &Command->V2.CommandMailbox;
memcpy(CommandMailbox, &UserCommand.CommandMailbox,
sizeof(DAC960_V2_CommandMailbox_T));
CommandMailbox->Common.CommandControlBits
.AdditionalScatterGatherListMemory = false;
CommandMailbox->Common.CommandControlBits
.NoAutoRequestSense = true;
CommandMailbox->Common.DataTransferSize = 0;
CommandMailbox->Common.DataTransferPageNumber = 0;
memset(&CommandMailbox->Common.DataTransferMemoryAddress, 0,
sizeof(DAC960_V2_DataTransferMemoryAddress_T));
if (DataTransferLength != 0)
{ {
CommandMailbox->Common.IOCTL_Opcode = DAC960_V2_StartDiscovery; if (DataTransferLength > 0)
DAC960_ExecuteCommand(Command);
DAC960_UserCritical("Discovery %s\n", Controller,
(Command->V2.CommandStatus
== DAC960_V2_NormalCompletion
? "Initiated" : "Not Initiated"));
if (Command->V2.CommandStatus == DAC960_V2_NormalCompletion)
{ {
CommandMailbox->ControllerInfo.CommandOpcode = DAC960_V2_IOCTL; CommandMailbox->Common.CommandControlBits
CommandMailbox->ControllerInfo.CommandControlBits
.DataTransferControllerToHost = true; .DataTransferControllerToHost = true;
CommandMailbox->ControllerInfo.CommandControlBits CommandMailbox->Common.DataTransferSize = DataTransferLength;
.NoAutoRequestSense = true; }
CommandMailbox->ControllerInfo.DataTransferSize = else
sizeof(DAC960_V2_ControllerInfo_T); {
CommandMailbox->ControllerInfo.ControllerNumber = 0; CommandMailbox->Common.CommandControlBits
CommandMailbox->ControllerInfo.IOCTL_Opcode = .DataTransferControllerToHost = false;
DAC960_V2_GetControllerInfo; CommandMailbox->Common.DataTransferSize = -DataTransferLength;
/* }
* How does this NOT race with the queued Monitoring CommandMailbox->Common.DataTransferMemoryAddress
* usage of this structure?
*/
CommandMailbox->ControllerInfo.DataTransferMemoryAddress
.ScatterGatherSegments[0] .ScatterGatherSegments[0]
.SegmentDataPointer = .SegmentDataPointer = DataTransferBufferDMA;
Controller->V2.NewControllerInformationDMA; CommandMailbox->Common.DataTransferMemoryAddress
CommandMailbox->ControllerInfo.DataTransferMemoryAddress
.ScatterGatherSegments[0] .ScatterGatherSegments[0]
.SegmentByteCount = .SegmentByteCount =
CommandMailbox->ControllerInfo.DataTransferSize; CommandMailbox->Common.DataTransferSize;
DAC960_ExecuteCommand(Command);
while (Controller->V2.NewControllerInformation->PhysicalScanActive)
{
DAC960_ExecuteCommand(Command);
sleep_on_timeout(&Controller->CommandWaitQueue, HZ);
}
DAC960_UserCritical("Discovery Completed\n", Controller);
} }
if (RequestSenseLength > 0)
{
CommandMailbox->Common.CommandControlBits
.NoAutoRequestSense = false;
CommandMailbox->Common.RequestSenseSize = RequestSenseLength;
CommandMailbox->Common.RequestSenseBusAddress =
RequestSenseBufferDMA;
} }
else if (strcmp(UserCommand, "suppress-enclosure-messages") == 0) DAC960_ExecuteCommand(Command);
Controller->SuppressEnclosureMessages = true; CommandStatus = Command->V2.CommandStatus;
else DAC960_UserCritical("Illegal User Command: '%s'\n", RequestSenseLength = Command->V2.RequestSenseLength;
Controller, UserCommand); DataTransferResidue = Command->V2.DataTransferResidue;
spin_lock_irqsave(&Controller->queue_lock, flags); spin_lock_irqsave(&Controller->queue_lock, flags);
DAC960_DeallocateCommand(Command); DAC960_DeallocateCommand(Command);
spin_unlock_irqrestore(&Controller->queue_lock, flags); spin_unlock_irqrestore(&Controller->queue_lock, flags);
return true; if (RequestSenseLength > UserCommand.RequestSenseLength)
} RequestSenseLength = UserCommand.RequestSenseLength;
if (copy_to_user(&UserSpaceUserCommand->DataTransferLength,
&DataTransferResidue,
/* sizeof(DataTransferResidue))) {
DAC960_ProcReadStatus implements reading /proc/rd/status. ErrorCode = -EFAULT;
*/ goto Failure2;
static int DAC960_ProcReadStatus(char *Page, char **Start, off_t Offset,
int Count, int *EOF, void *Data)
{
unsigned char *StatusMessage = "OK\n";
int ControllerNumber, BytesAvailable;
for (ControllerNumber = 0;
ControllerNumber < DAC960_ControllerCount;
ControllerNumber++)
{
DAC960_Controller_T *Controller = DAC960_Controllers[ControllerNumber];
if (Controller == NULL) continue;
if (Controller->MonitoringAlertMode)
{
StatusMessage = "ALERT\n";
break;
} }
if (copy_to_user(&UserSpaceUserCommand->RequestSenseLength,
&RequestSenseLength, sizeof(RequestSenseLength))) {
ErrorCode = -EFAULT;
goto Failure2;
} }
BytesAvailable = strlen(StatusMessage) - Offset; if (DataTransferLength > 0)
if (Count >= BytesAvailable)
{ {
Count = BytesAvailable; if (copy_to_user(UserCommand.DataTransferBuffer,
*EOF = true; DataTransferBuffer, DataTransferLength)) {
ErrorCode = -EFAULT;
goto Failure2;
} }
if (Count <= 0) return 0; }
*Start = Page; if (RequestSenseLength > 0)
memcpy(Page, &StatusMessage[Offset], Count);
return Count;
}
/*
DAC960_ProcReadInitialStatus implements reading /proc/rd/cN/initial_status.
*/
static int DAC960_ProcReadInitialStatus(char *Page, char **Start, off_t Offset,
int Count, int *EOF, void *Data)
{
DAC960_Controller_T *Controller = (DAC960_Controller_T *) Data;
int BytesAvailable = Controller->InitialStatusLength - Offset;
if (Count >= BytesAvailable)
{ {
Count = BytesAvailable; if (copy_to_user(UserCommand.RequestSenseBuffer,
*EOF = true; RequestSenseBuffer, RequestSenseLength)) {
ErrorCode = -EFAULT;
goto Failure2;
} }
if (Count <= 0) return 0; }
*Start = Page; ErrorCode = CommandStatus;
memcpy(Page, &Controller->CombinedStatusBuffer[Offset], Count); Failure2:
return Count; pci_free_consistent(Controller->PCIDevice, abs(DataTransferLength),
} DataTransferBuffer, DataTransferBufferDMA);
if (RequestSenseBuffer != NULL)
pci_free_consistent(Controller->PCIDevice, RequestSenseLength,
/* RequestSenseBuffer, RequestSenseBufferDMA);
DAC960_ProcReadCurrentStatus implements reading /proc/rd/cN/current_status. Failure2a:
*/ return ErrorCode;
}
static int DAC960_ProcReadCurrentStatus(char *Page, char **Start, off_t Offset, case DAC960_IOCTL_V2_GET_HEALTH_STATUS:
int Count, int *EOF, void *Data)
{
DAC960_Controller_T *Controller = (DAC960_Controller_T *) Data;
unsigned char *StatusMessage =
"No Rebuild or Consistency Check in Progress\n";
int ProgressMessageLength = strlen(StatusMessage);
int BytesAvailable;
if (jiffies != Controller->LastCurrentStatusTime)
{ {
Controller->CurrentStatusLength = 0; DAC960_V2_GetHealthStatus_T *UserSpaceGetHealthStatus =
DAC960_AnnounceDriver(Controller); (DAC960_V2_GetHealthStatus_T *) Argument;
DAC960_ReportControllerConfiguration(Controller); DAC960_V2_GetHealthStatus_T GetHealthStatus;
DAC960_ReportDeviceConfiguration(Controller); DAC960_V2_HealthStatusBuffer_T HealthStatusBuffer;
if (Controller->ProgressBufferLength > 0) DAC960_Controller_T *Controller;
ProgressMessageLength = Controller->ProgressBufferLength; int ControllerNumber;
if (DAC960_CheckStatusBuffer(Controller, 2 + ProgressMessageLength)) if (UserSpaceGetHealthStatus == NULL) return -EINVAL;
if (copy_from_user(&GetHealthStatus, UserSpaceGetHealthStatus,
sizeof(DAC960_V2_GetHealthStatus_T)))
return -EFAULT;
ControllerNumber = GetHealthStatus.ControllerNumber;
if (ControllerNumber < 0 ||
ControllerNumber > DAC960_ControllerCount - 1)
return -ENXIO;
Controller = DAC960_Controllers[ControllerNumber];
if (Controller == NULL) return -ENXIO;
if (Controller->FirmwareType != DAC960_V2_Controller) return -EINVAL;
if (copy_from_user(&HealthStatusBuffer,
GetHealthStatus.HealthStatusBuffer,
sizeof(DAC960_V2_HealthStatusBuffer_T)))
return -EFAULT;
while (Controller->V2.HealthStatusBuffer->StatusChangeCounter
== HealthStatusBuffer.StatusChangeCounter &&
Controller->V2.HealthStatusBuffer->NextEventSequenceNumber
== HealthStatusBuffer.NextEventSequenceNumber)
{ {
unsigned char *CurrentStatusBuffer = Controller->CurrentStatusBuffer; interruptible_sleep_on_timeout(&Controller->HealthStatusWaitQueue,
CurrentStatusBuffer[Controller->CurrentStatusLength++] = ' '; DAC960_MonitoringTimerInterval);
CurrentStatusBuffer[Controller->CurrentStatusLength++] = ' '; if (signal_pending(current)) return -EINTR;
if (Controller->ProgressBufferLength > 0)
strcpy(&CurrentStatusBuffer[Controller->CurrentStatusLength],
Controller->ProgressBuffer);
else
strcpy(&CurrentStatusBuffer[Controller->CurrentStatusLength],
StatusMessage);
Controller->CurrentStatusLength += ProgressMessageLength;
} }
Controller->LastCurrentStatusTime = jiffies; if (copy_to_user(GetHealthStatus.HealthStatusBuffer,
Controller->V2.HealthStatusBuffer,
sizeof(DAC960_V2_HealthStatusBuffer_T)))
return -EFAULT;
return 0;
} }
BytesAvailable = Controller->CurrentStatusLength - Offset;
if (Count >= BytesAvailable)
{
Count = BytesAvailable;
*EOF = true;
} }
if (Count <= 0) return 0; return -EINVAL;
*Start = Page;
memcpy(Page, &Controller->CurrentStatusBuffer[Offset], Count);
return Count;
} }
static struct file_operations DAC960_gam_fops = {
.owner = THIS_MODULE,
.ioctl = DAC960_gam_ioctl
};
/* static struct miscdevice DAC960_gam_dev = {
DAC960_ProcReadUserCommand implements reading /proc/rd/cN/user_command. DAC960_GAM_MINOR,
*/ "dac960_gam",
&DAC960_gam_fops
};
static int DAC960_ProcReadUserCommand(char *Page, char **Start, off_t Offset, static int DAC960_gam_init(void)
int Count, int *EOF, void *Data)
{ {
DAC960_Controller_T *Controller = (DAC960_Controller_T *) Data; int ret;
int BytesAvailable = Controller->UserStatusLength - Offset;
if (Count >= BytesAvailable)
{
Count = BytesAvailable;
*EOF = true;
}
if (Count <= 0) return 0;
*Start = Page;
memcpy(Page, &Controller->UserStatusBuffer[Offset], Count);
return Count;
}
/*
DAC960_ProcWriteUserCommand implements writing /proc/rd/cN/user_command.
*/
static int DAC960_ProcWriteUserCommand(struct file *file, const char *Buffer, ret = misc_register(&DAC960_gam_dev);
unsigned long Count, void *Data) if (ret)
{ printk(KERN_ERR "DAC960_gam: can't misc_register on minor %d\n", DAC960_GAM_MINOR);
DAC960_Controller_T *Controller = (DAC960_Controller_T *) Data; return ret;
unsigned char CommandBuffer[80];
int Length;
if (Count > sizeof(CommandBuffer)-1) return -EINVAL;
if (copy_from_user(CommandBuffer, Buffer, Count)) return -EFAULT;
CommandBuffer[Count] = '\0';
Length = strlen(CommandBuffer);
if (CommandBuffer[Length-1] == '\n')
CommandBuffer[--Length] = '\0';
if (Controller->FirmwareType == DAC960_V1_Controller)
return (DAC960_V1_ExecuteUserCommand(Controller, CommandBuffer)
? Count : -EBUSY);
else
return (DAC960_V2_ExecuteUserCommand(Controller, CommandBuffer)
? Count : -EBUSY);
} }
static void DAC960_gam_cleanup(void)
/*
DAC960_CreateProcEntries creates the /proc/rd/... entries for the
DAC960 Driver.
*/
static void DAC960_CreateProcEntries(DAC960_Controller_T *Controller)
{ {
struct proc_dir_entry *StatusProcEntry; misc_deregister(&DAC960_gam_dev);
struct proc_dir_entry *ControllerProcEntry;
struct proc_dir_entry *UserCommandProcEntry;
if (DAC960_ProcDirectoryEntry == NULL) {
DAC960_ProcDirectoryEntry = proc_mkdir("rd", NULL);
StatusProcEntry = create_proc_read_entry("status", 0,
DAC960_ProcDirectoryEntry,
DAC960_ProcReadStatus, NULL);
}
sprintf(Controller->ControllerName, "c%d", Controller->ControllerNumber);
ControllerProcEntry = proc_mkdir(Controller->ControllerName,
DAC960_ProcDirectoryEntry);
create_proc_read_entry("initial_status", 0, ControllerProcEntry,
DAC960_ProcReadInitialStatus, Controller);
create_proc_read_entry("current_status", 0, ControllerProcEntry,
DAC960_ProcReadCurrentStatus, Controller);
UserCommandProcEntry =
create_proc_read_entry("user_command", S_IWUSR | S_IRUSR,
ControllerProcEntry, DAC960_ProcReadUserCommand,
Controller);
UserCommandProcEntry->write_proc = DAC960_ProcWriteUserCommand;
Controller->ControllerProcEntry = ControllerProcEntry;
} }
#endif /* DAC960_GAM_MINOR */
/*
DAC960_DestroyProcEntries destroys the /proc/rd/... entries for the
DAC960 Driver.
*/
static void DAC960_DestroyProcEntries(DAC960_Controller_T *Controller)
{
if (Controller->ControllerProcEntry == NULL)
return;
remove_proc_entry("initial_status", Controller->ControllerProcEntry);
remove_proc_entry("current_status", Controller->ControllerProcEntry);
remove_proc_entry("user_command", Controller->ControllerProcEntry);
remove_proc_entry(Controller->ControllerName, DAC960_ProcDirectoryEntry);
Controller->ControllerProcEntry = NULL;
}
static struct DAC960_privdata DAC960_BA_privdata = { static struct DAC960_privdata DAC960_BA_privdata = {
.HardwareType = DAC960_BA_Controller, .HardwareType = DAC960_BA_Controller,
...@@ -7000,13 +7025,24 @@ static struct pci_driver DAC960_pci_driver = { ...@@ -7000,13 +7025,24 @@ static struct pci_driver DAC960_pci_driver = {
static int DAC960_init_module(void) static int DAC960_init_module(void)
{ {
return pci_module_init(&DAC960_pci_driver); int ret;
ret = pci_module_init(&DAC960_pci_driver);
#ifdef DAC960_GAM_MINOR
if (!ret)
DAC960_gam_init();
#endif
return ret;
} }
static void DAC960_cleanup_module(void) static void DAC960_cleanup_module(void)
{ {
int i; int i;
#ifdef DAC960_GAM_MINOR
DAC960_gam_cleanup();
#endif
for (i = 0; i < DAC960_ControllerCount; i++) { for (i = 0; i < DAC960_ControllerCount; i++) {
DAC960_Controller_T *Controller = DAC960_Controllers[i]; DAC960_Controller_T *Controller = DAC960_Controllers[i];
if (Controller == NULL) if (Controller == NULL)
......
...@@ -4138,8 +4138,6 @@ static irqreturn_t DAC960_P_InterruptHandler(int, void *, struct pt_regs *); ...@@ -4138,8 +4138,6 @@ static irqreturn_t DAC960_P_InterruptHandler(int, void *, struct pt_regs *);
static void DAC960_V1_QueueMonitoringCommand(DAC960_Command_T *); static void DAC960_V1_QueueMonitoringCommand(DAC960_Command_T *);
static void DAC960_V2_QueueMonitoringCommand(DAC960_Command_T *); static void DAC960_V2_QueueMonitoringCommand(DAC960_Command_T *);
static void DAC960_MonitoringTimerFunction(unsigned long); static void DAC960_MonitoringTimerFunction(unsigned long);
static int DAC960_UserIOCTL(struct inode *, struct file *,
unsigned int, unsigned long);
static void DAC960_Message(DAC960_MessageLevel_T, unsigned char *, static void DAC960_Message(DAC960_MessageLevel_T, unsigned char *,
DAC960_Controller_T *, ...); DAC960_Controller_T *, ...);
static void DAC960_CreateProcEntries(DAC960_Controller_T *); static void DAC960_CreateProcEntries(DAC960_Controller_T *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment