summaryrefslogtreecommitdiffstats
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.c72
1 files changed, 61 insertions, 11 deletions
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
index 956261f2518..94d2954d79a 100644
--- a/drivers/scsi/aacraid/commsup.c
+++ b/drivers/scsi/aacraid/commsup.c
@@ -189,7 +189,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))
@@ -390,6 +397,8 @@ 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;
+
if (!(hw_fib->header.XferState & cpu_to_le32(HostOwned)))
return -EBUSY;
@@ -471,9 +480,31 @@ 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 (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.
@@ -516,14 +547,15 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
udelay(5);
}
} else if (down_interruptible(&fibptr->event_wait)) {
- fibptr->done = 2;
- up(&fibptr->event_wait);
+ /* Do nothing ... satisfy
+ * down_interruptible must_check */
}
+
spin_lock_irqsave(&fibptr->event_lock, flags);
- if ((fibptr->done == 0) || (fibptr->done == 2)) {
+ 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);
@@ -689,6 +721,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;
/*
@@ -709,6 +742,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)))
{
@@ -1355,7 +1395,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);
}
}
@@ -1759,6 +1802,7 @@ int aac_command_thread(void *data)
struct fib *fibptr;
if ((fibptr = aac_fib_alloc(dev))) {
+ int status;
__le32 *info;
aac_fib_init(fibptr);
@@ -1769,15 +1813,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 {