| /* |
| |
| Linux Driver for Mylex DAC960/AcceleRAID/eXtremeRAID PCI RAID Controllers |
| |
| Copyright 1998-2001 by Leonard N. Zubkoff <lnz@dandelion.com> |
| Portions Copyright 2002 by Mylex (An IBM Business Unit) |
| |
| 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.49" |
| #define DAC960_DriverDate "21 Aug 2007" |
| |
| |
| #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/dma-mapping.h> |
| #include <linux/interrupt.h> |
| #include <linux/ioport.h> |
| #include <linux/mm.h> |
| #include <linux/slab.h> |
| #include <linux/mutex.h> |
| #include <linux/proc_fs.h> |
| #include <linux/seq_file.h> |
| #include <linux/reboot.h> |
| #include <linux/spinlock.h> |
| #include <linux/timer.h> |
| #include <linux/pci.h> |
| #include <linux/init.h> |
| #include <linux/jiffies.h> |
| #include <linux/random.h> |
| #include <linux/scatterlist.h> |
| #include <asm/io.h> |
| #include <linux/uaccess.h> |
| #include "DAC960.h" |
| |
| #define DAC960_GAM_MINOR 252 |
| |
| |
| static DEFINE_MUTEX(DAC960_mutex); |
| 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 block_device *bdev, fmode_t mode) |
| { |
| struct gendisk *disk = bdev->bd_disk; |
| DAC960_Controller_T *p = disk->queue->queuedata; |
| int drive_nr = (long)disk->private_data; |
| int ret = -ENXIO; |
| |
| mutex_lock(&DAC960_mutex); |
| if (p->FirmwareType == DAC960_V1_Controller) { |
| if (p->V1.LogicalDriveInformation[drive_nr]. |
| LogicalDriveState == DAC960_V1_LogicalDrive_Offline) |
| goto out; |
| } else { |
| DAC960_V2_LogicalDeviceInfo_T *i = |
| p->V2.LogicalDeviceInformation[drive_nr]; |
| if (!i || i->LogicalDeviceState == DAC960_V2_LogicalDevice_Offline) |
| goto out; |
| } |
| |
| check_disk_change(bdev); |
| |
| if (!get_capacity(p->disks[drive_nr])) |
| goto out; |
| ret = 0; |
| out: |
| mutex_unlock(&DAC960_mutex); |
| return ret; |
| } |
| |
| static int DAC960_getgeo(struct block_device *bdev, struct hd_geometry *geo) |
| { |
| struct gendisk *disk = bdev->bd_disk; |
| DAC960_Controller_T *p = disk->queue->queuedata; |
| int drive_nr = (long)disk->private_data; |
| |
| if (p->FirmwareType == DAC960_V1_Controller) { |
| geo->heads = p->V1.GeometryTranslationHeads; |
| geo->sectors = p->V1.GeometryTranslationSectors; |
| geo->cylinders = p->V1.LogicalDriveInformation[drive_nr]. |
| LogicalDriveSize / (geo->heads * geo->sectors); |
| } else { |
| DAC960_V2_LogicalDeviceInfo_T *i = |
| p->V2.LogicalDeviceInformation[drive_nr]; |
| switch (i->DriveGeometry) { |
| case DAC960_V2_Geometry_128_32: |
| geo->heads = 128; |
| geo->sectors = 32; |
| break; |
| case DAC960_V2_Geometry_255_63: |
| geo->heads = 255; |
| geo->sectors = 63; |
| break; |
| default: |
| DAC960_Error("Illegal Logical Device Geometry %d\n", |
| p, i->DriveGeometry); |
| return -EINVAL; |
| } |
| |
| geo->cylinders = i->ConfigurableDeviceSize / |
| (geo->heads * geo->sectors); |
| } |
| |
| return 0; |
| } |
| |
| static unsigned int DAC960_check_events(struct gendisk *disk, |
| unsigned int clearing) |
| { |
| DAC960_Controller_T *p = disk->queue->queuedata; |
| int drive_nr = (long)disk->private_data; |
| |
| if (!p->LogicalDriveInitiallyAccessible[drive_nr]) |
| return DISK_EVENT_MEDIA_CHANGE; |
| 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 const struct block_device_operations DAC960_BlockDeviceOperations = { |
| .owner = THIS_MODULE, |
| .open = DAC960_open, |
| .getgeo = DAC960_getgeo, |
| .check_events = DAC960_check_events, |
| .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 bool 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 bool 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; |
| |
| BUG_ON(cpu_end > loaf->cpu_base + loaf->length); |
| *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 bool 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 = kzalloc(CommandGroupByteCount, GFP_ATOMIC); |
| if (AllocationPointer == NULL) |
| return DAC960_Failure(Controller, |
| "AUXILIARY STRUCTURE CREATION"); |
| } |
| 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, GFP_ATOMIC, |
| &ScatterGatherDMA); |
| if (ScatterGatherCPU == NULL) |
| return DAC960_Failure(Controller, "AUXILIARY STRUCTURE CREATION"); |
| |
| if (RequestSensePool != NULL) { |
| RequestSenseCPU = pci_pool_alloc(RequestSensePool, GFP_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; |
| sg_init_table(Command->cmd_sglist, DAC960_V1_ScatterGatherLimit); |
| } 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; |
| sg_init_table(Command->cmd_sglist, DAC960_V2_ScatterGatherLimit); |
| } |
| } |
| 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. |
| */ |
| kfree(CommandGroup); |
| CommandGroup = Command; |
| } |
| Controller->Commands[i] = 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++) { |
| kfree(Controller->V2.LogicalDeviceInformation[i]); |
| Controller->V2.LogicalDeviceInformation[i] = NULL; |
| } |
| |
| for (i = 0; i < DAC960_V2_MaxPhysicalDevices; i++) |
| { |
| kfree(Controller->V2.PhysicalDeviceInformation[i]); |
| Controller->V2.PhysicalDeviceInformation[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_GEM_QueueCommand queues Command for DAC960 GEM Series Controllers. |
| */ |
| |
| static void DAC960_GEM_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_GEM_WriteCommandMailbox(NextCommandMailbox, CommandMailbox); |
| |
| if (Controller->V2.PreviousCommandMailbox1->Words[0] == 0 || |
| Controller->V2.PreviousCommandMailbox2->Words[0] == 0) |
| DAC960_GEM_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_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_ONSTACK(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 bool 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 bool 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 bool 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 bool 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 bool 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 bool 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 bool DAC960_V2_NewPhysicalDeviceInfo(DAC960_Controller_T *Controller, |
| unsigned char Channel, |
| unsigned char TargetID, |
| unsigned char LogicalUnit) |
| { |
| DAC960_Command_T *Command = DAC960_AllocateCommand(Controller); |
| DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox; |
| DAC960_V2_CommandStatus_T CommandStatus; |
| |
| DAC960_V2_ClearCommand(Command); |
| Command->CommandType = DAC960_ImmediateCommand; |
| CommandMailbox->PhysicalDeviceInfo.CommandOpcode = DAC960_V2_IOCTL; |
| CommandMailbox->PhysicalDeviceInfo.CommandControlBits |
| .DataTransferControllerToHost = true; |
| CommandMailbox->PhysicalDeviceInfo.CommandControlBits |
| .NoAutoRequestSense = true; |
| CommandMailbox->PhysicalDeviceInfo.DataTransferSize = |
| sizeof(DAC960_V2_PhysicalDeviceInfo_T); |
| CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.LogicalUnit = LogicalUnit; |
| CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.TargetID = TargetID; |
| CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.Channel = Channel; |
| CommandMailbox->PhysicalDeviceInfo.IOCTL_Opcode = |
| DAC960_V2_GetPhysicalDeviceInfoValid; |
| CommandMailbox->PhysicalDeviceInfo.DataTransferMemoryAddress |
| .ScatterGatherSegments[0] |
| .SegmentDataPointer = |
| Controller->V2.NewPhysicalDeviceInformationDMA; |
| CommandMailbox->PhysicalDeviceInfo.DataTransferMemoryAddress |
| .ScatterGatherSegments[0] |
| .SegmentByteCount = |
| CommandMailbox->PhysicalDeviceInfo.DataTransferSize; |
| DAC960_ExecuteCommand(Command); |
| CommandStatus = Command->V2.CommandStatus; |
| DAC960_DeallocateCommand(Command); |
| return (CommandStatus == DAC960_V2_NormalCompletion); |
| } |
| |
| |
| static void DAC960_V2_ConstructNewUnitSerialNumber( |
| DAC960_Controller_T *Controller, |
| DAC960_V2_CommandMailbox_T *CommandMailbox, int Channel, int TargetID, |
| int LogicalUnit) |
| { |
| CommandMailbox->SCSI_10.CommandOpcode = DAC960_V2_SCSI_10_Passthru; |
| CommandMailbox->SCSI_10.CommandControlBits |
| .DataTransferControllerToHost = true; |
| CommandMailbox->SCSI_10.CommandControlBits |
| .NoAutoRequestSense = true; |
| CommandMailbox->SCSI_10.DataTransferSize = |
| sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T); |
| CommandMailbox->SCSI_10.PhysicalDevice.LogicalUnit = LogicalUnit; |
| CommandMailbox->SCSI_10.PhysicalDevice.TargetID = TargetID; |
| CommandMailbox->SCSI_10.PhysicalDevice.Channel = Channel; |
| CommandMailbox->SCSI_10.CDBLength = 6; |
| CommandMailbox->SCSI_10.SCSI_CDB[0] = 0x12; /* INQUIRY */ |
| CommandMailbox->SCSI_10.SCSI_CDB[1] = 1; /* EVPD = 1 */ |
| CommandMailbox->SCSI_10.SCSI_CDB[2] = 0x80; /* Page Code */ |
| CommandMailbox->SCSI_10.SCSI_CDB[3] = 0; /* Reserved */ |
| CommandMailbox->SCSI_10.SCSI_CDB[4] = |
| sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T); |
| CommandMailbox->SCSI_10.SCSI_CDB[5] = 0; /* Control */ |
| CommandMailbox->SCSI_10.DataTransferMemoryAddress |
| .ScatterGatherSegments[0] |
| .SegmentDataPointer = |
| Controller->V2.NewInquiryUnitSerialNumberDMA; |
| CommandMailbox->SCSI_10.DataTransferMemoryAddress |
| .ScatterGatherSegments[0] |
| .SegmentByteCount = |
| CommandMailbox->SCSI_10.DataTransferSize; |
| } |
| |
| |
| /* |
| DAC960_V2_NewUnitSerialNumber executes an SCSI pass-through |
| Inquiry command to a SCSI device identified by Channel number, |
| Target id, Logical Unit Number. This function Waits for completion |
| of the command. |
| |
| The return data includes Unit Serial Number information for the |
| specified device. |
| |
| Data is stored in the controller's V2.NewPhysicalDeviceInfo dma-able |
| memory buffer. |
| */ |
| |
| static bool DAC960_V2_NewInquiryUnitSerialNumber(DAC960_Controller_T *Controller, |
| int Channel, int TargetID, int LogicalUnit) |
| { |
| DAC960_Command_T *Command; |
| DAC960_V2_CommandMailbox_T *CommandMailbox; |
| DAC960_V2_CommandStatus_T CommandStatus; |
| |
| Command = DAC960_AllocateCommand(Controller); |
| CommandMailbox = &Command->V2.CommandMailbox; |
| DAC960_V2_ClearCommand(Command); |
| Command->CommandType = DAC960_ImmediateCommand; |
| |
| DAC960_V2_ConstructNewUnitSerialNumber(Controller, CommandMailbox, |
| Channel, TargetID, LogicalUnit); |
| |
| DAC960_ExecuteCommand(Command); |
| CommandStatus = Command->V2.CommandStatus; |
| DAC960_DeallocateCommand(Command); |
| return (CommandStatus == DAC960_V2_NormalCompletion); |
| } |
| |
| |
| /* |
| DAC960_V2_DeviceOperation executes a DAC960 V2 Firmware Controller Device |
| Operation IOCTL Command and waits for completion. It returns true on |
| success and false on failure. |
| */ |
| |
| static bool DAC960_V2_DeviceOperation(DAC960_Controller_T *Controller, |
| DAC960_V2_IOCTL_Opcode_T IOCTL_Opcode, |
| DAC960_V2_OperationDevice_T |
| OperationDevice) |
| { |
| DAC960_Command_T *Command = DAC960_AllocateCommand(Controller); |
| DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox; |
| DAC960_V2_CommandStatus_T CommandStatus; |
| DAC960_V2_ClearCommand(Command); |
| Command->CommandType = DAC960_ImmediateCommand; |
| CommandMailbox->DeviceOperation.CommandOpcode = DAC960_V2_IOCTL; |
| CommandMailbox->DeviceOperation.CommandControlBits |
| .DataTransferControllerToHost = true; |
| CommandMailbox->DeviceOperation.CommandControlBits |
| .NoAutoRequestSense = true; |
| CommandMailbox->DeviceOperation.IOCTL_Opcode = IOCTL_Opcode; |
| CommandMailbox->DeviceOperation.OperationDevice = OperationDevice; |
| DAC960_ExecuteCommand(Command); |
| CommandStatus = Command->V2.CommandStatus; |
| DAC960_DeallocateCommand(Command); |
| return (CommandStatus == DAC960_V2_NormalCompletion); |
| } |
| |
| |
| /* |
| DAC960_V1_EnableMemoryMailboxInterface enables the Memory Mailbox Interface |
| for DAC960 V1 Firmware Controllers. |
| |
| PD and P controller types have no memory mailbox, but still need the |
| other dma mapped memory. |
| */ |
| |
| static bool DAC960_V1_EnableMemoryMailboxInterface(DAC960_Controller_T |
| *Controller) |
| { |
| void __iomem *ControllerBaseAddress = Controller->BaseAddress; |
| DAC960_HardwareType_T hw_type = Controller->HardwareType; |
| struct pci_dev *PCI_Device = Controller->PCIDevice; |
| struct dma_loaf *DmaPages = &Controller->DmaPages; |
| size_t DmaPagesSize; |
| size_t CommandMailboxesSize; |
| size_t StatusMailboxesSize; |
| |
| DAC960_V1_CommandMailbox_T *CommandMailboxesMemory; |
| dma_addr_t CommandMailboxesMemoryDMA; |
| |
| DAC960_V1_StatusMailbox_T *StatusMailboxesMemory; |
| dma_addr_t StatusMailboxesMemoryDMA; |
| |
| DAC960_V1_CommandMailbox_T CommandMailbox; |
| DAC960_V1_CommandStatus_T CommandStatus; |
| int TimeoutCounter; |
| int i; |
| |
| memset(&CommandMailbox, 0, sizeof(DAC960_V1_CommandMailbox_T)); |
| |
| if (pci_set_dma_mask(Controller->PCIDevice, DMA_BIT_MASK(32))) |
| return DAC960_Failure(Controller, "DMA mask out of range"); |
| Controller->BounceBufferLimit = DMA_BIT_MASK(32); |
| |
| if ((hw_type == DAC960_PD_Controller) || (hw_type == DAC960_P_Controller)) { |
| CommandMailboxesSize = 0; |
| StatusMailboxesSize = 0; |
| } else { |
| CommandMailboxesSize = DAC960_V1_CommandMailboxCount * sizeof(DAC960_V1_CommandMailbox_T); |
| StatusMailboxesSize = DAC960_V1_StatusMailboxCount * sizeof(DAC960_V1_StatusMailbox_T); |
| } |
| DmaPagesSize = CommandMailboxesSize + StatusMailboxesSize + |
| sizeof(DAC960_V1_DCDB_T) + sizeof(DAC960_V1_Enquiry_T) + |
| sizeof(DAC960_V1_ErrorTable_T) + sizeof(DAC960_V1_EventLogEntry_T) + |
| sizeof(DAC960_V1_RebuildProgress_T) + |
| sizeof(DAC960_V1_LogicalDriveInformationArray_T) + |
| sizeof(DAC960_V1_BackgroundInitializationStatus_T) + |
| sizeof(DAC960_V1_DeviceState_T) + sizeof(DAC960_SCSI_Inquiry_T) + |
| sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T); |
| |
| if (!init_dma_loaf(PCI_Device, DmaPages, DmaPagesSize)) |
| return false; |
| |
| |
| if ((hw_type == DAC960_PD_Controller) || (hw_type == DAC960_P_Controller)) |
| goto skip_mailboxes; |
| |
| CommandMailboxesMemory = slice_dma_loaf(DmaPages, |
| CommandMailboxesSize, &CommandMailboxesMemoryDMA); |
| |
| /* These are the base addresses for the command memory mailbox array */ |
| Controller->V1.FirstCommandMailbox = CommandMailboxesMemory; |
| Controller->V1.FirstCommandMailboxDMA = CommandMailboxesMemoryDMA; |
| |
| CommandMailboxesMemory += DAC960_V1_CommandMailboxCount - 1; |
| Controller->V1.LastCommandMailbox = CommandMailboxesMemory; |
| Controller->V1.NextCommandMailbox = Controller->V1.FirstCommandMailbox; |
| Controller->V1.PreviousCommandMailbox1 = Controller->V1.LastCommandMailbox; |
| Controller->V1.PreviousCommandMailbox2 = |
| Controller->V1.LastCommandMailbox - 1; |
| |
| /* These are the base addresses for the status memory mailbox array */ |
| StatusMailboxesMemory = slice_dma_loaf(DmaPages, |
| StatusMailboxesSize, &StatusMailboxesMemoryDMA); |
| |
| Controller->V1.FirstStatusMailbox = StatusMailboxesMemory; |
| Controller->V1.FirstStatusMailboxDMA = StatusMailboxesMemoryDMA; |
| StatusMailboxesMemory += DAC960_V1_StatusMailboxCount - 1; |
| Controller->V1.LastStatusMailbox = StatusMailboxesMemory; |
| Controller->V1.NextStatusMailbox = Controller->V1.FirstStatusMailbox; |
| |
| skip_mailboxes: |
| Controller->V1.MonitoringDCDB = slice_dma_loaf(DmaPages, |
| sizeof(DAC960_V1_DCDB_T), |
| &Controller->V1.MonitoringDCDB_DMA); |
| |
| Controller->V1.NewEnquiry = slice_dma_loaf(DmaPages, |
| sizeof(DAC960_V1_Enquiry_T), |
| &Controller->V1.NewEnquiryDMA); |
| |
| Controller->V1.NewErrorTable = slice_dma_loaf(DmaPages, |
| sizeof(DAC960_V1_ErrorTable_T), |
| &Controller->V1.NewErrorTableDMA); |
| |
| Controller->V1.EventLogEntry = slice_dma_loaf(DmaPages, |
| sizeof(DAC960_V1_EventLogEntry_T), |
| &Controller->V1.EventLogEntryDMA); |
| |
| Controller->V1.RebuildProgress = slice_dma_loaf(DmaPages, |
| sizeof(DAC960_V1_RebuildProgress_T), |
| &Controller->V1.RebuildProgressDMA); |
| |
| Controller->V1.NewLogicalDriveInformation = slice_dma_loaf(DmaPages, |
| sizeof(DAC960_V1_LogicalDriveInformationArray_T), |
| &Controller->V1.NewLogicalDriveInformationDMA); |
| |
| Controller->V1.BackgroundInitializationStatus = slice_dma_loaf(DmaPages, |
| sizeof(DAC960_V1_BackgroundInitializationStatus_T), |
| &Controller->V1.BackgroundInitializationStatusDMA); |
| |
| Controller->V1.NewDeviceState = slice_dma_loaf(DmaPages, |
| sizeof(DAC960_V1_DeviceState_T), |
| &Controller->V1.NewDeviceStateDMA); |
| |
| Controller->V1.NewInquiryStandardData = slice_dma_loaf(DmaPages, |
| sizeof(DAC960_SCSI_Inquiry_T), |
| &Controller->V1.NewInquiryStandardDataDMA); |
| |
| Controller->V1.NewInquiryUnitSerialNumber = slice_dma_loaf(DmaPages, |
| sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T), |
| &Controller->V1.NewInquiryUnitSerialNumberDMA); |
| |
| if ((hw_type == DAC960_PD_Controller) || (hw_type == DAC960_P_Controller)) |
| return true; |
| |
| /* Enable the Memory Mailbox Interface. */ |
| Controller->V1.DualModeMemoryMailboxInterface = true; |
| CommandMailbox.TypeX.CommandOpcode = 0x2B; |
| CommandMailbox.TypeX.CommandIdentifier = 0; |
| CommandMailbox.TypeX.CommandOpcode2 = 0x14; |
| CommandMailbox.TypeX.CommandMailboxesBusAddress = |
| Controller->V1.FirstCommandMailboxDMA; |
| CommandMailbox.TypeX.StatusMailboxesBusAddress = |
| Controller->V1.FirstStatusMailboxDMA; |
| #define TIMEOUT_COUNT 1000000 |
| |
| for (i = 0; i < 2; i++) |
| switch (Controller->HardwareType) |
| { |
| case DAC960_LA_Controller: |
| TimeoutCounter = TIMEOUT_COUNT; |
| while (--TimeoutCounter >= 0) |
| { |
| if (!DAC960_LA_HardwareMailboxFullP(ControllerBaseAddress)) |
| break; |
| udelay(10); |
| } |
| if (TimeoutCounter < 0) return false; |
| DAC960_LA_WriteHardwareMailbox(ControllerBaseAddress, &CommandMailbox); |
| DAC960_LA_HardwareMailboxNewCommand(ControllerBaseAddress); |
| TimeoutCounter = TIMEOUT_COUNT; |
| while (--TimeoutCounter >= 0) |
| { |
| if (DAC960_LA_HardwareMailboxStatusAvailableP( |
| ControllerBaseAddress)) |
| break; |
| udelay(10); |
| } |
| if (TimeoutCounter < 0) return false; |
| CommandStatus = DAC960_LA_ReadStatusRegister(ControllerBaseAddress); |
| DAC960_LA_AcknowledgeHardwareMailboxInterrupt(ControllerBaseAddress); |
| DAC960_LA_AcknowledgeHardwareMailboxStatus(ControllerBaseAddress); |
| if (CommandStatus == DAC960_V1_NormalCompletion) return true; |
| Controller->V1.DualModeMemoryMailboxInterface = false; |
| CommandMailbox.TypeX.CommandOpcode2 = 0x10; |
| break; |
| case DAC960_PG_Controller: |
| TimeoutCounter = TIMEOUT_COUNT; |
| while (--TimeoutCounter >= 0) |
| { |
| if (!DAC960_PG_HardwareMailboxFullP(ControllerBaseAddress)) |
| break; |
| udelay(10); |
| } |
| if (TimeoutCounter < 0) return false; |
| DAC960_PG_WriteHardwareMailbox(ControllerBaseAddress, &CommandMailbox); |
| DAC960_PG_HardwareMailboxNewCommand(ControllerBaseAddress); |
| |
| TimeoutCounter = TIMEOUT_COUNT; |
| while (--TimeoutCounter >= 0) |
| { |
| if (DAC960_PG_HardwareMailboxStatusAvailableP( |
| ControllerBaseAddress)) |
| break; |
| udelay(10); |
| } |
| if (TimeoutCounter < 0) return false; |
| CommandStatus = DAC960_PG_ReadStatusRegister(ControllerBaseAddress); |
| DAC960_PG_AcknowledgeHardwareMailboxInterrupt(ControllerBaseAddress); |
| DAC960_PG_AcknowledgeHardwareMailboxStatus(ControllerBaseAddress); |
| if (CommandStatus == DAC960_V1_NormalCompletion) return true; |
| Controller->V1.DualModeMemoryMailboxInterface = false; |
| CommandMailbox.TypeX.CommandOpcode2 = 0x10; |
| break; |
| default: |
| DAC960_Failure(Controller, "Unknown Controller Type\n"); |
| break; |
| } |
| return false; |
| } |
| |
| |
| /* |
| DAC960_V2_EnableMemoryMailboxInterface enables the Memory Mailbox Interface |
| for DAC960 V2 Firmware Controllers. |
| |
| Aggregate the space needed for the controller's memory mailbox and |
| the other data structures that will be targets of dma transfers with |
| the controller. Allocate a dma-mapped region of memory to hold these |
| structures. Then, save CPU pointers and dma_addr_t values to reference |
| the structures that are contained in that region. |
| */ |
| |
| static bool DAC960_V2_EnableMemoryMailboxInterface(DAC960_Controller_T |
| *Controller) |
| { |
| void __iomem *ControllerBaseAddress = Controller->BaseAddress; |
| struct pci_dev *PCI_Device = Controller->PCIDevice; |
| struct dma_loaf *DmaPages = &Controller->DmaPages; |
| size_t DmaPagesSize; |
| size_t CommandMailboxesSize; |
| size_t StatusMailboxesSize; |
| |
| DAC960_V2_CommandMailbox_T *CommandMailboxesMemory; |
| dma_addr_t CommandMailboxesMemoryDMA; |
| |
| DAC960_V2_StatusMailbox_T *StatusMailboxesMemory; |
| dma_addr_t StatusMailboxesMemoryDMA; |
| |
| DAC960_V2_CommandMailbox_T *CommandMailbox; |
| dma_addr_t CommandMailboxDMA; |
| DAC960_V2_CommandStatus_T CommandStatus; |
| |
| if (!pci_set_dma_mask(Controller->PCIDevice, DMA_BIT_MASK(64))) |
| Controller->BounceBufferLimit = DMA_BIT_MASK(64); |
| else if (!pci_set_dma_mask(Controller->PCIDevice, DMA_BIT_MASK(32))) |
| Controller->BounceBufferLimit = DMA_BIT_MASK(32); |
| else |
| return DAC960_Failure(Controller, "DMA mask out of range"); |
| |
| /* This is a temporary dma mapping, used only in the scope of this function */ |
| CommandMailbox = pci_alloc_consistent(PCI_Device, |
| sizeof(DAC960_V2_CommandMailbox_T), &CommandMailboxDMA); |
| if (CommandMailbox == NULL) |
| return false; |
| |
| CommandMailboxesSize = DAC960_V2_CommandMailboxCount * sizeof(DAC960_V2_CommandMailbox_T); |
| StatusMailboxesSize = DAC960_V2_StatusMailboxCount * sizeof(DAC960_V2_StatusMailbox_T); |
| DmaPagesSize = |
| CommandMailboxesSize + StatusMailboxesSize + |
| sizeof(DAC960_V2_HealthStatusBuffer_T) + |
| sizeof(DAC960_V2_ControllerInfo_T) + |
| sizeof(DAC960_V2_LogicalDeviceInfo_T) + |
| sizeof(DAC960_V2_PhysicalDeviceInfo_T) + |
| sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T) + |
| sizeof(DAC960_V2_Event_T) + |
| sizeof(DAC960_V2_PhysicalToLogicalDevice_T); |
| |
| if (!init_dma_loaf(PCI_Device, DmaPages, DmaPagesSize)) { |
| pci_free_consistent(PCI_Device, sizeof(DAC960_V2_CommandMailbox_T), |
| CommandMailbox, CommandMailboxDMA); |
| return false; |
| } |
| |
| CommandMailboxesMemory = slice_dma_loaf(DmaPages, |
| CommandMailboxesSize, &CommandMailboxesMemoryDMA); |
| |
| /* These are the base addresses for the command memory mailbox array */ |
| Controller->V2.FirstCommandMailbox = CommandMailboxesMemory; |
| Controller->V2.FirstCommandMailboxDMA = CommandMailboxesMemoryDMA; |
| |
| CommandMailboxesMemory += DAC960_V2_CommandMailboxCount - 1; |
| Controller->V2.LastCommandMailbox = CommandMailboxesMemory; |
| Controller->V2.NextCommandMailbox = Controller->V2.FirstCommandMailbox; |
| Controller->V2.PreviousCommandMailbox1 = Controller->V2.LastCommandMailbox; |
| Controller->V2.PreviousCommandMailbox2 = |
| Controller->V2.LastCommandMailbox - 1; |
| |
| /* These are the base addresses for the status memory mailbox array */ |
| StatusMailboxesMemory = slice_dma_loaf(DmaPages, |
| StatusMailboxesSize, &StatusMailboxesMemoryDMA); |
| |
| Controller->V2.FirstStatusMailbox = StatusMailboxesMemory; |
| Controller->V2.FirstStatusMailboxDMA = StatusMailboxesMemoryDMA; |
| StatusMailboxesMemory += DAC960_V2_StatusMailboxCount - 1; |
| Controller->V2.LastStatusMailbox = StatusMailboxesMemory; |
| Controller->V2.NextStatusMailbox = Controller->V2.FirstStatusMailbox; |
| |
| Controller->V2.HealthStatusBuffer = slice_dma_loaf(DmaPages, |
| sizeof(DAC960_V2_HealthStatusBuffer_T), |
| &Controller->V2.HealthStatusBufferDMA); |
| |
| Controller->V2.NewControllerInformation = slice_dma_loaf(DmaPages, |
| sizeof(DAC960_V2_ControllerInfo_T), |
| &Controller->V2.NewControllerInformationDMA); |
| |
| Controller->V2.NewLogicalDeviceInformation = slice_dma_loaf(DmaPages, |
| sizeof(DAC960_V2_LogicalDeviceInfo_T), |
| &Controller->V2.NewLogicalDeviceInformationDMA); |
| |
| Controller->V2.NewPhysicalDeviceInformation = slice_dma_loaf(DmaPages, |
| sizeof(DAC960_V2_PhysicalDeviceInfo_T), |
| &Controller->V2.NewPhysicalDeviceInformationDMA); |
| |
| Controller->V2.NewInquiryUnitSerialNumber = slice_dma_loaf(DmaPages, |
| sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T), |
| &Controller->V2.NewInquiryUnitSerialNumberDMA); |
| |
| Controller->V2.Event = slice_dma_loaf(DmaPages, |
| sizeof(DAC960_V2_Event_T), |
| &Controller->V2.EventDMA); |
| |
| Controller->V2.PhysicalToLogicalDevice = slice_dma_loaf(DmaPages, |
| sizeof(DAC960_V2_PhysicalToLogicalDevice_T), |
| &Controller->V2.PhysicalToLogicalDeviceDMA); |
| |
| /* |
| Enable the Memory Mailbox Interface. |
| |
| I don't know why we can't just use one of the memory mailboxes |
| we just allocated to do this, instead of using this temporary one. |
| Try this change later. |
| */ |
| memset(CommandMailbox, 0, sizeof(DAC960_V2_CommandMailbox_T)); |
| CommandMailbox->SetMemoryMailbox.CommandIdentifier = 1; |
| CommandMailbox->SetMemoryMailbox.CommandOpcode = DAC960_V2_IOCTL; |
| CommandMailbox->SetMemoryMailbox.CommandControlBits.NoAutoRequestSense = true; |
| CommandMailbox->SetMemoryMailbox.FirstCommandMailboxSizeKB = |
| (DAC960_V2_CommandMailboxCount * sizeof(DAC960_V2_CommandMailbox_T)) >> 10; |
| CommandMailbox->SetMemoryMailbox.FirstStatusMailboxSizeKB = |
| (DAC960_V2_StatusMailboxCount * sizeof(DAC960_V2_StatusMailbox_T)) >> 10; |
| CommandMailbox->SetMemoryMailbox.SecondCommandMailboxSizeKB = 0; |
| CommandMailbox->SetMemoryMailbox.SecondStatusMailboxSizeKB = 0; |
| CommandMailbox->SetMemoryMailbox.RequestSenseSize = 0; |
| CommandMailbox->SetMemoryMailbox.IOCTL_Opcode = DAC960_V2_SetMemoryMailbox; |
| CommandMailbox->SetMemoryMailbox.HealthStatusBufferSizeKB = 1; |
| CommandMailbox->SetMemoryMailbox.HealthStatusBufferBusAddress = |
| Controller->V2.HealthStatusBufferDMA; |
| CommandMailbox->SetMemoryMailbox.FirstCommandMailboxBusAddress = |
| Controller->V2.FirstCommandMailboxDMA; |
| CommandMailbox->SetMemoryMailbox.FirstStatusMailboxBusAddress = |
| Controller->V2.FirstStatusMailboxDMA; |
| switch (Controller->HardwareType) |
| { |
| case DAC960_GEM_Controller: |
| while (DAC960_GEM_HardwareMailboxFullP(ControllerBaseAddress)) |
| udelay(1); |
| DAC960_GEM_WriteHardwareMailbox(ControllerBaseAddress, CommandMailboxDMA); |
| DAC960_GEM_HardwareMailboxNewCommand(ControllerBaseAddress); |
| while (!DAC960_GEM_HardwareMailboxStatusAvailableP(ControllerBaseAddress)) |
| udelay(1); |
| CommandStatus = DAC960_GEM_ReadCommandStatus(ControllerBaseAddress); |
| DAC960_GEM_AcknowledgeHardwareMailboxInterrupt(ControllerBaseAddress); |
| DAC960_GEM_AcknowledgeHardwareMailboxStatus(ControllerBaseAddress); |
| break; |
| case DAC960_BA_Controller: |
| while (DAC960_BA_HardwareMailboxFullP(ControllerBaseAddress)) |
| udelay(1); |
| DAC960_BA_WriteHardwareMailbox(ControllerBaseAddress, CommandMailboxDMA); |
| DAC960_BA_HardwareMailboxNewCommand(ControllerBaseAddress); |
| while (!DAC960_BA_HardwareMailboxStatusAvailableP(ControllerBaseAddress)) |
| udelay(1); |
| CommandStatus = DAC960_BA_ReadCommandStatus(ControllerBaseAddress); |
| DAC960_BA_AcknowledgeHardwareMailboxInterrupt(ControllerBaseAddress); |
| DAC960_BA_AcknowledgeHardwareMailboxStatus(ControllerBaseAddress); |
| break; |
| case DAC960_LP_Controller: |
| while (DAC960_LP_HardwareMailboxFullP(ControllerBaseAddress)) |
| udelay(1); |
| DAC960_LP_WriteHardwareMailbox(ControllerBaseAddress, CommandMailboxDMA); |
| DAC960_LP_HardwareMailboxNewCommand(ControllerBaseAddress); |
| while (!DAC960_LP_HardwareMailboxStatusAvailableP(ControllerBaseAddress)) |
| udelay(1); |
| CommandStatus = DAC960_LP_ReadCommandStatus(ControllerBaseAddress); |
| DAC960_LP_AcknowledgeHardwareMailboxInterrupt(ControllerBaseAddress); |
| DAC960_LP_AcknowledgeHardwareMailboxStatus(ControllerBaseAddress); |
| break; |
| default: |
| DAC960_Failure(Controller, "Unknown Controller Type\n"); |
| CommandStatus = DAC960_V2_AbormalCompletion; |
| break; |
| } |
| pci_free_consistent(PCI_Device, sizeof(DAC960_V2_CommandMailbox_T), |
| CommandMailbox, CommandMailboxDMA); |
| return (CommandStatus == DAC960_V2_NormalCompletion); |
| } |
| |
| |
| /* |
| DAC960_V1_ReadControllerConfiguration reads the Configuration Information |
| from DAC960 V1 Firmware Controllers and initializes the Controller structure. |
| */ |
| |
| static bool DAC960_V1_ReadControllerConfiguration(DAC960_Controller_T |
| *Controller) |
| { |
| DAC960_V1_Enquiry2_T *Enquiry2; |
| dma_addr_t Enquiry2DMA; |
| DAC960_V1_Config2_T *Config2; |
| dma_addr_t Config2DMA; |
| int LogicalDriveNumber, Channel, TargetID; |
| struct dma_loaf local_dma; |
| |
| if (!init_dma_loaf(Controller->PCIDevice, &local_dma, |
| sizeof(DAC960_V1_Enquiry2_T) + sizeof(DAC960_V1_Config2_T))) |
| return DAC960_Failure(Controller, "LOGICAL DEVICE ALLOCATION"); |
| |
| Enquiry2 = slice_dma_loaf(&local_dma, sizeof(DAC960_V1_Enquiry2_T), &Enquiry2DMA); |
| Config2 = slice_dma_loaf(&local_dma, sizeof(DAC960_V1_Config2_T), &Config2DMA); |
| |
| if (!DAC960_V1_ExecuteType3(Controller, DAC960_V1_Enquiry, |
| Controller->V1.NewEnquiryDMA)) { |
| free_dma_loaf(Controller->PCIDevice, &local_dma); |
| return DAC960_Failure(Controller, "ENQUIRY"); |
| } |
| memcpy(&Controller->V1.Enquiry, Controller->V1.NewEnquiry, |
| sizeof(DAC960_V1_Enquiry_T)); |
| |
| if (!DAC960_V1_ExecuteType3(Controller, DAC960_V1_Enquiry2, Enquiry2DMA)) { |
| free_dma_loaf(Controller->PCIDevice, &local_dma); |
| return DAC960_Failure(Controller, "ENQUIRY2"); |
| } |
| |
| if (!DAC960_V1_ExecuteType3(Controller, DAC960_V1_ReadConfig2, Config2DMA)) { |
| free_dma_loaf(Controller->PCIDevice, &local_dma); |
| return DAC960_Failure(Controller, "READ CONFIG2"); |
| } |
| |
| if (!DAC960_V1_ExecuteType3(Controller, DAC960_V1_GetLogicalDriveInformation, |
| Controller->V1.NewLogicalDriveInformationDMA)) { |
| free_dma_loaf(Controller->PCIDevice, &local_dma); |
| return DAC960_Failure(Controller, "GET LOGICAL DRIVE INFORMATION"); |
| } |
| memcpy(&Controller->V1.LogicalDriveInformation, |
| Controller->V1.NewLogicalDriveInformation, |
| sizeof(DAC960_V1_LogicalDriveInformationArray_T)); |
| |
| for (Channel = 0; Channel < Enquiry2->ActualChannels; Channel++) |
| for (TargetID = 0; TargetID < Enquiry2->MaxTargets; TargetID++) { |
| if (!DAC960_V1_ExecuteType3D(Controller, DAC960_V1_GetDeviceState, |
| Channel, TargetID, |
| Controller->V1.NewDeviceStateDMA)) { |
| free_dma_loaf(Controller->PCIDevice, &local_dma); |
| return DAC960_Failure(Controller, "GET DEVICE STATE"); |
| } |
| memcpy(&Controller->V1.DeviceState[Channel][TargetID], |
| Controller->V1.NewDeviceState, sizeof(DAC960_V1_DeviceState_T)); |
| } |
| /* |
| Initialize the Controller Model Name and Full Model Name fields. |
| */ |
| switch (Enquiry2->HardwareID.SubModel) |
| { |
| case DAC960_V1_P_PD_PU: |
| if (Enquiry2->SCSICapability.BusSpeed == DAC960_V1_Ultra) |
| strcpy(Controller->ModelName, "DAC960PU"); |
| else strcpy(Controller->ModelName, "DAC960PD"); |
| break; |
| case DAC960_V1_PL: |
| strcpy(Controller->ModelName, "DAC960PL"); |
| break; |
| case DAC960_V1_PG: |
| strcpy(Controller->ModelName, "DAC960PG"); |
| break; |
| case DAC960_V1_PJ: |
| strcpy(Controller->ModelName, "DAC960PJ"); |
| break; |
| case DAC960_V1_PR: |
| strcpy(Controller->ModelName, "DAC960PR"); |
| break; |
| case DAC960_V1_PT: |
| strcpy(Controller->ModelName, "DAC960PT"); |
| break; |
| case DAC960_V1_PTL0: |
| strcpy(Controller->ModelName, "DAC960PTL0"); |
| break; |
| case DAC960_V1_PRL: |
| strcpy(Controller->ModelName, "DAC960PRL"); |
| break; |
| case DAC960_V1_PTL1: |
| strcpy(Controller->ModelName, "DAC960PTL1"); |
| break; |
| case DAC960_V1_1164P: |
| strcpy(Controller->ModelName, "DAC1164P"); |
| break; |
| default: |
| free_dma_loaf(Controller->PCIDevice, &local_dma); |
| return DAC960_Failure(Controller, "MODEL VERIFICATION"); |
| } |
| strcpy(Controller->FullModelName, "Mylex "); |
| strcat(Controller->FullModelName, Controller->ModelName); |
| /* |
| Initialize the Controller Firmware Version field and verify that it |
| is a supported firmware version. The supported firmware versions are: |
| |
| DAC1164P 5.06 and above |
| DAC960PTL/PRL/PJ/PG 4.06 and above |
| DAC960PU/PD/PL 3.51 and above |
| DAC960PU/PD/PL/P 2.73 and above |
| */ |
| #if defined(CONFIG_ALPHA) |
| /* |
| DEC Alpha machines were often equipped with DAC960 cards that were |
| OEMed from Mylex, and had their own custom firmware. Version 2.70, |
| the last custom FW revision to be released by DEC for these older |
| controllers, appears to work quite well with this driver. |
| |
| Cards tested successfully were several versions each of the PD and |
| PU, called by DEC the KZPSC and KZPAC, respectively, and having |
| the Manufacturer Numbers (from Mylex), usually on a sticker on the |
| back of the board, of: |
| |
| KZPSC: D040347 (1-channel) or D040348 (2-channel) or D040349 (3-channel) |
| KZPAC: D040395 (1-channel) or D040396 (2-channel) or D040397 (3-channel) |
| */ |
| # define FIRMWARE_27X "2.70" |
| #else |
| # define FIRMWARE_27X "2.73" |
| #endif |
| |
| if (Enquiry2->FirmwareID.MajorVersion == 0) |
| { |
| Enquiry2->FirmwareID.MajorVersion = |
| Controller->V1.Enquiry.MajorFirmwareVersion; |
| Enquiry2->FirmwareID.MinorVersion = |
| Controller->V1.Enquiry.MinorFirmwareVersion; |
| Enquiry2->FirmwareID.FirmwareType = '0'; |
| Enquiry2->FirmwareID.TurnID = 0; |
| } |
| snprintf(Controller->FirmwareVersion, sizeof(Controller->FirmwareVersion), |
| "%d.%02d-%c-%02d", |
| Enquiry2->FirmwareID.MajorVersion, |
| Enquiry2->FirmwareID.MinorVersion, |
| Enquiry2->FirmwareID.FirmwareType, |
| Enquiry2->FirmwareID.TurnID); |
| if (!((Controller->FirmwareVersion[0] == '5' && |
| strcmp(Controller->FirmwareVersion, "5.06") >= 0) || |
| (Controller->FirmwareVersion[0] == '4' && |
| strcmp(Controller->FirmwareVersion, "4.06") >= 0) || |
| (Controller->FirmwareVersion[0] == '3' && |
| strcmp(Controller->FirmwareVersion, "3.51") >= 0) || |
| (Controller->FirmwareVersion[0] == '2' && |
| strcmp(Controller->FirmwareVersion, FIRMWARE_27X) >= 0))) |
| { |
| DAC960_Failure(Controller, "FIRMWARE VERSION VERIFICATION"); |
| DAC960_Error("Firmware Version = '%s'\n", Controller, |
| Controller->FirmwareVersion); |
| free_dma_loaf(Controller->PCIDevice, &local_dma); |
| return false; |
| } |
| /* |
| Initialize the Controller Channels, Targets, Memory Size, and SAF-TE |
| Enclosure Management Enabled fields. |
| */ |
| Controller->Channels = Enquiry2->ActualChannels; |
| Controller->Targets = Enquiry2->MaxTargets; |
| Controller->MemorySize = Enquiry2->MemorySize >> 20; |
| Controller->V1.SAFTE_EnclosureManagementEnabled = |
| (Enquiry2->FaultManagementType == DAC960_V1_SAFTE); |
| /* |
| Initialize the Controller Queue Depth, Driver Queue Depth, Logical Drive |
| Count, Maximum Blocks per Command, Controller Scatter/Gather Limit, and |
| Driver Scatter/Gather Limit. The Driver Queue Depth must be at most one |
| less than the Controller Queue Depth to allow for an automatic drive |
| rebuild operation. |
| */ |
| Controller->ControllerQueueDepth = Controller->V1.Enquiry.MaxCommands; |
| Controller->DriverQueueDepth = Controller->ControllerQueueDepth - 1; |
| if (Controller->DriverQueueDepth > DAC960_MaxDriverQueueDepth) |
| Controller->DriverQueueDepth = DAC960_MaxDriverQueueDepth; |
| Controller->LogicalDriveCount = |
| Controller->V1.Enquiry.NumberOfLogicalDrives; |
| Controller->MaxBlocksPerCommand = Enquiry2->MaxBlocksPerCommand; |
| Controller->ControllerScatterGatherLimit = Enquiry2->MaxScatterGatherEntries; |
| Controller->DriverScatterGatherLimit = |
| Controller->ControllerScatterGatherLimit; |
| if (Controller->DriverScatterGatherLimit > DAC960_V1_ScatterGatherLimit) |
| Controller->DriverScatterGatherLimit = DAC960_V1_ScatterGatherLimit; |
| /* |
| Initialize the Stripe Size, Segment Size, and Geometry Translation. |
| */ |
| Controller->V1.StripeSize = Config2->BlocksPerStripe * Config2->BlockFactor |
| >> (10 - DAC960_BlockSizeBits); |
| Controller->V1.SegmentSize = Config2->BlocksPerCacheLine * Config2->BlockFactor |
| >> (10 - DAC960_BlockSizeBits); |
| switch (Config2->DriveGeometry) |
| { |
| case DAC960_V1_Geometry_128_32: |
| Controller->V1.GeometryTranslationHeads = 128; |
| Controller->V1.GeometryTranslationSectors = 32; |
| break; |
| case DAC960_V1_Geometry_255_63: |
| Controller->V1.GeometryTranslationHeads = 255; |
| Controller->V1.GeometryTranslationSectors = 63; |
| break; |
| default: |
| free_dma_loaf(Controller->PCIDevice, &local_dma); |
| return DAC960_Failure(Controller, "CONFIG2 DRIVE GEOMETRY"); |
| } |
| /* |
| Initialize the Background Initialization Status. |
| */ |
| if ((Controller->FirmwareVersion[0] == '4' && |
| strcmp(Controller->FirmwareVersion, "4.08") >= 0) || |
| (Controller->FirmwareVersion[0] == '5' && |
| strcmp(Controller->FirmwareVersion, "5.08") >= 0)) |
| { |
| Controller->V1.BackgroundInitializationStatusSupported = true; |
| DAC960_V1_ExecuteType3B(Controller, |
| DAC960_V1_BackgroundInitializationControl, 0x20, |
| Controller-> |
| V1.BackgroundInitializationStatusDMA); |
| memcpy(&Controller->V1.LastBackgroundInitializationStatus, |
| Controller->V1.BackgroundInitializationStatus, |
| sizeof(DAC960_V1_BackgroundInitializationStatus_T)); |
| } |
| /* |
| Initialize the Logical Drive Initially Accessible flag. |
| */ |
| for (LogicalDriveNumber = 0; |
| LogicalDriveNumber < Controller->LogicalDriveCount; |
| LogicalDriveNumber++) |
| if (Controller->V1.LogicalDriveInformation |
| [LogicalDriveNumber].LogicalDriveState != |
| DAC960_V1_LogicalDrive_Offline) |
| Controller->LogicalDriveInitiallyAccessible[LogicalDriveNumber] = true; |
| Controller->V1.LastRebuildStatus = DAC960_V1_NoRebuildOrCheckInProgress; |
| free_dma_loaf(Controller->PCIDevice, &local_dma); |
| return true; |
| } |
| |
| |
| /* |
| DAC960_V2_ReadControllerConfiguration reads the Configuration Information |
| from DAC960 V2 Firmware Controllers and initializes the Controller structure. |
| */ |
| |
| static bool DAC960_V2_ReadControllerConfiguration(DAC960_Controller_T |
| *Controller) |
| { |
| DAC960_V2_ControllerInfo_T *ControllerInfo = |
| &Controller->V2.ControllerInformation; |
| unsigned short LogicalDeviceNumber = 0; |
| int ModelNameLength; |
| |
| /* Get data into dma-able area, then copy into permanent location */ |
| if (!DAC960_V2_NewControllerInfo(Controller)) |
| return DAC960_Failure(Controller, "GET CONTROLLER INFO"); |
| memcpy(ControllerInfo, Controller->V2.NewControllerInformation, |
| sizeof(DAC960_V2_ControllerInfo_T)); |
| |
| |
| if (!DAC960_V2_GeneralInfo(Controller)) |
| return DAC960_Failure(Controller, "GET HEALTH STATUS"); |
| |
| /* |
| Initialize the Controller Model Name and Full Model Name fields. |
| */ |
| ModelNameLength = sizeof(ControllerInfo->ControllerName); |
| if (ModelNameLength > sizeof(Controller->ModelName)-1) |
| ModelNameLength = sizeof(Controller->ModelName)-1; |
| memcpy(Controller->ModelName, ControllerInfo->ControllerName, |
| ModelNameLength); |
| ModelNameLength--; |
| while (Controller->ModelName[ModelNameLength] == ' ' || |
| Controller->ModelName[ModelNameLength] == '\0') |
| ModelNameLength--; |
| Controller->ModelName[++ModelNameLength] = '\0'; |
| strcpy(Controller->FullModelName, "Mylex "); |
| strcat(Controller->FullModelName, Controller->ModelName); |
| /* |
| Initialize the Controller Firmware Version field. |
| */ |
| sprintf(Controller->FirmwareVersion, "%d.%02d-%02d", |
| ControllerInfo->FirmwareMajorVersion, |
| ControllerInfo->FirmwareMinorVersion, |
| ControllerInfo->FirmwareTurnNumber); |
| if (ControllerInfo->FirmwareMajorVersion == 6 && |
| ControllerInfo->FirmwareMinorVersion == 0 && |
| ControllerInfo->FirmwareTurnNumber < 1) |
| { |
| DAC960_Info("FIRMWARE VERSION %s DOES NOT PROVIDE THE CONTROLLER\n", |
| Controller, Controller->FirmwareVersion); |
| DAC960_Info("STATUS MONITORING FUNCTIONALITY NEEDED BY THIS DRIVER.\n", |
| Controller); |
| DAC960_Info("PLEASE UPGRADE TO VERSION 6.00-01 OR ABOVE.\n", |
| Controller); |
| } |
| /* |
| Initialize the Controller Channels, Targets, and Memory Size. |
| */ |
| Controller->Channels = ControllerInfo->NumberOfPhysicalChannelsPresent; |
| Controller->Targets = |
| ControllerInfo->MaximumTargetsPerChannel |
| [ControllerInfo->NumberOfPhysicalChannelsPresent-1]; |
| Controller->MemorySize = ControllerInfo->MemorySizeMB; |
| /* |
| Initialize the Controller Queue Depth, Driver Queue Depth, Logical Drive |
| Count, Maximum Blocks per Command, Controller Scatter/Gather Limit, and |
| Driver Scatter/Gather Limit. The Driver Queue Depth must be at most one |
| less than the Controller Queue Depth to allow for an automatic drive |
| rebuild operation. |
| */ |
| Controller->ControllerQueueDepth = ControllerInfo->MaximumParallelCommands; |
| Controller->DriverQueueDepth = Controller->ControllerQueueDepth - 1; |
| if (Controller->DriverQueueDepth > DAC960_MaxDriverQueueDepth) |
| Controller->DriverQueueDepth = DAC960_MaxDriverQueueDepth; |
| Controller->LogicalDriveCount = ControllerInfo->LogicalDevicesPresent; |
| Controller->MaxBlocksPerCommand = |
| ControllerInfo->MaximumDataTransferSizeInBlocks; |
| Controller->ControllerScatterGatherLimit = |
| ControllerInfo->MaximumScatterGatherEntries; |
| Controller->DriverScatterGatherLimit = |
| Controller->ControllerScatterGatherLimit; |
| if (Controller->DriverScatterGatherLimit > DAC960_V2_ScatterGatherLimit) |
| Controller->DriverScatterGatherLimit = DAC960_V2_ScatterGatherLimit; |
| /* |
| Initialize the Logical Device Information. |
| */ |
| while (true) |
| { |
| DAC960_V2_LogicalDeviceInfo_T *NewLogicalDeviceInfo = |
| Controller->V2.NewLogicalDeviceInformation; |
| DAC960_V2_LogicalDeviceInfo_T *LogicalDeviceInfo; |
| DAC960_V2_PhysicalDevice_T PhysicalDevice; |
| |
| if (!DAC960_V2_NewLogicalDeviceInfo(Controller, LogicalDeviceNumber)) |
| break; |
| LogicalDeviceNumber = NewLogicalDeviceInfo->LogicalDeviceNumber; |
| if (LogicalDeviceNumber >= DAC960_MaxLogicalDrives) { |
| DAC960_Error("DAC960: Logical Drive Number %d not supported\n", |
| Controller, LogicalDeviceNumber); |
| break; |
| } |
| if (NewLogicalDeviceInfo->DeviceBlockSizeInBytes != DAC960_BlockSize) { |
| DAC960_Error("DAC960: Logical Drive Block Size %d not supported\n", |
| Controller, NewLogicalDeviceInfo->DeviceBlockSizeInBytes); |
| LogicalDeviceNumber++; |
| continue; |
| } |
| PhysicalDevice.Controller = 0; |
| PhysicalDevice.Channel = NewLogicalDeviceInfo->Channel; |
| PhysicalDevice.TargetID = NewLogicalDeviceInfo->TargetID; |
| PhysicalDevice.LogicalUnit = NewLogicalDeviceInfo->LogicalUnit; |
| Controller->V2.LogicalDriveToVirtualDevice[LogicalDeviceNumber] = |
| PhysicalDevice; |
| if (NewLogicalDeviceInfo->LogicalDeviceState != |
| DAC960_V2_LogicalDevice_Offline) |
| Controller->LogicalDriveInitiallyAccessible[LogicalDeviceNumber] = true; |
| LogicalDeviceInfo = kmalloc(sizeof(DAC960_V2_LogicalDeviceInfo_T), |
| GFP_ATOMIC); |
| if (LogicalDeviceInfo == NULL) |
| return DAC960_Failure(Controller, "LOGICAL DEVICE ALLOCATION"); |
| Controller->V2.LogicalDeviceInformation[LogicalDeviceNumber] = |
| LogicalDeviceInfo; |
| memcpy(LogicalDeviceInfo, NewLogicalDeviceInfo, |
| sizeof(DAC960_V2_LogicalDeviceInfo_T)); |
| LogicalDeviceNumber++; |
| } |
| return true; |
| } |
| |
| |
| /* |
| DAC960_ReportControllerConfiguration reports the Configuration Information |
| for Controller. |
| */ |
| |
| static bool DAC960_ReportControllerConfiguration(DAC960_Controller_T |
| *Controller) |
| { |
| DAC960_Info("Configuring Mylex %s PCI RAID Controller\n", |
| Controller, Controller->ModelName); |
| DAC960_Info(" Firmware Version: %s, Channels: %d, Memory Size: %dMB\n", |
| Controller, Controller->FirmwareVersion, |
| Controller->Channels, Controller->MemorySize); |
| DAC960_Info(" PCI Bus: %d, Device: %d, Function: %d, I/O Address: ", |
| Controller, Controller->Bus, |
| Controller->Device, Controller->Function); |
| if (Controller->IO_Address == 0) |
| DAC960_Info("Unassigned\n", Controller); |
| else DAC960_Info("0x%X\n", Controller, Controller->IO_Address); |
| DAC960_Info(" PCI Address: 0x%X mapped at 0x%lX, IRQ Channel: %d\n", |
| Controller, Controller->PCI_Address, |
| (unsigned long) Controller->BaseAddress, |
| Controller->IRQ_Channel); |
| DAC960_Info(" Controller Queue Depth: %d, " |
| "Maximum Blocks per Command: %d\n", |
| Controller, Controller->ControllerQueueDepth, |
| Controller->MaxBlocksPerCommand); |
| DAC960_Info(" Driver Queue Depth: %d, " |
| "Scatter/Gather Limit: %d of %d Segments\n", |
| Controller, Controller->DriverQueueDepth, |
| Controller->DriverScatterGatherLimit, |
| Controller->ControllerScatterGatherLimit); |
| if (Controller->FirmwareType == DAC960_V1_Controller) |
| { |
| DAC960_Info(" Stripe Size: %dKB, Segment Size: %dKB, " |
| "BIOS Geometry: %d/%d\n", Controller, |
| Controller->V1.StripeSize, |
| Controller->V1.SegmentSize, |
| Controller->V1.GeometryTranslationHeads, |
| Controller->V1.GeometryTranslationSectors); |
| if (Controller->V1.SAFTE_EnclosureManagementEnabled) |
| DAC960_Info(" SAF-TE Enclosure Management Enabled\n", Controller); |
| } |
| return true; |
| } |
| |
| |
| /* |
| DAC960_V1_ReadDeviceConfiguration reads the Device Configuration Information |
| for DAC960 V1 Firmware Controllers by requesting the SCSI Inquiry and SCSI |
| Inquiry Unit Serial Number information for each device connected to |
| Controller. |
| */ |
| |
| static bool DAC960_V1_ReadDeviceConfiguration(DAC960_Controller_T |
| *Controller) |
| { |
| struct dma_loaf local_dma; |
| |
| dma_addr_t DCDBs_dma[DAC960_V1_MaxChannels]; |
| DAC960_V1_DCDB_T *DCDBs_cpu[DAC960_V1_MaxChannels]; |
| |
| dma_addr_t SCSI_Inquiry_dma[DAC960_V1_MaxChannels]; |
| DAC960_SCSI_Inquiry_T *SCSI_Inquiry_cpu[DAC960_V1_MaxChannels]; |
| |
| dma_addr_t SCSI_NewInquiryUnitSerialNumberDMA[DAC960_V1_MaxChannels]; |
| DAC960_SCSI_Inquiry_UnitSerialNumber_T *SCSI_NewInquiryUnitSerialNumberCPU[DAC960_V1_MaxChannels]; |
| |
| struct completion Completions[DAC960_V1_MaxChannels]; |
| unsigned long flags; |
| int Channel, TargetID; |
| |
| if (!init_dma_loaf(Controller->PCIDevice, &local_dma, |
| DAC960_V1_MaxChannels*(sizeof(DAC960_V1_DCDB_T) + |
| sizeof(DAC960_SCSI_Inquiry_T) + |
| sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T)))) |
| return DAC960_Failure(Controller, |
| "DMA ALLOCATION FAILED IN ReadDeviceConfiguration"); |
| |
| for (Channel = 0; Channel < Controller->Channels; Channel++) { |
| DCDBs_cpu[Channel] = slice_dma_loaf(&local_dma, |
| sizeof(DAC960_V1_DCDB_T), DCDBs_dma + Channel); |
| SCSI_Inquiry_cpu[Channel] = slice_dma_loaf(&local_dma, |
| sizeof(DAC960_SCSI_Inquiry_T), |
| SCSI_Inquiry_dma + Channel); |
| SCSI_NewInquiryUnitSerialNumberCPU[Channel] = slice_dma_loaf(&local_dma, |
| sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T), |
| SCSI_NewInquiryUnitSerialNumberDMA + Channel); |
| } |
| |
| for (TargetID = 0; TargetID < Controller->Targets; TargetID++) |
| { |
| /* |
| * For each channel, submit a probe for a device on that channel. |
| * The timeout interval for a device that is present is 10 seconds. |
| * With this approach, the timeout periods can elapse in parallel |
| * on each channel. |
| */ |
| for (Channel = 0; Channel < Controller->Channels; Channel++) |
| { |
| dma_addr_t NewInquiryStandardDataDMA = SCSI_Inquiry_dma[Channel]; |
| DAC960_V1_DCDB_T *DCDB = DCDBs_cpu[Channel]; |
| dma_addr_t DCDB_dma = DCDBs_dma[Channel]; |
| DAC960_Command_T *Command = Controller->Commands[Channel]; |
| struct completion *Completion = &Completions[Channel]; |
| |
| init_completion(Completion); |
| DAC960_V1_ClearCommand(Command); |
| Command->CommandType = DAC960_ImmediateCommand; |
| Command->Completion = Completion; |
| Command->V1.CommandMailbox.Type3.CommandOpcode = DAC960_V1_DCDB; |
| Command->V1.CommandMailbox.Type3.BusAddress = DCDB_dma; |
| DCDB->Channel = Channel; |
| DCDB->TargetID = TargetID; |
| DCDB->Direction = DAC960_V1_DCDB_DataTransferDeviceToSystem; |
| DCDB->EarlyStatus = false; |
| DCDB->Timeout = DAC960_V1_DCDB_Timeout_10_seconds; |
| DCDB->NoAutomaticRequestSense = false; |
| DCDB->DisconnectPermitted = true; |
| DCDB->TransferLength = sizeof(DAC960_SCSI_Inquiry_T); |
| DCDB->BusAddress = NewInquiryStandardDataDMA; |
| DCDB->CDBLength = 6; |
| DCDB->TransferLengthHigh4 = 0; |
| DCDB->SenseLength = sizeof(DCDB->SenseData); |
| DCDB->CDB[0] = 0x12; /* INQUIRY */ |
| DCDB->CDB[1] = 0; /* EVPD = 0 */ |
| DCDB->CDB[2] = 0; /* Page Code */ |
| DCDB->CDB[3] = 0; /* Reserved */ |
| DCDB->CDB[4] = sizeof(DAC960_SCSI_Inquiry_T); |
| DCDB->CDB[5] = 0; /* Control */ |
| |
| spin_lock_irqsave(&Controller->queue_lock, flags); |
| DAC960_QueueCommand(Command); |
| spin_unlock_irqrestore(&Controller->queue_lock, flags); |
| } |
| /* |
| * Wait for the problems submitted in the previous loop |
| * to complete. On the probes that are successful, |
| * get the serial number of the device that was found. |
| */ |
| for (Channel = 0; Channel < Controller->Channels; Channel++) |
| { |
| DAC960_SCSI_Inquiry_T *InquiryStandardData = |
| &Controller->V1.InquiryStandardData[Channel][TargetID]; |
| DAC960_SCSI_Inquiry_T *NewInquiryStandardData = SCSI_Inquiry_cpu[Channel]; |
| dma_addr_t NewInquiryUnitSerialNumberDMA = |
| SCSI_NewInquiryUnitSerialNumberDMA[Channel]; |
| DAC960_SCSI_Inquiry_UnitSerialNumber_T *NewInquiryUnitSerialNumber = |
| SCSI_NewInquiryUnitSerialNumberCPU[Channel]; |
| DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber = |
| &Controller->V1.InquiryUnitSerialNumber[Channel][TargetID]; |
| DAC960_Command_T *Command = Controller->Commands[Channel]; |
| DAC960_V1_DCDB_T *DCDB = DCDBs_cpu[Channel]; |
| struct completion *Completion = &Completions[Channel]; |
| |
| wait_for_completion(Completion); |
| |
| if (Command->V1.CommandStatus != DAC960_V1_NormalCompletion) { |
| memset(InquiryStandardData, 0, sizeof(DAC960_SCSI_Inquiry_T)); |
| InquiryStandardData->PeripheralDeviceType = 0x1F; |
| continue; |
| } else |
| memcpy(InquiryStandardData, NewInquiryStandardData, sizeof(DAC960_SCSI_Inquiry_T)); |
| |
| /* Preserve Channel and TargetID values from the previous loop */ |
| Command->Completion = Completion; |
| DCDB->TransferLength = sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T); |
| DCDB->BusAddress = NewInquiryUnitSerialNumberDMA; |
| DCDB->SenseLength = sizeof(DCDB->SenseData); |
| DCDB->CDB[0] = 0x12; /* INQUIRY */ |
| DCDB->CDB[1] = 1; /* EVPD = 1 */ |
| DCDB->CDB[2] = 0x80; /* Page Code */ |
| DCDB->CDB[3] = 0; /* Reserved */ |
| DCDB->CDB[4] = sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T); |
| DCDB->CDB[5] = 0; /* Control */ |
| |
| spin_lock_irqsave(&Controller->queue_lock, flags); |
| DAC960_QueueCommand(Command); |
| spin_unlock_irqrestore(&Controller->queue_lock, flags); |
| wait_for_completion(Completion); |
| |
| if (Command->V1.CommandStatus != DAC960_V1_NormalCompletion) { |
| memset(InquiryUnitSerialNumber, 0, |
| sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T)); |
| InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F; |
| } else |
| memcpy(InquiryUnitSerialNumber, NewInquiryUnitSerialNumber, |
| sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T)); |
| } |
| } |
| free_dma_loaf(Controller->PCIDevice, &local_dma); |
| return true; |
| } |
| |
| |
| /* |
| DAC960_V2_ReadDeviceConfiguration reads the Device Configuration Information |
| for DAC960 V2 Firmware Controllers by requesting the Physical Device |
| Information and SCSI Inquiry Unit Serial Number information for each |
| device connected to Controller. |
| */ |
| |
| static bool DAC960_V2_ReadDeviceConfiguration(DAC960_Controller_T |
| *Controller) |
| { |
| unsigned char Channel = 0, TargetID = 0, LogicalUnit = 0; |
| unsigned short PhysicalDeviceIndex = 0; |
| |
| while (true) |
| { |
| DAC960_V2_PhysicalDeviceInfo_T *NewPhysicalDeviceInfo = |
| Controller->V2.NewPhysicalDeviceInformation; |
| DAC960_V2_PhysicalDeviceInfo_T *PhysicalDeviceInfo; |
| DAC960_SCSI_Inquiry_UnitSerialNumber_T *NewInquiryUnitSerialNumber = |
| Controller->V2.NewInquiryUnitSerialNumber; |
| DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber; |
| |
| if (!DAC960_V2_NewPhysicalDeviceInfo(Controller, Channel, TargetID, LogicalUnit)) |
| break; |
| |
| PhysicalDeviceInfo = kmalloc(sizeof(DAC960_V2_PhysicalDeviceInfo_T), |
| GFP_ATOMIC); |
| if (PhysicalDeviceInfo == NULL) |
| return DAC960_Failure(Controller, "PHYSICAL DEVICE ALLOCATION"); |
| Controller->V2.PhysicalDeviceInformation[PhysicalDeviceIndex] = |
| PhysicalDeviceInfo; |
| memcpy(PhysicalDeviceInfo, NewPhysicalDeviceInfo, |
| sizeof(DAC960_V2_PhysicalDeviceInfo_T)); |
| |
| InquiryUnitSerialNumber = kmalloc( |
| sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T), GFP_ATOMIC); |
| if (InquiryUnitSerialNumber == NULL) { |
| kfree(PhysicalDeviceInfo); |
| return DAC960_Failure(Controller, "SERIAL NUMBER ALLOCATION"); |
| } |
| Controller->V2.InquiryUnitSerialNumber[PhysicalDeviceIndex] = |
| InquiryUnitSerialNumber; |
| |
| Channel = NewPhysicalDeviceInfo->Channel; |
| TargetID = NewPhysicalDeviceInfo->TargetID; |
| LogicalUnit = NewPhysicalDeviceInfo->LogicalUnit; |
| |
| /* |
| Some devices do NOT have Unit Serial Numbers. |
| This command fails for them. But, we still want to |
| remember those devices are there. Construct a |
| UnitSerialNumber structure for the failure case. |
| */ |
| if (!DAC960_V2_NewInquiryUnitSerialNumber(Controller, Channel, TargetID, LogicalUnit)) { |
| memset(InquiryUnitSerialNumber, 0, |
| sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T)); |
| InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F; |
| } else |
| memcpy(InquiryUnitSerialNumber, NewInquiryUnitSerialNumber, |
| sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T)); |
| |
| PhysicalDeviceIndex++; |
| LogicalUnit++; |
| } |
| return true; |
| } |
| |
| |
| /* |
| DAC960_SanitizeInquiryData sanitizes the Vendor, Model, Revision, and |
| Product Serial Number fields of the Inquiry Standard Data and Inquiry |
| Unit Serial Number structures. |
| */ |
| |
| static void DAC960_SanitizeInquiryData(DAC960_SCSI_Inquiry_T |
| *InquiryStandardData, |
| DAC960_SCSI_Inquiry_UnitSerialNumber_T |
| *InquiryUnitSerialNumber, |
| unsigned char *Vendor, |
| unsigned char *Model, |
| unsigned char *Revision, |
| unsigned char *SerialNumber) |
| { |
| int SerialNumberLength, i; |
| if (InquiryStandardData->PeripheralDeviceType == 0x1F) return; |
| for (i = 0; i < sizeof(InquiryStandardData->VendorIdentification); i++) |
| { |
| unsigned char VendorCharacter = |
| InquiryStandardData->VendorIdentification[i]; |
| Vendor[i] = (VendorCharacter >= ' ' && VendorCharacter <= '~' |
| ? VendorCharacter : ' '); |
| } |
| Vendor[sizeof(InquiryStandardData->VendorIdentification)] = '\0'; |
| for (i = 0; i < sizeof(InquiryStandardData->ProductIdentification); i++) |
| { |
| unsigned char ModelCharacter = |
| InquiryStandardData->ProductIdentification[i]; |
| Model[i] = (ModelCharacter >= ' ' && ModelCharacter <= '~' |
| ? ModelCharacter : ' '); |
| } |
| Model[sizeof(InquiryStandardData->ProductIdentification)] = '\0'; |
| for (i = 0; i < sizeof(InquiryStandardData->ProductRevisionLevel); i++) |
| { |
| unsigned char RevisionCharacter = |
| InquiryStandardData->ProductRevisionLevel[i]; |
| Revision[i] = (RevisionCharacter >= ' ' && RevisionCharacter <= '~' |
| ? RevisionCharacter : ' '); |
| } |
| Revision[sizeof(InquiryStandardData->ProductRevisionLevel)] = '\0'; |
| if (InquiryUnitSerialNumber->PeripheralDeviceType == 0x1F) return; |
| SerialNumberLength = InquiryUnitSerialNumber->PageLength; |
| if (SerialNumberLength > |
| sizeof(InquiryUnitSerialNumber->ProductSerialNumber)) |
| SerialNumberLength = sizeof(InquiryUnitSerialNumber->ProductSerialNumber); |
| for (i = 0; i < SerialNumberLength; i++) |
| { |
| unsigned char SerialNumberCharacter = |
| InquiryUnitSerialNumber->ProductSerialNumber[i]; |
| SerialNumber[i] = |
| (SerialNumberCharacter >= ' ' && SerialNumberCharacter <= '~' |
| ? SerialNumberCharacter : ' '); |
| } |
| SerialNumber[SerialNumberLength] = '\0'; |
| } |
| |
| |
| /* |
| DAC960_V1_ReportDeviceConfiguration reports the Device Configuration |
| Information for DAC960 V1 Firmware Controllers. |
| */ |
| |
| static bool DAC960_V1_ReportDeviceConfiguration(DAC960_Controller_T |
| *Controller) |
| { |
| int LogicalDriveNumber, Channel, TargetID; |
| DAC960_Info(" Physical Devices:\n", Controller); |
| for (Channel = 0; Channel < Controller->Channels; Channel++) |
| for (TargetID = 0; TargetID < Controller->Targets; TargetID++) |
| { |
| DAC960_SCSI_Inquiry_T *InquiryStandardData = |
| &Controller->V1.InquiryStandardData[Channel][TargetID]; |
| DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber = |
| &Controller->V1.InquiryUnitSerialNumber[Channel][TargetID]; |
| DAC960_V1_DeviceState_T *DeviceState = |
| &Controller->V1.DeviceState[Channel][TargetID]; |
| DAC960_V1_ErrorTableEntry_T *ErrorEntry = |
| &Controller->V1.ErrorTable.ErrorTableEntries[Channel][TargetID]; |
| char Vendor[1+sizeof(InquiryStandardData->VendorIdentification)]; |
| char Model[1+sizeof(InquiryStandardData->ProductIdentification)]; |
| char Revision[1+sizeof(InquiryStandardData->ProductRevisionLevel)]; |
| char SerialNumber[1+sizeof(InquiryUnitSerialNumber |
| ->ProductSerialNumber)]; |
| if (InquiryStandardData->PeripheralDeviceType == 0x1F) continue; |
| DAC960_SanitizeInquiryData(InquiryStandardData, InquiryUnitSerialNumber, |
| Vendor, Model, Revision, SerialNumber); |
| DAC960_Info(" %d:%d%s Vendor: %s Model: %s Revision: %s\n", |
| Controller, Channel, TargetID, (TargetID < 10 ? " " : ""), |
| Vendor, Model, Revision); |
| if (InquiryUnitSerialNumber->PeripheralDeviceType != 0x1F) |
| DAC960_Info(" Serial Number: %s\n", Controller, SerialNumber); |
| if (DeviceState->Present && |
| DeviceState->DeviceType == DAC960_V1_DiskType) |
| { |
| if (Controller->V1.DeviceResetCount[Channel][TargetID] > 0) |
| DAC960_Info(" Disk Status: %s, %u blocks, %d resets\n", |
| Controller, |
| (DeviceState->DeviceState == DAC960_V1_Device_Dead |
| ? "Dead" |
| : DeviceState->DeviceState |
| == DAC960_V1_Device_WriteOnly |
| ? "Write-Only" |
| : DeviceState->DeviceState |
| == DAC960_V1_Device_Online |
| ? "Online" : "Standby"), |
| DeviceState->DiskSize, |
| Controller->V1.DeviceResetCount[Channel][TargetID]); |
| else |
| DAC960_Info(" Disk Status: %s, %u blocks\n", Controller, |
| (DeviceState->DeviceState == DAC960_V1_Device_Dead |
| ? "Dead" |
| : DeviceState->DeviceState |
| == DAC960_V1_Device_WriteOnly |
| ? "Write-Only" |
| : DeviceState->DeviceState |
| == DAC960_V1_Device_Online |
| ? "Online" : "Standby"), |
| DeviceState->DiskSize); |
| } |
| if (ErrorEntry->ParityErrorCount > 0 || |
| ErrorEntry->SoftErrorCount > 0 || |
| ErrorEntry->HardErrorCount > 0 || |
| ErrorEntry->MiscErrorCount > 0) |
| DAC960_Info(" Errors - Parity: %d, Soft: %d, " |
| "Hard: %d, Misc: %d\n", Controller, |
| ErrorEntry->ParityErrorCount, |
| ErrorEntry->SoftErrorCount, |
| ErrorEntry->HardErrorCount, |
| ErrorEntry->MiscErrorCount); |
| } |
| DAC960_Info(" Logical Drives:\n", Controller); |
| for (LogicalDriveNumber = 0; |
| LogicalDriveNumber < Controller->LogicalDriveCount; |
| LogicalDriveNumber++) |
| { |
| DAC960_V1_LogicalDriveInformation_T *LogicalDriveInformation = |
| &Controller->V1.LogicalDriveInformation[LogicalDriveNumber]; |
| DAC960_Info(" /dev/rd/c%dd%d: RAID-%d, %s, %u blocks, %s\n", |
| Controller, Controller->ControllerNumber, LogicalDriveNumber, |
| LogicalDriveInformation->RAIDLevel, |
| (LogicalDriveInformation->LogicalDriveState |
| == DAC960_V1_LogicalDrive_Online |
| ? "Online" |
| : LogicalDriveInformation->LogicalDriveState |
| == DAC960_V1_LogicalDrive_Critical |
| ? "Critical" : "Offline"), |
| LogicalDriveInformation->LogicalDriveSize, |
| (LogicalDriveInformation->WriteBack |
| ? "Write Back" : "Write Thru")); |
| } |
| return true; |
| } |
| |
| |
| /* |
| DAC960_V2_ReportDeviceConfiguration reports the Device Configuration |
| Information for DAC960 V2 Firmware Controllers. |
| */ |
| |
| static bool DAC960_V2_ReportDeviceConfiguration(DAC960_Controller_T |
| *Controller) |
| { |
| int PhysicalDeviceIndex, LogicalDriveNumber; |
| DAC960_Info(" Physical Devices:\n", Controller); |
| for (PhysicalDeviceIndex = 0; |
| PhysicalDeviceIndex < DAC960_V2_MaxPhysicalDevices; |
| PhysicalDeviceIndex++) |
| { |
| DAC960_V2_PhysicalDeviceInfo_T *PhysicalDeviceInfo = |
| Controller->V2.PhysicalDeviceInformation[PhysicalDeviceIndex]; |
| DAC960_SCSI_Inquiry_T *InquiryStandardData = |
| (DAC960_SCSI_Inquiry_T *) &PhysicalDeviceInfo->SCSI_InquiryData; |
| DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber = |
| Controller->V2.InquiryUnitSerialNumber[PhysicalDeviceIndex]; |
| char Vendor[1+sizeof(InquiryStandardData->VendorIdentification)]; |
| char Model[1+sizeof(InquiryStandardData->ProductIdentification)]; |
| char Revision[1+sizeof(InquiryStandardData->ProductRevisionLevel)]; |
| char SerialNumber[1+sizeof(InquiryUnitSerialNumber->ProductSerialNumber)]; |
| if (PhysicalDeviceInfo == NULL) break; |
| DAC960_SanitizeInquiryData(InquiryStandardData, InquiryUnitSerialNumber, |
| Vendor, Model, Revision, SerialNumber); |
| DAC960_Info(" %d:%d%s Vendor: %s Model: %s Revision: %s\n", |
| Controller, |
| PhysicalDeviceInfo->Channel, |
| PhysicalDeviceInfo->TargetID, |
| (PhysicalDeviceInfo->TargetID < 10 ? " " : ""), |
| Vendor, Model, Revision); |
| if (PhysicalDeviceInfo->NegotiatedSynchronousMegaTransfers == 0) |
| DAC960_Info(" %sAsynchronous\n", Controller, |
| (PhysicalDeviceInfo->NegotiatedDataWidthBits == 16 |
| ? "Wide " :"")); |
| else |
| DAC960_Info(" %sSynchronous at %d MB/sec\n", Controller, |
| (PhysicalDeviceInfo->NegotiatedDataWidthBits == 16 |
| ? "Wide " :""), |
| (PhysicalDeviceInfo->NegotiatedSynchronousMegaTransfers |
| * PhysicalDeviceInfo->NegotiatedDataWidthBits/8)); |
| if (InquiryUnitSerialNumber->PeripheralDeviceType != 0x1F) |
| DAC960_Info(" Serial Number: %s\n", Controller, SerialNumber); |
| if (PhysicalDeviceInfo->PhysicalDeviceState == |
| DAC960_V2_Device_Unconfigured) |
| continue; |
| DAC960_Info(" Disk Status: %s, %u blocks\n", Controller, |
| (PhysicalDeviceInfo->PhysicalDeviceState |
| == DAC960_V2_Device_Online |
| ? "Online" |
| : PhysicalDeviceInfo->PhysicalDeviceState |
| == DAC960_V2_Device_Rebuild |
| ? "Rebuild" |
| : PhysicalDeviceInfo->PhysicalDeviceState |
| == DAC960_V2_Device_Missing |
| ? "Missing" |
| : PhysicalDeviceInfo->PhysicalDeviceState |
| == DAC960_V2_Device_Critical |
| ? "Critical" |
| : PhysicalDeviceInfo->PhysicalDeviceState |
| == DAC960_V2_Device_Dead |
| ? "Dead" |
| : PhysicalDeviceInfo->PhysicalDeviceState |
| == DAC960_V2_Device_SuspectedDead |
| ? "Suspected-Dead" |
| : PhysicalDeviceInfo->PhysicalDeviceState |
| == DAC960_V2_Device_CommandedOffline |
| ? "Commanded-Offline" |
| : PhysicalDeviceInfo->PhysicalDeviceState |
| == DAC960_V2_Device_Standby |
| ? "Standby" : "Unknown"), |
| PhysicalDeviceInfo->ConfigurableDeviceSize); |
| if (PhysicalDeviceInfo->ParityErrors == 0 && |
| PhysicalDeviceInfo->SoftErrors == 0 && |
| PhysicalDeviceInfo->HardErrors == 0 && |
| PhysicalDeviceInfo->MiscellaneousErrors == 0 && |
| PhysicalDeviceInfo->CommandTimeouts == 0 && |
| PhysicalDeviceInfo->Retries == 0 && |
| PhysicalDeviceInfo->Aborts == 0 && |
| PhysicalDeviceInfo->PredictedFailuresDetected == 0) |
| continue; |
| DAC960_Info(" Errors - Parity: %d, Soft: %d, " |
| "Hard: %d, Misc: %d\n", Controller, |
| PhysicalDeviceInfo->ParityErrors, |
| PhysicalDeviceInfo->SoftErrors, |
| PhysicalDeviceInfo->HardErrors, |
| PhysicalDeviceInfo->MiscellaneousErrors); |
| DAC960_Info(" Timeouts: %d, Retries: %d, " |
| "Aborts: %d, Predicted: %d\n", Controller, |
| PhysicalDeviceInfo->CommandTimeouts, |
| PhysicalDeviceInfo->Retries, |
| PhysicalDeviceInfo->Aborts, |
| PhysicalDeviceInfo->PredictedFailuresDetected); |
| } |
| DAC960_Info(" Logical Drives:\n", Controller); |
| for (LogicalDriveNumber = 0; |
| LogicalDriveNumber < DAC960_MaxLogicalDrives; |
| LogicalDriveNumber++) |
| { |
| DAC960_V2_LogicalDeviceInfo_T *LogicalDeviceInfo = |
| Controller->V2.LogicalDeviceInformation[LogicalDriveNumber]; |
| unsigned char *ReadCacheStatus[] = { "Read Cache Disabled", |
| "Read Cache Enabled", |
| "Read Ahead Enabled", |
| "Intelligent Read Ahead Enabled", |
| "-", "-", "-", "-" }; |
| unsigned char *WriteCacheStatus[] = { "Write Cache Disabled", |
| "Logical Device Read Only", |
| "Write Cache Enabled", |
| "Intelligent Write Cache Enabled", |
| "-", "-", "-", "-" }; |
| unsigned char *GeometryTranslation; |
| if (LogicalDeviceInfo == NULL) continue; |
| switch (LogicalDeviceInfo->DriveGeometry) |
| { |
| case DAC960_V2_Geometry_128_32: |
| GeometryTranslation = "128/32"; |
| break; |
| case DAC960_V2_Geometry_255_63: |
| GeometryTranslation = "255/63"; |
| break; |
| default: |
| GeometryTranslation = "Invalid"; |
| DAC960_Error("Illegal Logical Device Geometry %d\n", |
| Controller, LogicalDeviceInfo->DriveGeometry); |
| break; |
| } |
| DAC960_Info(" /dev/rd/c%dd%d: RAID-%d, %s, %u blocks\n", |
| Controller, Controller->ControllerNumber, LogicalDriveNumber, |
| LogicalDeviceInfo->RAIDLevel, |
| (LogicalDeviceInfo->LogicalDeviceState |
| == DAC960_V2_LogicalDevice_Online |
| ? "Online" |
| : LogicalDeviceInfo->LogicalDeviceState |
| == DAC960_V2_LogicalDevice_Critical |
| ? "Critical" : "Offline"), |
| LogicalDeviceInfo->ConfigurableDeviceSize); |
| DAC960_Info(" Logical Device %s, BIOS Geometry: %s\n", |
| Controller, |
| (LogicalDeviceInfo->LogicalDeviceControl |
| .LogicalDeviceInitialized |
| ? "Initialized" : "Uninitialized"), |
| GeometryTranslation); |
| if (LogicalDeviceInfo->StripeSize == 0) |
| { |
| if (LogicalDeviceInfo->CacheLineSize == 0) |
| DAC960_Info(" Stripe Size: N/A, " |
| "Segment Size: N/A\n", Controller); |
| else |
| DAC960_Info(" Stripe Size: N/A, " |
| "Segment Size: %dKB\n", Controller, |
| 1 << (LogicalDeviceInfo->CacheLineSize - 2)); |
| } |
| else |
| { |
| if (LogicalDeviceInfo->CacheLineSize == 0) |
| DAC960_Info(" Stripe Size: %dKB, " |
| "Segment Size: N/A\n", Controller, |
| 1 << (LogicalDeviceInfo->StripeSize - 2)); |
| else |
| DAC960_Info(" Stripe Size: %dKB, " |
| "Segment Size: %dKB\n", Controller, |
| 1 << (LogicalDeviceInfo->StripeSize - 2), |
| 1 << (LogicalDeviceInfo->CacheLineSize - 2)); |
| } |
| DAC960_Info(" %s, %s\n", Controller, |
| ReadCacheStatus[ |
| LogicalDeviceInfo->LogicalDeviceControl.ReadCache], |
| WriteCacheStatus[ |
| LogicalDeviceInfo->LogicalDeviceControl.WriteCache]); |
| if (LogicalDeviceInfo->SoftErrors > 0 || |
| LogicalDeviceInfo->CommandsFailed > 0 || |
| LogicalDeviceInfo->DeferredWriteErrors) |
| DAC960_Info(" Errors - Soft: %d, Failed: %d, " |
| "Deferred Write: %d\n", Controller, |
| LogicalDeviceInfo->SoftErrors, |
| LogicalDeviceInfo->CommandsFailed, |
| LogicalDeviceInfo->DeferredWriteErrors); |
| |
| } |
| return true; |
| } |
| |
| /* |
| DAC960_RegisterBlockDevice registers the Block Device structures |
| associated with Controller. |
| */ |
| |
| static bool DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller) |
| { |
| int MajorNumber = DAC960_MAJOR + Controller->ControllerNumber; |
| int n; |
| |
| /* |
| Register the Block Device Major Number for this DAC960 Controller. |
| */ |
| if (register_blkdev(MajorNumber, "dac960") < 0) |
| return false; |
| |
| for (n = 0; n < DAC960_MaxLogicalDrives; n++) { |
| struct gendisk *disk = Controller->disks[n]; |
| struct request_queue *RequestQueue; |
| |
| /* for now, let all request queues share controller's lock */ |
| RequestQueue = blk_init_queue(DAC960_RequestFunction,&Controller->queue_lock); |
| if (!RequestQueue) { |
| printk("DAC960: failure to allocate request queue\n"); |
| continue; |
| } |
| Controller->RequestQueue[n] = RequestQueue; |
| blk_queue_bounce_limit(RequestQueue, Controller->BounceBufferLimit); |
| RequestQueue->queuedata = Controller; |
| blk_queue_max_segments(RequestQueue, Controller->DriverScatterGatherLimit); |
| blk_queue_max_hw_sectors(RequestQueue, Controller->MaxBlocksPerCommand); |
| disk->queue = RequestQueue; |
| sprintf(disk->disk_name, "rd/c%dd%d", Controller->ControllerNumber, n); |
| disk->major = MajorNumber; |
| disk->first_minor = n << DAC960_MaxPartitionsBits; |
| disk->fops = &DAC960_BlockDeviceOperations; |
| } |
| /* |
| 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; |
| int disk; |
| |
| /* does order matter when deleting gendisk and cleanup in request queue? */ |
| for (disk = 0; disk < DAC960_MaxLogicalDrives; disk++) { |
| del_gendisk(Controller->disks[disk]); |
| blk_cleanup_queue(Controller->RequestQueue[disk]); |
| Controller->RequestQueue[disk] = NULL; |
| } |
| |
| /* |
| Unregister the Block Device Major Number for this DAC960 Controller. |
| */ |
| unregister_blkdev(MajorNumber, "dac960"); |
| } |
| |
| /* |
| DAC960_ComputeGenericDiskInfo computes the values for the Generic Disk |
| Information Partition Sector Counts and Block Sizes. |
| */ |
| |
| static void DAC960_ComputeGenericDiskInfo(DAC960_Controller_T *Controller) |
| { |
| int disk; |
| for (disk = 0; disk < DAC960_MaxLogicalDrives; disk++) |
| set_capacity(Controller->disks[disk], disk_size(Controller, disk)); |
| } |
| |
| /* |
| DAC960_ReportErrorStatus reports Controller BIOS Messages passed through |
| the Error Status Register when the driver performs the BIOS handshaking. |
| It returns true for fatal errors and false otherwise. |
| */ |
| |
| static bool DAC960_ReportErrorStatus(DAC960_Controller_T *Controller, |
| unsigned char ErrorStatus, |
| unsigned char Parameter0, |
| unsigned char Parameter1) |
| { |
| switch (ErrorStatus) |
| { |
| case 0x00: |
| DAC960_Notice("Physical Device %d:%d Not Responding\n", |
| Controller, Parameter1, Parameter0); |
| break; |
| case 0x08: |
| if (Controller->DriveSpinUpMessageDisplayed) break; |
| DAC960_Notice("Spinning Up Drives\n", Controller); |
| Controller->DriveSpinUpMessageDisplayed = true; |
| break; |
| case 0x30: |
| DAC960_Notice("Configuration Checksum Error\n", Controller); |
| break; |
| case 0x60: |
| DAC960_Notice("Mirror Race Recovery Failed\n", Controller); |
| break; |
| case 0x70: |
| DAC960_Notice("Mirror Race Recovery In Progress\n", Controller); |
| break; |
| case 0x90: |
| DAC960_Notice("Physical Device %d:%d COD Mismatch\n", |
| Controller, Parameter1, Parameter0); |
| break; |
| case 0xA0: |
| DAC960_Notice("Logical Drive Installation Aborted\n", Controller); |
| break; |
| case 0xB0: |
| DAC960_Notice("Mirror Race On A Critical Logical Drive\n", Controller); |
| break; |
| case 0xD0: |
| DAC960_Notice("New Controller Configuration Found\n", Controller); |
| break; |
| case 0xF0: |
| DAC960_Error("Fatal Memory Parity Error for Controller at\n", Controller); |
| return true; |
| default: |
| DAC960_Error("Unknown Initialization Error %02X for Controller at\n", |
| Controller, ErrorStatus); |
| return true; |
| } |
| return false; |
| } |
| |
| |
| /* |
| * DAC960_DetectCleanup releases the resources that were allocated |
| * during DAC960_DetectController(). DAC960_DetectController can |
| * has several internal failure points, so not ALL resources may |
| * have been allocated. It's important to free only |
| * resources that HAVE been allocated. The code below always |
| * tests that the resource has been allocated before attempting to |
| * free it. |
| */ |
| static void DAC960_DetectCleanup(DAC960_Controller_T *Controller) |
| { |
| int i; |
| |
| /* Free the memory mailbox, status, and related structures */ |
| free_dma_loaf(Controller->PCIDevice, &Controller->DmaPages); |
| if (Controller->MemoryMappedAddress) { |
| switch(Controller->HardwareType) |
| { |
| case DAC960_GEM_Controller: |
| DAC960_GEM_DisableInterrupts(Controller->BaseAddress); |
| break; |
| case DAC960_BA_Controller: |
| DAC960_BA_DisableInterrupts(Controller->BaseAddress); |
| break; |
| case DAC960_LP_Controller: |
| DAC960_LP_DisableInterrupts(Controller->BaseAddress); |
| break; |
| case DAC960_LA_Controller: |
| DAC960_LA_DisableInterrupts(Controller->BaseAddress); |
| break; |
| case DAC960_PG_Controller: |
| DAC960_PG_DisableInterrupts(Controller->BaseAddress); |
| break; |
| case DAC960_PD_Controller: |
| DAC960_PD_DisableInterrupts(Controller->BaseAddress); |
| break; |
| case DAC960_P_Controller: |
| DAC960_PD_DisableInterrupts(Controller->BaseAddress); |
| break; |
| } |
| iounmap(Controller->MemoryMappedAddress); |
| } |
| if (Controller->IRQ_Channel) |
| free_irq(Controller->IRQ_Channel, Controller); |
| if (Controller->IO_Address) |
| release_region(Controller->IO_Address, 0x80); |
| pci_disable_device(Controller->PCIDevice); |
| for (i = 0; (i < DAC960_MaxLogicalDrives) && Controller->disks[i]; i++) |
| put_disk(Controller->disks[i]); |
| DAC960_Controllers[Controller->ControllerNumber] = NULL; |
| kfree(Controller); |
| } |
| |
| |
| /* |
| DAC960_DetectController detects Mylex DAC960/AcceleRAID/eXtremeRAID |
| PCI RAID Controllers by interrogating the PCI Configuration Space for |
| Controller Type. |
| */ |
| |
| static DAC960_Controller_T * |
| DAC960_DetectController(struct pci_dev *PCI_Device, |
| const struct pci_device_id *entry) |
| { |
| struct DAC960_privdata *privdata = |
| (struct DAC960_privdata *)entry->driver_data; |
| irq_handler_t InterruptHandler = privdata->InterruptHandler; |
| unsigned int MemoryWindowSize = privdata->MemoryWindowSize; |
| DAC960_Controller_T *Controller = NULL; |
| unsigned char DeviceFunction = PCI_Device->devfn; |
| unsigned char ErrorStatus, Parameter0, Parameter1; |
| unsigned int IRQ_Channel; |
| void __iomem *BaseAddress; |
| int i; |
| |
| Controller = kzalloc(sizeof(DAC960_Controller_T), GFP_ATOMIC); |
| if (Controller == NULL) { |
| DAC960_Error("Unable to allocate Controller structure for " |
| "Controller at\n", NULL); |
| return NULL; |
| } |
| Controller->ControllerNumber = DAC960_ControllerCount; |
| DAC960_Controllers[DAC960_ControllerCount++] = Controller; |
| Controller->Bus = PCI_Device->bus->number; |
| Controller->FirmwareType = privdata->FirmwareType; |
| Controller->HardwareType = privdata->HardwareType; |
| Controller->Device = DeviceFunction >> 3; |
| Controller->Function = DeviceFunction & 0x7; |
| Controller->PCIDevice = PCI_Device; |
| strcpy(Controller->FullModelName, "DAC960"); |
| |
| if (pci_enable_device(PCI_Device)) |
| goto Failure; |
| |
| switch (Controller->HardwareType) |
| { |
| case DAC960_GEM_Controller: |
| Controller->PCI_Address = pci_resource_start(PCI_Device, 0); |
| break; |
| case DAC960_BA_Controller: |
| Controller->PCI_Address = pci_resource_start(PCI_Device, 0); |
| break; |
| case DAC960_LP_Controller: |
| Controller->PCI_Address = pci_resource_start(PCI_Device, 0); |
| break; |
| case DAC960_LA_Controller: |
| Controller->PCI_Address = pci_resource_start(PCI_Device, 0); |
| break; |
| case DAC960_PG_Controller: |
| Controller->PCI_Address = pci_resource_start(PCI_Device, 0); |
| break; |
| case DAC960_PD_Controller: |
| Controller->IO_Address = pci_resource_start(PCI_Device, 0); |
| Controller->PCI_Address = pci_resource_start(PCI_Device, 1); |
| break; |
| case DAC960_P_Controller: |
| Controller->IO_Address = pci_resource_start(PCI_Device, 0); |
| Controller->PCI_Address = pci_resource_start(PCI_Device, 1); |
| break; |
| } |
| |
| pci_set_drvdata(PCI_Device, (void *)((long)Controller->ControllerNumber)); |
| for (i = 0; i < DAC960_MaxLogicalDrives; i++) { |
| Controller->disks[i] = alloc_disk(1<<DAC960_MaxPartitionsBits); |
| if (!Controller->disks[i]) |
| goto Failure; |
| Controller->disks[i]->private_data = (void *)((long)i); |
| } |
| init_waitqueue_head(&Controller->CommandWaitQueue); |
| init_waitqueue_head(&Controller->HealthStatusWaitQueue); |
| spin_lock_init(&Controller->queue_lock); |
| DAC960_AnnounceDriver(Controller); |
| /* |
| Map the Controller Register Window. |
| */ |
| if (MemoryWindowSize < PAGE_SIZE) |
| MemoryWindowSize = PAGE_SIZE; |
| Controller->MemoryMappedAddress = |
| ioremap_nocache(Controller->PCI_Address & PAGE_MASK, MemoryWindowSize); |
| Controller->BaseAddress = |
| Controller->MemoryMappedAddress + (Controller->PCI_Address & ~PAGE_MASK); |
| if (Controller->MemoryMappedAddress == NULL) |
| { |
| DAC960_Error("Unable to map Controller Register Window for " |
| "Controller at\n", Controller); |
| goto Failure; |
| } |
| BaseAddress = Controller->BaseAddress; |
| switch (Controller->HardwareType) |
| { |
| case DAC960_GEM_Controller: |
| DAC960_GEM_DisableInterrupts(BaseAddress); |
| DAC960_GEM_AcknowledgeHardwareMailboxStatus(BaseAddress); |
| udelay(1000); |
| while (DAC960_GEM_InitializationInProgressP(BaseAddress)) |
| { |
| if (DAC960_GEM_ReadErrorStatus(BaseAddress, &ErrorStatus, |
| &Parameter0, &Parameter1) && |
| DAC960_ReportErrorStatus(Controller, ErrorStatus, |
| Parameter0, Parameter1)) |
| goto Failure; |
| udelay(10); |
| } |
| if (!DAC960_V2_EnableMemoryMailboxInterface(Controller)) |
| { |
| DAC960_Error("Unable to Enable Memory Mailbox Interface " |
| "for Controller at\n", Controller); |
| goto Failure; |
| } |
| DAC960_GEM_EnableInterrupts(BaseAddress); |
| Controller->QueueCommand = DAC960_GEM_QueueCommand; |
| Controller->ReadControllerConfiguration = |
| DAC960_V2_ReadControllerConfiguration; |
| Controller->ReadDeviceConfiguration = |
| DAC960_V2_ReadDeviceConfiguration; |
| Controller->ReportDeviceConfiguration |