]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/commitdiff
[SCSI] aacraid: Added Sync.mode to support series 7/8/9 controllers
authorMahesh Rajashekhara <Mahesh_Rajashekhara@pmc-sierra.com>
Thu, 9 Feb 2012 06:51:04 +0000 (22:51 -0800)
committerJames Bottomley <JBottomley@Parallels.com>
Sun, 19 Feb 2012 14:09:01 +0000 (08:09 -0600)
Added Sync. mode to support Series 7/8/9 controller families: This is a
compatibility mode for all these controller families. The Async. (Performance)
mode can be changed in the future.  First Async. mode version added for Series
7; Controller parameter aac_sync_mode added

Signed-off-by: Mahesh Rajashekhara <aacraid@pmc-sierra.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
drivers/scsi/aacraid/aachba.c
drivers/scsi/aacraid/aacraid.h
drivers/scsi/aacraid/comminit.c
drivers/scsi/aacraid/commsup.c
drivers/scsi/aacraid/linit.c
drivers/scsi/aacraid/rx.c
drivers/scsi/aacraid/sa.c
drivers/scsi/aacraid/src.c

index 409f5805bdd63e06459906a04a7592eebeea9aae..52551662d1077d7188236a1ecf0ff482213ffc3c 100644 (file)
@@ -151,7 +151,11 @@ int aac_msi;
 int aac_commit = -1;
 int startup_timeout = 180;
 int aif_timeout = 120;
+int aac_sync_mode;  /* Only Sync. transfer - disabled */
 
