diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/block/DAC960.c |
Linux-2.6.12-rc2v2.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.c | 7099 |
1 files changed, 7099 insertions, 0 deletions
diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c new file mode 100644 index 00000000000..423bbf2000d --- /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,< |