diff options
Diffstat (limited to 'drivers/scsi/aacraid/src.c')
-rw-r--r-- | drivers/scsi/aacraid/src.c | 293 |
1 files changed, 242 insertions, 51 deletions
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) | |||
96 | our_interrupt = 1; | 96 | our_interrupt = 1; |
97 | /* handle AIF */ | 97 | /* handle AIF */ |
98 | aac_intr_normal(dev, 0, 2, 0, NULL); | 98 | aac_intr_normal(dev, 0, 2, 0, NULL); |
99 | } else if (bellbits_shifted & OUTBOUNDDOORBELL_0) { | ||
100 | unsigned long sflags; | ||
101 | struct list_head *entry; | ||
102 | int send_it = 0; | ||
103 | |||
104 | if (dev->sync_fib) { | ||
105 | our_interrupt = 1; | ||
106 | if (dev->sync_fib->callback) | ||
107 | dev->sync_fib->callback(dev->sync_fib->callback_data, | ||
108 | dev->sync_fib); | ||
109 | spin_lock_irqsave(&dev->sync_fib->event_lock, sflags); | ||
110 | if (dev->sync_fib->flags & FIB_CONTEXT_FLAG_WAIT) { | ||
111 | dev->management_fib_count--; | ||
112 | up(&dev->sync_fib->event_wait); | ||
113 | } | ||
114 | spin_unlock_irqrestore(&dev->sync_fib->event_lock, sflags); | ||
115 | spin_lock_irqsave(&dev->sync_lock, sflags); | ||
116 | if (!list_empty(&dev->sync_fib_list)) { | ||
117 | entry = dev->sync_fib_list.next; | ||
118 | dev->sync_fib = list_entry(entry, struct fib, fiblink); | ||
119 | list_del(entry); | ||
120 | send_it = 1; | ||
121 | } else { | ||
122 | dev->sync_fib = NULL; | ||
123 | } | ||
124 | spin_unlock_irqrestore(&dev->sync_lock, sflags); | ||
125 | if (send_it) { | ||
126 | aac_adapter_sync_cmd(dev, SEND_SYNCHRONOUS_FIB, | ||
127 | (u32)dev->sync_fib->hw_fib_pa, 0, 0, 0, 0, 0, | ||
128 | NULL, NULL, NULL, NULL, NULL); | ||
129 | } | ||
130 | } | ||
99 | } | 131 | } |
100 | } | 132 | } |
101 | 133 | ||
@@ -177,56 +209,63 @@ static int src_sync_cmd(struct aac_dev *dev, u32 command, | |||
177 | */ | 209 | */ |
178 | src_writel(dev, MUnit.IDR, INBOUNDDOORBELL_0 << SRC_IDR_SHIFT); | 210 | src_writel(dev, MUnit.IDR, INBOUNDDOORBELL_0 << SRC_IDR_SHIFT); |
179 | 211 | ||
180 | ok = 0; | 212 | if (!dev->sync_mode || command != SEND_SYNCHRONOUS_FIB) { |
181 | start = jiffies; | 213 | ok = 0; |
214 | start = jiffies; | ||
182 | 215 | ||
183 | /* | 216 | /* |
184 | * Wait up to 30 seconds | 217 | * Wait up to 5 minutes |
185 | */ | ||
186 | while (time_before(jiffies, start+30*HZ)) { | ||
187 | /* Delay 5 microseconds to let Mon960 get info. */ | ||
188 | udelay(5); | ||
189 | |||
190 | /* Mon960 will set doorbell0 bit | ||
191 | * when it has completed the command | ||
192 | */ | 218 | */ |
193 | if ((src_readl(dev, MUnit.ODR_R) >> SRC_ODR_SHIFT) & OUTBOUNDDOORBELL_0) { | 219 | while (time_before(jiffies, start+300*HZ)) { |
194 | /* Clear the doorbell */ | 220 | udelay(5); /* Delay 5 microseconds to let Mon960 get info. */ |
195 | src_writel(dev, | 221 | /* |
196 | MUnit.ODR_C, | 222 | * Mon960 will set doorbell0 bit when it has completed the command. |
197 | OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT); | 223 | */ |
198 | ok = 1; | 224 | if ((src_readl(dev, MUnit.ODR_R) >> SRC_ODR_SHIFT) & OUTBOUNDDOORBELL_0) { |
199 | break; | 225 | /* |
226 | * Clear the doorbell. | ||
227 | */ | ||
228 | src_writel(dev, MUnit.ODR_C, OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT); | ||
229 | ok = 1; | ||
230 | break; | ||
231 | } | ||
232 | /* | ||
233 | * Yield the processor in case we are slow | ||
234 | */ | ||
235 | msleep(1); | ||
200 | } | 236 | } |
201 | 237 | if (unlikely(ok != 1)) { | |
202 | /* Yield the processor in case we are slow */ | 238 | /* |
203 | msleep(1); | 239 | * Restore interrupt mask even though we timed out |
204 | } | 240 | */ |
205 | if (unlikely(ok != 1)) { | 241 | aac_adapter_enable_int(dev); |
206 | /* Restore interrupt mask even though we timed out */ | 242 | return -ETIMEDOUT; |
207 | aac_adapter_enable_int(dev); | 243 | } |
208 | return -ETIMEDOUT; | 244 | /* |
245 | * Pull the synch status from Mailbox 0. | ||
246 | */ | ||
247 | if (status) | ||
248 | *status = readl(&dev->IndexRegs->Mailbox[0]); | ||
249 | if (r1) | ||
250 | *r1 = readl(&dev->IndexRegs->Mailbox[1]); | ||
251 | if (r2) | ||
252 | *r2 = readl(&dev->IndexRegs->Mailbox[2]); | ||
253 | if (r3) | ||
254 | *r3 = readl(&dev->IndexRegs->Mailbox[3]); | ||
255 | if (r4) | ||
256 | *r4 = readl(&dev->IndexRegs->Mailbox[4]); | ||
257 | |||
258 | /* | ||
259 | * Clear the synch command doorbell. | ||
260 | */ | ||
261 | src_writel(dev, MUnit.ODR_C, OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT); | ||
209 | } | 262 | } |
210 | 263 | ||
211 | /* Pull the synch status from Mailbox 0 */ | 264 | /* |
212 | if (status) | 265 | * Restore interrupt mask |
213 | *status = readl(&dev->IndexRegs->Mailbox[0]); | 266 | */ |
214 | if (r1) | ||
215 | *r1 = readl(&dev->IndexRegs->Mailbox[1]); | ||
216 | if (r2) | ||
217 | *r2 = readl(&dev->IndexRegs->Mailbox[2]); | ||
218 | if (r3) | ||
219 | *r3 = readl(&dev->IndexRegs->Mailbox[3]); | ||
220 | if (r4) | ||
221 | *r4 = readl(&dev->IndexRegs->Mailbox[4]); | ||
222 | |||
223 | /* Clear the synch command doorbell */ | ||
224 | src_writel(dev, MUnit.ODR_C, OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT); | ||
225 | |||
226 | /* Restore interrupt mask */ | ||
227 | aac_adapter_enable_int(dev); | 267 | aac_adapter_enable_int(dev); |
228 | return 0; | 268 | return 0; |
229 | |||
230 | } | 269 | } |
231 | 270 | ||
232 | /** | 271 | /** |
@@ -386,9 +425,7 @@ static int aac_src_ioremap(struct aac_dev *dev, u32 size) | |||
386 | { | 425 | { |
387 | if (!size) { | 426 | if (!size) { |
388 | iounmap(dev->regs.src.bar0); | 427 | iounmap(dev->regs.src.bar0); |
389 | dev->regs.src.bar0 = NULL; | 428 | dev->base = dev->regs.src.bar0 = NULL; |
390 | iounmap(dev->base); | ||
391 | dev->base = NULL; | ||
392 | return 0; | 429 | return 0; |
393 | } | 430 | } |
394 | dev->regs.src.bar1 = ioremap(pci_resource_start(dev->pdev, 2), | 431 | 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) | |||
404 | return -1; | 441 | return -1; |
405 | } | 442 | } |
406 | dev->IndexRegs = &((struct src_registers __iomem *) | 443 | dev->IndexRegs = &((struct src_registers __iomem *) |
407 | dev->base)->IndexRegs; | 444 | dev->base)->u.tupelo.IndexRegs; |
445 | return 0; | ||
446 | } | ||
447 | |||
448 | /** | ||
449 | * aac_srcv_ioremap | ||
450 | * @size: mapping resize request | ||
451 | * | ||
452 | */ | ||
453 | static int aac_srcv_ioremap(struct aac_dev *dev, u32 size) | ||
454 | { | ||
455 | if (!size) { | ||
456 | iounmap(dev->regs.src.bar0); | ||
457 | dev->base = dev->regs.src.bar0 = NULL; | ||
458 | return 0; | ||
459 | } | ||
460 | dev->base = dev->regs.src.bar0 = ioremap(dev->scsi_host_ptr->base, size); | ||
461 | if (dev->base == NULL) | ||
462 | return -1; | ||
463 | dev->IndexRegs = &((struct src_registers __iomem *) | ||
464 | dev->base)->u.denali.IndexRegs; | ||
408 | return 0; | 465 | return 0; |
409 | } | 466 | } |
410 | 467 | ||
@@ -419,7 +476,7 @@ static int aac_src_restart_adapter(struct aac_dev *dev, int bled) | |||
419 | bled = aac_adapter_sync_cmd(dev, IOP_RESET_ALWAYS, | 476 | bled = aac_adapter_sync_cmd(dev, IOP_RESET_ALWAYS, |
420 | 0, 0, 0, 0, 0, 0, &var, &reset_mask, NULL, NULL, NULL); | 477 | 0, 0, 0, 0, 0, 0, &var, &reset_mask, NULL, NULL, NULL); |
421 | if (bled || (var != 0x00000001)) | 478 | if (bled || (var != 0x00000001)) |
422 | bled = -EINVAL; | 479 | return -EINVAL; |
423 | if (dev->supplement_adapter_info.SupportedOptions2 & | 480 | if (dev->supplement_adapter_info.SupportedOptions2 & |
424 | AAC_OPTION_DOORBELL_RESET) { | 481 | AAC_OPTION_DOORBELL_RESET) { |
425 | src_writel(dev, MUnit.IDR, reset_mask); | 482 | src_writel(dev, MUnit.IDR, reset_mask); |
@@ -579,15 +636,149 @@ int aac_src_init(struct aac_dev *dev) | |||
579 | dev->dbg_size = AAC_MIN_SRC_BAR1_SIZE; | 636 | dev->dbg_size = AAC_MIN_SRC_BAR1_SIZE; |
580 | 637 | ||
581 | aac_adapter_enable_int(dev); | 638 | aac_adapter_enable_int(dev); |
639 | |||
640 | if (!dev->sync_mode) { | ||
641 | /* | ||
642 | * Tell the adapter that all is configured, and it can | ||
643 | * start accepting requests | ||
644 | */ | ||
645 | aac_src_start_adapter(dev); | ||
646 | } | ||
647 | return 0; | ||
648 | |||
649 | error_iounmap: | ||
650 | |||
651 | return -1; | ||
652 | } | ||
653 | |||
654 | /** | ||
655 | * aac_srcv_init - initialize an SRCv card | ||
656 | * @dev: device to configure | ||
657 | * | ||
658 | */ | ||
659 | |||
660 | int aac_srcv_init(struct aac_dev *dev) | ||
661 | { | ||
662 | unsigned long start; | ||
663 | unsigned long status; | ||
664 | int restart = 0; | ||
665 | int instance = dev->id; | ||
666 | const char *name = dev->name; | ||
667 | |||
668 | dev->a_ops.adapter_ioremap = aac_srcv_ioremap; | ||
669 | dev->a_ops.adapter_comm = aac_src_select_comm; | ||
670 | |||
671 | dev->base_size = AAC_MIN_SRCV_BAR0_SIZE; | ||
672 | if (aac_adapter_ioremap(dev, dev->base_size)) { | ||
673 | printk(KERN_WARNING "%s: unable to map adapter.\n", name); | ||
674 | goto error_iounmap; | ||
675 | } | ||
676 | |||
677 | /* Failure to reset here is an option ... */ | ||
678 | dev->a_ops.adapter_sync_cmd = src_sync_cmd; | ||
679 | dev->a_ops.adapter_enable_int = aac_src_disable_interrupt; | ||
680 | if ((aac_reset_devices || reset_devices) && | ||
681 | !aac_src_restart_adapter(dev, 0)) | ||
682 | ++restart; | ||
582 | /* | 683 | /* |
583 | * Tell the adapter that all is configured, and it can | 684 | * Check to see if the board panic'd while booting. |
584 | * start accepting requests | ||
585 | */ | 685 | */ |
586 | aac_src_start_adapter(dev); | 686 | status = src_readl(dev, MUnit.OMR); |
687 | if (status & KERNEL_PANIC) { | ||
688 | if (aac_src_restart_adapter(dev, aac_src_check_health(dev))) | ||
689 | goto error_iounmap; | ||
690 | ++restart; | ||
691 | } | ||
692 | /* | ||
693 | * Check to see if the board failed any self tests. | ||
694 | */ | ||
695 | status = src_readl(dev, MUnit.OMR); | ||
696 | if (status & SELF_TEST_FAILED) { | ||
697 | printk(KERN_ERR "%s%d: adapter self-test failed.\n", dev->name, instance); | ||
698 | goto error_iounmap; | ||
699 | } | ||
700 | /* | ||
701 | * Check to see if the monitor panic'd while booting. | ||
702 | */ | ||
703 | if (status & MONITOR_PANIC) { | ||
704 | printk(KERN_ERR "%s%d: adapter monitor panic.\n", dev->name, instance); | ||
705 | goto error_iounmap; | ||
706 | } | ||
707 | start = jiffies; | ||
708 | /* | ||
709 | * Wait for the adapter to be up and running. Wait up to 3 minutes | ||
710 | */ | ||
711 | while (!((status = src_readl(dev, MUnit.OMR)) & KERNEL_UP_AND_RUNNING)) { | ||
712 | if ((restart && | ||
713 | (status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC))) || | ||
714 | time_after(jiffies, start+HZ*startup_timeout)) { | ||
715 | printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %lx.\n", | ||
716 | dev->name, instance, status); | ||
717 | goto error_iounmap; | ||
718 | } | ||
719 | if (!restart && | ||
720 | ((status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC)) || | ||
721 | time_after(jiffies, start + HZ * | ||
722 | ((startup_timeout > 60) | ||
723 | ? (startup_timeout - 60) | ||
724 | : (startup_timeout / 2))))) { | ||
725 | if (likely(!aac_src_restart_adapter(dev, aac_src_check_health(dev)))) | ||
726 | start = jiffies; | ||
727 | ++restart; | ||
728 | } | ||
729 | msleep(1); | ||
730 | } | ||
731 | if (restart && aac_commit) | ||
732 | aac_commit = 1; | ||
733 | /* | ||
734 | * Fill in the common function dispatch table. | ||
735 | */ | ||
736 | dev->a_ops.adapter_interrupt = aac_src_interrupt_adapter; | ||
737 | dev->a_ops.adapter_disable_int = aac_src_disable_interrupt; | ||
738 | dev->a_ops.adapter_notify = aac_src_notify_adapter; | ||
739 | dev->a_ops.adapter_sync_cmd = src_sync_cmd; | ||
740 | dev->a_ops.adapter_check_health = aac_src_check_health; | ||
741 | dev->a_ops.adapter_restart = aac_src_restart_adapter; | ||
742 | |||
743 | /* | ||
744 | * First clear out all interrupts. Then enable the one's that we | ||
745 | * can handle. | ||
746 | */ | ||
747 | aac_adapter_comm(dev, AAC_COMM_MESSAGE); | ||
748 | aac_adapter_disable_int(dev); | ||
749 | src_writel(dev, MUnit.ODR_C, 0xffffffff); | ||
750 | aac_adapter_enable_int(dev); | ||
587 | 751 | ||
752 | if (aac_init_adapter(dev) == NULL) | ||
753 | goto error_iounmap; | ||
754 | if (dev->comm_interface != AAC_COMM_MESSAGE_TYPE1) | ||
755 | goto error_iounmap; | ||
756 | dev->msi = aac_msi && !pci_enable_msi(dev->pdev); | ||
757 | if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr, | ||
758 | IRQF_SHARED|IRQF_DISABLED, "aacraid", dev) < 0) { | ||
759 | if (dev->msi) | ||
760 | pci_disable_msi(dev->pdev); | ||
761 | printk(KERN_ERR "%s%d: Interrupt unavailable.\n", | ||
762 | name, instance); | ||
763 | goto error_iounmap; | ||
764 | } | ||
765 | dev->dbg_base = dev->scsi_host_ptr->base; | ||
766 | dev->dbg_base_mapped = dev->base; | ||
767 | dev->dbg_size = dev->base_size; | ||
768 | |||
769 | aac_adapter_enable_int(dev); | ||
770 | |||
771 | if (!dev->sync_mode) { | ||
772 | /* | ||
773 | * Tell the adapter that all is configured, and it can | ||
774 | * start accepting requests | ||
775 | */ | ||
776 | aac_src_start_adapter(dev); | ||
777 | } | ||
588 | return 0; | 778 | return 0; |
589 | 779 | ||
590 | error_iounmap: | 780 | error_iounmap: |
591 | 781 | ||
592 | return -1; | 782 | return -1; |
593 | } | 783 | } |
784 | |||