+module_param(aac_sync_mode, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(aac_sync_mode, "Force sync. transfer mode"
+       " 0=off, 1=on");
 module_param(nondasd, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(nondasd, "Control scanning of hba for nondasd devices."
        " 0=off, 1=on");
index ffb587817efce6de2443434007dcf72abaf39572..3fcf62724fadaf227583fa4c881472687425b107 100644 (file)
@@ -12,7 +12,7 @@
  *----------------------------------------------------------------------------*/
 
 #ifndef AAC_DRIVER_BUILD
-# define AAC_DRIVER_BUILD 28000
+# define AAC_DRIVER_BUILD 28900
 # define AAC_DRIVER_BRANCH "-ms"
 #endif
 #define MAXIMUM_NUM_CONTAINERS 32
@@ -756,8 +756,16 @@ struct src_mu_registers {
 
 struct src_registers {
        struct src_mu_registers MUnit;  /* 00h - c7h */
-       __le32 reserved1[130790];       /* c8h - 7fc5fh */
-       struct src_inbound IndexRegs;   /* 7fc60h */
+       union {
+               struct {
+                       __le32 reserved1[130790];       /* c8h - 7fc5fh */
+                       struct src_inbound IndexRegs;   /* 7fc60h */
+               } tupelo;
+               struct {
+                       __le32 reserved1[974];          /* c8h - fffh */
+                       struct src_inbound IndexRegs;   /* 1000h */
+               } denali;
+       } u;
 };
 
 #define src_readb(AEP, CSR)            readb(&((AEP)->regs.src.bar0->CSR))
@@ -999,6 +1007,10 @@ struct aac_bus_info_response {
 #define AAC_OPT_NEW_COMM               cpu_to_le32(1<<17)
 #define AAC_OPT_NEW_COMM_64            cpu_to_le32(1<<18)
 #define AAC_OPT_NEW_COMM_TYPE1         cpu_to_le32(1<<28)
+#define AAC_OPT_NEW_COMM_TYPE2         cpu_to_le32(1<<29)
+#define AAC_OPT_NEW_COMM_TYPE3         cpu_to_le32(1<<30)
+#define AAC_OPT_NEW_COMM_TYPE4         cpu_to_le32(1<<31)
+
 
 struct aac_dev
 {
@@ -1076,6 +1088,8 @@ struct aac_dev
 #      define AAC_MIN_FOOTPRINT_SIZE 8192
 #      define AAC_MIN_SRC_BAR0_SIZE 0x400000
 #      define AAC_MIN_SRC_BAR1_SIZE 0x800
+#      define AAC_MIN_SRCV_BAR0_SIZE 0x100000
+#      define AAC_MIN_SRCV_BAR1_SIZE 0x400
 #endif
        union
        {
@@ -1116,7 +1130,10 @@ struct aac_dev
        u8                      msi;
        int                     management_fib_count;
        spinlock_t              manage_lock;
-
+       spinlock_t              sync_lock;
+       int                     sync_mode;
+       struct fib              *sync_fib;
+       struct list_head        sync_fib_list;
 };
 
 #define aac_adapter_interrupt(dev) \
@@ -1163,6 +1180,7 @@ struct aac_dev
 
 #define FIB_CONTEXT_FLAG_TIMED_OUT             (0x00000001)
 #define FIB_CONTEXT_FLAG                       (0x00000002)
+#define FIB_CONTEXT_FLAG_WAIT                  (0x00000004)
 
 /*
  *     Define the command values
@@ -1970,6 +1988,7 @@ int aac_rkt_init(struct aac_dev *dev);
 int aac_nark_init(struct aac_dev *dev);
 int aac_sa_init(struct aac_dev *dev);
 int aac_src_init(struct aac_dev *dev);
+int aac_srcv_init(struct aac_dev *dev);
 int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * hw_fib, int wait, struct fib * fibptr, unsigned long *nonotify);
 unsigned int aac_response_normal(struct aac_queue * q);
 unsigned int aac_command_normal(struct aac_queue * q);
index 7ac8fdb5577b2cc922bb15a8737eea1ff3751cfa..a35f54ebdce003509864280f437fa50bf7c371da 100644 (file)
@@ -325,12 +325,14 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev)
 {
        u32 status[5];
        struct Scsi_Host * host = dev->scsi_host_ptr;
+       extern int aac_sync_mode;
 
        /*
         *      Check the preferred comm settings, defaults from template.
         */
        dev->management_fib_count = 0;
        spin_lock_init(&dev->manage_lock);
+       spin_lock_init(&dev->sync_lock);
        dev->max_fib_size = sizeof(struct hw_fib);
        dev->sg_tablesize = host->sg_tablesize = (dev->max_fib_size
                - sizeof(struct aac_fibhdr)
@@ -344,13 +346,21 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev)
                        (status[0] == 0x00000001)) {
                if (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_64))
                        dev->raw_io_64 = 1;
-               if (dev->a_ops.adapter_comm) {
-                       if (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_TYPE1)) {
-                               dev->comm_interface = AAC_COMM_MESSAGE_TYPE1;
-                               dev->raw_io_interface = 1;
-                       } else if (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM)) {
+               dev->sync_mode = aac_sync_mode;
+               if (dev->a_ops.adapter_comm &&
+                       (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM))) {
                                dev->comm_interface = AAC_COMM_MESSAGE;
                                dev->raw_io_interface = 1;
+                       if ((status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_TYPE1))) {
+                               /* driver supports TYPE1 (Tupelo) */
+                               dev->comm_interface = AAC_COMM_MESSAGE_TYPE1;
+                       } else if ((status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_TYPE4)) ||
+                                 (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_TYPE3)) ||
+                                 (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_TYPE2))) {
+                                       /* driver doesn't support TYPE2 (Series7), TYPE3 and TYPE4 */
+                                       /* switch to sync. mode */
+                                       dev->comm_interface = AAC_COMM_MESSAGE_TYPE1;
+                                       dev->sync_mode = 1;
                        }
                }
                if ((dev->comm_interface == AAC_COMM_MESSAGE) &&
@@ -455,6 +465,7 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev)
        }
                
        INIT_LIST_HEAD(&dev->fib_list);
+       INIT_LIST_HEAD(&dev->sync_fib_list);
 
        return dev;
 }
