aboutsummaryrefslogtreecommitdiff
path: root/drivers/scsi/aacraid/dpcsup.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/aacraid/dpcsup.c')
-rw-r--r--drivers/scsi/aacraid/dpcsup.c182
1 files changed, 137 insertions, 45 deletions
diff --git a/drivers/scsi/aacraid/dpcsup.c b/drivers/scsi/aacraid/dpcsup.c
index 439948ef825..d81b2810f0f 100644
--- a/drivers/scsi/aacraid/dpcsup.c
+++ b/drivers/scsi/aacraid/dpcsup.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 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
@@ -32,13 +33,11 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/pci.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/completion.h>
#include <linux/blkdev.h>
-#include <asm/semaphore.h>
+#include <linux/semaphore.h>
#include "aacraid.h"
@@ -59,9 +58,9 @@ unsigned int aac_response_normal(struct aac_queue * q)
struct hw_fib * hwfib;
struct fib * fib;
int consumed = 0;
- unsigned long flags;
+ unsigned long flags, mflags;
- spin_lock_irqsave(q->lock, flags);
+ spin_lock_irqsave(q->lock, flags);
/*
* Keep pulling response QEs off the response queue and waking
* up the waiters until there are no more QEs. We then return
@@ -74,7 +73,7 @@ unsigned int aac_response_normal(struct aac_queue * q)
u32 index = le32_to_cpu(entry->addr);
fast = index & 0x01;
fib = &dev->fibs[index >> 2];
- hwfib = fib->hw_fib;
+ hwfib = fib->hw_fib_va;
aac_consumer_free(dev, q, HostNormRespQueue);
/*
@@ -85,12 +84,13 @@ unsigned int aac_response_normal(struct aac_queue * q)
* continue. The caller has already been notified that
* the fib timed out.
*/
- if (!(fib->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) {
- list_del(&fib->queue);
- dev->queues->queue[AdapNormCmdQueue].numpending--;
- } else {
- printk(KERN_WARNING "aacraid: FIB timeout (%x).\n", fib->flags);
- printk(KERN_DEBUG"aacraid: hwfib=%p fib index=%i fib=%p\n",hwfib, hwfib->header.SenderData,fib);
+ dev->queues->queue[AdapNormCmdQueue].numpending--;
+
+ if (unlikely(fib->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) {
+ spin_unlock_irqrestore(q->lock, flags);
+ aac_fib_complete(fib);
+ aac_fib_free(fib);
+ spin_lock_irqsave(q->lock, flags);
continue;
}
spin_unlock_irqrestore(q->lock, flags);
@@ -101,6 +101,7 @@ unsigned int aac_response_normal(struct aac_queue * q)
*/
*(__le32 *)hwfib->data = cpu_to_le32(ST_OK);
hwfib->header.XferState |= cpu_to_le32(AdapterProcessed);
+ fib->flags |= FIB_CONTEXT_FLAG_FASTRESP;
}
FIB_COUNTER_INCREMENT(aac_config.FibRecved);
@@ -121,14 +122,29 @@ unsigned int aac_response_normal(struct aac_queue * q)
* NOTE: we cannot touch the fib after this
* call, because it may have been deallocated.
*/
+ fib->flags &= FIB_CONTEXT_FLAG_FASTRESP;
fib->callback(fib->callback_data, fib);
} else {
unsigned long flagv;
spin_lock_irqsave(&fib->event_lock, flagv);
- fib->done = 1;
- up(&fib->event_wait);
+ if (!fib->done) {
+ fib->done = 1;
+ up(&fib->event_wait);
+ }
spin_unlock_irqrestore(&fib->event_lock, flagv);
+
+ spin_lock_irqsave(&dev->manage_lock, mflags);
+ dev->management_fib_count--;
+ spin_unlock_irqrestore(&dev->manage_lock, mflags);
+
FIB_COUNTER_INCREMENT(aac_config.NormalRecved);
+ if (fib->done == 2) {
+ spin_lock_irqsave(&fib->event_lock, flagv);
+ fib->done = 0;
+ spin_unlock_irqrestore(&fib->event_lock, flagv);
+ aac_fib_complete(fib);
+ aac_fib_free(fib);
+ }
}
consumed++;
spin_lock_irqsave(q->lock, flags);
@@ -190,7 +206,7 @@ unsigned int aac_command_normal(struct aac_queue *q)
INIT_LIST_HEAD(&fib->fiblink);
fib->type = FSAFS_NTC_FIB_CONTEXT;
fib->size = sizeof(struct fib);
- fib->hw_fib = hw_fib;
+ fib->hw_fib_va = hw_fib;
fib->data = hw_fib->data;
fib->dev = dev;
@@ -206,7 +222,7 @@ unsigned int aac_command_normal(struct aac_queue *q)
* Set the status of this FIB
*/
*(__le32 *)hw_fib->data = cpu_to_le32(ST_OK);
- fib_adapter_complete(fib, sizeof(u32));
+ aac_fib_adapter_complete(fib, sizeof(u32));
spin_lock_irqsave(q->lock, flags);
}
}
@@ -214,6 +230,48 @@ unsigned int aac_command_normal(struct aac_queue *q)
return 0;
}
+/*
+ *
+ * aac_aif_callback
+ * @context: the context set in the fib - here it is scsi cmd
+ * @fibptr: pointer to the fib
+ *
+ * Handles the AIFs - new method (SRC)
+ *
+ */
+
+static void aac_aif_callback(void *context, struct fib * fibptr)
+{
+ struct fib *fibctx;
+ struct aac_dev *dev;
+ struct aac_aifcmd *cmd;
+ int status;
+
+ fibctx = (struct fib *)context;
+ BUG_ON(fibptr == NULL);
+ dev = fibptr->dev;
+
+ if (fibptr->hw_fib_va->header.XferState &
+ cpu_to_le32(NoMoreAifDataAvailable)) {
+ aac_fib_complete(fibptr);
+ aac_fib_free(fibptr);
+ return;
+ }
+
+ aac_intr_normal(dev, 0, 1, 0, fibptr->hw_fib_va);
+
+ aac_fib_init(fibctx);
+ cmd = (struct aac_aifcmd *) fib_data(fibctx);
+ cmd->command = cpu_to_le32(AifReqEvent);
+
+ status = aac_fib_send(AifRequest,
+ fibctx,
+ sizeof(struct hw_fib)-sizeof(struct aac_fibhdr),
+ FsaNormal,
+ 0, 1,
+ (fib_callback)aac_aif_callback, fibctx);
+}
+
/**
* aac_intr_normal - Handle command replies
@@ -224,39 +282,40 @@ unsigned int aac_command_normal(struct aac_queue *q)
* know there is a response on our normal priority queue. We will pull off
* all QE there are and wake up all the waiters before exiting.
*/
-
-unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index)
+unsigned int aac_intr_normal(struct aac_dev *dev, u32 index,
+ int isAif, int isFastResponse, struct hw_fib *aif_fib)
{
- u32 index = le32_to_cpu(Index);
-
- dprintk((KERN_INFO "aac_intr_normal(%p,%x)\n", dev, Index));
- if ((index & 0x00000002L)) {
+ unsigned long mflags;
+ dprintk((KERN_INFO "aac_intr_normal(%p,%x)\n", dev, index));
+ if (isAif == 1) { /* AIF - common */
struct hw_fib * hw_fib;
struct fib * fib;
struct aac_queue *q = &dev->queues->queue[HostNormCmdQueue];
unsigned long flags;
- if (index == 0xFFFFFFFEL) /* Special Case */
- return 0; /* Do nothing */
/*
* Allocate a FIB. For non queued stuff we can just use
* the stack so we are happy. We need a fib object in order to
* manage the linked lists.
*/
if ((!dev->aif_thread)
- || (!(fib = kmalloc(sizeof(struct fib),GFP_ATOMIC))))
+ || (!(fib = kzalloc(sizeof(struct fib),GFP_ATOMIC))))
return 1;
- if (!(hw_fib = kmalloc(sizeof(struct hw_fib),GFP_ATOMIC))) {
+ if (!(hw_fib = kzalloc(sizeof(struct hw_fib),GFP_ATOMIC))) {
kfree (fib);
return 1;
}
- memset(hw_fib, 0, sizeof(struct hw_fib));
- memcpy(hw_fib, (struct hw_fib *)(((unsigned long)(dev->regs.sa)) + (index & ~0x00000002L)), sizeof(struct hw_fib));
- memset(fib, 0, sizeof(struct fib));
+ if (aif_fib != NULL) {
+ memcpy(hw_fib, aif_fib, sizeof(struct hw_fib));
+ } else {
+ memcpy(hw_fib,
+ (struct hw_fib *)(((uintptr_t)(dev->regs.sa)) +
+ index), sizeof(struct hw_fib));
+ }
INIT_LIST_HEAD(&fib->fiblink);
fib->type = FSAFS_NTC_FIB_CONTEXT;
fib->size = sizeof(struct fib);
- fib->hw_fib = hw_fib;
+ fib->hw_fib_va = hw_fib;
fib->data = hw_fib->data;
fib->dev = dev;
@@ -265,10 +324,27 @@ unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index)
wake_up_interruptible(&q->cmdready);
spin_unlock_irqrestore(q->lock, flags);
return 1;
+ } else if (isAif == 2) { /* AIF - new (SRC) */
+ struct fib *fibctx;
+ struct aac_aifcmd *cmd;
+
+ fibctx = aac_fib_alloc(dev);
+ if (!fibctx)
+ return 1;
+ aac_fib_init(fibctx);
+
+ cmd = (struct aac_aifcmd *) fib_data(fibctx);
+ cmd->command = cpu_to_le32(AifReqEvent);
+
+ return aac_fib_send(AifRequest,
+ fibctx,
+ sizeof(struct hw_fib)-sizeof(struct aac_fibhdr),
+ FsaNormal,
+ 0, 1,
+ (fib_callback)aac_aif_callback, fibctx);
} else {
- int fast = index & 0x01;
- struct fib * fib = &dev->fibs[index >> 2];
- struct hw_fib * hwfib = fib->hw_fib;
+ struct fib *fib = &dev->fibs[index];
+ struct hw_fib * hwfib = fib->hw_fib_va;
/*
* Remove this fib from the Outstanding I/O queue.
@@ -278,28 +354,28 @@ unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index)
* continue. The caller has already been notified that
* the fib timed out.
*/
- if ((fib->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) {
- printk(KERN_WARNING "aacraid: FIB timeout (%x).\n", fib->flags);
- printk(KERN_DEBUG"aacraid: hwfib=%p index=%i fib=%p\n",hwfib, hwfib->header.SenderData,fib);
+ dev->queues->queue[AdapNormCmdQueue].numpending--;
+
+ if (unlikely(fib->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) {
+ aac_fib_complete(fib);
+ aac_fib_free(fib);
return 0;
}
- list_del(&fib->queue);
- dev->queues->queue[AdapNormCmdQueue].numpending--;
-
- if (fast) {
+ if (isFastResponse) {
/*
* Doctor the fib
*/
*(__le32 *)hwfib->data = cpu_to_le32(ST_OK);
hwfib->header.XferState |= cpu_to_le32(AdapterProcessed);
+ fib->flags |= FIB_CONTEXT_FLAG_FASTRESP;
}
FIB_COUNTER_INCREMENT(aac_config.FibRecved);
if (hwfib->header.Command == cpu_to_le16(NuFileSystem))
{
- u32 *pstatus = (u32 *)hwfib->data;
+ __le32 *pstatus = (__le32 *)hwfib->data;
if (*pstatus & cpu_to_le32(0xffff0000))
*pstatus = cpu_to_le32(ST_OK);
}
@@ -313,15 +389,31 @@ unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index)
* NOTE: we cannot touch the fib after this
* call, because it may have been deallocated.
*/
+ fib->flags &= FIB_CONTEXT_FLAG_FASTRESP;
fib->callback(fib->callback_data, fib);
} else {
unsigned long flagv;
dprintk((KERN_INFO "event_wait up\n"));
spin_lock_irqsave(&fib->event_lock, flagv);
- fib->done = 1;
- up(&fib->event_wait);
+ if (!fib->done) {
+ fib->done = 1;
+ up(&fib->event_wait);
+ }
spin_unlock_irqrestore(&fib->event_lock, flagv);
+
+ spin_lock_irqsave(&dev->manage_lock, mflags);
+ dev->management_fib_count--;
+ spin_unlock_irqrestore(&dev->manage_lock, mflags);
+
FIB_COUNTER_INCREMENT(aac_config.NormalRecved);
+ if (fib->done == 2) {
+ spin_lock_irqsave(&fib->event_lock, flagv);
+ fib->done = 0;
+ spin_unlock_irqrestore(&fib->event_lock, flagv);
+ aac_fib_complete(fib);
+ aac_fib_free(fib);
+ }
+
}
return 0;
}