Merge mulgrave-w:git/scsi-misc-2.6
[pandora-kernel.git] / drivers / scsi / aacraid / dpcsup.c
index be2e98d..8335f07 100644 (file)
@@ -73,7 +73,7 @@ unsigned int aac_response_normal(struct aac_queue * q)
                int fast;
                u32 index = le32_to_cpu(entry->addr);
                fast = index & 0x01;
-               fib = &dev->fibs[index >> 1];
+               fib = &dev->fibs[index >> 2];
                hwfib = fib->hw_fib;
                
                aac_consumer_free(dev, q, HostNormRespQueue);
@@ -85,10 +85,9 @@ 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);
+               if (!(fib->flags & FIB_CONTEXT_FLAG_TIMED_OUT))
                        dev->queues->queue[AdapNormCmdQueue].numpending--;
-               else {
+               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);
                        continue;
@@ -125,10 +124,15 @@ unsigned int aac_response_normal(struct aac_queue * q)
                } else {
                        unsigned long flagv;
                        spin_lock_irqsave(&fib->event_lock, flagv);
-                       fib->done = 1;
+                       if (!fib->done)
+                               fib->done = 1;
                        up(&fib->event_wait);
                        spin_unlock_irqrestore(&fib->event_lock, flagv);
                        FIB_COUNTER_INCREMENT(aac_config.NormalRecved);
+                       if (fib->done == 2) {
+                               aac_fib_complete(fib);
+                               aac_fib_free(fib);
+                       }
                }
                consumed++;
                spin_lock_irqsave(q->lock, flags);
@@ -206,10 +210,123 @@ 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);
                }               
        }
        spin_unlock_irqrestore(q->lock, flags);
        return 0;
 }
+
+
+/**
+ *     aac_intr_normal -       Handle command replies
+ *     @dev: Device
+ *     @index: completion reference
+ *
+ *     This DPC routine will be run when the adapter interrupts us to let us
+ *     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)
+{
+       u32 index = le32_to_cpu(Index);
+
+       dprintk((KERN_INFO "aac_intr_normal(%p,%x)\n", dev, Index));
+       if ((index & 0x00000002L)) {
+               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))))
+                       return 1;
+               if (!(hw_fib = kmalloc(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));
+               INIT_LIST_HEAD(&fib->fiblink);
+               fib->type = FSAFS_NTC_FIB_CONTEXT;
+               fib->size = sizeof(struct fib);
+               fib->hw_fib = hw_fib;
+               fib->data = hw_fib->data;
+               fib->dev = dev;
+       
+               spin_lock_irqsave(q->lock, flags);
+               list_add_tail(&fib->fiblink, &q->cmdq);
+               wake_up_interruptible(&q->cmdready);
+               spin_unlock_irqrestore(q->lock, flags);
+               return 1;
+       } else {
+               int fast = index & 0x01;
+               struct fib * fib = &dev->fibs[index >> 2];
+               struct hw_fib * hwfib = fib->hw_fib;
+
+               /*
+                *      Remove this fib from the Outstanding I/O queue.
+                *      But only if it has not already been timed out.
+                *
+                *      If the fib has been timed out already, then just 
+                *      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);
+                       return 0;
+               }
+
+               dev->queues->queue[AdapNormCmdQueue].numpending--;
+
+               if (fast) {
+                       /*
+                        *      Doctor the fib
+                        */
+                       *(__le32 *)hwfib->data = cpu_to_le32(ST_OK);
+                       hwfib->header.XferState |= cpu_to_le32(AdapterProcessed);
+               }
+
+               FIB_COUNTER_INCREMENT(aac_config.FibRecved);
+
+               if (hwfib->header.Command == cpu_to_le16(NuFileSystem))
+               {
+                       u32 *pstatus = (u32 *)hwfib->data;
+                       if (*pstatus & cpu_to_le32(0xffff0000))
+                               *pstatus = cpu_to_le32(ST_OK);
+               }
+               if (hwfib->header.XferState & cpu_to_le32(NoResponseExpected | Async)) 
+               {
+                       if (hwfib->header.XferState & cpu_to_le32(NoResponseExpected))
+                               FIB_COUNTER_INCREMENT(aac_config.NoResponseRecved);
+                       else 
+                               FIB_COUNTER_INCREMENT(aac_config.AsyncRecved);
+                       /*
+                        *      NOTE:  we cannot touch the fib after this
+                        *          call, because it may have been deallocated.
+                        */
+                       fib->callback(fib->callback_data, fib);
+               } else {
+                       unsigned long flagv;
+                       dprintk((KERN_INFO "event_wait up\n"));
+                       spin_lock_irqsave(&fib->event_lock, flagv);
+                       if (!fib->done)
+                               fib->done = 1;
+                       up(&fib->event_wait);
+                       spin_unlock_irqrestore(&fib->event_lock, flagv);
+                       FIB_COUNTER_INCREMENT(aac_config.NormalRecved);
+               }
+               return 0;
+       }
+}