index e5f2d7d9002ec4df139d9db4260069d58d2fcfce..4b32ca442433036860bc819eff2909efc6155e46 100644 (file)
@@ -416,6 +416,7 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
        unsigned long flags = 0;
        unsigned long qflags;
        unsigned long mflags = 0;
+       unsigned long sflags = 0;
 
 
        if (!(hw_fib->header.XferState & cpu_to_le32(HostOwned)))
@@ -512,6 +513,31 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
                spin_lock_irqsave(&fibptr->event_lock, flags);
        }
 
+       if (dev->sync_mode) {
+               if (wait)
+                       spin_unlock_irqrestore(&fibptr->event_lock, flags);
+               spin_lock_irqsave(&dev->sync_lock, sflags);
+               if (dev->sync_fib) {
+                       list_add_tail(&fibptr->fiblink, &dev->sync_fib_list);
+                       spin_unlock_irqrestore(&dev->sync_lock, sflags);
+               } else {
+                       dev->sync_fib = fibptr;
+                       spin_unlock_irqrestore(&dev->sync_lock, sflags);
+                       aac_adapter_sync_cmd(dev, SEND_SYNCHRONOUS_FIB,
+                               (u32)fibptr->hw_fib_pa, 0, 0, 0, 0, 0,
+                               NULL, NULL, NULL, NULL, NULL);
+               }
+               if (wait) {
+                       fibptr->flags |= FIB_CONTEXT_FLAG_WAIT;
+                       if (down_interruptible(&fibptr->event_wait)) {
+                               fibptr->flags &= ~FIB_CONTEXT_FLAG_WAIT;
+                               return -EFAULT;
+                       }
+                       return 0;
+               }
+               return -EINPROGRESS;
+       }
+
        if (aac_adapter_deliver(fibptr) != 0) {
                printk(KERN_ERR "aac_fib_send: returned -EBUSY\n");
                if (wait) {
index 705e13e470af18850ae4375533ae4f85495b592c..0d279c445a30c3ceb92d8e00dbd7cbcf190f2cc6 100644 (file)
@@ -56,7 +56,7 @@
 
 #include "aacraid.h"
 
-#define AAC_DRIVER_VERSION             "1.1-7"
+#define AAC_DRIVER_VERSION             "1.2-0"
 #ifndef AAC_DRIVER_BRANCH
 #define AAC_DRIVER_BRANCH              ""
 #endif
@@ -162,7 +162,10 @@ static const struct pci_device_id aac_pci_tbl[] __devinitdata = {
        { 0x9005, 0x0285, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 59 }, /* Adaptec Catch All */
        { 0x9005, 0x0286, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 60 }, /* Adaptec Rocket Catch All */
        { 0x9005, 0x0288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 61 }, /* Adaptec NEMER/ARK Catch All */
-       { 0x9005, 0x028b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 62 }, /* Adaptec PMC Catch All */
+       { 0x9005, 0x028b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 62 }, /* Adaptec PMC Series 6 (Tupelo) */
+       { 0x9005, 0x028c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 63 }, /* Adaptec PMC Series 7 (Denali) */
+       { 0x9005, 0x028d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 64 }, /* Adaptec PMC Series 8 */
+       { 0x9005, 0x028f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 65 }, /* Adaptec PMC Series 9 */
        { 0,}
 };
 MODULE_DEVICE_TABLE(pci, aac_pci_tbl);
@@ -238,7 +241,10 @@ static struct aac_driver_ident aac_drivers[] = {
        { aac_rx_init, "aacraid",  "ADAPTEC ", "RAID            ", 2 }, /* Adaptec Catch All */
        { aac_rkt_init, "aacraid", "ADAPTEC ", "RAID            ", 2 }, /* Adaptec Rocket Catch All */
        { aac_nark_init, "aacraid", "ADAPTEC ", "RAID           ", 2 }, /* Adaptec NEMER/ARK Catch All */
-       { aac_src_init, "aacraid", "ADAPTEC ", "RAID            ", 2 } /* Adaptec PMC Catch All */
+       { aac_src_init, "aacraid", "ADAPTEC ", "RAID            ", 2 }, /* Adaptec PMC Series 6 (Tupelo) */
+       { aac_srcv_init, "aacraid", "ADAPTEC ", "RAID            ", 2 }, /* Adaptec PMC Series 7 (Denali) */
+       { aac_srcv_init, "aacraid", "ADAPTEC ", "RAID            ", 2 }, /* Adaptec PMC Series 8 */
+       { aac_srcv_init, "aacraid", "ADAPTEC ", "RAID            ", 2 } /* Adaptec PMC Series 9 */
 };
 
 /**
@@ -1102,6 +1108,7 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
        int error = -ENODEV;
        int unique_id = 0;
        u64 dmamask;
+       extern int aac_sync_mode;
 
        list_for_each_entry(aac, &aac_devices, entry) {
                if (aac->id > unique_id)
@@ -1162,6 +1169,21 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
        if ((*aac_drivers[index].init)(aac))
                goto out_unmap;
 
+       if (aac->sync_mode) {
+               if (aac_sync_mode)
+                       printk(KERN_INFO "%s%d: Sync. mode enforced "
+                               "by driver parameter. This will cause "
+                               "a significant performance decrease!\n",
+                               aac->name,
+                               aac->id);
+               else
+                       printk(KERN_INFO "%s%d: Async. mode not supported "
+                               "by current driver, sync. mode enforced."
+                               "\nPlease update driver to get full performance.\n",
+                               aac->name,
+                               aac->id);
+       }
+
        /*
         *      Start any kernel threads needed
         */
index ce530f113fdb92f18e9889c07de889515a824e61..b029c7cc785b2262d8d17f771568253c4373dc78 100644 (file)
@@ -643,6 +643,7 @@ int _aac_rx_init(struct aac_dev *dev)
        if (aac_init_adapter(dev) == NULL)
                goto error_iounmap;
        aac_adapter_comm(dev, dev->comm_interface);
+       dev->sync_mode = 0;     /* sync. mode not supported */
        dev->msi = aac_msi && !pci_enable_msi(dev->pdev);
        if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr,
                        IRQF_SHARED|IRQF_DISABLED, "aacraid", dev) < 0) {
index e5d4457121eaa87d4d88e30094b011e7a56c8d48..beb533630d4b329588e09582b533db01e2285412 100644 (file)
@@ -385,6 +385,7 @@ int aac_sa_init(struct aac_dev *dev)
 
        if(aac_init_adapter(dev) == NULL)
                goto error_irq;
+       dev->sync_mode = 0;     /* sync. mode not supported */
        if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr,
                        IRQF_SHARED|IRQF_DISABLED,
                        "aacraid", (void *)dev ) < 0) {
index 957595a7a45c1bc40f1de6f68d3d68a456219a9b..2bee51506a910805ef5d961d1b289fba7c7cc1e6 100644 (file)
@@ -96,6 +96,38 @@ static irqreturn_t aac_src_intr_message(int irq, void *dev_id)
                        our_interrupt = 1;
                        /* handle AIF */
                        aac_intr_normal(dev, 0, 2, 0, NULL);
+               } else if (bellbits_shifted & OUTBOUNDDOORBELL_0) {
+                       unsigned long sflags;
+                       struct list_head *entry;
+                       int send_it = 0;
+
+                       if (dev->sync_fib) {
+                               our_interrupt = 1;
+                               if (dev->sync_fib->callback)
+                                       dev->sync_fib->callback(dev->sync_fib->callback_data,
+                                               dev->sync_fib);
+                               spin_lock_irqsave(&dev->sync_fib->event_lock, sflags);
+                               if (dev->sync_fib->flags & FIB_CONTEXT_FLAG_WAIT) {
+                                       dev->management_fib_count--;
+                                       up(&dev->sync_fib->event_wait);
+                               }
+                               spin_unlock_irqrestore(&dev->sync_fib->event_lock, sflags);
+                               spin_lock_irqsave(&dev->sync_lock, sflags);
+                               if (!list_empty(&dev->sync_fib_list)) {
+                                       entry = dev->sync_fib_list.next;
+                                       dev->sync_fib = list_entry(entry, struct fib, fiblink);
+                                       list_del(entry);
+                                       send_it = 1;
+                               } else {
+                                       dev->sync_fib = NULL;
+                               }
+                               spin_unlock_irqrestore(&dev->sync_lock, sflags);
+                               if (send_it) {
+                                       aac_adapter_sync_cmd(dev, SEND_SYNCHRONOUS_FIB,
+                                               (u32)dev->sync_fib->hw_fib_pa, 0, 0, 0, 0, 0,
+                                               NULL, NULL, NULL, NULL, NULL);
+                               }
+                       }
                }
        }
 
