Merge branch 'master' into for_paulus
[linux-drm-fsl-dcu.git] / drivers / scsi / aacraid / rx.c
index 729b9eb268c24ea0d103da98e4e3a965b4c75c70..c632d9354a261a5af10e9407f38d04bfcabd9bd3 100644 (file)
 
 #include "aacraid.h"
 
-static irqreturn_t aac_rx_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t aac_rx_intr_producer(int irq, void *dev_id)
 {
        struct aac_dev *dev = dev_id;
+       unsigned long bellbits;
+       u8 intstat = rx_readb(dev, MUnit.OISR);
 
-       dprintk((KERN_DEBUG "aac_rx_intr(%d,%p,%p)\n", irq, dev_id, regs));
-       if (dev->new_comm_interface) {
-               u32 Index = rx_readl(dev, MUnit.OutboundQueue);
-               if (Index == 0xFFFFFFFFL)
-                       Index = rx_readl(dev, MUnit.OutboundQueue);
-               if (Index != 0xFFFFFFFFL) {
-                       do {
-                               if (aac_intr_normal(dev, Index)) {
-                                       rx_writel(dev, MUnit.OutboundQueue, Index);
-                                       rx_writel(dev, MUnit.ODR, DoorBellAdapterNormRespReady);
-                               }
-                               Index = rx_readl(dev, MUnit.OutboundQueue);
-                       } while (Index != 0xFFFFFFFFL);
-                       return IRQ_HANDLED;
+       /*
+        *      Read mask and invert because drawbridge is reversed.
+        *      This allows us to only service interrupts that have
+        *      been enabled.
+        *      Check to see if this is our interrupt.  If it isn't just return
+        */
+       if (intstat & ~(dev->OIMR)) {
+               bellbits = rx_readl(dev, OutboundDoorbellReg);
+               if (bellbits & DoorBellPrintfReady) {
+                       aac_printf(dev, readl (&dev->IndexRegs->Mailbox[5]));
+                       rx_writel(dev, MUnit.ODR,DoorBellPrintfReady);
+                       rx_writel(dev, InboundDoorbellReg,DoorBellPrintfDone);
                }
-       } else {
-               unsigned long bellbits;
-               u8 intstat;
-               intstat = rx_readb(dev, MUnit.OISR);
-               /*
-                *      Read mask and invert because drawbridge is reversed.
-                *      This allows us to only service interrupts that have 
-                *      been enabled.
-                *      Check to see if this is our interrupt.  If it isn't just return
-                */
-               if (intstat & ~(dev->OIMR)) 
-               {
-                       bellbits = rx_readl(dev, OutboundDoorbellReg);
-                       if (bellbits & DoorBellPrintfReady) {
-                               aac_printf(dev, rx_readl (dev, IndexRegs.Mailbox[5]));
-                               rx_writel(dev, MUnit.ODR,DoorBellPrintfReady);
-                               rx_writel(dev, InboundDoorbellReg,DoorBellPrintfDone);
-                       }
-                       else if (bellbits & DoorBellAdapterNormCmdReady) {
-                               rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdReady);
-                               aac_command_normal(&dev->queues->queue[HostNormCmdQueue]);
-                       }
-                       else if (bellbits & DoorBellAdapterNormRespReady) {
-                               rx_writel(dev, MUnit.ODR,DoorBellAdapterNormRespReady);
-                               aac_response_normal(&dev->queues->queue[HostNormRespQueue]);
-                       }
-                       else if (bellbits & DoorBellAdapterNormCmdNotFull) {
-                               rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull);
-                       }
-                       else if (bellbits & DoorBellAdapterNormRespNotFull) {
-                               rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull);
-                               rx_writel(dev, MUnit.ODR, DoorBellAdapterNormRespNotFull);
-                       }
-                       return IRQ_HANDLED;
+               else if (bellbits & DoorBellAdapterNormCmdReady) {
+                       rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdReady);
+                       aac_command_normal(&dev->queues->queue[HostNormCmdQueue]);
+               }
+               else if (bellbits & DoorBellAdapterNormRespReady) {
+                       rx_writel(dev, MUnit.ODR,DoorBellAdapterNormRespReady);
+                       aac_response_normal(&dev->queues->queue[HostNormRespQueue]);
+               }
+               else if (bellbits & DoorBellAdapterNormCmdNotFull) {
+                       rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull);
+               }
+               else if (bellbits & DoorBellAdapterNormRespNotFull) {
+                       rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull);
+                       rx_writel(dev, MUnit.ODR, DoorBellAdapterNormRespNotFull);
                }
+               return IRQ_HANDLED;
+       }
+       return IRQ_NONE;
+}
+
+static irqreturn_t aac_rx_intr_message(int irq, void *dev_id)
+{
+       struct aac_dev *dev = dev_id;
+       u32 Index = rx_readl(dev, MUnit.OutboundQueue);
+       if (Index == 0xFFFFFFFFL)
+               Index = rx_readl(dev, MUnit.OutboundQueue);
+       if (Index != 0xFFFFFFFFL) {
+               do {
+                       if (aac_intr_normal(dev, Index)) {
+                               rx_writel(dev, MUnit.OutboundQueue, Index);
+                               rx_writel(dev, MUnit.ODR, DoorBellAdapterNormRespReady);
+                       }
+                       Index = rx_readl(dev, MUnit.OutboundQueue);
+               } while (Index != 0xFFFFFFFFL);
+               return IRQ_HANDLED;
        }
        return IRQ_NONE;
 }
@@ -114,6 +114,26 @@ static void aac_rx_disable_interrupt(struct aac_dev *dev)
        rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff);
 }
 
+/**
+ *     aac_rx_enable_interrupt_producer        -       Enable interrupts
+ *     @dev: Adapter
+ */
+
+static void aac_rx_enable_interrupt_producer(struct aac_dev *dev)
+{
+       rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb);
+}
+
+/**
+ *     aac_rx_enable_interrupt_message -       Enable interrupts
+ *     @dev: Adapter
+ */
+
+static void aac_rx_enable_interrupt_message(struct aac_dev *dev)
+{
+       rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xf7);
+}
+
 /**
  *     rx_sync_cmd     -       send a command and wait
  *     @dev: Adapter
@@ -134,14 +154,14 @@ static int rx_sync_cmd(struct aac_dev *dev, u32 command,
        /*
         *      Write the command into Mailbox 0
         */
-       rx_writel(dev, InboundMailbox0, command);
+       writel(command, &dev->IndexRegs->Mailbox[0]);
        /*
         *      Write the parameters into Mailboxes 1 - 6
         */
-       rx_writel(dev, InboundMailbox1, p1);
-       rx_writel(dev, InboundMailbox2, p2);
-       rx_writel(dev, InboundMailbox3, p3);
-       rx_writel(dev, InboundMailbox4, p4);
+       writel(p1, &dev->IndexRegs->Mailbox[1]);
+       writel(p2, &dev->IndexRegs->Mailbox[2]);
+       writel(p3, &dev->IndexRegs->Mailbox[3]);
+       writel(p4, &dev->IndexRegs->Mailbox[4]);
        /*
         *      Clear the synch command doorbell to start on a clean slate.
         */
@@ -189,25 +209,22 @@ static int rx_sync_cmd(struct aac_dev *dev, u32 command,
                /*
                 *      Restore interrupt mask even though we timed out
                 */
-               if (dev->new_comm_interface)
-                       rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xf7);
-               else
-                       rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb);
+               aac_adapter_enable_int(dev);
                return -ETIMEDOUT;
        }
        /*
         *      Pull the synch status from Mailbox 0.
         */
        if (status)
-               *status = rx_readl(dev, IndexRegs.Mailbox[0]);
+               *status = readl(&dev->IndexRegs->Mailbox[0]);
        if (r1)
-               *r1 = rx_readl(dev, IndexRegs.Mailbox[1]);
+               *r1 = readl(&dev->IndexRegs->Mailbox[1]);
        if (r2)
-               *r2 = rx_readl(dev, IndexRegs.Mailbox[2]);
+               *r2 = readl(&dev->IndexRegs->Mailbox[2]);
        if (r3)
-               *r3 = rx_readl(dev, IndexRegs.Mailbox[3]);
+               *r3 = readl(&dev->IndexRegs->Mailbox[3]);
        if (r4)
