diff options
author | Mahesh Rajashekhara <Mahesh_Rajashekhara@pmc-sierra.com> | 2012-02-08 22:51:04 -0800 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2012-02-19 08:09:01 -0600 |
commit | 116046127d1a3bad2853d02781ad9fee33f05e5a (patch) | |
tree | f5a0ca20662b98960ce20587f666b6267367478b | |
parent | 70fc872c738d1e0af7d0420047e4ca3acf283c9d (diff) | |
download | linux-116046127d1a3bad2853d02781ad9fee33f05e5a.tar.bz2 |
[SCSI] aacraid: Added Sync.mode to support series 7/8/9 controllers
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>
-rw-r--r-- | drivers/scsi/aacraid/aachba.c | 4 | ||||
-rw-r--r-- | drivers/scsi/aacraid/aacraid.h | 27 | ||||
-rw-r--r-- | drivers/scsi/aacraid/comminit.c | 21 | ||||
-rw-r--r-- | drivers/scsi/aacraid/commsup.c | 26 | ||||
-rw-r--r-- | drivers/scsi/aacraid/linit.c | 28 | ||||
-rw-r--r-- | drivers/scsi/aacraid/rx.c | 1 | ||||
-rw-r--r-- | drivers/scsi/aacraid/sa.c | 1 | ||||
-rw-r--r-- | drivers/scsi/aacraid/src.c | 293 |
8 files changed, 338 insertions, 63 deletions
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index 409f5805bdd6..52551662d107 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -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"); diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index ffb587817efc..3fcf62724fad 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h @@ -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); diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c index 7ac8fdb5577b..a35f54ebdce0 100644 --- a/drivers/scsi/aacraid/comminit.c +++ b/drivers/scsi/aacraid/comminit.c @@ -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; } diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index e5f2d7d9002e..4b32ca442433 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c @@ -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) { diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 705e13e470af..0d279c445a30 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -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 */ diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c index ce530f113fdb..b029c7cc785b 100644 --- a/drivers/scsi/aacraid/rx.c +++ b/drivers/scsi/aacraid/rx.c @@ -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) { diff --git a/drivers/scsi/aacraid/sa.c b/drivers/scsi/aacraid/sa.c index e5d4457121ea..beb533630d4b 100644 --- a/drivers/scsi/aacraid/sa.c +++ b/drivers/scsi/aacraid/sa.c @@ -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) { diff --git a/drivers/scsi/aacraid/src.c b/drivers/scsi/aacraid/src.c index 957595a7a45c..2bee51506a91 100644 --- a/drivers/scsi/aacraid/src.c +++ b/drivers/scsi/aacraid/src.c @@ -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; } + |