summaryrefslogtreecommitdiffstats
path: root/drivers/block/DAC960.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/block/DAC960.c
Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'drivers/block/DAC960.c')
-rw-r--r--drivers/block/DAC960.c7099
1 files changed, 7099 insertions, 0 deletions
diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c
new file mode 100644
index 000000000000..423bbf2000d2
--- /dev/null
+++ b/drivers/block/DAC960.c
@@ -0,0 +1,7099 @@
+/*
+
+ Linux Driver for Mylex DAC960/AcceleRAID/eXtremeRAID PCI RAID Controllers
+
+ Copyright 1998-2001 by Leonard N. Zubkoff <lnz@dandelion.com>
+
+ This program is free software; you may redistribute and/or modify it under
+ the terms of the GNU General Public License Version 2 as published by the
+ Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for complete details.
+
+*/
+
+
+#define DAC960_DriverVersion "2.5.47"
+#define DAC960_DriverDate "14 November 2002"
+
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/blkdev.h>
+#include <linux/bio.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/genhd.h>
+#include <linux/hdreg.h>
+#include <linux/blkpg.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/reboot.h>
+#include <linux/spinlock.h>
+#include <linux/timer.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include "DAC960.h"
+
+#define DAC960_GAM_MINOR 252
+
+
+static DAC960_Controller_T *DAC960_Controllers[DAC960_MaxControllers];
+static int DAC960_ControllerCount;
+static struct proc_dir_entry *DAC960_ProcDirectoryEntry;
+
+static long disk_size(DAC960_Controller_T *p, int drive_nr)
+{
+ if (p->FirmwareType == DAC960_V1_Controller) {
+ if (drive_nr >= p->LogicalDriveCount)
+ return 0;
+ return p->V1.LogicalDriveInformation[drive_nr].
+ LogicalDriveSize;
+ } else {
+ DAC960_V2_LogicalDeviceInfo_T *i =
+ p->V2.LogicalDeviceInformation[drive_nr];
+ if (i == NULL)
+ return 0;
+ return i->ConfigurableDeviceSize;
+ }
+}
+
+static int DAC960_open(struct inode *inode, struct file *file)
+{
+ struct gendisk *disk = inode->i_bdev->bd_disk;
+ DAC960_Controller_T *p = disk->queue->queuedata;
+ int drive_nr = (long)disk->private_data;
+
+ if (p->FirmwareType == DAC960_V1_Controller) {
+ if (p->V1.LogicalDriveInformation[drive_nr].
+ LogicalDriveState == DAC960_V1_LogicalDrive_Offline)
+ return -ENXIO;
+ } else {
+ DAC960_V2_LogicalDeviceInfo_T *i =
+ p->V2.LogicalDeviceInformation[drive_nr];
+ if (!i || i->LogicalDeviceState == DAC960_V2_LogicalDevice_Offline)
+ return -ENXIO;
+ }
+
+ check_disk_change(inode->i_bdev);
+
+ if (!get_capacity(p->disks[drive_nr]))
+ return -ENXIO;
+ return 0;
+}
+
+static int DAC960_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct gendisk *disk = inode->i_bdev->bd_disk;
+ DAC960_Controller_T *p = disk->queue->queuedata;
+ int drive_nr = (long)disk->private_data;
+ struct hd_geometry g;
+ struct hd_geometry __user *loc = (struct hd_geometry __user *)arg;
+
+ if (cmd != HDIO_GETGEO || !loc)
+ return -EINVAL;
+
+ if (p->FirmwareType == DAC960_V1_Controller) {
+ g.heads = p->V1.GeometryTranslationHeads;
+ g.sectors = p->V1.GeometryTranslationSectors;
+ g.cylinders = p->V1.LogicalDriveInformation[drive_nr].
+ LogicalDriveSize / (g.heads * g.sectors);
+ } else {
+ DAC960_V2_LogicalDeviceInfo_T *i =
+ p->V2.LogicalDeviceInformation[drive_nr];
+ switch (i->DriveGeometry) {
+ case DAC960_V2_Geometry_128_32:
+ g.heads = 128;
+ g.sectors = 32;
+ break;
+ case DAC960_V2_Geometry_255_63:
+ g.heads = 255;
+ g.sectors = 63;
+ break;
+ default:
+ DAC960_Error("Illegal Logical Device Geometry %d\n",
+ p, i->DriveGeometry);
+ return -EINVAL;
+ }
+
+ g.cylinders = i->ConfigurableDeviceSize / (g.heads * g.sectors);
+ }
+
+ g.start = get_start_sect(inode->i_bdev);
+
+ return copy_to_user(loc, &g, sizeof g) ? -EFAULT : 0;
+}
+
+static int DAC960_media_changed(struct gendisk *disk)
+{
+ DAC960_Controller_T *p = disk->queue->queuedata;
+ int drive_nr = (long)disk->private_data;
+
+ if (!p->LogicalDriveInitiallyAccessible[drive_nr])
+ return 1;
+ return 0;
+}
+
+static int DAC960_revalidate_disk(struct gendisk *disk)
+{
+ DAC960_Controller_T *p = disk->queue->queuedata;
+ int unit = (long)disk->private_data;
+
+ set_capacity(disk, disk_size(p, unit));
+ return 0;
+}
+
+static struct block_device_operations DAC960_BlockDeviceOperations = {
+ .owner = THIS_MODULE,
+ .open = DAC960_open,
+ .ioctl = DAC960_ioctl,
+ .media_changed = DAC960_media_changed,
+ .revalidate_disk = DAC960_revalidate_disk,
+};
+
+
+/*
+ DAC960_AnnounceDriver announces the Driver Version and Date, Author's Name,
+ Copyright Notice, and Electronic Mail Address.
+*/
+
+static void DAC960_AnnounceDriver(DAC960_Controller_T *Controller)
+{
+ DAC960_Announce("***** DAC960 RAID Driver Version "
+ DAC960_DriverVersion " of "
+ DAC960_DriverDate " *****\n", Controller);
+ DAC960_Announce("Copyright 1998-2001 by Leonard N. Zubkoff "
+ "<lnz@dandelion.com>\n", Controller);
+}
+
+
+/*
+ DAC960_Failure prints a standardized error message, and then returns false.
+*/
+
+static boolean DAC960_Failure(DAC960_Controller_T *Controller,
+ unsigned char *ErrorMessage)
+{
+ DAC960_Error("While configuring DAC960 PCI RAID Controller at\n",
+ Controller);
+ if (Controller->IO_Address == 0)
+ DAC960_Error("PCI Bus %d Device %d Function %d I/O Address N/A "
+ "PCI Address 0x%X\n", Controller,
+ Controller->Bus, Controller->Device,
+ Controller->Function, Controller->PCI_Address);
+ else DAC960_Error("PCI Bus %d Device %d Function %d I/O Address "
+ "0x%X PCI Address 0x%X\n", Controller,
+ Controller->Bus, Controller->Device,
+ Controller->Function, Controller->IO_Address,
+ Controller->PCI_Address);
+ DAC960_Error("%s FAILED - DETACHING\n", Controller, ErrorMessage);
+ return false;
+}
+
+/*
+ init_dma_loaf() and slice_dma_loaf() are helper functions for
+ aggregating the dma-mapped memory for a well-known collection of
+ data structures that are of different lengths.
+
+ These routines don't guarantee any alignment. The caller must
+ include any space needed for alignment in the sizes of the structures
+ that are passed in.
+ */
+
+static boolean init_dma_loaf(struct pci_dev *dev, struct dma_loaf *loaf,
+ size_t len)
+{
+ void *cpu_addr;
+ dma_addr_t dma_handle;
+
+ cpu_addr = pci_alloc_consistent(dev, len, &dma_handle);
+ if (cpu_addr == NULL)
+ return false;
+
+ loaf->cpu_free = loaf->cpu_base = cpu_addr;
+ loaf->dma_free =loaf->dma_base = dma_handle;
+ loaf->length = len;
+ memset(cpu_addr, 0, len);
+ return true;
+}
+
+static void *slice_dma_loaf(struct dma_loaf *loaf, size_t len,
+ dma_addr_t *dma_handle)
+{
+ void *cpu_end = loaf->cpu_free + len;
+ void *cpu_addr = loaf->cpu_free;
+
+ if (cpu_end > loaf->cpu_base + loaf->length)
+ BUG();
+ *dma_handle = loaf->dma_free;
+ loaf->cpu_free = cpu_end;
+ loaf->dma_free += len;
+ return cpu_addr;
+}
+
+static void free_dma_loaf(struct pci_dev *dev, struct dma_loaf *loaf_handle)
+{
+ if (loaf_handle->cpu_base != NULL)
+ pci_free_consistent(dev, loaf_handle->length,
+ loaf_handle->cpu_base, loaf_handle->dma_base);
+}
+
+
+/*
+ DAC960_CreateAuxiliaryStructures allocates and initializes the auxiliary
+ data structures for Controller. It returns true on success and false on
+ failure.
+*/
+
+static boolean DAC960_CreateAuxiliaryStructures(DAC960_Controller_T *Controller)
+{
+ int CommandAllocationLength, CommandAllocationGroupSize;
+ int CommandsRemaining = 0, CommandIdentifier, CommandGroupByteCount;
+ void *AllocationPointer = NULL;
+ void *ScatterGatherCPU = NULL;
+ dma_addr_t ScatterGatherDMA;
+ struct pci_pool *ScatterGatherPool;
+ void *RequestSenseCPU = NULL;
+ dma_addr_t RequestSenseDMA;
+ struct pci_pool *RequestSensePool = NULL;
+
+ if (Controller->FirmwareType == DAC960_V1_Controller)
+ {
+ CommandAllocationLength = offsetof(DAC960_Command_T, V1.EndMarker);
+ CommandAllocationGroupSize = DAC960_V1_CommandAllocationGroupSize;
+ ScatterGatherPool = pci_pool_create("DAC960_V1_ScatterGather",
+ Controller->PCIDevice,
+ DAC960_V1_ScatterGatherLimit * sizeof(DAC960_V1_ScatterGatherSegment_T),
+ sizeof(DAC960_V1_ScatterGatherSegment_T), 0);
+ if (ScatterGatherPool == NULL)
+ return DAC960_Failure(Controller,
+ "AUXILIARY STRUCTURE CREATION (SG)");
+ Controller->ScatterGatherPool = ScatterGatherPool;
+ }
+ else
+ {
+ CommandAllocationLength = offsetof(DAC960_Command_T, V2.EndMarker);
+ CommandAllocationGroupSize = DAC960_V2_CommandAllocationGroupSize;
+ ScatterGatherPool = pci_pool_create("DAC960_V2_ScatterGather",
+ Controller->PCIDevice,
+ DAC960_V2_ScatterGatherLimit * sizeof(DAC960_V2_ScatterGatherSegment_T),
+ sizeof(DAC960_V2_ScatterGatherSegment_T), 0);
+ if (ScatterGatherPool == NULL)
+ return DAC960_Failure(Controller,
+ "AUXILIARY STRUCTURE CREATION (SG)");
+ RequestSensePool = pci_pool_create("DAC960_V2_RequestSense",
+ Controller->PCIDevice, sizeof(DAC960_SCSI_RequestSense_T),
+ sizeof(int), 0);
+ if (RequestSensePool == NULL) {
+ pci_pool_destroy(ScatterGatherPool);
+ return DAC960_Failure(Controller,
+ "AUXILIARY STRUCTURE CREATION (SG)");
+ }
+ Controller->ScatterGatherPool = ScatterGatherPool;
+ Controller->V2.RequestSensePool = RequestSensePool;
+ }
+ Controller->CommandAllocationGroupSize = CommandAllocationGroupSize;
+ Controller->FreeCommands = NULL;
+ for (CommandIdentifier = 1;
+ CommandIdentifier <= Controller->DriverQueueDepth;
+ CommandIdentifier++)
+ {
+ DAC960_Command_T *Command;
+ if (--CommandsRemaining <= 0)
+ {
+ CommandsRemaining =
+ Controller->DriverQueueDepth - CommandIdentifier + 1;
+ if (CommandsRemaining > CommandAllocationGroupSize)
+ CommandsRemaining = CommandAllocationGroupSize;
+ CommandGroupByteCount =
+ CommandsRemaining * CommandAllocationLength;
+ AllocationPointer = kmalloc(CommandGroupByteCount, GFP_ATOMIC);
+ if (AllocationPointer == NULL)
+ return DAC960_Failure(Controller,
+ "AUXILIARY STRUCTURE CREATION");
+ memset(AllocationPointer, 0, CommandGroupByteCount);
+ }
+ Command = (DAC960_Command_T *) AllocationPointer;
+ AllocationPointer += CommandAllocationLength;
+ Command->CommandIdentifier = CommandIdentifier;
+ Command->Controller = Controller;
+ Command->Next = Controller->FreeCommands;
+ Controller->FreeCommands = Command;
+ Controller->Commands[CommandIdentifier-1] = Command;
+ ScatterGatherCPU = pci_pool_alloc(ScatterGatherPool, SLAB_ATOMIC,
+ &ScatterGatherDMA);
+ if (ScatterGatherCPU == NULL)
+ return DAC960_Failure(Controller, "AUXILIARY STRUCTURE CREATION");
+
+ if (RequestSensePool != NULL) {
+ RequestSenseCPU = pci_pool_alloc(RequestSensePool, SLAB_ATOMIC,
+ &RequestSenseDMA);
+ if (RequestSenseCPU == NULL) {
+ pci_pool_free(ScatterGatherPool, ScatterGatherCPU,
+ ScatterGatherDMA);
+ return DAC960_Failure(Controller,
+ "AUXILIARY STRUCTURE CREATION");
+ }
+ }
+ if (Controller->FirmwareType == DAC960_V1_Controller) {
+ Command->cmd_sglist = Command->V1.ScatterList;
+ Command->V1.ScatterGatherList =
+ (DAC960_V1_ScatterGatherSegment_T *)ScatterGatherCPU;
+ Command->V1.ScatterGatherListDMA = ScatterGatherDMA;
+ } else {
+ Command->cmd_sglist = Command->V2.ScatterList;
+ Command->V2.ScatterGatherList =
+ (DAC960_V2_ScatterGatherSegment_T *)ScatterGatherCPU;
+ Command->V2.ScatterGatherListDMA = ScatterGatherDMA;
+ Command->V2.RequestSense =
+ (DAC960_SCSI_RequestSense_T *)RequestSenseCPU;
+ Command->V2.RequestSenseDMA = RequestSenseDMA;
+ }
+ }
+ return true;
+}
+
+
+/*
+ DAC960_DestroyAuxiliaryStructures deallocates the auxiliary data
+ structures for Controller.
+*/
+
+static void DAC960_DestroyAuxiliaryStructures(DAC960_Controller_T *Controller)
+{
+ int i;
+ struct pci_pool *ScatterGatherPool = Controller->ScatterGatherPool;
+ struct pci_pool *RequestSensePool = NULL;
+ void *ScatterGatherCPU;
+ dma_addr_t ScatterGatherDMA;
+ void *RequestSenseCPU;
+ dma_addr_t RequestSenseDMA;
+ DAC960_Command_T *CommandGroup = NULL;
+
+
+ if (Controller->FirmwareType == DAC960_V2_Controller)
+ RequestSensePool = Controller->V2.RequestSensePool;
+
+ Controller->FreeCommands = NULL;
+ for (i = 0; i < Controller->DriverQueueDepth; i++)
+ {
+ DAC960_Command_T *Command = Controller->Commands[i];
+
+ if (Command == NULL)
+ continue;
+
+ if (Controller->FirmwareType == DAC960_V1_Controller) {
+ ScatterGatherCPU = (void *)Command->V1.ScatterGatherList;
+ ScatterGatherDMA = Command->V1.ScatterGatherListDMA;
+ RequestSenseCPU = NULL;
+ RequestSenseDMA = (dma_addr_t)0;
+ } else {
+ ScatterGatherCPU = (void *)Command->V2.ScatterGatherList;
+ ScatterGatherDMA = Command->V2.ScatterGatherListDMA;
+ RequestSenseCPU = (void *)Command->V2.RequestSense;
+ RequestSenseDMA = Command->V2.RequestSenseDMA;
+ }
+ if (ScatterGatherCPU != NULL)
+ pci_pool_free(ScatterGatherPool, ScatterGatherCPU, ScatterGatherDMA);
+ if (RequestSenseCPU != NULL)
+ pci_pool_free(RequestSensePool, RequestSenseCPU, RequestSenseDMA);
+
+ if ((Command->CommandIdentifier
+ % Controller->CommandAllocationGroupSize) == 1) {
+ /*
+ * We can't free the group of commands until all of the
+ * request sense and scatter gather dma structures are free.
+ * Remember the beginning of the group, but don't free it
+ * until we've reached the beginning of the next group.
+ */
+ if (CommandGroup != NULL)
+ kfree(CommandGroup);
+ CommandGroup = Command;
+ }
+ Controller->Commands[i] = NULL;
+ }
+ if (CommandGroup != NULL)
+ kfree(CommandGroup);
+
+ if (Controller->CombinedStatusBuffer != NULL)
+ {
+ kfree(Controller->CombinedStatusBuffer);
+ Controller->CombinedStatusBuffer = NULL;
+ Controller->CurrentStatusBuffer = NULL;
+ }
+
+ if (ScatterGatherPool != NULL)
+ pci_pool_destroy(ScatterGatherPool);
+ if (Controller->FirmwareType == DAC960_V1_Controller) return;
+
+ if (RequestSensePool != NULL)
+ pci_pool_destroy(RequestSensePool);
+
+ for (i = 0; i < DAC960_MaxLogicalDrives; i++)
+ if (Controller->V2.LogicalDeviceInformation[i] != NULL)
+ {
+ kfree(Controller->V2.LogicalDeviceInformation[i]);
+ Controller->V2.LogicalDeviceInformation[i] = NULL;
+ }
+
+ for (i = 0; i < DAC960_V2_MaxPhysicalDevices; i++)
+ {
+ if (Controller->V2.PhysicalDeviceInformation[i] != NULL)
+ {
+ kfree(Controller->V2.PhysicalDeviceInformation[i]);
+ Controller->V2.PhysicalDeviceInformation[i] = NULL;
+ }
+ if (Controller->V2.InquiryUnitSerialNumber[i] != NULL)
+ {
+ kfree(Controller->V2.InquiryUnitSerialNumber[i]);
+ Controller->V2.InquiryUnitSerialNumber[i] = NULL;
+ }
+ }
+}
+
+
+/*
+ DAC960_V1_ClearCommand clears critical fields of Command for DAC960 V1
+ Firmware Controllers.
+*/
+
+static inline void DAC960_V1_ClearCommand(DAC960_Command_T *Command)
+{
+ DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
+ memset(CommandMailbox, 0, sizeof(DAC960_V1_CommandMailbox_T));
+ Command->V1.CommandStatus = 0;
+}
+
+
+/*
+ DAC960_V2_ClearCommand clears critical fields of Command for DAC960 V2
+ Firmware Controllers.
+*/
+
+static inline void DAC960_V2_ClearCommand(DAC960_Command_T *Command)
+{
+ DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
+ memset(CommandMailbox, 0, sizeof(DAC960_V2_CommandMailbox_T));
+ Command->V2.CommandStatus = 0;
+}
+
+
+/*
+ DAC960_AllocateCommand allocates a Command structure from Controller's
+ free list. During driver initialization, a special initialization command
+ has been placed on the free list to guarantee that command allocation can
+ never fail.
+*/
+
+static inline DAC960_Command_T *DAC960_AllocateCommand(DAC960_Controller_T
+ *Controller)
+{
+ DAC960_Command_T *Command = Controller->FreeCommands;
+ if (Command == NULL) return NULL;
+ Controller->FreeCommands = Command->Next;
+ Command->Next = NULL;
+ return Command;
+}
+
+
+/*
+ DAC960_DeallocateCommand deallocates Command, returning it to Controller's
+ free list.
+*/
+
+static inline void DAC960_DeallocateCommand(DAC960_Command_T *Command)
+{
+ DAC960_Controller_T *Controller = Command->Controller;
+
+ Command->Request = NULL;
+ Command->Next = Controller->FreeCommands;
+ Controller->FreeCommands = Command;
+}
+
+
+/*
+ DAC960_WaitForCommand waits for a wake_up on Controller's Command Wait Queue.
+*/
+
+static void DAC960_WaitForCommand(DAC960_Controller_T *Controller)
+{
+ spin_unlock_irq(&Controller->queue_lock);
+ __wait_event(Controller->CommandWaitQueue, Controller->FreeCommands);
+ spin_lock_irq(&Controller->queue_lock);
+}
+
+
+/*
+ DAC960_BA_QueueCommand queues Command for DAC960 BA Series Controllers.
+*/
+
+static void DAC960_BA_QueueCommand(DAC960_Command_T *Command)
+{
+ DAC960_Controller_T *Controller = Command->Controller;
+ void __iomem *ControllerBaseAddress = Controller->BaseAddress;
+ DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
+ DAC960_V2_CommandMailbox_T *NextCommandMailbox =
+ Controller->V2.NextCommandMailbox;
+ CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier;
+ DAC960_BA_WriteCommandMailbox(NextCommandMailbox, CommandMailbox);
+ if (Controller->V2.PreviousCommandMailbox1->Words[0] == 0 ||
+ Controller->V2.PreviousCommandMailbox2->Words[0] == 0)
+ DAC960_BA_MemoryMailboxNewCommand(ControllerBaseAddress);
+ Controller->V2.PreviousCommandMailbox2 =
+ Controller->V2.PreviousCommandMailbox1;
+ Controller->V2.PreviousCommandMailbox1 = NextCommandMailbox;
+ if (++NextCommandMailbox > Controller->V2.LastCommandMailbox)
+ NextCommandMailbox = Controller->V2.FirstCommandMailbox;
+ Controller->V2.NextCommandMailbox = NextCommandMailbox;
+}
+
+
+/*
+ DAC960_LP_QueueCommand queues Command for DAC960 LP Series Controllers.
+*/
+
+static void DAC960_LP_QueueCommand(DAC960_Command_T *Command)
+{
+ DAC960_Controller_T *Controller = Command->Controller;
+ void __iomem *ControllerBaseAddress = Controller->BaseAddress;
+ DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
+ DAC960_V2_CommandMailbox_T *NextCommandMailbox =
+ Controller->V2.NextCommandMailbox;
+ CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier;
+ DAC960_LP_WriteCommandMailbox(NextCommandMailbox, CommandMailbox);
+ if (Controller->V2.PreviousCommandMailbox1->Words[0] == 0 ||
+ Controller->V2.PreviousCommandMailbox2->Words[0] == 0)
+ DAC960_LP_MemoryMailboxNewCommand(ControllerBaseAddress);
+ Controller->V2.PreviousCommandMailbox2 =
+ Controller->V2.PreviousCommandMailbox1;
+ Controller->V2.PreviousCommandMailbox1 = NextCommandMailbox;
+ if (++NextCommandMailbox > Controller->V2.LastCommandMailbox)
+ NextCommandMailbox = Controller->V2.FirstCommandMailbox;
+ Controller->V2.NextCommandMailbox = NextCommandMailbox;
+}
+
+
+/*
+ DAC960_LA_QueueCommandDualMode queues Command for DAC960 LA Series
+ Controllers with Dual Mode Firmware.
+*/
+
+static void DAC960_LA_QueueCommandDualMode(DAC960_Command_T *Command)
+{
+ DAC960_Controller_T *Controller = Command->Controller;
+ void __iomem *ControllerBaseAddress = Controller->BaseAddress;
+ DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
+ DAC960_V1_CommandMailbox_T *NextCommandMailbox =
+ Controller->V1.NextCommandMailbox;
+ CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier;
+ DAC960_LA_WriteCommandMailbox(NextCommandMailbox, CommandMailbox);
+ if (Controller->V1.PreviousCommandMailbox1->Words[0] == 0 ||
+ Controller->V1.PreviousCommandMailbox2->Words[0] == 0)
+ DAC960_LA_MemoryMailboxNewCommand(ControllerBaseAddress);
+ Controller->V1.PreviousCommandMailbox2 =
+ Controller->V1.PreviousCommandMailbox1;
+ Controller->V1.PreviousCommandMailbox1 = NextCommandMailbox;
+ if (++NextCommandMailbox > Controller->V1.LastCommandMailbox)
+ NextCommandMailbox = Controller->V1.FirstCommandMailbox;
+ Controller->V1.NextCommandMailbox = NextCommandMailbox;
+}
+
+
+/*
+ DAC960_LA_QueueCommandSingleMode queues Command for DAC960 LA Series
+ Controllers with Single Mode Firmware.
+*/
+
+static void DAC960_LA_QueueCommandSingleMode(DAC960_Command_T *Command)
+{
+ DAC960_Controller_T *Controller = Command->Controller;
+ void __iomem *ControllerBaseAddress = Controller->BaseAddress;
+ DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
+ DAC960_V1_CommandMailbox_T *NextCommandMailbox =
+ Controller->V1.NextCommandMailbox;
+ CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier;
+ DAC960_LA_WriteCommandMailbox(NextCommandMailbox, CommandMailbox);
+ if (Controller->V1.PreviousCommandMailbox1->Words[0] == 0 ||
+ Controller->V1.PreviousCommandMailbox2->Words[0] == 0)
+ DAC960_LA_HardwareMailboxNewCommand(ControllerBaseAddress);
+ Controller->V1.PreviousCommandMailbox2 =
+ Controller->V1.PreviousCommandMailbox1;
+ Controller->V1.PreviousCommandMailbox1 = NextCommandMailbox;
+ if (++NextCommandMailbox > Controller->V1.LastCommandMailbox)
+ NextCommandMailbox = Controller->V1.FirstCommandMailbox;
+ Controller->V1.NextCommandMailbox = NextCommandMailbox;
+}
+
+
+/*
+ DAC960_PG_QueueCommandDualMode queues Command for DAC960 PG Series
+ Controllers with Dual Mode Firmware.
+*/
+
+static void DAC960_PG_QueueCommandDualMode(DAC960_Command_T *Command)
+{
+ DAC960_Controller_T *Controller = Command->Controller;
+ void __iomem *ControllerBaseAddress = Controller->BaseAddress;
+ DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
+ DAC960_V1_CommandMailbox_T *NextCommandMailbox =
+ Controller->V1.NextCommandMailbox;
+ CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier;
+ DAC960_PG_WriteCommandMailbox(NextCommandMailbox, CommandMailbox);
+ if (Controller->V1.PreviousCommandMailbox1->Words[0] == 0 ||
+ Controller->V1.PreviousCommandMailbox2->Words[0] == 0)
+ DAC960_PG_MemoryMailboxNewCommand(ControllerBaseAddress);
+ Controller->V1.PreviousCommandMailbox2 =
+ Controller->V1.PreviousCommandMailbox1;
+ Controller->V1.PreviousCommandMailbox1 = NextCommandMailbox;
+ if (++NextCommandMailbox > Controller->V1.LastCommandMailbox)
+ NextCommandMailbox = Controller->V1.FirstCommandMailbox;
+ Controller->V1.NextCommandMailbox = NextCommandMailbox;
+}
+
+
+/*
+ DAC960_PG_QueueCommandSingleMode queues Command for DAC960 PG Series
+ Controllers with Single Mode Firmware.
+*/
+
+static void DAC960_PG_QueueCommandSingleMode(DAC960_Command_T *Command)
+{
+ DAC960_Controller_T *Controller = Command->Controller;
+ void __iomem *ControllerBaseAddress = Controller->BaseAddress;
+ DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
+ DAC960_V1_CommandMailbox_T *NextCommandMailbox =
+ Controller->V1.NextCommandMailbox;
+ CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier;
+ DAC960_PG_WriteCommandMailbox(NextCommandMailbox, CommandMailbox);
+ if (Controller->V1.PreviousCommandMailbox1->Words[0] == 0 ||
+ Controller->V1.PreviousCommandMailbox2->Words[0] == 0)
+ DAC960_PG_HardwareMailboxNewCommand(ControllerBaseAddress);
+ Controller->V1.PreviousCommandMailbox2 =
+ Controller->V1.PreviousCommandMailbox1;
+ Controller->V1.PreviousCommandMailbox1 = NextCommandMailbox;
+ if (++NextCommandMailbox > Controller->V1.LastCommandMailbox)
+ NextCommandMailbox = Controller->V1.FirstCommandMailbox;
+ Controller->V1.NextCommandMailbox = NextCommandMailbox;
+}
+
+
+/*
+ DAC960_PD_QueueCommand queues Command for DAC960 PD Series Controllers.
+*/
+
+static void DAC960_PD_QueueCommand(DAC960_Command_T *Command)
+{
+ DAC960_Controller_T *Controller = Command->Controller;
+ void __iomem *ControllerBaseAddress = Controller->BaseAddress;
+ DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
+ CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier;
+ while (DAC960_PD_MailboxFullP(ControllerBaseAddress))
+ udelay(1);
+ DAC960_PD_WriteCommandMailbox(ControllerBaseAddress, CommandMailbox);
+ DAC960_PD_NewCommand(ControllerBaseAddress);
+}
+
+
+/*
+ DAC960_P_QueueCommand queues Command for DAC960 P Series Controllers.
+*/
+
+static void DAC960_P_QueueCommand(DAC960_Command_T *Command)
+{
+ DAC960_Controller_T *Controller = Command->Controller;
+ void __iomem *ControllerBaseAddress = Controller->BaseAddress;
+ DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
+ CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier;
+ switch (CommandMailbox->Common.CommandOpcode)
+ {
+ case DAC960_V1_Enquiry:
+ CommandMailbox->Common.CommandOpcode = DAC960_V1_Enquiry_Old;
+ break;
+ case DAC960_V1_GetDeviceState:
+ CommandMailbox->Common.CommandOpcode = DAC960_V1_GetDeviceState_Old;
+ break;
+ case DAC960_V1_Read:
+ CommandMailbox->Common.CommandOpcode = DAC960_V1_Read_Old;
+ DAC960_PD_To_P_TranslateReadWriteCommand(CommandMailbox);
+ break;
+ case DAC960_V1_Write:
+ CommandMailbox->Common.CommandOpcode = DAC960_V1_Write_Old;
+ DAC960_PD_To_P_TranslateReadWriteCommand(CommandMailbox);
+ break;
+ case DAC960_V1_ReadWithScatterGather:
+ CommandMailbox->Common.CommandOpcode =
+ DAC960_V1_ReadWithScatterGather_Old;
+ DAC960_PD_To_P_TranslateReadWriteCommand(CommandMailbox);
+ break;
+ case DAC960_V1_WriteWithScatterGather:
+ CommandMailbox->Common.CommandOpcode =
+ DAC960_V1_WriteWithScatterGather_Old;
+ DAC960_PD_To_P_TranslateReadWriteCommand(CommandMailbox);
+ break;
+ default:
+ break;
+ }
+ while (DAC960_PD_MailboxFullP(ControllerBaseAddress))
+ udelay(1);
+ DAC960_PD_WriteCommandMailbox(ControllerBaseAddress, CommandMailbox);
+ DAC960_PD_NewCommand(ControllerBaseAddress);
+}
+
+
+/*
+ DAC960_ExecuteCommand executes Command and waits for completion.
+*/
+
+static void DAC960_ExecuteCommand(DAC960_Command_T *Command)
+{
+ DAC960_Controller_T *Controller = Command->Controller;
+ DECLARE_COMPLETION(Completion);
+ unsigned long flags;
+ Command->Completion = &Completion;
+
+ spin_lock_irqsave(&Controller->queue_lock, flags);
+ DAC960_QueueCommand(Command);
+ spin_unlock_irqrestore(&Controller->queue_lock, flags);
+
+ if (in_interrupt())
+ return;
+ wait_for_completion(&Completion);
+}
+
+
+/*
+ DAC960_V1_ExecuteType3 executes a DAC960 V1 Firmware Controller Type 3
+ Command and waits for completion. It returns true on success and false
+ on failure.
+*/
+
+static boolean DAC960_V1_ExecuteType3(DAC960_Controller_T *Controller,
+ DAC960_V1_CommandOpcode_T CommandOpcode,
+ dma_addr_t DataDMA)
+{
+ DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
+ DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
+ DAC960_V1_CommandStatus_T CommandStatus;
+ DAC960_V1_ClearCommand(Command);
+ Command->CommandType = DAC960_ImmediateCommand;
+ CommandMailbox->Type3.CommandOpcode = CommandOpcode;
+ CommandMailbox->Type3.BusAddress = DataDMA;
+ DAC960_ExecuteCommand(Command);
+ CommandStatus = Command->V1.CommandStatus;
+ DAC960_DeallocateCommand(Command);
+ return (CommandStatus == DAC960_V1_NormalCompletion);
+}
+
+
+/*
+ DAC960_V1_ExecuteTypeB executes a DAC960 V1 Firmware Controller Type 3B
+ Command and waits for completion. It returns true on success and false
+ on failure.
+*/
+
+static boolean DAC960_V1_ExecuteType3B(DAC960_Controller_T *Controller,
+ DAC960_V1_CommandOpcode_T CommandOpcode,
+ unsigned char CommandOpcode2,
+ dma_addr_t DataDMA)
+{
+ DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
+ DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
+ DAC960_V1_CommandStatus_T CommandStatus;
+ DAC960_V1_ClearCommand(Command);
+ Command->CommandType = DAC960_ImmediateCommand;
+ CommandMailbox->Type3B.CommandOpcode = CommandOpcode;
+ CommandMailbox->Type3B.CommandOpcode2 = CommandOpcode2;
+ CommandMailbox->Type3B.BusAddress = DataDMA;
+ DAC960_ExecuteCommand(Command);
+ CommandStatus = Command->V1.CommandStatus;
+ DAC960_DeallocateCommand(Command);
+ return (CommandStatus == DAC960_V1_NormalCompletion);
+}
+
+
+/*
+ DAC960_V1_ExecuteType3D executes a DAC960 V1 Firmware Controller Type 3D
+ Command and waits for completion. It returns true on success and false
+ on failure.
+*/
+
+static boolean DAC960_V1_ExecuteType3D(DAC960_Controller_T *Controller,
+ DAC960_V1_CommandOpcode_T CommandOpcode,
+ unsigned char Channel,
+ unsigned char TargetID,
+ dma_addr_t DataDMA)
+{
+ DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
+ DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
+ DAC960_V1_CommandStatus_T CommandStatus;
+ DAC960_V1_ClearCommand(Command);
+ Command->CommandType = DAC960_ImmediateCommand;
+ CommandMailbox->Type3D.CommandOpcode = CommandOpcode;
+ CommandMailbox->Type3D.Channel = Channel;
+ CommandMailbox->Type3D.TargetID = TargetID;
+ CommandMailbox->Type3D.BusAddress = DataDMA;
+ DAC960_ExecuteCommand(Command);
+ CommandStatus = Command->V1.CommandStatus;
+ DAC960_DeallocateCommand(Command);
+ return (CommandStatus == DAC960_V1_NormalCompletion);
+}
+
+
+/*
+ DAC960_V2_GeneralInfo executes a DAC960 V2 Firmware General Information
+ Reading IOCTL Command and waits for completion. It returns true on success
+ and false on failure.
+
+ Return data in The controller's HealthStatusBuffer, which is dma-able memory
+*/
+
+static boolean DAC960_V2_GeneralInfo(DAC960_Controller_T *Controller)
+{
+ DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
+ DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
+ DAC960_V2_CommandStatus_T CommandStatus;
+ DAC960_V2_ClearCommand(Command);
+ Command->CommandType = DAC960_ImmediateCommand;
+ CommandMailbox->Common.CommandOpcode = DAC960_V2_IOCTL;
+ CommandMailbox->Common.CommandControlBits
+ .DataTransferControllerToHost = true;
+ CommandMailbox->Common.CommandControlBits
+ .NoAutoRequestSense = true;
+ CommandMailbox->Common.DataTransferSize = sizeof(DAC960_V2_HealthStatusBuffer_T);
+ CommandMailbox->Common.IOCTL_Opcode = DAC960_V2_GetHealthStatus;
+ CommandMailbox->Common.DataTransferMemoryAddress
+ .ScatterGatherSegments[0]
+ .SegmentDataPointer =
+ Controller->V2.HealthStatusBufferDMA;
+ CommandMailbox->Common.DataTransferMemoryAddress
+ .ScatterGatherSegments[0]
+ .SegmentByteCount =
+ CommandMailbox->Common.DataTransferSize;
+ DAC960_ExecuteCommand(Command);
+ CommandStatus = Command->V2.CommandStatus;
+ DAC960_DeallocateCommand(Command);
+ return (CommandStatus == DAC960_V2_NormalCompletion);
+}
+
+
+/*
+ DAC960_V2_ControllerInfo executes a DAC960 V2 Firmware Controller
+ Information Reading IOCTL Command and waits for completion. It returns
+ true on success and false on failure.
+
+ Data is returned in the controller's V2.NewControllerInformation dma-able
+ memory buffer.
+*/
+
+static boolean DAC960_V2_NewControllerInfo(DAC960_Controller_T *Controller)
+{
+ DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
+ DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
+ DAC960_V2_CommandStatus_T CommandStatus;
+ DAC960_V2_ClearCommand(Command);
+ Command->CommandType = DAC960_ImmediateCommand;
+ CommandMailbox->ControllerInfo.CommandOpcode = DAC960_V2_IOCTL;
+ CommandMailbox->ControllerInfo.CommandControlBits
+ .DataTransferControllerToHost = true;
+ CommandMailbox->ControllerInfo.CommandControlBits
+ .NoAutoRequestSense = true;
+ CommandMailbox->ControllerInfo.DataTransferSize = sizeof(DAC960_V2_ControllerInfo_T);
+ CommandMailbox->ControllerInfo.ControllerNumber = 0;
+ CommandMailbox->ControllerInfo.IOCTL_Opcode = DAC960_V2_GetControllerInfo;
+ CommandMailbox->ControllerInfo.DataTransferMemoryAddress
+ .ScatterGatherSegments[0]
+ .SegmentDataPointer =
+ Controller->V2.NewControllerInformationDMA;
+ CommandMailbox->ControllerInfo.DataTransferMemoryAddress
+ .ScatterGatherSegments[0]
+ .SegmentByteCount =
+ CommandMailbox->ControllerInfo.DataTransferSize;
+ DAC960_ExecuteCommand(Command);
+ CommandStatus = Command->V2.CommandStatus;
+ DAC960_DeallocateCommand(Command);
+ return (CommandStatus == DAC960_V2_NormalCompletion);
+}
+
+
+/*
+ DAC960_V2_LogicalDeviceInfo executes a DAC960 V2 Firmware Controller Logical
+ Device Information Reading IOCTL Command and waits for completion. It
+ returns true on success and false on failure.
+
+ Data is returned in the controller's V2.NewLogicalDeviceInformation
+*/
+
+static boolean DAC960_V2_NewLogicalDeviceInfo(DAC960_Controller_T *Controller,
+ unsigned short LogicalDeviceNumber)
+{
+ DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
+ DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
+ DAC960_V2_CommandStatus_T CommandStatus;
+
+ DAC960_V2_ClearCommand(Command);
+ Command->CommandType = DAC960_ImmediateCommand;
+ CommandMailbox->LogicalDeviceInfo.CommandOpcode =
+ DAC960_V2_IOCTL;
+ CommandMailbox->LogicalDeviceInfo.CommandControlBits
+ .DataTransferControllerToHost = true;
+ CommandMailbox->LogicalDeviceInfo.CommandControlBits
+ .NoAutoRequestSense = true;
+ CommandMailbox->LogicalDeviceInfo.DataTransferSize =
+ sizeof(DAC960_V2_LogicalDeviceInfo_T);
+ CommandMailbox->LogicalDeviceInfo.LogicalDevice.LogicalDeviceNumber =
+ LogicalDeviceNumber;
+ CommandMailbox->LogicalDeviceInfo.IOCTL_Opcode = DAC960_V2_GetLogicalDeviceInfoValid;
+ CommandMailbox->LogicalDeviceInfo.DataTransferMemoryAddress
+ .ScatterGatherSegments[0]
+ .SegmentDataPointer =
+ Controller->V2.NewLogicalDeviceInformationDMA;
+ CommandMailbox->LogicalDeviceInfo.DataTransferMemoryAddress
+ .ScatterGatherSegments[0]
+ .SegmentByteCount =
+ CommandMailbox->LogicalDeviceInfo.DataTransferSize;
+ DAC960_ExecuteCommand(Command);
+ CommandStatus = Command->V2.CommandStatus;
+ DAC960_DeallocateCommand(Command);
+ return (CommandStatus == DAC960_V2_NormalCompletion);
+}
+
+
+/*
+ DAC960_V2_PhysicalDeviceInfo executes a DAC960 V2 Firmware Controller "Read
+ Physical Device Information" IOCTL Command and waits for completion. It
+ returns true on success and false on failure.
+
+ The Channel, TargetID, LogicalUnit arguments should be 0 the first time
+ this function is called for a given controller. This will return data
+ for the "first" device on that controller. The returned data includes a
+ Channel, TargetID, LogicalUnit that can be passed in to this routine to
+ get data for the NEXT device on that controller.
+
+ Data is stored in the controller's V2.NewPhysicalDeviceInfo dma-able
+ memory buffer.
+
+*/
+
+static boolean DAC960_V2_NewPhysicalDeviceInfo(DAC960_Controller_T *Controller,
+ unsigned char Channel,
+ unsigned char TargetID,
+ unsigned char LogicalUnit)
+{
+ DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);