aboutsummaryrefslogtreecommitdiff
path: root/drivers/scsi/aacraid/commsup.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/aacraid/commsup.c')
-rw-r--r--drivers/scsi/aacraid/commsup.c245
1 files changed, 196 insertions, 49 deletions
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
index 47434499e82..cab190af634 100644
--- a/drivers/scsi/aacraid/commsup.c
+++ b/drivers/scsi/aacraid/commsup.c
@@ -1,11 +1,12 @@
/*
* Adaptec AAC series RAID controller driver
- * (c) Copyright 2001 Red Hat Inc. <alan@redhat.com>
+ * (c) Copyright 2001 Red Hat Inc.
*
* based on the old aacraid driver that is..
* Adaptec aacraid device driver for Linux.
*
- * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com)
+ * Copyright (c) 2000-2010 Adaptec, Inc.
+ * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -41,11 +42,11 @@
#include <linux/delay.h>
#include <linux/kthread.h>
#include <linux/interrupt.h>
+#include <linux/semaphore.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_cmnd.h>
-#include <asm/semaphore.h>
#include "aacraid.h"
@@ -63,9 +64,11 @@ static int fib_map_alloc(struct aac_dev *dev)
"allocate hardware fibs pci_alloc_consistent(%p, %d * (%d + %d), %p)\n",
dev->pdev, dev->max_fib_size, dev->scsi_host_ptr->can_queue,
AAC_NUM_MGT_FIB, &dev->hw_fib_pa));
- if((dev->hw_fib_va = pci_alloc_consistent(dev->pdev, dev->max_fib_size
- * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB),
- &dev->hw_fib_pa))==NULL)
+ dev->hw_fib_va = pci_alloc_consistent(dev->pdev,
+ (dev->max_fib_size + sizeof(struct aac_fib_xporthdr))
+ * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB) + (ALIGN32 - 1),
+ &dev->hw_fib_pa);
+ if (dev->hw_fib_va == NULL)
return -ENOMEM;
return 0;
}
@@ -91,7 +94,7 @@ void aac_fib_map_free(struct aac_dev *dev)
* aac_fib_setup - setup the fibs
* @dev: Adapter to set up
*
- * Allocate the PCI space for the fibs, map it and then intialise the
+ * Allocate the PCI space for the fibs, map it and then initialise the
* fib area, the unmapped fib data and also the free list
*/
@@ -110,9 +113,22 @@ int aac_fib_setup(struct aac_dev * dev)
if (i<0)
return -ENOMEM;
+ /* 32 byte alignment for PMC */
+ hw_fib_pa = (dev->hw_fib_pa + (ALIGN32 - 1)) & ~(ALIGN32 - 1);
+ dev->hw_fib_va = (struct hw_fib *)((unsigned char *)dev->hw_fib_va +
+ (hw_fib_pa - dev->hw_fib_pa));
+ dev->hw_fib_pa = hw_fib_pa;
+ memset(dev->hw_fib_va, 0,
+ (dev->max_fib_size + sizeof(struct aac_fib_xporthdr)) *
+ (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB));
+
+ /* add Xport header */
+ dev->hw_fib_va = (struct hw_fib *)((unsigned char *)dev->hw_fib_va +
+ sizeof(struct aac_fib_xporthdr));
+ dev->hw_fib_pa += sizeof(struct aac_fib_xporthdr);
+
hw_fib = dev->hw_fib_va;
hw_fib_pa = dev->hw_fib_pa;
- memset(hw_fib, 0, dev->max_fib_size * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB));
/*
* Initialise the fibs
*/
@@ -120,17 +136,20 @@ int aac_fib_setup(struct aac_dev * dev)
i < (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB);
i++, fibptr++)
{
+ fibptr->flags = 0;
fibptr->dev = dev;
fibptr->hw_fib_va = hw_fib;
fibptr->data = (void *) fibptr->hw_fib_va->data;
fibptr->next = fibptr+1; /* Forward chain the fibs */
- init_MUTEX_LOCKED(&fibptr->event_wait);
+ sema_init(&fibptr->event_wait, 0);
spin_lock_init(&fibptr->event_lock);
hw_fib->header.XferState = cpu_to_le32(0xffffffff);
hw_fib->header.SenderSize = cpu_to_le16(dev->max_fib_size);
fibptr->hw_fib_pa = hw_fib_pa;
- hw_fib = (struct hw_fib *)((unsigned char *)hw_fib + dev->max_fib_size);
- hw_fib_pa = hw_fib_pa + dev->max_fib_size;
+ hw_fib = (struct hw_fib *)((unsigned char *)hw_fib +
+ dev->max_fib_size + sizeof(struct aac_fib_xporthdr));
+ hw_fib_pa = hw_fib_pa +
+ dev->max_fib_size + sizeof(struct aac_fib_xporthdr);
}
/*
* Add the fib chain to the free list
@@ -189,7 +208,14 @@ struct fib *aac_fib_alloc(struct aac_dev *dev)
void aac_fib_free(struct fib *fibptr)
{
- unsigned long flags;
+ unsigned long flags, flagsv;
+
+ spin_lock_irqsave(&fibptr->event_lock, flagsv);
+ if (fibptr->done == 2) {
+ spin_unlock_irqrestore(&fibptr->event_lock, flagsv);
+ return;
+ }
+ spin_unlock_irqrestore(&fibptr->event_lock, flagsv);
spin_lock_irqsave(&fibptr->dev->fib_lock, flags);
if (unlikely(fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT))
@@ -215,11 +241,11 @@ void aac_fib_init(struct fib *fibptr)
{
struct hw_fib *hw_fib = fibptr->hw_fib_va;
+ memset(&hw_fib->header, 0, sizeof(struct aac_fibhdr));
hw_fib->header.StructType = FIB_MAGIC;
hw_fib->header.Size = cpu_to_le16(fibptr->dev->max_fib_size);
hw_fib->header.XferState = cpu_to_le32(HostOwned | FibInitialized | FibEmpty | FastResponseCapable);
- hw_fib->header.SenderFibAddress = 0; /* Filled in later if needed */
- hw_fib->header.ReceiverFibAddress = cpu_to_le32(fibptr->hw_fib_pa);
+ hw_fib->header.u.ReceiverFibAddress = cpu_to_le32(fibptr->hw_fib_pa);
hw_fib->header.SenderSize = cpu_to_le16(fibptr->dev->max_fib_size);
}
@@ -234,7 +260,6 @@ void aac_fib_init(struct fib *fibptr)
static void fib_dealloc(struct fib * fibptr)
{
struct hw_fib *hw_fib = fibptr->hw_fib_va;
- BUG_ON(hw_fib->header.StructType != FIB_MAGIC);
hw_fib->header.XferState = 0;
}
@@ -345,7 +370,7 @@ int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * hw
entry->size = cpu_to_le32(le16_to_cpu(hw_fib->header.Size));
entry->addr = hw_fib->header.SenderFibAddress;
/* Restore adapters pointer to the FIB */
- hw_fib->header.ReceiverFibAddress = hw_fib->header.SenderFibAddress; /* Let the adapter now where to find its data */
+ hw_fib->header.u.ReceiverFibAddress = hw_fib->header.SenderFibAddress; /* Let the adapter now where to find its data */
map = 0;
}
/*
@@ -390,11 +415,14 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
struct hw_fib * hw_fib = fibptr->hw_fib_va;
unsigned long flags = 0;
unsigned long qflags;
+ unsigned long mflags = 0;
+ unsigned long sflags = 0;
+
if (!(hw_fib->header.XferState & cpu_to_le32(HostOwned)))
return -EBUSY;
/*
- * There are 5 cases with the wait and reponse requested flags.
+ * There are 5 cases with the wait and response requested flags.
* The only invalid cases are if the caller requests to wait and
* does not request a response and if the caller does not want a
* response and the Fib is not allocated from pool. If a response
@@ -422,7 +450,7 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
*/
hw_fib->header.SenderFibAddress = cpu_to_le32(((u32)(fibptr - dev->fibs)) << 2);
- hw_fib->header.SenderData = (u32)(fibptr - dev->fibs);
+ hw_fib->header.Handle = (u32)(fibptr - dev->fibs) + 1;
/*
* Set FIB state to indicate where it came from and if we want a
* response from the adapter. Also load the command from the
@@ -432,7 +460,6 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
*/
hw_fib->header.Command = cpu_to_le16(command);
hw_fib->header.XferState |= cpu_to_le32(SentFromHost);
- fibptr->hw_fib_va->header.Flags = 0; /* 0 the flags field - internal only*/
/*
* Set the size of the Fib we want to send to the adapter
*/
@@ -471,9 +498,56 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
if (!dev->queues)
return -EBUSY;
- if(wait)
+ if (wait) {
+
+ spin_lock_irqsave(&dev->manage_lock, mflags);
+ if (dev->management_fib_count >= AAC_NUM_MGT_FIB) {
+ printk(KERN_INFO "No management Fibs Available:%d\n",
+ dev->management_fib_count);
+ spin_unlock_irqrestore(&dev->manage_lock, mflags);
+ return -EBUSY;
+ }
+ dev->management_fib_count++;
+ spin_unlock_irqrestore(&dev->manage_lock, mflags);
spin_lock_irqsave(&fibptr->event_lock, flags);
- aac_adapter_deliver(fibptr);
+ }
+
+ if (dev->sync_mode) {
+ if (wait)
+ spin_unlock_irqrestore(&fibptr->event_lock, flags);
+ spin_lock_irqsave(&dev->sync_lock, sflags);
+ if (dev->sync_fib) {
+ list_add_tail(&fibptr->fiblink, &dev->sync_fib_list);
+ spin_unlock_irqrestore(&dev->sync_lock, sflags);
+ } else {
+ dev->sync_fib = fibptr;
+ spin_unlock_irqrestore(&dev->sync_lock, sflags);
+ aac_adapter_sync_cmd(dev, SEND_SYNCHRONOUS_FIB,
+ (u32)fibptr->hw_fib_pa, 0, 0, 0, 0, 0,
+ NULL, NULL, NULL, NULL, NULL);
+ }
+ if (wait) {
+ fibptr->flags |= FIB_CONTEXT_FLAG_WAIT;
+ if (down_interruptible(&fibptr->event_wait)) {
+ fibptr->flags &= ~FIB_CONTEXT_FLAG_WAIT;
+ return -EFAULT;
+ }
+ return 0;
+ }
+ return -EINPROGRESS;
+ }
+
+ if (aac_adapter_deliver(fibptr) != 0) {
+ printk(KERN_ERR "aac_fib_send: returned -EBUSY\n");
+ if (wait) {
+ spin_unlock_irqrestore(&fibptr->event_lock, flags);
+ spin_lock_irqsave(&dev->manage_lock, mflags);
+ dev->management_fib_count--;
+ spin_unlock_irqrestore(&dev->manage_lock, mflags);
+ }
+ return -EBUSY;
+ }
+
/*
* If the caller wanted us to wait for response wait now.
@@ -489,10 +563,10 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
* functioning because an interrupt routing or other
* hardware failure has occurred.
*/
- unsigned long count = 36000000L; /* 3 minutes */
+ unsigned long timeout = jiffies + (180 * HZ); /* 3 minutes */
while (down_trylock(&fibptr->event_wait)) {
int blink;
- if (--count == 0) {
+ if (time_is_before_eq_jiffies(timeout)) {
struct aac_queue * q = &dev->queues->queue[AdapNormCmdQueue];
spin_lock_irqsave(q->lock, qflags);
q->numpending--;
@@ -513,15 +587,21 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
}
return -EFAULT;
}
- udelay(5);
+ /* We used to udelay() here but that absorbed
+ * a CPU when a timeout occured. Not very
+ * useful. */
+ cpu_relax();
}
- } else
- (void)down_interruptible(&fibptr->event_wait);
+ } else if (down_interruptible(&fibptr->event_wait)) {
+ /* Do nothing ... satisfy
+ * down_interruptible must_check */
+ }
+
spin_lock_irqsave(&fibptr->event_lock, flags);
if (fibptr->done == 0) {
fibptr->done = 2; /* Tell interrupt we aborted */
spin_unlock_irqrestore(&fibptr->event_lock, flags);
- return -EINTR;
+ return -ERESTARTSYS;
}
spin_unlock_irqrestore(&fibptr->event_lock, flags);
BUG_ON(fibptr->done == 0);
@@ -594,7 +674,7 @@ void aac_consumer_free(struct aac_dev * dev, struct aac_queue *q, u32 qid)
if (le32_to_cpu(*q->headers.consumer) >= q->entries)
*q->headers.consumer = cpu_to_le32(1);
else
- *q->headers.consumer = cpu_to_le32(le32_to_cpu(*q->headers.consumer)+1);
+ le32_add_cpu(q->headers.consumer, 1);
if (wasfull) {
switch (qid) {
@@ -630,17 +710,25 @@ int aac_fib_adapter_complete(struct fib *fibptr, unsigned short size)
unsigned long nointr = 0;
unsigned long qflags;
+ if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE1 ||
+ dev->comm_interface == AAC_COMM_MESSAGE_TYPE2) {
+ kfree(hw_fib);
+ return 0;
+ }
+
if (hw_fib->header.XferState == 0) {
if (dev->comm_interface == AAC_COMM_MESSAGE)
- kfree (hw_fib);
+ kfree(hw_fib);
return 0;
}
/*
* If we plan to do anything check the structure type first.
*/
- if (hw_fib->header.StructType != FIB_MAGIC) {
+ if (hw_fib->header.StructType != FIB_MAGIC &&
+ hw_fib->header.StructType != FIB_MAGIC2 &&
+ hw_fib->header.StructType != FIB_MAGIC2_64) {
if (dev->comm_interface == AAC_COMM_MESSAGE)
- kfree (hw_fib);
+ kfree(hw_fib);
return -EINVAL;
}
/*
@@ -687,6 +775,7 @@ int aac_fib_adapter_complete(struct fib *fibptr, unsigned short size)
int aac_fib_complete(struct fib *fibptr)
{
+ unsigned long flags;
struct hw_fib * hw_fib = fibptr->hw_fib_va;
/*
@@ -699,7 +788,9 @@ int aac_fib_complete(struct fib *fibptr)
* If we plan to do anything check the structure type first.
*/
- if (hw_fib->header.StructType != FIB_MAGIC)
+ if (hw_fib->header.StructType != FIB_MAGIC &&
+ hw_fib->header.StructType != FIB_MAGIC2 &&
+ hw_fib->header.StructType != FIB_MAGIC2_64)
return -EINVAL;
/*
* This block completes a cdb which orginated on the host and we
@@ -707,6 +798,13 @@ int aac_fib_complete(struct fib *fibptr)
* command is complete that we had sent to the adapter and this
* cdb could be reused.
*/
+ spin_lock_irqsave(&fibptr->event_lock, flags);
+ if (fibptr->done == 2) {
+ spin_unlock_irqrestore(&fibptr->event_lock, flags);
+ return 0;
+ }
+ spin_unlock_irqrestore(&fibptr->event_lock, flags);
+
if((hw_fib->header.XferState & cpu_to_le32(SentFromHost)) &&
(hw_fib->header.XferState & cpu_to_le32(AdapterProcessed)))
{
@@ -904,19 +1002,36 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
case AifEnAddJBOD:
case AifEnDeleteJBOD:
container = le32_to_cpu(((__le32 *)aifcmd->data)[1]);
- if ((container >> 28))
+ if ((container >> 28)) {
+ container = (u32)-1;
break;
+ }
channel = (container >> 24) & 0xF;
- if (channel >= dev->maximum_num_channels)
+ if (channel >= dev->maximum_num_channels) {
+ container = (u32)-1;
break;
+ }
id = container & 0xFFFF;
- if (id >= dev->maximum_num_physicals)
+ if (id >= dev->maximum_num_physicals) {
+ container = (u32)-1;
break;
+ }
lun = (container >> 16) & 0xFF;
+ container = (u32)-1;
channel = aac_phys_to_logical(channel);
device_config_needed =
(((__le32 *)aifcmd->data)[0] ==
cpu_to_le32(AifEnAddJBOD)) ? ADD : DELETE;
+ if (device_config_needed == ADD) {
+ device = scsi_device_lookup(dev->scsi_host_ptr,
+ channel,
+ id,
+ lun);
+ if (device) {
+ scsi_remove_device(device);
+ scsi_device_put(device);
+ }
+ }
break;
case AifEnEnclosureManagement:
@@ -931,13 +1046,18 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
case EM_DRIVE_REMOVAL:
container = le32_to_cpu(
((__le32 *)aifcmd->data)[2]);
- if ((container >> 28))
+ if ((container >> 28)) {
+ container = (u32)-1;
break;
+ }
channel = (container >> 24) & 0xF;
- if (channel >= dev->maximum_num_channels)
+ if (channel >= dev->maximum_num_channels) {
+ container = (u32)-1;
break;
+ }
id = container & 0xFFFF;
lun = (container >> 16) & 0xFF;
+ container = (u32)-1;
if (id >= dev->maximum_num_physicals) {
/* legacy dev_t ? */
if ((0x2000 <= id) || lun || channel ||
@@ -1023,9 +1143,10 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
break;
}
+ container = 0;
+retry_next:
if (device_config_needed == NOTHING)
- for (container = 0; container < dev->maximum_num_containers;
- ++container) {
+ for (; container < dev->maximum_num_containers; ++container) {
if ((dev->fsa_dev[container].config_waiting_on == 0) &&
(dev->fsa_dev[container].config_needed != NOTHING) &&
time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT)) {
@@ -1068,6 +1189,9 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
if (device) {
switch (device_config_needed) {
case DELETE:
+#if (defined(AAC_DEBUG_INSTRUMENT_AIF_DELETE))
+ scsi_remove_device(device);
+#else
if (scsi_device_online(device)) {
scsi_device_set_state(device, SDEV_OFFLINE);
sdev_printk(KERN_INFO, device,
@@ -1076,6 +1200,7 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
"array deleted" :
"enclosure services event");
}
+#endif
break;
case ADD:
if (!scsi_device_online(device)) {
@@ -1090,12 +1215,16 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
case CHANGE:
if ((channel == CONTAINER_CHANNEL)
&& (!dev->fsa_dev[container].valid)) {
+#if (defined(AAC_DEBUG_INSTRUMENT_AIF_DELETE))
+ scsi_remove_device(device);
+#else
if (!scsi_device_online(device))
break;
scsi_device_set_state(device, SDEV_OFFLINE);
sdev_printk(KERN_INFO, device,
"Device offlined - %s\n",
"array failed");
+#endif
break;
}
scsi_rescan_device(&device->sdev_gendev);
@@ -1108,6 +1237,11 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
}
if (device_config_needed == ADD)
scsi_add_device(dev->scsi_host_ptr, channel, id, lun);
+ if (channel == CONTAINER_CHANNEL) {
+ container++;
+ device_config_needed = NOTHING;
+ goto retry_next;
+ }
}
static int _aac_reset_adapter(struct aac_dev *aac, int forced)
@@ -1182,25 +1316,28 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced)
kfree(aac->queues);
aac->queues = NULL;
free_irq(aac->pdev->irq, aac);
+ if (aac->msi)
+ pci_disable_msi(aac->pdev);
kfree(aac->fsa_dev);
aac->fsa_dev = NULL;
quirks = aac_get_driver_ident(index)->quirks;
if (quirks & AAC_QUIRK_31BIT) {
- if (((retval = pci_set_dma_mask(aac->pdev, DMA_31BIT_MASK))) ||
- ((retval = pci_set_consistent_dma_mask(aac->pdev, DMA_31BIT_MASK))))
+ if (((retval = pci_set_dma_mask(aac->pdev, DMA_BIT_MASK(31)))) ||
+ ((retval = pci_set_consistent_dma_mask(aac->pdev, DMA_BIT_MASK(31)))))
goto out;
} else {
- if (((retval = pci_set_dma_mask(aac->pdev, DMA_32BIT_MASK))) ||
- ((retval = pci_set_consistent_dma_mask(aac->pdev, DMA_32BIT_MASK))))
+ if (((retval = pci_set_dma_mask(aac->pdev, DMA_BIT_MASK(32)))) ||
+ ((retval = pci_set_consistent_dma_mask(aac->pdev, DMA_BIT_MASK(32)))))
goto out;
}
if ((retval = (*(aac_get_driver_ident(index)->init))(aac)))
goto out;
if (quirks & AAC_QUIRK_31BIT)
- if ((retval = pci_set_dma_mask(aac->pdev, DMA_32BIT_MASK)))
+ if ((retval = pci_set_dma_mask(aac->pdev, DMA_BIT_MASK(32))))
goto out;
if (jafo) {
- aac->thread = kthread_run(aac_command_thread, aac, aac->name);
+ aac->thread = kthread_run(aac_command_thread, aac, "%s",
+ aac->name);
if (IS_ERR(aac->thread)) {
retval = PTR_ERR(aac->thread);
goto out;
@@ -1335,7 +1472,10 @@ int aac_reset_adapter(struct aac_dev * aac, int forced)
if (status >= 0)
aac_fib_complete(fibctx);
- aac_fib_free(fibctx);
+ /* FIB should be freed only after getting
+ * the response from the F/W */
+ if (status != -ERESTARTSYS)
+ aac_fib_free(fibctx);
}
}
@@ -1739,6 +1879,7 @@ int aac_command_thread(void *data)
struct fib *fibptr;
if ((fibptr = aac_fib_alloc(dev))) {
+ int status;
__le32 *info;
aac_fib_init(fibptr);
@@ -1749,15 +1890,21 @@ int aac_command_thread(void *data)
*info = cpu_to_le32(now.tv_sec);
- (void)aac_fib_send(SendHostTime,
+ status = aac_fib_send(SendHostTime,
fibptr,
sizeof(*info),
FsaNormal,
1, 1,
NULL,
NULL);
- aac_fib_complete(fibptr);
- aac_fib_free(fibptr);
+ /* Do not set XferState to zero unless
+ * receives a response from F/W */
+ if (status >= 0)
+ aac_fib_complete(fibptr);
+ /* FIB should be freed only after
+ * getting the response from the F/W */
+ if (status != -ERESTARTSYS)
+ aac_fib_free(fibptr);
}
difference = (long)(unsigned)update_interval*HZ;
} else {