patch-2.0.37 linux/drivers/block/DAC960.c
Next file: linux/drivers/block/DAC960.h
Previous file: linux/drivers/block/Config.in
Back to the patch index
Back to the overall index
- Lines: 1981
- Date:
Sun Jun 13 10:21:00 1999
- Orig file:
v2.0.36/linux/drivers/block/DAC960.c
- Orig date:
Wed Dec 31 16:00:00 1969
diff -u --recursive --new-file v2.0.36/linux/drivers/block/DAC960.c linux/drivers/block/DAC960.c
@@ -0,0 +1,1980 @@
+/*
+
+ Linux Driver for Mylex DAC960 PCI RAID Controllers
+
+ Copyright 1998 by Leonard N. Zubkoff <lnz@dandelion.com>
+
+ This program is free software; you may redistribute and/or modify it under
+ the terms of the GNU General Public License Version 2 as published by the
+ Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for complete details.
+
+ The author respectfully requests that any modifications to this software be
+ sent directly to him for evaluation and testing.
+
+*/
+
+
+#define DAC960_DriverVersion "2.0.0 Beta3"
+#define DAC960_DriverDate "29 November 1998"
+
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ioport.h>
+#include <linux/locks.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/timer.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/segment.h>
+#include "DAC960.h"
+
+
+/*
+ DAC960_ControllerCount is the number of DAC960 Controllers.
+*/
+
+static int
+ DAC960_ControllerCount = 0;
+
+
+/*
+ DAC960_Controllers is an array of pointers to the DAC960 Controller
+ structures.
+*/
+
+static DAC960_Controller_T
+ *DAC960_Controllers[DAC960_MaxControllers] = { NULL };
+
+
+/*
+ DAC960_FileOperations is the File Operations structure for DAC960 Logical
+ Disk Devices.
+*/
+
+static FileOperations_T
+ DAC960_FileOperations =
+ { lseek: NULL,
+ read: block_read,
+ write: block_write,
+ readdir: NULL,
+ select: NULL,
+ ioctl: DAC960_Ioctl,
+ mmap: NULL,
+ open: DAC960_Open,
+ release: DAC960_Release,
+ fsync: block_fsync,
+ fasync: NULL,
+ check_media_change: NULL,
+ revalidate: NULL };
+
+
+/*
+ DAC960_AnnounceDriver announces the Driver Version and Date, Author's Name,
+ Copyright Notice, and Electronic Mail Address.
+*/
+
+static void DAC960_AnnounceDriver(DAC960_Controller_T *Controller)
+{
+ DAC960_Announce("***** DAC960 RAID Driver Version "
+ DAC960_DriverVersion " of "
+ DAC960_DriverDate " *****\n", Controller);
+ DAC960_Announce("Copyright 1998 by Leonard N. Zubkoff "
+ "<lnz@dandelion.com>\n", Controller);
+}
+
+
+/*
+ DAC960_Failure prints a standardized error message, and then returns false.
+*/
+
+static boolean DAC960_Failure(DAC960_Controller_T *Controller,
+ char *ErrorMessage)
+{
+ DAC960_Error("While configuring DAC960 PCI RAID Controller at\n",
+ Controller);
+ if (Controller->IO_Address == 0)
+ DAC960_Error("PCI Bus %d Device %d Function %d I/O Address N/A "
+ "PCI Address 0x%X\n", Controller,
+ Controller->Bus, Controller->Device,
+ Controller->Function, Controller->PCI_Address);
+ else DAC960_Error("PCI Bus %d Device %d Function %d I/O Address "
+ "0x%X PCI Address 0x%X\n", Controller,
+ Controller->Bus, Controller->Device,
+ Controller->Function, Controller->IO_Address,
+ Controller->PCI_Address);
+ DAC960_Error("%s FAILED - DETACHING\n", Controller, ErrorMessage);
+ return false;
+}
+
+
+/*
+ DAC960_ClearCommand clears critical fields of Command.
+*/
+
+static inline void DAC960_ClearCommand(DAC960_Command_T *Command)
+{
+ DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
+ CommandMailbox->Words[0] = 0;
+ CommandMailbox->Words[1] = 0;
+ CommandMailbox->Words[2] = 0;
+ CommandMailbox->Words[3] = 0;
+ Command->CommandStatus = 0;
+}
+
+
+/*
+ DAC960_AllocateCommand allocates a Command structure from Controller's
+ free list.
+*/
+
+static inline DAC960_Command_T *DAC960_AllocateCommand(DAC960_Controller_T
+ *Controller)
+{
+ DAC960_Command_T *Command = Controller->FreeCommands;
+ if (Command == NULL) return NULL;
+ Controller->FreeCommands = Command->Next;
+ Command->Next = NULL;
+ return Command;
+}
+
+
+/*
+ DAC960_DeallocateCommand deallocates Command, returning it to Controller's
+ free list.
+*/
+
+static inline void DAC960_DeallocateCommand(DAC960_Command_T *Command)
+{
+ DAC960_Controller_T *Controller = Command->Controller;
+ Command->Next = Controller->FreeCommands;
+ Controller->FreeCommands = Command;
+}
+
+
+/*
+ DAC960_QueueCommand queues Command.
+*/
+
+static void DAC960_QueueCommand(DAC960_Command_T *Command)
+{
+ DAC960_Controller_T *Controller = Command->Controller;
+ void *ControllerBaseAddress = Controller->BaseAddress;
+ DAC960_V4_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
+ DAC960_V4_CommandMailbox_T *NextCommandMailbox;
+ CommandMailbox->Common.CommandIdentifier = Command - Controller->Commands;
+ switch (Controller->ControllerType)
+ {
+ case DAC960_V4_Controller:
+ NextCommandMailbox = Controller->NextCommandMailbox;
+ DAC960_V4_WriteCommandMailbox(NextCommandMailbox, CommandMailbox);
+ if (Controller->PreviousCommandMailbox->Words[0] == 0)
+ DAC960_V4_NewCommand(ControllerBaseAddress);
+ Controller->PreviousCommandMailbox = NextCommandMailbox;
+ if (++NextCommandMailbox > Controller->LastCommandMailbox)
+ NextCommandMailbox = Controller->FirstCommandMailbox;
+ Controller->NextCommandMailbox = NextCommandMailbox;
+ break;
+ case DAC960_V3_Controller:
+ while (DAC960_V3_MailboxFullP(ControllerBaseAddress))
+ udelay(1);
+ DAC960_V3_WriteCommandMailbox(ControllerBaseAddress, CommandMailbox);
+ DAC960_V3_NewCommand(ControllerBaseAddress);
+ break;
+ }
+}
+
+
+/*
+ DAC960_ExecuteCommand executes Command and waits for completion. It
+ returns true on success and false on failure.
+*/
+
+static boolean DAC960_ExecuteCommand(DAC960_Command_T *Command)
+{
+ Semaphore_T Semaphore = MUTEX_LOCKED;
+ Command->Semaphore = &Semaphore;
+ DAC960_QueueCommand(Command);
+ down(&Semaphore);
+ return Command->CommandStatus == DAC960_NormalCompletion;
+}
+
+
+/*
+ DAC960_ExecuteType3 executes a DAC960 Type 3 Command and waits for
+ completion. It returns true on success and false on failure.
+*/
+
+static boolean DAC960_ExecuteType3(DAC960_Controller_T *Controller,
+ DAC960_CommandOpcode_T CommandOpcode,
+ void *DataPointer)
+{
+ DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
+ DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
+ boolean Result;
+ DAC960_ClearCommand(Command);
+ Command->CommandType = DAC960_ImmediateCommand;
+ CommandMailbox->Type3.CommandOpcode = CommandOpcode;
+ CommandMailbox->Type3.BusAddress = Virtual_to_Bus(DataPointer);
+ Result = DAC960_ExecuteCommand(Command);
+ DAC960_DeallocateCommand(Command);
+ return Result;
+}
+
+
+/*
+ DAC960_ExecuteType3D executes a DAC960 Type 3D Command and waits for
+ completion. It returns true on success and false on failure.
+*/
+
+static boolean DAC960_ExecuteType3D(DAC960_Controller_T *Controller,
+ DAC960_CommandOpcode_T CommandOpcode,
+ unsigned char Channel,
+ unsigned char TargetID,
+ void *DataPointer)
+{
+ DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
+ DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
+ boolean Result;
+ DAC960_ClearCommand(Command);
+ Command->CommandType = DAC960_ImmediateCommand;
+ CommandMailbox->Type3D.CommandOpcode = CommandOpcode;
+ CommandMailbox->Type3D.Channel = Channel;
+ CommandMailbox->Type3D.TargetID = TargetID;
+ CommandMailbox->Type3D.BusAddress = Virtual_to_Bus(DataPointer);
+ Result = DAC960_ExecuteCommand(Command);
+ DAC960_DeallocateCommand(Command);
+ return Result;
+}
+
+
+/*
+ DAC960_V4_EnableMemoryMailboxInterface enables the V4 Memory Mailbox
+ Interface.
+*/
+
+static boolean DAC960_V4_EnableMemoryMailboxInterface(DAC960_Controller_T
+ *Controller)
+{
+ void *ControllerBaseAddress = Controller->BaseAddress;
+ DAC960_V4_CommandMailbox_T *CommandMailboxesMemory;
+ DAC960_V4_StatusMailbox_T *StatusMailboxesMemory;
+ DAC960_CommandMailbox_T CommandMailbox;
+ DAC960_CommandStatus_T CommandStatus;
+ CommandMailboxesMemory =
+ (DAC960_V4_CommandMailbox_T *) __get_free_pages(GFP_KERNEL, 1, 0);
+ memset(CommandMailboxesMemory, 0, PAGE_SIZE << 1);
+ Controller->FirstCommandMailbox = CommandMailboxesMemory;
+ CommandMailboxesMemory += DAC960_CommandMailboxCount - 1;
+ Controller->LastCommandMailbox = CommandMailboxesMemory;
+ Controller->NextCommandMailbox = Controller->FirstCommandMailbox;
+ Controller->PreviousCommandMailbox = Controller->LastCommandMailbox;
+ StatusMailboxesMemory =
+ (DAC960_V4_StatusMailbox_T *) (CommandMailboxesMemory + 1);
+ Controller->FirstStatusMailbox = StatusMailboxesMemory;
+ StatusMailboxesMemory += DAC960_StatusMailboxCount - 1;
+ Controller->LastStatusMailbox = StatusMailboxesMemory;
+ Controller->NextStatusMailbox = Controller->FirstStatusMailbox;
+ /* Enable the Memory Mailbox Interface. */
+ CommandMailbox.TypeX.CommandOpcode = 0x2B;
+ CommandMailbox.TypeX.CommandIdentifier = 0;
+ CommandMailbox.TypeX.CommandOpcode2 = 0x10;
+ CommandMailbox.TypeX.CommandMailboxesBusAddress =
+ Virtual_to_Bus(Controller->FirstCommandMailbox);
+ CommandMailbox.TypeX.StatusMailboxesBusAddress =
+ Virtual_to_Bus(Controller->FirstStatusMailbox);
+ while (DAC960_V4_MailboxFullP(ControllerBaseAddress))
+ udelay(1);
+ DAC960_V4_WriteLegacyCommand(ControllerBaseAddress, &CommandMailbox);
+ DAC960_V4_NewCommand(ControllerBaseAddress);
+ while (!DAC960_V4_StatusAvailableP(ControllerBaseAddress))
+ udelay(1);
+ CommandStatus = DAC960_V4_ReadStatusRegister(ControllerBaseAddress);
+ DAC960_V4_AcknowledgeInterrupt(ControllerBaseAddress);
+ DAC960_V4_AcknowledgeStatus(ControllerBaseAddress);
+ return CommandStatus == DAC960_NormalCompletion;
+}
+
+
+/*
+ DAC960_DetectControllers detects DAC960 PCI RAID Controllers by interrogating
+ the PCI Configuration Space for DeviceID.
+*/
+
+static void DAC960_DetectControllers(unsigned short DeviceID)
+{
+ unsigned char Bus, DeviceFunction, IRQ_Channel;
+ unsigned int BaseAddress0, BaseAddress1;
+ unsigned int MemoryWindowSize = 0;
+ unsigned short Index = 0;
+ while (pcibios_find_device(PCI_VENDOR_ID_MYLEX, DeviceID,
+ Index++, &Bus, &DeviceFunction) == 0)
+ {
+ DAC960_Controller_T *Controller = (DAC960_Controller_T *)
+ kmalloc(sizeof(DAC960_Controller_T), GFP_ATOMIC);
+ DAC960_ControllerType_T ControllerType = 0;
+ DAC960_IO_Address_T IO_Address = 0;
+ DAC960_PCI_Address_T PCI_Address = 0;
+ unsigned char Device = DeviceFunction >> 3;
+ unsigned char Function = DeviceFunction & 0x7;
+ pcibios_read_config_dword(Bus, DeviceFunction,
+ PCI_BASE_ADDRESS_0, &BaseAddress0);
+ pcibios_read_config_dword(Bus, DeviceFunction,
+ PCI_BASE_ADDRESS_1, &BaseAddress1);
+ pcibios_read_config_byte(Bus, DeviceFunction,
+ PCI_INTERRUPT_LINE, &IRQ_Channel);
+ switch (DeviceID)
+ {
+ case PCI_DEVICE_ID_MYLEX_DAC960P_V4:
+ ControllerType = DAC960_V4_Controller;
+ PCI_Address = BaseAddress0 & PCI_BASE_ADDRESS_MEM_MASK;
+ MemoryWindowSize = DAC960_V4_RegisterWindowSize;
+ break;
+ case PCI_DEVICE_ID_MYLEX_DAC960P_V3:
+ ControllerType = DAC960_V3_Controller;
+ IO_Address = BaseAddress0 & PCI_BASE_ADDRESS_IO_MASK;
+ PCI_Address = BaseAddress1 & PCI_BASE_ADDRESS_MEM_MASK;
+ MemoryWindowSize = DAC960_V3_RegisterWindowSize;
+ break;
+ }
+ if (DAC960_ControllerCount == DAC960_MaxControllers)
+ {
+ DAC960_Error("More than %d DAC960 Controllers detected - "
+ "ignoring from Controller at\n",
+ NULL, DAC960_MaxControllers);
+ goto Failure;
+ }
+ if (Controller == NULL)
+ {
+ DAC960_Error("Unable to allocate Controller structure for "
+ "Controller at\n", NULL);
+ goto Failure;
+ }
+ memset(Controller, 0, sizeof(DAC960_Controller_T));
+ Controller->ControllerNumber = DAC960_ControllerCount;
+ DAC960_Controllers[DAC960_ControllerCount++] = Controller;
+ if (IRQ_Channel == 0 || IRQ_Channel >= NR_IRQS)
+ {
+ DAC960_Error("IRQ Channel %d illegal for Controller at\n",
+ NULL, IRQ_Channel);
+ goto Failure;
+ }
+ Controller->ControllerType = ControllerType;
+ Controller->IO_Address = IO_Address;
+ Controller->PCI_Address = PCI_Address;
+ Controller->Bus = Bus;
+ Controller->Device = Device;
+ Controller->Function = Function;
+ /*
+ Acquire shared access to the IRQ Channel.
+ */
+ strcpy(Controller->FullModelName, "DAC960");
+ if (request_irq(IRQ_Channel, DAC960_InterruptHandler,
+ SA_INTERRUPT | SA_SHIRQ, Controller->FullModelName,
+ Controller) < 0)
+ {
+ DAC960_Error("Unable to acquire IRQ Channel %d for Controller at\n",
+ NULL, IRQ_Channel);
+ goto Failure;
+ }
+ Controller->IRQ_Channel = IRQ_Channel;
+ /*
+ Map the Controller Register Window.
+ */
+ if (MemoryWindowSize < PAGE_SIZE)
+ MemoryWindowSize = PAGE_SIZE;
+ Controller->MemoryMappedAddress =
+ ioremap_nocache(PCI_Address & PAGE_MASK, MemoryWindowSize);
+ Controller->BaseAddress =
+ Controller->MemoryMappedAddress + (PCI_Address & ~PAGE_MASK);
+ if (Controller->MemoryMappedAddress == NULL)
+ {
+ DAC960_Error("Unable to map Controller Register Window for "
+ "Controller at\n", NULL);
+ goto Failure;
+ }
+ switch (DeviceID)
+ {
+ case PCI_DEVICE_ID_MYLEX_DAC960P_V4:
+ DAC960_V4_DisableInterrupts(Controller->BaseAddress);
+ if (!DAC960_V4_EnableMemoryMailboxInterface(Controller))
+ {
+ DAC960_Error("Unable to Enable V4 Memory Mailbox Interface "
+ "for Controller at\n", NULL);
+ goto Failure;
+ }
+ DAC960_V4_EnableInterrupts(Controller->BaseAddress);
+ break;
+ case PCI_DEVICE_ID_MYLEX_DAC960P_V3:
+ request_region(Controller->IO_Address, 0x80,
+ Controller->FullModelName);
+ DAC960_V3_EnableInterrupts(Controller->BaseAddress);
+ break;
+ }
+ Controller->Commands[0].Controller = Controller;
+ Controller->Commands[0].Next = NULL;
+ Controller->FreeCommands = &Controller->Commands[0];
+ continue;
+ Failure:
+ if (IO_Address == 0)
+ DAC960_Error("PCI Bus %d Device %d Function %d I/O Address N/A "
+ "PCI Address 0x%X\n", NULL,
+ Bus, Device, Function, PCI_Address);
+ else DAC960_Error("PCI Bus %d Device %d Function %d I/O Address "
+ "0x%X PCI Address 0x%X\n", NULL,
+ Bus, Device, Function, IO_Address, PCI_Address);
+ if (Controller == NULL) break;
+ if (Controller->IRQ_Channel > 0)
+ free_irq(IRQ_Channel, Controller);
+ if (Controller->MemoryMappedAddress != NULL)
+ iounmap(Controller->MemoryMappedAddress);
+ kfree(Controller);
+ break;
+ }
+}
+
+
+/*
+ DAC960_ReadControllerConfiguration reads the Configuration Information
+ from Controller and initializes the Controller structure.
+*/
+
+static boolean DAC960_ReadControllerConfiguration(DAC960_Controller_T
+ *Controller)
+{
+ DAC960_Enquiry2_T Enquiry2;
+ DAC960_Config2_T Config2;
+ int Channel, TargetID;
+ if (!DAC960_ExecuteType3(Controller, DAC960_Enquiry,
+ &Controller->Enquiry[0]))
+ return DAC960_Failure(Controller, "ENQUIRY");
+ if (!DAC960_ExecuteType3(Controller, DAC960_Enquiry2, &Enquiry2))
+ return DAC960_Failure(Controller, "ENQUIRY2");
+ if (!DAC960_ExecuteType3(Controller, DAC960_ReadConfig2, &Config2))
+ return DAC960_Failure(Controller, "READ CONFIG2");
+ if (!DAC960_ExecuteType3(Controller, DAC960_GetLogicalDriveInformation,
+ &Controller->LogicalDriveInformation[0]))
+ return DAC960_Failure(Controller, "GET LOGICAL DRIVE INFORMATION");
+ for (Channel = 0; Channel < Enquiry2.ActualChannels; Channel++)
+ for (TargetID = 0; TargetID < DAC960_MaxTargets; TargetID++)
+ if (!DAC960_ExecuteType3D(Controller, DAC960_GetDeviceState,
+ Channel, TargetID,
+ &Controller->DeviceState[0][Channel][TargetID]))
+ return DAC960_Failure(Controller, "GET DEVICE STATE");
+ /*
+ Initialize the Controller Model Name and Full Model Name fields.
+ */
+ switch (Enquiry2.HardwareID.SubModel)
+ {
+ case DAC960_P_PD_PU:
+ if (Enquiry2.SCSICapability.BusSpeed == DAC960_Ultra)
+ strcpy(Controller->ModelName, "DAC960PU");
+ else strcpy(Controller->ModelName, "DAC960PD");
+ break;
+ case DAC960_PL:
+ strcpy(Controller->ModelName, "DAC960PL");
+ break;
+ case DAC960_PG:
+ strcpy(Controller->ModelName, "DAC960PG");
+ break;
+ case DAC960_PJ:
+ strcpy(Controller->ModelName, "DAC960PJ");
+ break;
+ case DAC960_PTL_0:
+ strcpy(Controller->ModelName, "DAC960PTL-0");
+ break;
+ case DAC960_PTL_1:
+ strcpy(Controller->ModelName, "DAC960PTL-1");
+ break;
+ default:
+ return DAC960_Failure(Controller, "MODEL VERIFICATION");
+ }
+ strcpy(Controller->FullModelName, "Mylex ");
+ strcat(Controller->FullModelName, Controller->ModelName);
+ /*
+ Initialize the Controller Firmware Version field and verify that it
+ is a supported firmware version. The supported firmware versions are:
+
+ DAC960PTL/PJ/PG 4.06 and above
+ DAC960PU/PD/PL 3.51 and above
+ */
+ sprintf(Controller->FirmwareVersion, "%d.%02d-%c-%02d",
+ Enquiry2.FirmwareID.MajorVersion, Enquiry2.FirmwareID.MinorVersion,
+ Enquiry2.FirmwareID.FirmwareType, Enquiry2.FirmwareID.TurnID);
+ if (!((Controller->FirmwareVersion[0] == '4' &&
+ strcmp(Controller->FirmwareVersion, "4.06") >= 0) ||
+ (Controller->FirmwareVersion[0] == '3' &&
+ strcmp(Controller->FirmwareVersion, "3.51") >= 0)))
+ {
+ DAC960_Failure(Controller, "FIRMWARE VERSION VERIFICATION");
+ DAC960_Error("Firmware Version = '%s'\n", Controller,
+ Controller->FirmwareVersion);
+ return false;
+ }
+ /*
+ Initialize the Controller Channels, Memory Size, and SAF-TE Fault
+ Management Enabled fields.
+ */
+ Controller->Channels = Enquiry2.ActualChannels;
+ Controller->MemorySize = Enquiry2.MemorySize >> 20;
+ Controller->SAFTE_FaultManagementEnabled =
+ Enquiry2.FaultManagementType == DAC960_SAFTE;
+ /*
+ Initialize the Controller Queue Depth, Driver Queue Depth, Logical Drive
+ Count, Maximum Blocks per Command, and Maximum Scatter/Gather Segments.
+ The Driver Queue Depth must be at most one less than the Controller Queue
+ Depth to allow for an automatic drive rebuild operation.
+ */
+ Controller->ControllerQueueDepth = Controller->Enquiry[0].MaxCommands;
+ Controller->DriverQueueDepth = Controller->ControllerQueueDepth - 1;
+ Controller->LogicalDriveCount = Controller->Enquiry[0].NumberOfLogicalDrives;
+ Controller->MaxBlocksPerCommand = Enquiry2.MaxBlocksPerCommand;
+ Controller->MaxScatterGatherSegments = Enquiry2.MaxScatterGatherEntries;
+ /*
+ Initialize the Stripe Size, Segment Size, and Geometry Translation.
+ */
+ Controller->StripeSize = Config2.BlocksPerStripe * Config2.BlockFactor
+ >> (10 - DAC960_BlockSizeBits);
+ Controller->SegmentSize = Config2.BlocksPerCacheLine * Config2.BlockFactor
+ >> (10 - DAC960_BlockSizeBits);
+ switch (Config2.DriveGeometry)
+ {
+ case DAC960_Geometry_128_32:
+ Controller->GeometryTranslationHeads = 128;
+ Controller->GeometryTranslationSectors = 32;
+ break;
+ case DAC960_Geometry_255_63:
+ Controller->GeometryTranslationHeads = 255;
+ Controller->GeometryTranslationSectors = 63;
+ break;
+ default:
+ return DAC960_Failure(Controller, "CONFIG2 DRIVE GEOMETRY");
+ }
+ return true;
+}
+
+
+/*
+ DAC960_ReportControllerConfiguration reports the configuration of
+ Controller.
+*/
+
+static boolean DAC960_ReportControllerConfiguration(DAC960_Controller_T
+ *Controller)
+{
+ int LogicalDriveNumber, Channel, TargetID;
+ DAC960_Info("Configuring Mylex %s PCI RAID Controller\n",
+ Controller, Controller->ModelName);
+ DAC960_Info(" Firmware Version: %s, Channels: %d, Memory Size: %dMB\n",
+ Controller, Controller->FirmwareVersion,
+ Controller->Channels, Controller->MemorySize);
+ DAC960_Info(" PCI Bus: %d, Device: %d, Function: %d, I/O Address: ",
+ Controller, Controller->Bus,
+ Controller->Device, Controller->Function);
+ if (Controller->IO_Address == 0)
+ DAC960_Info("Unassigned\n", Controller);
+ else DAC960_Info("0x%X\n", Controller, Controller->IO_Address);
+ DAC960_Info(" PCI Address: 0x%X mapped at 0x%lX, IRQ Channel: %d\n",
+ Controller, Controller->PCI_Address,
+ (unsigned long) Controller->BaseAddress,
+ Controller->IRQ_Channel);
+ DAC960_Info(" Controller Queue Depth: %d, "
+ "Maximum Blocks per Command: %d\n",
+ Controller, Controller->ControllerQueueDepth,
+ Controller->MaxBlocksPerCommand);
+ DAC960_Info(" Driver Queue Depth: %d, "
+ "Maximum Scatter/Gather Segments: %d\n",
+ Controller, Controller->DriverQueueDepth,
+ Controller->MaxScatterGatherSegments);
+ DAC960_Info(" Stripe Size: %dKB, Segment Size: %dKB, "
+ "BIOS Geometry: %d/%d\n", Controller,
+ Controller->StripeSize,
+ Controller->SegmentSize,
+ Controller->GeometryTranslationHeads,
+ Controller->GeometryTranslationSectors);
+ if (Controller->SAFTE_FaultManagementEnabled)
+ DAC960_Info(" SAF-TE Fault Management Enabled\n", Controller);
+ DAC960_Info(" Physical Devices:\n", Controller);
+ for (Channel = 0; Channel < Controller->Channels; Channel++)
+ for (TargetID = 0; TargetID < DAC960_MaxTargets; TargetID++)
+ {
+ DAC960_DeviceState_T *DeviceState =
+ &Controller->DeviceState[0][Channel][TargetID];
+ if (!DeviceState->Present) continue;
+ switch (DeviceState->DeviceType)
+ {
+ case DAC960_OtherType:
+ DAC960_Info(" %d:%d - Other\n", Controller, Channel, TargetID);
+ break;
+ case DAC960_DiskType:
+ DAC960_Info(" %d:%d - Disk: %s, %d blocks\n", Controller,
+ Channel, TargetID,
+ (DeviceState->DeviceState == DAC960_Device_Dead
+ ? "Dead"
+ : DeviceState->DeviceState == DAC960_Device_WriteOnly
+ ? "Write-Only"
+ : DeviceState->DeviceState == DAC960_Device_Online
+ ? "Online" : "Standby"),
+ DeviceState->DiskSize);
+ break;
+ case DAC960_SequentialType:
+ DAC960_Info(" %d:%d - Sequential\n", Controller,
+ Channel, TargetID);
+ break;
+ case DAC960_CDROM_or_WORM_Type:
+ DAC960_Info(" %d:%d - CD-ROM or WORM\n", Controller,
+ Channel, TargetID);
+ break;
+ }
+
+ }
+ DAC960_Info(" Logical Drives:\n", Controller);
+ for (LogicalDriveNumber = 0;
+ LogicalDriveNumber < Controller->LogicalDriveCount;
+ LogicalDriveNumber++)
+ {
+ DAC960_LogicalDriveInformation_T *LogicalDriveInformation =
+ &Controller->LogicalDriveInformation[0][LogicalDriveNumber];
+ DAC960_Info(" /dev/rd/c%dd%d: RAID-%d, %s, %d blocks, %s\n",
+ Controller, Controller->ControllerNumber, LogicalDriveNumber,
+ LogicalDriveInformation->RAIDLevel,
+ (LogicalDriveInformation->LogicalDriveState ==
+ DAC960_LogicalDrive_Online
+ ? "Online"
+ : LogicalDriveInformation->LogicalDriveState ==
+ DAC960_LogicalDrive_Critical
+ ? "Critical" : "Offline"),
+ LogicalDriveInformation->LogicalDriveSize,
+ (LogicalDriveInformation->WriteBack
+ ? "Write Back" : "Write Thru"));
+ }
+ DAC960_Info("\n", Controller);
+ return true;
+}
+
+
+/*
+ DAC960_RegisterBlockDevice registers the Block Device structures
+ associated with Controller.
+*/
+
+static boolean DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller)
+{
+ static void (*RequestFunctions[DAC960_MaxControllers])(void) =
+ { DAC960_RequestFunction0, DAC960_RequestFunction1,
+ DAC960_RequestFunction2, DAC960_RequestFunction3,
+ DAC960_RequestFunction4, DAC960_RequestFunction5,
+ DAC960_RequestFunction6, DAC960_RequestFunction7 };
+ int MajorNumber = DAC960_MAJOR + Controller->ControllerNumber;
+ GenericDiskInfo_T *GenericDiskInfo;
+ int MinorNumber;
+ /*
+ Register the Block Device Major Number for this DAC960 Controller.
+ */
+ if (register_blkdev(MajorNumber, "rd", &DAC960_FileOperations) < 0)
+ {
+ DAC960_Error("UNABLE TO ACQUIRE MAJOR NUMBER %d - DETACHING\n",
+ Controller, MajorNumber);
+ return false;
+ }
+ /*
+ Initialize the I/O Request Function.
+ */
+ blk_dev[MajorNumber].request_fn =
+ RequestFunctions[Controller->ControllerNumber];
+ /*
+ Initialize the Disk Partitions array, Partition Sizes array, Block Sizes
+ array, Max Sectors per Request array, and Max Segments per Request array.
+ */
+ for (MinorNumber = 0; MinorNumber < DAC960_MinorCount; MinorNumber++)
+ {
+ Controller->BlockSizes[MinorNumber] = BLOCK_SIZE;
+ Controller->MaxSectorsPerRequest[MinorNumber] =
+ Controller->MaxBlocksPerCommand;
+ Controller->MaxSegmentsPerRequest[MinorNumber] =
+ Controller->MaxScatterGatherSegments;
+ }
+ Controller->GenericDiskInfo.part = Controller->DiskPartitions;
+ Controller->GenericDiskInfo.sizes = Controller->PartitionSizes;
+ blksize_size[MajorNumber] = Controller->BlockSizes;
+ max_sectors[MajorNumber] = Controller->MaxSectorsPerRequest;
+ max_segments[MajorNumber] = Controller->MaxSegmentsPerRequest;
+ /*
+ Initialize Read Ahead to 128 sectors.
+ */
+ read_ahead[MajorNumber] = 128;
+ /*
+ Complete initialization of the Generic Disk Information structure.
+ */
+ Controller->GenericDiskInfo.major = MajorNumber;
+ Controller->GenericDiskInfo.major_name = "rd";
+ Controller->GenericDiskInfo.minor_shift = DAC960_MaxPartitionsBits;
+ Controller->GenericDiskInfo.max_p = DAC960_MaxPartitions;
+ Controller->GenericDiskInfo.max_nr = DAC960_MaxLogicalDrives;
+ Controller->GenericDiskInfo.init = DAC960_InitializeGenericDiskInfo;
+ Controller->GenericDiskInfo.nr_real = Controller->LogicalDriveCount;
+ Controller->GenericDiskInfo.real_devices = Controller;
+ Controller->GenericDiskInfo.next = NULL;
+ /*
+ Install the Generic Disk Information structure at the end of the list.
+ */
+ if ((GenericDiskInfo = gendisk_head) != NULL)
+ {
+ while (GenericDiskInfo->next != NULL)
+ GenericDiskInfo = GenericDiskInfo->next;
+ GenericDiskInfo->next = &Controller->GenericDiskInfo;
+ }
+ else gendisk_head = &Controller->GenericDiskInfo;
+ /*
+ Indicate the Block Device Registration completed successfully,
+ */
+ return true;
+}
+
+
+/*
+ DAC960_UnregisterBlockDevice unregisters the Block Device structures
+ associated with Controller.
+*/
+
+static void DAC960_UnregisterBlockDevice(DAC960_Controller_T *Controller)
+{
+ int MajorNumber = DAC960_MAJOR + Controller->ControllerNumber;
+ /*
+ Unregister the Block Device Major Number for this DAC960 Controller.
+ */
+ unregister_blkdev(MajorNumber, "rd");
+ /*
+ Remove the I/O Request Function.
+ */
+ blk_dev[MajorNumber].request_fn = NULL;
+ /*
+ Remove the Disk Partitions array, Partition Sizes array, Block Sizes
+ array, Max Sectors per Request array, and Max Segments per Request array.
+ */
+ Controller->GenericDiskInfo.part = NULL;
+ Controller->GenericDiskInfo.sizes = NULL;
+ blk_size[MajorNumber] = NULL;
+ blksize_size[MajorNumber] = NULL;
+ max_sectors[MajorNumber] = NULL;
+ max_segments[MajorNumber] = NULL;
+ /*
+ Remove the Generic Disk Information structure from the list.
+ */
+ if (gendisk_head != &Controller->GenericDiskInfo)
+ {
+ GenericDiskInfo_T *GenericDiskInfo = gendisk_head;
+ while (GenericDiskInfo != NULL &&
+ GenericDiskInfo->next != &Controller->GenericDiskInfo)
+ GenericDiskInfo = GenericDiskInfo->next;
+ if (GenericDiskInfo != NULL)
+ GenericDiskInfo->next = GenericDiskInfo->next->next;
+ }
+ else gendisk_head = Controller->GenericDiskInfo.next;
+}
+
+
+/*
+ DAC960_InitializeController initializes Controller.
+*/
+
+static void DAC960_InitializeController(DAC960_Controller_T *Controller)
+{
+ DAC960_AnnounceDriver(Controller);
+ if (DAC960_ReadControllerConfiguration(Controller) &&
+ DAC960_ReportControllerConfiguration(Controller) &&
+ DAC960_RegisterBlockDevice(Controller))
+ {
+ /*
+ Initialize the Command structures.
+ */
+ DAC960_Command_T *Commands = Controller->Commands;
+ int CommandIdentifier;
+ Controller->FreeCommands = NULL;
+ for (CommandIdentifier = 0;
+ CommandIdentifier < Controller->DriverQueueDepth;
+ CommandIdentifier++)
+ {
+ Commands[CommandIdentifier].Controller = Controller;
+ Commands[CommandIdentifier].Next = Controller->FreeCommands;
+ Controller->FreeCommands = &Commands[CommandIdentifier];
+ }
+ /*
+ Initialize the Monitoring Timer.
+ */
+ init_timer(&Controller->MonitoringTimer);
+ Controller->MonitoringTimer.expires =
+ jiffies + DAC960_MonitoringTimerInterval;
+ Controller->MonitoringTimer.data = (unsigned long) Controller;
+ Controller->MonitoringTimer.function = DAC960_MonitoringTimerFunction;
+ add_timer(&Controller->MonitoringTimer);
+ }
+ else
+ {
+ free_irq(Controller->IRQ_Channel, Controller);
+ iounmap(Controller->MemoryMappedAddress);
+ DAC960_UnregisterBlockDevice(Controller);
+ DAC960_Controllers[Controller->ControllerNumber] = NULL;
+ kfree(Controller);
+ }
+}
+
+
+/*
+ DAC960_Initialize initializes the DAC960 Driver.
+*/
+
+void DAC960_Initialize(void)
+{
+ int ControllerNumber;
+ DAC960_DetectControllers(PCI_DEVICE_ID_MYLEX_DAC960P_V4);
+ DAC960_DetectControllers(PCI_DEVICE_ID_MYLEX_DAC960P_V3);
+ for (ControllerNumber = 0;
+ ControllerNumber < DAC960_ControllerCount;
+ ControllerNumber++)
+ if (DAC960_Controllers[ControllerNumber] != NULL)
+ DAC960_InitializeController(DAC960_Controllers[ControllerNumber]);
+}
+
+
+/*
+ DAC960_Finalize flushes all DAC960 caches before the system halts.
+*/
+
+void DAC960_Finalize(void)
+{
+ int ControllerNumber;
+ for (ControllerNumber = 0;
+ ControllerNumber < DAC960_ControllerCount;
+ ControllerNumber++)
+ {
+ DAC960_Controller_T *Controller = DAC960_Controllers[ControllerNumber];
+ if (Controller == NULL) continue;
+ DAC960_Notice("Flushing Cache...", Controller);
+ DAC960_ExecuteType3(Controller, DAC960_Flush, NULL);
+ DAC960_Notice("done\n", Controller);
+ }
+}
+
+
+/*
+ DAC960_ProcessRequest attempts to remove one I/O Request from Controller's
+ I/O Request Queue and queues it to the Controller. Command is either a
+ previously allocated Command to be reused, or NULL if a new Command is to
+ be allocated for this I/O Request. It returns true if an I/O Request was
+ queued and false otherwise.
+*/
+
+static boolean DAC960_ProcessRequest(DAC960_Controller_T *Controller,
+ DAC960_Command_T *Command)
+{
+ int MajorNumber = DAC960_MAJOR + Controller->ControllerNumber;
+ IO_Request_T *Request = blk_dev[MajorNumber].current_request;
+ DAC960_CommandMailbox_T *CommandMailbox;
+ char *RequestBuffer;
+ if (Request == NULL || Request->rq_status == RQ_INACTIVE) return false;
+ if (Command == NULL)
+ Command = DAC960_AllocateCommand(Controller);
+ if (Command == NULL) return false;
+ DAC960_ClearCommand(Command);
+ if (Request->cmd == READ)
+ Command->CommandType = DAC960_ReadCommand;
+ else Command->CommandType = DAC960_WriteCommand;
+ Command->Semaphore = Request->sem;
+ Command->LogicalDriveNumber = DAC960_LogicalDriveNumber(Request->rq_dev);
+ Command->BlockNumber =
+ Request->sector
+ + Controller->GenericDiskInfo.part[MINOR(Request->rq_dev)].start_sect;
+ Command->BlockCount = Request->nr_sectors;
+ Command->SegmentCount = Request->nr_segments;
+ Command->BufferHeader = Request->bh;
+ RequestBuffer = Request->buffer;
+ Request->rq_status = RQ_INACTIVE;
+ blk_dev[MajorNumber].current_request = Request->next;
+ wake_up(&wait_for_request);
+ CommandMailbox = &Command->CommandMailbox;
+ if (Command->SegmentCount == 1)
+ {
+ if (Command->CommandType == DAC960_ReadCommand)
+ CommandMailbox->Type5.CommandOpcode = DAC960_Read;
+ else CommandMailbox->Type5.CommandOpcode = DAC960_Write;
+ CommandMailbox->Type5.LD.TransferLength = Command->BlockCount;
+ CommandMailbox->Type5.LD.LogicalDriveNumber = Command->LogicalDriveNumber;
+ CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber;
+ CommandMailbox->Type5.BusAddress = Virtual_to_Bus(RequestBuffer);
+ }
+ else
+ {
+ DAC960_ScatterGatherSegment_T
+ *ScatterGatherList = Command->ScatterGatherList;
+ BufferHeader_T *BufferHeader = Command->BufferHeader;
+ char *LastDataEndPointer = NULL;
+ int SegmentNumber = 0;
+ if (Command->CommandType == DAC960_ReadCommand)
+ CommandMailbox->Type5.CommandOpcode = DAC960_ReadWithOldScatterGather;
+ else
+ CommandMailbox->Type5.CommandOpcode = DAC960_WriteWithOldScatterGather;
+ CommandMailbox->Type5.LD.TransferLength = Command->BlockCount;
+ CommandMailbox->Type5.LD.LogicalDriveNumber = Command->LogicalDriveNumber;
+ CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber;
+ CommandMailbox->Type5.BusAddress = Virtual_to_Bus(ScatterGatherList);
+ CommandMailbox->Type5.ScatterGatherCount = Command->SegmentCount;
+ while (BufferHeader != NULL)
+ {
+ if (BufferHeader->b_data == LastDataEndPointer)
+ {
+ ScatterGatherList[SegmentNumber-1].SegmentByteCount +=
+ BufferHeader->b_size;
+ LastDataEndPointer += BufferHeader->b_size;
+ }
+ else
+ {
+ ScatterGatherList[SegmentNumber].SegmentDataPointer =
+ Virtual_to_Bus(BufferHeader->b_data);
+ ScatterGatherList[SegmentNumber].SegmentByteCount =
+ BufferHeader->b_size;
+ LastDataEndPointer = BufferHeader->b_data + BufferHeader->b_size;
+ if (SegmentNumber++ > Controller->MaxScatterGatherSegments)
+ panic("DAC960: Scatter/Gather Segment Overflow\n");
+ }
+ BufferHeader = BufferHeader->b_reqnext;
+ }
+ if (SegmentNumber != Command->SegmentCount)
+ panic("DAC960: SegmentNumber != SegmentCount\n");
+ }
+ DAC960_QueueCommand(Command);
+ return true;
+}
+
+
+/*
+ DAC960_ProcessRequests attempts to remove as many I/O Requests as possible
+ from Controller's I/O Request Queue and queue them to the Controller.
+*/
+
+static inline void DAC960_ProcessRequests(DAC960_Controller_T *Controller)
+{
+ while (Controller->FreeCommands != NULL)
+ if (!DAC960_ProcessRequest(Controller, NULL)) break;
+}
+
+
+/*
+ DAC960_RequestFunction0 is the I/O Request Function for DAC960 Controller 0.
+*/
+
+static void DAC960_RequestFunction0(void)
+{
+ DAC960_Controller_T *Controller = DAC960_Controllers[0];
+ ProcessorFlags_T ProcessorFlags;
+ /*
+ Acquire exclusive access to Controller.
+ */
+ DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags);
+ /*
+ Process I/O Requests for Controller.
+ */
+ DAC960_ProcessRequests(Controller);
+ /*
+ Release exclusive access to Controller.
+ */
+ DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags);
+}
+
+
+/*
+ DAC960_RequestFunction1 is the I/O Request Function for DAC960 Controller 1.
+*/
+
+static void DAC960_RequestFunction1(void)
+{
+ DAC960_Controller_T *Controller = DAC960_Controllers[1];
+ ProcessorFlags_T ProcessorFlags;
+ /*
+ Acquire exclusive access to Controller.
+ */
+ DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags);
+ /*
+ Process I/O Requests for Controller.
+ */
+ DAC960_ProcessRequests(Controller);
+ /*
+ Release exclusive access to Controller.
+ */
+ DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags);
+}
+
+
+/*
+ DAC960_RequestFunction2 is the I/O Request Function for DAC960 Controller 2.
+*/
+
+static void DAC960_RequestFunction2(void)
+{
+ DAC960_Controller_T *Controller = DAC960_Controllers[2];
+ ProcessorFlags_T ProcessorFlags;
+ /*
+ Acquire exclusive access to Controller.
+ */
+ DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags);
+ /*
+ Process I/O Requests for Controller.
+ */
+ DAC960_ProcessRequests(Controller);
+ /*
+ Release exclusive access to Controller.
+ */
+ DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags);
+}
+
+
+/*
+ DAC960_RequestFunction3 is the I/O Request Function for DAC960 Controller 3.
+*/
+
+static void DAC960_RequestFunction3(void)
+{
+ DAC960_Controller_T *Controller = DAC960_Controllers[3];
+ ProcessorFlags_T ProcessorFlags;
+ /*
+ Acquire exclusive access to Controller.
+ */
+ DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags);
+ /*
+ Process I/O Requests for Controller.
+ */
+ DAC960_ProcessRequests(Controller);
+ /*
+ Release exclusive access to Controller.
+ */
+ DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags);
+}
+
+
+/*
+ DAC960_RequestFunction4 is the I/O Request Function for DAC960 Controller 4.
+*/
+
+static void DAC960_RequestFunction4(void)
+{
+ DAC960_Controller_T *Controller = DAC960_Controllers[4];
+ ProcessorFlags_T ProcessorFlags;
+ /*
+ Acquire exclusive access to Controller.
+ */
+ DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags);
+ /*
+ Process I/O Requests for Controller.
+ */
+ DAC960_ProcessRequests(Controller);
+ /*
+ Release exclusive access to Controller.
+ */
+ DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags);
+}
+
+
+/*
+ DAC960_RequestFunction5 is the I/O Request Function for DAC960 Controller 5.
+*/
+
+static void DAC960_RequestFunction5(void)
+{
+ DAC960_Controller_T *Controller = DAC960_Controllers[5];
+ ProcessorFlags_T ProcessorFlags;
+ /*
+ Acquire exclusive access to Controller.
+ */
+ DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags);
+ /*
+ Process I/O Requests for Controller.
+ */
+ DAC960_ProcessRequests(Controller);
+ /*
+ Release exclusive access to Controller.
+ */
+ DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags);
+}
+
+
+/*
+ DAC960_RequestFunction6 is the I/O Request Function for DAC960 Controller 6.
+*/
+
+static void DAC960_RequestFunction6(void)
+{
+ DAC960_Controller_T *Controller = DAC960_Controllers[6];
+ ProcessorFlags_T ProcessorFlags;
+ /*
+ Acquire exclusive access to Controller.
+ */
+ DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags);
+ /*
+ Process I/O Requests for Controller.
+ */
+ DAC960_ProcessRequests(Controller);
+ /*
+ Release exclusive access to Controller.
+ */
+ DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags);
+}
+
+
+/*
+ DAC960_RequestFunction7 is the I/O Request Function for DAC960 Controller 7.
+*/
+
+static void DAC960_RequestFunction7(void)
+{
+ DAC960_Controller_T *Controller = DAC960_Controllers[7];
+ ProcessorFlags_T ProcessorFlags;
+ /*
+ Acquire exclusive access to Controller.
+ */
+ DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags);
+ /*
+ Process I/O Requests for Controller.
+ */
+ DAC960_ProcessRequests(Controller);
+ /*
+ Release exclusive access to Controller.
+ */
+ DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags);
+}
+
+
+/*
+ DAC960_ReadWriteError prints an appropriate error message for Command when
+ an error occurs on a read or write operation.
+*/
+
+static void DAC960_ReadWriteError(DAC960_Command_T *Command)
+{
+ DAC960_Controller_T *Controller = Command->Controller;
+ char *CommandName = "UNKNOWN";
+ switch (Command->CommandType)
+ {
+ case DAC960_ReadCommand:
+ case DAC960_ReadRetryCommand:
+ CommandName = "READ";
+ break;
+ case DAC960_WriteCommand:
+ case DAC960_WriteRetryCommand:
+ CommandName = "WRITE";
+ break;
+ case DAC960_MonitoringCommand:
+ case DAC960_ImmediateCommand:
+ break;
+ }
+ switch (Command->CommandStatus)
+ {
+ case DAC960_IrrecoverableDataError:
+ DAC960_Error("Irrecoverable Data Error on %s:\n",
+ Controller, CommandName);
+ break;
+ case DAC960_LogicalDriveNonexistentOrOffline:
+ break;
+ case DAC960_AccessBeyondEndOfLogicalDrive:
+ DAC960_Error("Attempt to Access Beyond End of Logical Drive "
+ "on %s:\n", Controller, CommandName);
+ break;
+ case DAC960_BadDataEncountered:
+ DAC960_Error("Bad Data Encountered on %s:\n", Controller, CommandName);
+ break;
+ default:
+ DAC960_Error("Unexpected Error Status %04X on %s:\n",
+ Controller, Command->CommandStatus, CommandName);
+ break;
+ }
+ DAC960_Error(" /dev/rd/c%dd%d: absolute blocks %d..%d\n",
+ Controller, Controller->ControllerNumber,
+ Command->LogicalDriveNumber, Command->BlockNumber,
+ Command->BlockNumber + Command->BlockCount - 1);
+ if (DAC960_PartitionNumber(Command->BufferHeader->b_rdev) > 0)
+ DAC960_Error(" /dev/rd/c%dd%dp%d: relative blocks %d..%d\n",
+ Controller, Controller->ControllerNumber,
+ Command->LogicalDriveNumber,
+ DAC960_PartitionNumber(Command->BufferHeader->b_rdev),
+ Command->BufferHeader->b_rsector,
+ Command->BufferHeader->b_rsector + Command->BlockCount - 1);
+}
+
+
+/*
+ DAC960_ProcessCompletedBuffer performs completion processing for an
+ individual Buffer.
+*/
+
+static inline void DAC960_ProcessCompletedBuffer(BufferHeader_T *BufferHeader,
+ boolean SuccessfulIO)
+{
+ mark_buffer_uptodate(BufferHeader, SuccessfulIO);
+ unlock_buffer(BufferHeader);
+}
+
+
+/*
+ DAC960_ProcessCompletedCommand performs completion processing for Command.
+*/
+
+static void DAC960_ProcessCompletedCommand(DAC960_Command_T *Command)
+{
+ DAC960_Controller_T *Controller = Command->Controller;
+ DAC960_CommandType_T CommandType = Command->CommandType;
+ DAC960_CommandStatus_T CommandStatus = Command->CommandStatus;
+ BufferHeader_T *BufferHeader = Command->BufferHeader;
+ if (CommandType == DAC960_ReadCommand ||
+ CommandType == DAC960_WriteCommand)
+ {
+ if (CommandStatus == DAC960_NormalCompletion)
+ {
+ /*
+ Perform completion processing for all buffers in this I/O Request.
+ */
+ while (BufferHeader != NULL)
+ {
+ BufferHeader_T *NextBufferHeader = BufferHeader->b_reqnext;
+ BufferHeader->b_reqnext = NULL;
+ DAC960_ProcessCompletedBuffer(BufferHeader, true);
+ BufferHeader = NextBufferHeader;
+ }
+ /*
+ Wake up requestor for swap file paging requests.
+ */
+ if (Command->Semaphore != NULL)
+ {
+ up(Command->Semaphore);
+ Command->Semaphore = NULL;
+ }
+ }
+ else if ((CommandStatus == DAC960_IrrecoverableDataError ||
+ CommandStatus == DAC960_BadDataEncountered) &&
+ BufferHeader != NULL &&
+ BufferHeader->b_reqnext != NULL)
+ {
+ DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
+ if (CommandType == DAC960_ReadCommand)
+ {
+ Command->CommandType = DAC960_ReadRetryCommand;
+ CommandMailbox->Type5.CommandOpcode = DAC960_Read;
+ }
+ else
+ {
+ Command->CommandType = DAC960_WriteRetryCommand;
+ CommandMailbox->Type5.CommandOpcode = DAC960_Write;
+ }
+ Command->BlockCount = BufferHeader->b_size >> DAC960_BlockSizeBits;
+ CommandMailbox->Type5.LD.TransferLength = Command->BlockCount;
+ CommandMailbox->Type5.BusAddress =
+ Virtual_to_Bus(BufferHeader->b_data);
+ DAC960_QueueCommand(Command);
+ return;
+ }
+ else
+ {
+ DAC960_ReadWriteError(Command);
+ /*
+ Perform completion processing for all buffers in this I/O Request.
+ */
+ while (BufferHeader != NULL)
+ {
+ BufferHeader_T *NextBufferHeader = BufferHeader->b_reqnext;
+ BufferHeader->b_reqnext = NULL;
+ DAC960_ProcessCompletedBuffer(BufferHeader, false);
+ BufferHeader = NextBufferHeader;
+ }
+ /*
+ Wake up requestor for swap file paging requests.
+ */
+ if (Command->Semaphore != NULL)
+ {
+ up(Command->Semaphore);
+ Command->Semaphore = NULL;
+ }
+ }
+ }
+ else if (CommandType == DAC960_ReadRetryCommand ||
+ CommandType == DAC960_WriteRetryCommand)
+ {
+ BufferHeader_T *NextBufferHeader = BufferHeader->b_reqnext;
+ BufferHeader->b_reqnext = NULL;
+ /*
+ Perform completion processing for this single buffer.
+ */
+ if (CommandStatus == DAC960_NormalCompletion)
+ DAC960_ProcessCompletedBuffer(BufferHeader, true);
+ else
+ {
+ DAC960_ReadWriteError(Command);
+ DAC960_ProcessCompletedBuffer(BufferHeader, false);
+ }
+ if (NextBufferHeader != NULL)
+ {
+ DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
+ Command->BlockNumber +=
+ BufferHeader->b_size >> DAC960_BlockSizeBits;
+ Command->BlockCount =
+ NextBufferHeader->b_size >> DAC960_BlockSizeBits;
+ Command->BufferHeader = NextBufferHeader;
+ CommandMailbox->Type5.LD.TransferLength = Command->BlockCount;
+ CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber;
+ CommandMailbox->Type5.BusAddress =
+ Virtual_to_Bus(NextBufferHeader->b_data);
+ DAC960_QueueCommand(Command);
+ return;
+ }
+ }
+ else if (CommandType == DAC960_MonitoringCommand)
+ {
+ DAC960_CommandOpcode_T CommandOpcode =
+ Command->CommandMailbox.Common.CommandOpcode;
+ unsigned int OldCriticalLogicalDriveCount = 0;
+ unsigned int NewCriticalLogicalDriveCount = 0;
+ if (CommandOpcode == DAC960_Enquiry)
+ {
+ DAC960_Enquiry_T *OldEnquiry =
+ &Controller->Enquiry[Controller->EnquiryIndex];
+ DAC960_Enquiry_T *NewEnquiry =
+ &Controller->Enquiry[Controller->EnquiryIndex ^= 1];
+ OldCriticalLogicalDriveCount = OldEnquiry->CriticalLogicalDriveCount;
+ NewCriticalLogicalDriveCount = NewEnquiry->CriticalLogicalDriveCount;
+ if (NewEnquiry->StatusFlags.DeferredWriteError !=
+ OldEnquiry->StatusFlags.DeferredWriteError)
+ DAC960_Critical("Deferred Write Error Flag is now %s\n", Controller,
+ (NewEnquiry->StatusFlags.DeferredWriteError
+ ? "TRUE" : "FALSE"));
+ if ((NewCriticalLogicalDriveCount > 0 ||
+ NewCriticalLogicalDriveCount != OldCriticalLogicalDriveCount) ||
+ (NewEnquiry->OfflineLogicalDriveCount > 0 ||
+ NewEnquiry->OfflineLogicalDriveCount !=
+ OldEnquiry->OfflineLogicalDriveCount) ||
+ (NewEnquiry->DeadDriveCount > 0 ||
+ NewEnquiry->DeadDriveCount !=
+ OldEnquiry->DeadDriveCount) ||
+ (NewEnquiry->EventLogSequenceNumber !=
+ OldEnquiry->EventLogSequenceNumber) ||
+ (jiffies - Controller->SecondaryMonitoringTime
+ >= DAC960_SecondaryMonitoringInterval))
+ {
+ Controller->NeedLogicalDriveInformation = true;
+ Controller->NewEventLogSequenceNumber =
+ NewEnquiry->EventLogSequenceNumber;
+ Controller->NeedDeviceStateInformation = true;
+ Controller->DeviceStateChannel = 0;
+ Controller->DeviceStateTargetID = 0;
+ Controller->SecondaryMonitoringTime = jiffies;
+ }
+ if ((NewEnquiry->RebuildCount > 0 &&
+ jiffies - Controller->RebuildLastReportTime
+ >= DAC960_RebuildStatusReportingInterval) ||
+ NewEnquiry->RebuildCount != OldEnquiry->RebuildCount)
+ Controller->NeedRebuildProgress = true;
+ }
+ else if (CommandOpcode == DAC960_GetLogicalDriveInformation)
+ {
+ int LogicalDriveNumber;
+ for (LogicalDriveNumber = 0;
+ LogicalDriveNumber < Controller->LogicalDriveCount;
+ LogicalDriveNumber++)
+ {
+ DAC960_LogicalDriveInformation_T *OldLogicalDriveInformation =
+ &Controller->LogicalDriveInformation
+ [Controller->LogicalDriveInformationIndex]
+ [LogicalDriveNumber];
+ DAC960_LogicalDriveInformation_T *NewLogicalDriveInformation =
+ &Controller->LogicalDriveInformation
+ [Controller->LogicalDriveInformationIndex ^ 1]
+ [LogicalDriveNumber];
+ if (NewLogicalDriveInformation->LogicalDriveState !=
+ OldLogicalDriveInformation->LogicalDriveState)
+ DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) "
+ "is now %s\n", Controller,
+ LogicalDriveNumber,
+ Controller->ControllerNumber,
+ LogicalDriveNumber,
+ (NewLogicalDriveInformation->LogicalDriveState
+ == DAC960_LogicalDrive_Online
+ ? "ONLINE"
+ : NewLogicalDriveInformation->LogicalDriveState
+ == DAC960_LogicalDrive_Critical
+ ? "CRITICAL" : "OFFLINE"));
+ if (NewLogicalDriveInformation->WriteBack !=
+ OldLogicalDriveInformation->WriteBack)
+ DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) "
+ "is now %s\n", Controller,
+ LogicalDriveNumber,
+ Controller->ControllerNumber,
+ LogicalDriveNumber,
+ (NewLogicalDriveInformation->WriteBack
+ ? "WRITE BACK" : "WRITE THRU"));
+ }
+ Controller->LogicalDriveInformationIndex ^= 1;
+ }
+ else if (CommandOpcode == DAC960_PerformEventLogOperation)
+ {
+ DAC960_EventLogEntry_T *EventLogEntry = &Controller->EventLogEntry;
+ if (EventLogEntry->SequenceNumber ==
+ Controller->OldEventLogSequenceNumber)
+ {
+ unsigned char SenseKey = EventLogEntry->SenseKey;
+ unsigned char AdditionalSenseCode =
+ EventLogEntry->AdditionalSenseCode;
+ unsigned char AdditionalSenseCodeQualifier =
+ EventLogEntry->AdditionalSenseCodeQualifier;
+ if (SenseKey == 9 &&
+ AdditionalSenseCode == 0x80 &&
+ AdditionalSenseCodeQualifier < DAC960_EventMessagesCount)
+ DAC960_Critical("Physical Drive %d:%d %s\n", Controller,
+ EventLogEntry->Channel,
+ EventLogEntry->TargetID,
+ DAC960_EventMessages[
+ AdditionalSenseCodeQualifier]);
+ else if (!((SenseKey == 2 &&
+ AdditionalSenseCode == 0x04 &&
+ (AdditionalSenseCodeQualifier == 0x01 ||
+ AdditionalSenseCodeQualifier == 0x02)) ||
+ (SenseKey == 6 && AdditionalSenseCode == 0x29)))
+ DAC960_Critical("Physical Drive %d:%d Error Log: "
+ "Sense Key = %d, ASC = %02X, ASCQ = %02X\n",
+ Controller,
+ EventLogEntry->Channel,
+ EventLogEntry->TargetID,
+ SenseKey,
+ AdditionalSenseCode,
+ AdditionalSenseCodeQualifier);
+ }
+ Controller->OldEventLogSequenceNumber++;
+ }
+ else if (CommandOpcode == DAC960_GetDeviceState)
+ {
+ DAC960_DeviceState_T *OldDeviceState =
+ &Controller->DeviceState[Controller->DeviceStateIndex]
+ [Controller->DeviceStateChannel]
+ [Controller->DeviceStateTargetID];
+ DAC960_DeviceState_T *NewDeviceState =
+ &Controller->DeviceState[Controller->DeviceStateIndex ^ 1]
+ [Controller->DeviceStateChannel]
+ [Controller->DeviceStateTargetID];
+ if (NewDeviceState->DeviceState != OldDeviceState->DeviceState)
+ DAC960_Critical("Physical Drive %d:%d is now %s\n", Controller,
+ Controller->DeviceStateChannel,
+ Controller->DeviceStateTargetID,
+ (NewDeviceState->DeviceState == DAC960_Device_Dead
+ ? "DEAD"
+ : NewDeviceState->DeviceState
+ == DAC960_Device_WriteOnly
+ ? "WRITE-ONLY"
+ : NewDeviceState->DeviceState
+ == DAC960_Device_Online
+ ? "ONLINE" : "STANDBY"));
+ if (++Controller->DeviceStateTargetID == DAC960_MaxTargets)
+ {
+ Controller->DeviceStateChannel++;
+ Controller->DeviceStateTargetID = 0;
+ }
+ }
+ else if (CommandOpcode == DAC960_GetRebuildProgress)
+ {
+ unsigned int LogicalDriveNumber =
+ Controller->RebuildProgress.LogicalDriveNumber;
+ unsigned int LogicalDriveSize =
+ Controller->RebuildProgress.LogicalDriveSize;
+ unsigned int BlocksCompleted =
+ LogicalDriveSize - Controller->RebuildProgress.RemainingBlocks;
+ switch (CommandStatus)
+ {
+ case DAC960_NormalCompletion:
+ DAC960_Critical("REBUILD IN PROGRESS: "
+ "Logical Drive %d (/dev/rd/c%dd%d) "
+ "%d%% completed\n",
+ Controller, LogicalDriveNumber,
+ Controller->ControllerNumber,
+ LogicalDriveNumber,
+ (100 * (BlocksCompleted >> 7))
+ / (LogicalDriveSize >> 7));
+ break;
+ case DAC960_RebuildFailed_LogicalDriveFailure:
+ DAC960_Critical("REBUILD FAILED due to "
+ "LOGICAL DRIVE FAILURE\n", Controller);
+ break;
+ case DAC960_RebuildFailed_BadBlocksOnOther:
+ DAC960_Critical("REBUILD FAILED due to "
+ "BAD BLOCKS ON OTHER DRIVES\n", Controller);
+ break;
+ case DAC960_RebuildFailed_NewDriveFailed:
+ DAC960_Critical("REBUILD FAILED due to "
+ "FAILURE OF DRIVE BEING REBUILT\n", Controller);
+ break;
+ case DAC960_RebuildSuccessful:
+ DAC960_Critical("REBUILD COMPLETED SUCCESSFULLY\n", Controller);
+ break;
+ case DAC960_NoRebuildOrCheckInProgress:
+ break;
+ }
+ Controller->RebuildLastReportTime = jiffies;
+ }
+ if (Controller->NeedLogicalDriveInformation &&
+ NewCriticalLogicalDriveCount >= OldCriticalLogicalDriveCount)
+ {
+ Controller->NeedLogicalDriveInformation = false;
+ Command->CommandMailbox.Type3.CommandOpcode =
+ DAC960_GetLogicalDriveInformation;
+ Command->CommandMailbox.Type3.BusAddress =
+ Virtual_to_Bus(
+ &Controller->LogicalDriveInformation
+ [Controller->LogicalDriveInformationIndex ^ 1]);
+ DAC960_QueueCommand(Command);
+ return;
+ }
+ if (Controller->NewEventLogSequenceNumber
+ - Controller->OldEventLogSequenceNumber > 0)
+ {
+ Command->CommandMailbox.Type3E.CommandOpcode =
+ DAC960_PerformEventLogOperation;
+ Command->CommandMailbox.Type3E.OperationType =
+ DAC960_GetEventLogEntry;
+ Command->CommandMailbox.Type3E.OperationQualifier = 1;
+ Command->CommandMailbox.Type3E.SequenceNumber =
+ Controller->OldEventLogSequenceNumber;
+ Command->CommandMailbox.Type3E.BusAddress =
+ Virtual_to_Bus(&Controller->EventLogEntry);
+ DAC960_QueueCommand(Command);
+ return;
+ }
+ if (Controller->NeedDeviceStateInformation)
+ {
+ while (Controller->DeviceStateChannel < Controller->Channels)
+ {
+ DAC960_DeviceState_T *OldDeviceState =
+ &Controller->DeviceState[Controller->DeviceStateIndex]
+ [Controller->DeviceStateChannel]
+ [Controller->DeviceStateTargetID];
+ if (OldDeviceState->Present &&
+ OldDeviceState->DeviceType == DAC960_DiskType)
+ {
+ Command->CommandMailbox.Type3D.CommandOpcode =
+ DAC960_GetDeviceState;
+ Command->CommandMailbox.Type3D.Channel =
+ Controller->DeviceStateChannel;
+ Command->CommandMailbox.Type3D.TargetID =
+ Controller->DeviceStateTargetID;
+ Command->CommandMailbox.Type3D.BusAddress =
+ Virtual_to_Bus(&Controller->DeviceState
+ [Controller->DeviceStateIndex ^ 1]
+ [Controller->DeviceStateChannel]
+ [Controller->DeviceStateTargetID]);
+ DAC960_QueueCommand(Command);
+ return;
+ }
+ if (++Controller->DeviceStateTargetID == DAC960_MaxTargets)
+ {
+ Controller->DeviceStateChannel++;
+ Controller->DeviceStateTargetID = 0;
+ }
+ }
+ Controller->NeedDeviceStateInformation = false;
+ Controller->DeviceStateIndex ^= 1;
+ }
+ if (Controller->NeedRebuildProgress)
+ {
+ Controller->NeedRebuildProgress = false;
+ Command->CommandMailbox.Type3.CommandOpcode =
+ DAC960_GetRebuildProgress;
+ Command->CommandMailbox.Type3.BusAddress =
+ Virtual_to_Bus(&Controller->RebuildProgress);
+ DAC960_QueueCommand(Command);
+ return;
+ }
+ if (Controller->NeedLogicalDriveInformation &&
+ NewCriticalLogicalDriveCount < OldCriticalLogicalDriveCount)
+ {
+ Controller->NeedLogicalDriveInformation = false;
+ Command->CommandMailbox.Type3.CommandOpcode =
+ DAC960_GetLogicalDriveInformation;
+ Command->CommandMailbox.Type3.BusAddress =
+ Virtual_to_Bus(
+ &Controller->LogicalDriveInformation
+ [Controller->LogicalDriveInformationIndex ^ 1]);
+ DAC960_QueueCommand(Command);
+ return;
+ }
+ Controller->MonitoringTimer.expires =
+ jiffies + DAC960_MonitoringTimerInterval;
+ add_timer(&Controller->MonitoringTimer);
+ }
+ else if (CommandType == DAC960_ImmediateCommand)
+ {
+ up(Command->Semaphore);
+ Command->Semaphore = NULL;
+ return;
+ }
+ else panic("DAC960: Unknown Command Type %d\n", CommandType);
+ /*
+ Queue a Monitoring Command to the Controller using the just completed
+ Command if one was deferred previously due to lack of a free Command when
+ the Monitoring Timer Function was called.
+ */
+ if (Controller->MonitoringCommandDeferred)
+ {
+ Controller->MonitoringCommandDeferred = false;
+ DAC960_QueueMonitoringCommand(Command);
+ return;
+ }
+ /*
+ Attempt to remove a new I/O Request from the Controller's I/O Request
+ Queue and queue it to the Controller using the just completed Command.
+ If there is no I/O Request to be queued, deallocate the Command.
+ */
+ if (!DAC960_ProcessRequest(Controller, Command))
+ DAC960_DeallocateCommand(Command);
+}
+
+
+/*
+ DAC960_InterruptHandler handles hardware interrupts from DAC960 Controllers.
+*/
+
+static void DAC960_InterruptHandler(int IRQ_Channel,
+ void *DeviceIdentifier,
+ Registers_T *InterruptRegisters)
+{
+ DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier;
+ void *ControllerBaseAddress = Controller->BaseAddress;
+ DAC960_V4_StatusMailbox_T *NextStatusMailbox;
+ ProcessorFlags_T ProcessorFlags;
+ /*
+ Acquire exclusive access to Controller.
+ */
+ DAC960_AcquireControllerLockIH(Controller, &ProcessorFlags);
+ /*
+ Process Hardware Interrupts for Controller.
+ */
+ switch (Controller->ControllerType)
+ {
+ case DAC960_V4_Controller:
+ DAC960_V4_AcknowledgeInterrupt(ControllerBaseAddress);
+ NextStatusMailbox = Controller->NextStatusMailbox;
+ while (NextStatusMailbox->Fields.Valid)
+ {
+ DAC960_CommandIdentifier_T CommandIdentifier =
+ NextStatusMailbox->Fields.CommandIdentifier;
+ DAC960_Command_T *Command = &Controller->Commands[CommandIdentifier];
+ Command->CommandStatus = NextStatusMailbox->Fields.CommandStatus;
+ NextStatusMailbox->Word = 0;
+ if (++NextStatusMailbox > Controller->LastStatusMailbox)
+ NextStatusMailbox = Controller->FirstStatusMailbox;
+ DAC960_ProcessCompletedCommand(Command);
+ }
+ Controller->NextStatusMailbox = NextStatusMailbox;
+ break;
+ case DAC960_V3_Controller:
+ while (DAC960_V3_StatusAvailableP(ControllerBaseAddress))
+ {
+ DAC960_CommandIdentifier_T CommandIdentifier =
+ DAC960_V3_ReadStatusCommandIdentifier(ControllerBaseAddress);
+ DAC960_Command_T *Command = &Controller->Commands[CommandIdentifier];
+ Command->CommandStatus =
+ DAC960_V3_ReadStatusRegister(ControllerBaseAddress);
+ DAC960_V3_AcknowledgeInterrupt(ControllerBaseAddress);
+ DAC960_V3_AcknowledgeStatus(ControllerBaseAddress);
+ DAC960_ProcessCompletedCommand(Command);
+ }
+ break;
+ }
+ /*
+ Attempt to remove additional I/O Requests from the Controller's
+ I/O Request Queue and queue them to the Controller.
+ */
+ DAC960_ProcessRequests(Controller);
+ /*
+ Release exclusive access to Controller.
+ */
+ DAC960_ReleaseControllerLockIH(Controller, &ProcessorFlags);
+}
+
+
+/*
+ DAC960_QueueMonitoringCommand queues a Monitoring Command to Controller.
+*/
+
+static void DAC960_QueueMonitoringCommand(DAC960_Command_T *Command)
+{
+ DAC960_Controller_T *Controller = Command->Controller;
+ DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
+ DAC960_ClearCommand(Command);
+ Command->CommandType = DAC960_MonitoringCommand;
+ CommandMailbox->Type3.CommandOpcode = DAC960_Enquiry;
+ CommandMailbox->Type3.BusAddress =
+ Virtual_to_Bus(&Controller->Enquiry[Controller->EnquiryIndex ^ 1]);
+ DAC960_QueueCommand(Command);
+}
+
+
+/*
+ DAC960_MonitoringTimerFunction is the timer function for monitoring
+ the status of DAC960 Controllers.
+*/
+
+static void DAC960_MonitoringTimerFunction(unsigned long TimerData)
+{
+ DAC960_Controller_T *Controller = (DAC960_Controller_T *) TimerData;
+ DAC960_Command_T *Command;
+ ProcessorFlags_T ProcessorFlags;
+ /*
+ Acquire exclusive access to Controller.
+ */
+ DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
+ /*
+ Queue a Status Monitoring Command for Controller;
+ */
+ Command = DAC960_AllocateCommand(Controller);
+ if (Command != NULL)
+ DAC960_QueueMonitoringCommand(Command);
+ else Controller->MonitoringCommandDeferred = true;
+ /*
+ Release exclusive access to Controller.
+ */
+ DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
+}
+
+
+/*
+ DAC960_Open is the Device Open Function for the DAC960 Driver.
+*/
+
+static int DAC960_Open(Inode_T *Inode, File_T *File)
+{
+ int ControllerNumber = DAC960_ControllerNumber(Inode->i_rdev);
+ int LogicalDriveNumber = DAC960_LogicalDriveNumber(Inode->i_rdev);
+ DAC960_Controller_T *Controller;
+ if (ControllerNumber < 0 || ControllerNumber > DAC960_ControllerCount - 1)
+ return -ENXIO;
+ Controller = DAC960_Controllers[ControllerNumber];
+ if (Controller == NULL ||
+ LogicalDriveNumber > Controller->LogicalDriveCount - 1)
+ return -ENXIO;
+ if (Controller->LogicalDriveInformation
+ [Controller->LogicalDriveInformationIndex]
+ [LogicalDriveNumber] .LogicalDriveState
+ == DAC960_LogicalDrive_Offline)
+ return -ENXIO;
+ if (Controller->GenericDiskInfo.sizes[MINOR(Inode->i_rdev)] == 0)
+ return -ENXIO;
+ /*
+ Increment Controller and Logical Drive Usage Counts.
+ */
+ Controller->ControllerUsageCount++;
+ Controller->LogicalDriveUsageCount[LogicalDriveNumber]++;
+ return 0;
+}
+
+
+/*
+ DAC960_Release is the Device Release Function for the DAC960 Driver.
+*/
+
+static void DAC960_Release(Inode_T *Inode, File_T *File)
+{
+ int ControllerNumber = DAC960_ControllerNumber(Inode->i_rdev);
+ int LogicalDriveNumber = DAC960_LogicalDriveNumber(Inode->i_rdev);
+ DAC960_Controller_T *Controller = DAC960_Controllers[ControllerNumber];
+ /*
+ Force any buffered data to be written.
+ */
+ fsync_dev(Inode->i_rdev);
+ /*
+ Decrement the Logical Drive and Controller Usage Counts.
+ */
+ Controller->LogicalDriveUsageCount[LogicalDriveNumber]--;
+ Controller->ControllerUsageCount--;
+}
+
+
+/*
+ DAC960_Ioctl is the Device Ioctl Function for the DAC960 Driver.
+*/
+
+static int DAC960_Ioctl(Inode_T *Inode, File_T *File,
+ unsigned int Request, unsigned long Argument)
+{
+ int ControllerNumber = DAC960_ControllerNumber(Inode->i_rdev);
+ int LogicalDriveNumber = DAC960_LogicalDriveNumber(Inode->i_rdev);
+ int PartitionNumber, ErrorCode;
+ unsigned short Cylinders;
+ DiskGeometry_T *Geometry;
+ DAC960_Controller_T *Controller;
+ if (ControllerNumber < 0 || ControllerNumber > DAC960_ControllerCount - 1)
+ return -ENXIO;
+ Controller = DAC960_Controllers[ControllerNumber];
+ if (Controller == NULL ||
+ LogicalDriveNumber > Controller->LogicalDriveCount - 1)
+ return -ENXIO;
+ switch (Request)
+ {
+ case HDIO_GETGEO:
+ /* Get BIOS Disk Geometry. */
+ Geometry = (DiskGeometry_T *) Argument;
+ if (Geometry == NULL) return -EINVAL;
+ ErrorCode = verify_area(VERIFY_WRITE, Geometry, sizeof(DiskGeometry_T));
+ if (ErrorCode != 0) return ErrorCode;
+ Cylinders =
+ Controller->LogicalDriveInformation
+ [Controller->LogicalDriveInformationIndex]
+ [LogicalDriveNumber].LogicalDriveSize
+ / (Controller->GeometryTranslationHeads *
+ Controller->GeometryTranslationSectors);
+ put_user(Controller->GeometryTranslationHeads, &Geometry->heads);
+ put_user(Controller->GeometryTranslationSectors, &Geometry->sectors);
+ put_user(Cylinders, &Geometry->cylinders);
+ put_user(Controller->GenericDiskInfo.part[MINOR(Inode->i_rdev)]
+ .start_sect, &Geometry->start);
+ return 0;
+ case BLKGETSIZE:
+ /* Get Device Size. */
+ if ((long *) Argument == NULL) return -EINVAL;
+ ErrorCode = verify_area(VERIFY_WRITE, (long *) Argument, sizeof(long));
+ if (ErrorCode != 0) return ErrorCode;
+ put_user(Controller->GenericDiskInfo.part[MINOR(Inode->i_rdev)].nr_sects,
+ (long *) Argument);
+ return 0;
+ case BLKRAGET:
+ /* Get Read-Ahead. */
+ if ((int *) Argument == NULL) return -EINVAL;
+ ErrorCode = verify_area(VERIFY_WRITE, (int *) Argument, sizeof(int));
+ if (ErrorCode != 0) return ErrorCode;
+ put_user(read_ahead[MAJOR(Inode->i_rdev)], (int *) Argument);
+ return 0;
+ case BLKRASET:
+ /* Set Read-Ahead. */
+ if (!suser()) return -EACCES;
+ if (Argument > 256) return -EINVAL;
+ read_ahead[MAJOR(Inode->i_rdev)] = Argument;
+ return 0;
+ case BLKFLSBUF:
+ /* Flush Buffers. */
+ if (!suser()) return -EACCES;
+ fsync_dev(Inode->i_rdev);
+ invalidate_buffers(Inode->i_rdev);
+ return 0;
+ case BLKRRPART:
+ /* Re-Read Partition Table. */
+ if (!suser()) return -EACCES;
+ if (Controller->LogicalDriveUsageCount[LogicalDriveNumber] > 1)
+ return -EBUSY;
+ for (PartitionNumber = 0;
+ PartitionNumber < DAC960_MaxPartitions;
+ PartitionNumber++)
+ {
+ KernelDevice_T Device = DAC960_KernelDevice(ControllerNumber,
+ LogicalDriveNumber,
+ PartitionNumber);
+ int MinorNumber = DAC960_MinorNumber(LogicalDriveNumber,
+ PartitionNumber);
+ if (Controller->GenericDiskInfo.part[MinorNumber].nr_sects == 0)
+ continue;
+ /*
+ Flush all changes and invalidate buffered state.
+ */
+ sync_dev(Device);
+ invalidate_inodes(Device);
+ invalidate_buffers(Device);
+ /*
+ Clear existing partition sizes.
+ */
+ if (PartitionNumber > 0)
+ {
+ Controller->GenericDiskInfo.part[MinorNumber].start_sect = 0;
+ Controller->GenericDiskInfo.part[MinorNumber].nr_sects = 0;
+ }
+ /*
+ Reset the Block Size so that the partition table can be read.
+ */
+ set_blocksize(Device, BLOCK_SIZE);
+ }
+ resetup_one_dev(&Controller->GenericDiskInfo, LogicalDriveNumber);
+ return 0;
+ }
+ return -EINVAL;
+}
+
+
+/*
+ DAC960_GenericDiskInit is the Generic Disk Information Initialization
+ Function for the DAC960 Driver.
+*/
+
+static void DAC960_InitializeGenericDiskInfo(GenericDiskInfo_T *GenericDiskInfo)
+{
+ DAC960_Controller_T *Controller =
+ (DAC960_Controller_T *) GenericDiskInfo->real_devices;
+ DAC960_LogicalDriveInformation_T *LogicalDriveInformation =
+ Controller->LogicalDriveInformation
+ [Controller->LogicalDriveInformationIndex];
+ int LogicalDriveNumber;
+ for (LogicalDriveNumber = 0;
+ LogicalDriveNumber < Controller->LogicalDriveCount;
+ LogicalDriveNumber++)
+ GenericDiskInfo->part[DAC960_MinorNumber(LogicalDriveNumber, 0)].nr_sects =
+ LogicalDriveInformation[LogicalDriveNumber].LogicalDriveSize;
+}
+
+
+/*
+ DAC960_Message prints Driver Messages.
+*/
+
+static void DAC960_Message(DAC960_MessageLevel_T MessageLevel,
+ char *Format,
+ DAC960_Controller_T *Controller,
+ ...)
+{
+ static 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 (MessageLevel == DAC960_AnnounceLevel)
+ {
+ static int AnnouncementLines = 0;
+ strcpy(&Controller->MessageBuffer[Controller->MessageBufferLength],
+ Buffer);
+ Controller->MessageBufferLength += Length;
+ if (++AnnouncementLines <= 2)
+ printk("%sDAC960: %s", DAC960_MessageLevelMap[MessageLevel], Buffer);
+ }
+ else if (MessageLevel == DAC960_InfoLevel)
+ {
+ strcpy(&Controller->MessageBuffer[Controller->MessageBufferLength],
+ Buffer);
+ Controller->MessageBufferLength += Length;
+ if (BeginningOfLine)
+ {
+ if (Buffer[0] != '\n' || Length > 1)
+ printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel],
+ Controller->ControllerNumber, Buffer);
+ }
+ else printk("%s", Buffer);
+ }
+ else
+ {
+ if (BeginningOfLine)
+ printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel],
+ Controller->ControllerNumber, Buffer);
+ else printk("%s", Buffer);
+ }
+ BeginningOfLine = (Buffer[Length-1] == '\n');
+}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov