Merge master.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
[pandora-kernel.git] / drivers / scsi / aacraid / rx.c
index 391d475..ebc65b9 100644 (file)
@@ -294,7 +294,7 @@ static void aac_rx_notify_adapter(struct aac_dev *dev, u32 event)
  *     Start up processing on an i960 based AAC adapter
  */
 
-void aac_rx_start_adapter(struct aac_dev *dev)
+static void aac_rx_start_adapter(struct aac_dev *dev)
 {
        struct aac_init *init;
 
@@ -378,7 +378,7 @@ static int aac_rx_check_health(struct aac_dev *dev)
  *
  *     Will send a fib, returning 0 if successful.
  */
-static int aac_rx_deliver_producer(struct fib * fib)
+int aac_rx_deliver_producer(struct fib * fib)
 {
        struct aac_dev *dev = fib->dev;
        struct aac_queue *q = &dev->queues->queue[AdapNormCmdQueue];
@@ -464,19 +464,25 @@ static int aac_rx_restart_adapter(struct aac_dev *dev, int bled)
 {
        u32 var;
 
-       if (bled)
-               printk(KERN_ERR "%s%d: adapter kernel panic'd %x.\n",
-                       dev->name, dev->id, bled);
-       else
-               bled = aac_adapter_sync_cmd(dev, IOP_RESET_ALWAYS,
-                 0, 0, 0, 0, 0, 0, &var, NULL, NULL, NULL, NULL);
-       if (bled)
-               bled = aac_adapter_sync_cmd(dev, IOP_RESET,
-                 0, 0, 0, 0, 0, 0, &var, NULL, NULL, NULL, NULL);
-
-       if (bled)
-               return -EINVAL;
-       if (var == 0x3803000F) { /* USE_OTHER_METHOD */
+       if (!(dev->supplement_adapter_info.SupportedOptions2 &
+         le32_to_cpu(AAC_OPTION_MU_RESET)) || (bled >= 0) || (bled == -2)) {
+               if (bled)
+                       printk(KERN_ERR "%s%d: adapter kernel panic'd %x.\n",
+                               dev->name, dev->id, bled);
+               else {
+                       bled = aac_adapter_sync_cmd(dev, IOP_RESET_ALWAYS,
+                         0, 0, 0, 0, 0, 0, &var, NULL, NULL, NULL, NULL);
+                       if (!bled && (var != 0x00000001))
+                               bled = -EINVAL;
+               }
+               if (bled && (bled != -ETIMEDOUT))
+                       bled = aac_adapter_sync_cmd(dev, IOP_RESET,
+                         0, 0, 0, 0, 0, 0, &var, NULL, NULL, NULL, NULL);
+
+               if (bled && (bled != -ETIMEDOUT))
+                       return -EINVAL;
+       }
+       if (bled || (var == 0x3803000F)) { /* USE_OTHER_METHOD */
                rx_writel(dev, MUnit.reserved2, 3);
                msleep(5000); /* Delay 5 seconds */
                var = 0x00000001;
@@ -485,6 +491,8 @@ static int aac_rx_restart_adapter(struct aac_dev *dev, int bled)
                return -EINVAL;
        if (rx_readl(dev, MUnit.OMRx[0]) & KERNEL_PANIC)
                return -ENODEV;
+       if (startup_timeout < 300)
+               startup_timeout = 300;
        return 0;
 }
 
@@ -526,6 +534,7 @@ int _aac_rx_init(struct aac_dev *dev)
 {
        unsigned long start;
        unsigned long status;
+       int restart = 0;
        int instance = dev->id;
        const char * name = dev->name;
 
@@ -534,15 +543,21 @@ int _aac_rx_init(struct aac_dev *dev)
                goto error_iounmap;
        }
 
+       /* Failure to reset here is an option ... */
+       dev->a_ops.adapter_sync_cmd = rx_sync_cmd;
+       dev->a_ops.adapter_enable_int = aac_rx_disable_interrupt;
+       dev->OIMR = status = rx_readb (dev, MUnit.OIMR);
+       if ((((status & 0x0c) != 0x0c) || aac_reset_devices || reset_devices) &&
+         !aac_rx_restart_adapter(dev, 0))
+               ++restart;
        /*
         *      Check to see if the board panic'd while booting.
         */
        status = rx_readl(dev, MUnit.OMRx[0]);
        if (status & KERNEL_PANIC) {
-               if ((status = aac_rx_check_health(dev)) <= 0)
-                       goto error_iounmap;
-               if (aac_rx_restart_adapter(dev, status))
+               if (aac_rx_restart_adapter(dev, aac_rx_check_health(dev)))
                        goto error_iounmap;
+               ++restart;
        }
        /*
         *      Check to see if the board failed any self tests.
@@ -565,13 +580,27 @@ int _aac_rx_init(struct aac_dev *dev)
         */
        while (!((status = rx_readl(dev, MUnit.OMRx[0])) & KERNEL_UP_AND_RUNNING))
        {
-               if(time_after(jiffies, start+startup_timeout*HZ)) {
+               if ((restart &&
+                 (status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC))) ||
+                 time_after(jiffies, start+HZ*startup_timeout)) {
                        printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %lx.\n", 
                                        dev->name, instance, status);
                        goto error_iounmap;
                }
+               if (!restart &&
+                 ((status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC)) ||
+                 time_after(jiffies, start + HZ *
+                 ((startup_timeout > 60)
+                   ? (startup_timeout - 60)
+                   : (startup_timeout / 2))))) {
+                       if (likely(!aac_rx_restart_adapter(dev, aac_rx_check_health(dev))))
+                               start = jiffies;
+                       ++restart;
+               }
                msleep(1);
        }
+       if (restart && aac_commit)
+               aac_commit = 1;
        /*
         *      Fill in the common function dispatch table.
         */