-               *r4 = rx_readl(dev, IndexRegs.Mailbox[4]);
+               *r4 = readl(&dev->IndexRegs->Mailbox[4]);
        /*
         *      Clear the synch command doorbell.
         */
@@ -215,10 +232,7 @@ static int rx_sync_cmd(struct aac_dev *dev, u32 command,
        /*
         *      Restore interrupt mask
         */
-       if (dev->new_comm_interface)
-               rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xf7);
-       else
-               rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb);
+       aac_adapter_enable_int(dev);
        return 0;
 
 }
@@ -261,8 +275,6 @@ static void aac_rx_notify_adapter(struct aac_dev *dev, u32 event)
                rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_3);
                break;
        case HostShutdown:
-//             rx_sync_cmd(dev, HOST_CRASHING, 0, 0, 0, 0, 0, 0,
-//               NULL, NULL, NULL, NULL, NULL);
                break;
        case FastIo:
                rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_6);
@@ -283,7 +295,7 @@ static void aac_rx_notify_adapter(struct aac_dev *dev, u32 event)
  *     Start up processing on an i960 based AAC adapter
  */
 
-static void aac_rx_start_adapter(struct aac_dev *dev)
+void aac_rx_start_adapter(struct aac_dev *dev)
 {
        struct aac_init *init;
 
@@ -362,35 +374,134 @@ static int aac_rx_check_health(struct aac_dev *dev)
 }
 
 /**
- *     aac_rx_send
+ *     aac_rx_deliver_producer
  *     @fib: fib to issue
  *
  *     Will send a fib, returning 0 if successful.
  */