@@ -177,56 +209,63 @@ static int src_sync_cmd(struct aac_dev *dev, u32 command,
         */
        src_writel(dev, MUnit.IDR, INBOUNDDOORBELL_0 << SRC_IDR_SHIFT);
 
-       ok = 0;
-       start = jiffies;
+       if (!dev->sync_mode || command != SEND_SYNCHRONOUS_FIB) {
+               ok = 0;
+               start = jiffies;
 
-       /*
-        *      Wait up to 30 seconds
-        */
-       while (time_before(jiffies, start+30*HZ)) {
-               /* Delay 5 microseconds to let Mon960 get info. */
-               udelay(5);
-
-               /* Mon960 will set doorbell0 bit
-                * when it has completed the command
+               /*
+                *      Wait up to 5 minutes
                 */
-               if ((src_readl(dev, MUnit.ODR_R) >> SRC_ODR_SHIFT) & OUTBOUNDDOORBELL_0) {
-                       /* Clear the doorbell */
-                       src_writel(dev,
-                               MUnit.ODR_C,
-                               OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT);
-                       ok = 1;
-                       break;
+               while (time_before(jiffies, start+300*HZ)) {
+                       udelay(5);      /* Delay 5 microseconds to let Mon960 get info. */
+                       /*
+                        *      Mon960 will set doorbell0 bit when it has completed the command.
+                        */
+                       if ((src_readl(dev, MUnit.ODR_R) >> SRC_ODR_SHIFT) & OUTBOUNDDOORBELL_0) {
+                               /*
+                                *      Clear the doorbell.
+                                */
+                               src_writel(dev, MUnit.ODR_C, OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT);
+                               ok = 1;
+                               break;
+                       }
+                       /*
+                        *      Yield the processor in case we are slow
+                        */
+                       msleep(1);
                }
-
-                /* Yield the processor in case we are slow */
-               msleep(1);
-       }
-       if (unlikely(ok != 1)) {
-                /* Restore interrupt mask even though we timed out */
-               aac_adapter_enable_int(dev);
-               return -ETIMEDOUT;
+               if (unlikely(ok != 1)) {
+                       /*
+                        *      Restore interrupt mask even though we timed out
+                        */
+                       aac_adapter_enable_int(dev);
+                       return -ETIMEDOUT;
+               }
+               /*
+                *      Pull the synch status from Mailbox 0.
+                */
+               if (status)
+                       *status = readl(&dev->IndexRegs->Mailbox[0]);
+               if (r1)
+                       *r1 = readl(&dev->IndexRegs->Mailbox[1]);
+               if (r2)
+                       *r2 = readl(&dev->IndexRegs->Mailbox[2]);
+               if (r3)
+                       *r3 = readl(&dev->IndexRegs->Mailbox[3]);
+               if (r4)
+                       *r4 = readl(&dev->IndexRegs->Mailbox[4]);
+
+               /*
+                *      Clear the synch command doorbell.
+                */
+               src_writel(dev, MUnit.ODR_C, OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT);
        }
 
-        /* Pull the synch status from Mailbox 0 */
-       if (status)
-               *status = readl(&dev->IndexRegs->Mailbox[0]);
-       if (r1)
-               *r1 = readl(&dev->IndexRegs->Mailbox[1]);
-       if (r2)
-               *r2 = readl(&dev->IndexRegs->Mailbox[2]);
-       if (r3)
-               *r3 = readl(&dev->IndexRegs->Mailbox[3]);
-       if (r4)
-               *r4 = readl(&dev->IndexRegs->Mailbox[4]);
-
-        /* Clear the synch command doorbell */
-       src_writel(dev, MUnit.ODR_C, OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT);
-
-        /* Restore interrupt mask */
+       /*
+        *      Restore interrupt mask
+        */
        aac_adapter_enable_int(dev);
        return 0;
-
 }
 
 /**
@@ -386,9 +425,7 @@ static int aac_src_ioremap(struct aac_dev *dev, u32 size)
 {
        if (!size) {
                iounmap(dev->regs.src.bar0);
-               dev->regs.src.bar0 = NULL;
-               iounmap(dev->base);
-               dev->base = NULL;
+               dev->base = dev->regs.src.bar0 = NULL;
                return 0;
        }
        dev->regs.src.bar1 = ioremap(pci_resource_start(dev->pdev, 2),
@@ -404,7 +441,27 @@ static int aac_src_ioremap(struct aac_dev *dev, u32 size)
                return -1;
        }
        dev->IndexRegs = &((struct src_registers __iomem *)
-               dev->base)->IndexRegs;
+               dev->base)->u.tupelo.IndexRegs;
+       return 0;
+}
+
+/**
+ *  aac_srcv_ioremap
+ *     @size: mapping resize request
+ *
+ */
+static int aac_srcv_ioremap(struct aac_dev *dev, u32 size)
+{
+       if (!size) {
+               iounmap(dev->regs.src.bar0);
+               dev->base = dev->regs.src.bar0 = NULL;
+               return 0;
+       }
+       dev->base = dev->regs.src.bar0 = ioremap(dev->scsi_host_ptr->base, size);
+       if (dev->base == NULL)
+               return -1;
+       dev->IndexRegs = &((struct src_registers __iomem *)
+               dev->base)->u.denali.IndexRegs;
        return 0;
 }
 
@@ -419,7 +476,7 @@ static int aac_src_restart_adapter(struct aac_dev *dev, int bled)
                bled = aac_adapter_sync_cmd(dev, IOP_RESET_ALWAYS,
                        0, 0, 0, 0, 0, 0, &var, &reset_mask, NULL, NULL, NULL);
                        if (bled || (var != 0x00000001))
-                               bled = -EINVAL;
+                               return -EINVAL;
                if (dev->supplement_adapter_info.SupportedOptions2 &
                        AAC_OPTION_DOORBELL_RESET) {
                        src_writel(dev, MUnit.IDR, reset_mask);
@@ -579,15 +636,149 @@ int aac_src_init(struct aac_dev *dev)
        dev->dbg_size = AAC_MIN_SRC_BAR1_SIZE;
 
        aac_adapter_enable_int(dev);
+
+       if (!dev->sync_mode) {
+               /*
+                * Tell the adapter that all is configured, and it can
+                * start accepting requests
+                */
+               aac_src_start_adapter(dev);
+       }
+       return 0;
+
+error_iounmap:
+
+       return -1;
+}
+
+/**
+ *  aac_srcv_init      -       initialize an SRCv card
+ *  @dev: device to configure
+ *
+ */
+
+int aac_srcv_init(struct aac_dev *dev)
+{
+       unsigned long start;
+       unsigned long status;
+       int restart = 0;
+       int instance = dev->id;
+       const char *name = dev->name;
+
+       dev->a_ops.adapter_ioremap = aac_srcv_ioremap;
+       dev->a_ops.adapter_comm = aac_src_select_comm;
+
+       dev->base_size = AAC_MIN_SRCV_BAR0_SIZE;
+       if (aac_adapter_ioremap(dev, dev->base_size)) {
+               printk(KERN_WARNING "%s: unable to map adapter.\n", name);
+               goto error_iounmap;
+       }
+
+       /* Failure to reset here is an option ... */
+       dev->a_ops.adapter_sync_cmd = src_sync_cmd;
+       dev->a_ops.adapter_enable_int = aac_src_disable_interrupt;
+       if ((aac_reset_devices || reset_devices) &&
+               !aac_src_restart_adapter(dev, 0))
+               ++restart;
        /*
-        *      Tell the adapter that all is configured, and it can
-        * start accepting requests
+        *      Check to see if the board panic'd while booting.
         */
-       aac_src_start_adapter(dev);
+       status = src_readl(dev, MUnit.OMR);
+       if (status & KERNEL_PANIC) {
+               if (aac_src_restart_adapter(dev, aac_src_check_health(dev)))
+                       goto error_iounmap;
+               ++restart;
+       }
+       /*
+        *      Check to see if the board failed any self tests.
+        */
+       status = src_readl(dev, MUnit.OMR);
+       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 monitor panic'd while booting.
+        */
+       if (status & MONITOR_PANIC) {
+               printk(KERN_ERR "%s%d: adapter monitor panic.\n", dev->name, instance);
+               goto error_iounmap;
+       }
+       start = jiffies;
+       /*
+        *      Wait for the adapter to be up and running. Wait up to 3 minutes
+        */
+       while (!((status = src_readl(dev, MUnit.OMR)) & KERNEL_UP_AND_RUNNING)) {
+               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_src_restart_adapter(dev, aac_src_check_health(dev))))
+                               start = jiffies;
+                       ++restart;
+               }
+               msleep(1);
+       }
+       if (restart && aac_commit)
+               aac_commit = 1;
+       /*
+        *      Fill in the common function dispatch table.
+        */
+       dev->a_ops.adapter_interrupt = aac_src_interrupt_adapter;
+       dev->a_ops.adapter_disable_int = aac_src_disable_interrupt;
+       dev->a_ops.adapter_notify = aac_src_notify_adapter;
+       dev->a_ops.adapter_sync_cmd = src_sync_cmd;
+       dev->a_ops.adapter_check_health = aac_src_check_health;
+       dev->a_ops.adapter_restart = aac_src_restart_adapter;
+
+       /*
+        *      First clear out all interrupts.  Then enable the one's that we
+        *      can handle.
+        */
+       aac_adapter_comm(dev, AAC_COMM_MESSAGE);
+       aac_adapter_disable_int(dev);
+       src_writel(dev, MUnit.ODR_C, 0xffffffff);
+       aac_adapter_enable_int(dev);
 
+       if (aac_init_adapter(dev) == NULL)
+               goto error_iounmap;
+       if (dev->comm_interface != AAC_COMM_MESSAGE_TYPE1)
+               goto error_iounmap;
+       dev->msi = aac_msi && !pci_enable_msi(dev->pdev);
+       if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr,
+               IRQF_SHARED|IRQF_DISABLED, "aacraid", dev) < 0) {
+               if (dev->msi)
+                       pci_disable_msi(dev->pdev);
+               printk(KERN_ERR "%s%d: Interrupt unavailable.\n",
+                       name, instance);
+               goto error_iounmap;
+       }
+       dev->dbg_base = dev->scsi_host_ptr->base;
+       dev->dbg_base_mapped = dev->base;
+       dev->dbg_size = dev->base_size;
+
+       aac_adapter_enable_int(dev);
+
+       if (!dev->sync_mode) {
+               /*
+                * Tell the adapter that all is configured, and it can
+                * start accepting requests
+                */
+               aac_src_start_adapter(dev);
+       }
        return 0;
 
 error_iounmap:
 
        return -1;
 }
+