-static int aac_rx_send(struct fib * fib)
+static int aac_rx_deliver_producer(struct fib * fib)
 {
-       u64 addr = fib->hw_fib_pa;
        struct aac_dev *dev = fib->dev;
-       volatile void __iomem *device = dev->regs.rx;
+       struct aac_queue *q = &dev->queues->queue[AdapNormCmdQueue];
+       unsigned long qflags;
        u32 Index;
+       unsigned long nointr = 0;
 
-       dprintk((KERN_DEBUG "%p->aac_rx_send(%p->%llx)\n", dev, fib, addr));
-       Index = rx_readl(dev, MUnit.InboundQueue);
-       if (Index == 0xFFFFFFFFL)
+       spin_lock_irqsave(q->lock, qflags);
+       aac_queue_get( dev, &Index, AdapNormCmdQueue, fib->hw_fib, 1, fib, &nointr);
+
+       q->numpending++;
+       *(q->headers.producer) = cpu_to_le32(Index + 1);
+       spin_unlock_irqrestore(q->lock, qflags);
+       if (!(nointr & aac_config.irq_mod))
+               aac_adapter_notify(dev, AdapNormCmdQueue);
+
+       return 0;
+}
+
+/**
+ *     aac_rx_deliver_message
+ *     @fib: fib to issue
+ *
+ *     Will send a fib, returning 0 if successful.
+ */
+static int aac_rx_deliver_message(struct fib * fib)
+{
+       struct aac_dev *dev = fib->dev;
+       struct aac_queue *q = &dev->queues->queue[AdapNormCmdQueue];
+       unsigned long qflags;
+       u32 Index;
+       u64 addr;
+       volatile void __iomem *device;
+
+       unsigned long count = 10000000L; /* 50 seconds */
+       spin_lock_irqsave(q->lock, qflags);
+       q->numpending++;
+       spin_unlock_irqrestore(q->lock, qflags);
+       for(;;) {
                Index = rx_readl(dev, MUnit.InboundQueue);
-       dprintk((KERN_DEBUG "Index = 0x%x\n", Index));
-       if (Index == 0xFFFFFFFFL)
-               return Index;
-       device += Index;
-       dprintk((KERN_DEBUG "entry = %x %x %u\n", (u32)(addr & 0xffffffff),
-         (u32)(addr >> 32), (u32)le16_to_cpu(fib->hw_fib->header.Size)));
+               if (Index == 0xFFFFFFFFL)
+                       Index = rx_readl(dev, MUnit.InboundQueue);
+               if (Index != 0xFFFFFFFFL)
+                       break;
+               if (--count == 0) {
+                       spin_lock_irqsave(q->lock, qflags);
+                       q->numpending--;
+                       spin_unlock_irqrestore(q->lock, qflags);
+                       return -ETIMEDOUT;
+               }
+               udelay(5);
+       }
+       device = dev->base + Index;
+       addr = fib->hw_fib_pa;
        writel((u32)(addr & 0xffffffff), device);
        device += sizeof(u32);
        writel((u32)(addr >> 32), device);
        device += sizeof(u32);
        writel(le16_to_cpu(fib->hw_fib->header.Size), device);
        rx_writel(dev, MUnit.InboundQueue, Index);
-       dprintk((KERN_DEBUG "aac_rx_send - return 0\n"));
+       return 0;
+}
+
+/**
+ *     aac_rx_ioremap
+ *     @size: mapping resize request
+ *
+ */
+static int aac_rx_ioremap(struct aac_dev * dev, u32 size)
+{
+       if (!size) {
+               iounmap(dev->regs.rx);
+               return 0;
+       }
+       dev->base = dev->regs.rx = ioremap(dev->scsi_host_ptr->base, size);
+       if (dev->base == NULL)
+               return -1;
+       dev->IndexRegs = &dev->regs.rx->IndexRegs;
+       return 0;
+}
+
+static int aac_rx_restart_adapter(struct aac_dev *dev)
+{
+       u32 var;
+
+       printk(KERN_ERR "%s%d: adapter kernel panic'd.\n",
+                       dev->name, dev->id);
+
+       if (aac_rx_check_health(dev) <= 0)
+               return 1;
+       if (rx_sync_cmd(dev, IOP_RESET, 0, 0, 0, 0, 0, 0,
+                       &var, NULL, NULL, NULL, NULL))
+               return 1;
+       if (var != 0x00000001)
+                return 1;
+       if (rx_readl(dev, MUnit.OMRx[0]) & KERNEL_PANIC)
+               return 1;
+       return 0;
+}
+
+/**
+ *     aac_rx_select_comm      -       Select communications method
+ *     @dev: Adapter
+ *     @comm: communications method
+ */
+
+int aac_rx_select_comm(struct aac_dev *dev, int comm)
+{
+       switch (comm) {
+       case AAC_COMM_PRODUCER:
+               dev->a_ops.adapter_enable_int = aac_rx_enable_interrupt_producer;
+               dev->a_ops.adapter_intr = aac_rx_intr_producer;
+               dev->a_ops.adapter_deliver = aac_rx_deliver_producer;
+               break;
+       case AAC_COMM_MESSAGE:
+               dev->a_ops.adapter_enable_int = aac_rx_enable_interrupt_message;
+               dev->a_ops.adapter_intr = aac_rx_intr_message;
+               dev->a_ops.adapter_deliver = aac_rx_deliver_message;
+               break;
+       default:
+               return 1;
+       }
        return 0;
 }
 
@@ -403,7 +514,7 @@ static int aac_rx_send(struct fib * fib)
  *     to the comm region.
  */
 
-int aac_rx_init(struct aac_dev *dev)
+int _aac_rx_init(struct aac_dev *dev)
 {
        unsigned long start;
        unsigned long status;
@@ -413,27 +524,30 @@ int aac_rx_init(struct aac_dev *dev)
        instance = dev->id;
        name     = dev->name;
 
+       if (aac_adapter_ioremap(dev, dev->base_size)) {
+               printk(KERN_WARNING "%s: unable to map adapter.\n", name);
+               goto error_iounmap;
+       }
+
        /*
         *      Check to see if the board panic'd while booting.
         */
+       status = rx_readl(dev, MUnit.OMRx[0]);
+       if (status & KERNEL_PANIC)
+               if (aac_rx_restart_adapter(dev))
+                       goto error_iounmap;
        /*
         *      Check to see if the board failed any self tests.
         */
-       if (rx_readl(dev, MUnit.OMRx[0]) & SELF_TEST_FAILED) {
+       status = rx_readl(dev, MUnit.OMRx[0]);
+       if (status & SELF_TEST_FAILED) {
                printk(KERN_ERR "%s%d: adapter self-test failed.\n", dev->name, instance);
                goto error_iounmap;
        }
-       /*
-        *      Check to see if the board panic'd while booting.
-        */
-       if (rx_readl(dev, MUnit.OMRx[0]) & KERNEL_PANIC) {
-               printk(KERN_ERR "%s%d: adapter kernel panic.\n", dev->name, instance);
-               goto error_iounmap;
-       }
        /*
         *      Check to see if the monitor panic'd while booting.
         */
-       if (rx_readl(dev, MUnit.OMRx[0]) & MONITOR_PANIC) {
+       if (status & MONITOR_PANIC) {
                printk(KERN_ERR "%s%d: adapter monitor panic.\n", dev->name, instance);
                goto error_iounmap;
        }
@@ -441,58 +555,64 @@ int aac_rx_init(struct aac_dev *dev)
        /*
         *      Wait for the adapter to be up and running. Wait up to 3 minutes
         */
-       while ((!(rx_readl(dev, IndexRegs.Mailbox[7]) & KERNEL_UP_AND_RUNNING))
-               || (!(rx_readl(dev, MUnit.OMRx[0]) & KERNEL_UP_AND_RUNNING)))
+       while (!((status = rx_readl(dev, MUnit.OMRx[0])) & KERNEL_UP_AND_RUNNING))
        {
-               if(time_after(jiffies, start+180*HZ))
+               if(time_after(jiffies, start+startup_timeout*HZ))
                {
-                       status = rx_readl(dev, IndexRegs.Mailbox[7]);
                        printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %lx.\n", 
                                        dev->name, instance, status);
                        goto error_iounmap;
                }
-               schedule_timeout_uninterruptible(1);
-       }
-       if (request_irq(dev->scsi_host_ptr->irq, aac_rx_intr, SA_SHIRQ|SA_INTERRUPT, "aacraid", (void *)dev)<0) 
-       {
-               printk(KERN_ERR "%s%d: Interrupt unavailable.\n", name, instance);
-               goto error_iounmap;
+               msleep(1);
        }
        /*
-        *      Fill in the function dispatch table.
+        *      Fill in the common function dispatch table.
         */
        dev->a_ops.adapter_interrupt = aac_rx_interrupt_adapter;
        dev->a_ops.adapter_disable_int = aac_rx_disable_interrupt;
        dev->a_ops.adapter_notify = aac_rx_notify_adapter;
        dev->a_ops.adapter_sync_cmd = rx_sync_cmd;
        dev->a_ops.adapter_check_health = aac_rx_check_health;
-       dev->a_ops.adapter_send = aac_rx_send;
 
        /*
         *      First clear out all interrupts.  Then enable the one's that we
         *      can handle.
         */
-       rx_writeb(dev, MUnit.OIMR, 0xff);
+       aac_adapter_comm(dev, AAC_COMM_PRODUCER);
+       aac_adapter_disable_int(dev);
        rx_writel(dev, MUnit.ODR, 0xffffffff);
-       rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb);
+       aac_adapter_enable_int(dev);
 
        if (aac_init_adapter(dev) == NULL)
-               goto error_irq;
-       if (dev->new_comm_interface)
-               rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xf7);
-
+               goto error_iounmap;
+       aac_adapter_comm(dev, dev->comm_interface);
+       if (request_irq(dev->scsi_host_ptr->irq, dev->a_ops.adapter_intr,
+                       IRQF_SHARED|IRQF_DISABLED, "aacraid", dev) < 0) {
+               printk(KERN_ERR "%s%d: Interrupt unavailable.\n",
+                       name, instance);
+               goto error_iounmap;
+       }
+       aac_adapter_enable_int(dev);
        /*
-        *      Tell the adapter that all is configured, and it can start
-        *      accepting requests
+        *      Tell the adapter that all is configured, and it can
+        * start accepting requests
         */
        aac_rx_start_adapter(dev);
-       return 0;
 
-error_irq:
-       rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff);
-       free_irq(dev->scsi_host_ptr->irq, (void *)dev);
+       return 0;
 
 error_iounmap:
 
        return -1;
 }
+
+int aac_rx_init(struct aac_dev *dev)
+{
+       /*
+        *      Fill in the function dispatch table.
+        */
+       dev->a_ops.adapter_ioremap = aac_rx_ioremap;
+       dev->a_ops.adapter_comm = aac_rx_select_comm;
+
+       return _aac_rx_init(dev);
+}