X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fscsi%2Faacraid%2Frx.c;h=dcc8b0ea7a9d213b4605857c574702a059cbb869;hb=refs%2Fheads%2Fvserver;hp=3963287c238bb24af3b985fbc1770fd31c87d497;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c index 3963287c2..dcc8b0ea7 100644 --- a/drivers/scsi/aacraid/rx.c +++ b/drivers/scsi/aacraid/rx.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -45,105 +46,72 @@ #include "aacraid.h" -static irqreturn_t aac_rx_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t aac_rx_intr(int irq, void *dev_id) { struct aac_dev *dev = dev_id; - unsigned long bellbits; - u8 intstat, mask; - 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. - */ - mask = ~(dev->OIMR); - /* Check to see if this is our interrupt. If it isn't just return */ - if (intstat & mask) - { - bellbits = rx_readl(dev, OutboundDoorbellReg); - if (bellbits & DoorBellPrintfReady) { - aac_printf(dev, le32_to_cpu(rx_readl (dev, IndexRegs.Mailbox[5]))); - rx_writel(dev, MUnit.ODR,DoorBellPrintfReady); - rx_writel(dev, InboundDoorbellReg,DoorBellPrintfDone); - } - else if (bellbits & DoorBellAdapterNormCmdReady) { - aac_command_normal(&dev->queues->queue[HostNormCmdQueue]); - rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdReady); - } - else if (bellbits & DoorBellAdapterNormRespReady) { - aac_response_normal(&dev->queues->queue[HostNormRespQueue]); - rx_writel(dev, MUnit.ODR,DoorBellAdapterNormRespReady); - } - else if (bellbits & DoorBellAdapterNormCmdNotFull) { - rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull); + + dprintk((KERN_DEBUG "aac_rx_intr(%d,%p)\n", irq, dev_id)); + 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; } - else if (bellbits & DoorBellAdapterNormRespNotFull) { - rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull); - rx_writel(dev, MUnit.ODR, DoorBellAdapterNormRespNotFull); + } 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, 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; } - return IRQ_HANDLED; } return IRQ_NONE; } /** - * aac_rx_enable_interrupt - Enable event reporting - * @dev: Adapter - * @event: Event to enable - * - * Enable event reporting from the i960 for a given event. - */ - -static void aac_rx_enable_interrupt(struct aac_dev * dev, u32 event) -{ - switch (event) { - - case HostNormCmdQue: - dev->irq_mask &= ~(OUTBOUNDDOORBELL_1); - break; - - case HostNormRespQue: - dev->irq_mask &= ~(OUTBOUNDDOORBELL_2); - break; - - case AdapNormCmdNotFull: - dev->irq_mask &= ~(OUTBOUNDDOORBELL_3); - break; - - case AdapNormRespNotFull: - dev->irq_mask &= ~(OUTBOUNDDOORBELL_4); - break; - } -} - -/** - * aac_rx_disable_interrupt - Disable event reporting + * aac_rx_disable_interrupt - Disable interrupts * @dev: Adapter - * @event: Event to enable - * - * Disable event reporting from the i960 for a given event. */ -static void aac_rx_disable_interrupt(struct aac_dev *dev, u32 event) +static void aac_rx_disable_interrupt(struct aac_dev *dev) { - switch (event) { - - case HostNormCmdQue: - dev->irq_mask |= (OUTBOUNDDOORBELL_1); - break; - - case HostNormRespQue: - dev->irq_mask |= (OUTBOUNDDOORBELL_2); - break; - - case AdapNormCmdNotFull: - dev->irq_mask |= (OUTBOUNDDOORBELL_3); - break; - - case AdapNormRespNotFull: - dev->irq_mask |= (OUTBOUNDDOORBELL_4); - break; - } + rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff); } /** @@ -153,25 +121,27 @@ static void aac_rx_disable_interrupt(struct aac_dev *dev, u32 event) * @p1: first parameter * @ret: adapter status * - * This routine will send a synchronous comamnd to the adapter and wait + * This routine will send a synchronous command to the adapter and wait * for its completion. */ -static int rx_sync_cmd(struct aac_dev *dev, u32 command, u32 p1, u32 *status) +static int rx_sync_cmd(struct aac_dev *dev, u32 command, + u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6, + u32 *status, u32 * r1, u32 * r2, u32 * r3, u32 * r4) { unsigned long start; int ok; /* * Write the command into Mailbox 0 */ - rx_writel(dev, InboundMailbox0, cpu_to_le32(command)); + writel(command, &dev->IndexRegs->Mailbox[0]); /* - * Write the parameters into Mailboxes 1 - 4 + * Write the parameters into Mailboxes 1 - 6 */ - rx_writel(dev, InboundMailbox1, cpu_to_le32(p1)); - rx_writel(dev, InboundMailbox2, 0); - rx_writel(dev, InboundMailbox3, 0); - rx_writel(dev, InboundMailbox4, 0); + 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. */ @@ -179,7 +149,7 @@ static int rx_sync_cmd(struct aac_dev *dev, u32 command, u32 p1, u32 *status) /* * Disable doorbell interrupts */ - rx_writeb(dev, MUnit.OIMR, dev->OIMR |= 0x04); + rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff); /* * Force the completion of the mask register write before issuing * the interrupt. @@ -213,20 +183,31 @@ static int rx_sync_cmd(struct aac_dev *dev, u32 command, u32 p1, u32 *status) /* * Yield the processor in case we are slow */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + msleep(1); } if (ok != 1) { /* * Restore interrupt mask even though we timed out */ - rx_writeb(dev, MUnit.OIMR, dev->OIMR &= 0xfb); + if (dev->new_comm_interface) + rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xf7); + else + rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb); return -ETIMEDOUT; } /* * Pull the synch status from Mailbox 0. */ - *status = le32_to_cpu(rx_readl(dev, IndexRegs.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. */ @@ -234,7 +215,10 @@ static int rx_sync_cmd(struct aac_dev *dev, u32 command, u32 p1, u32 *status) /* * Restore interrupt mask */ - rx_writeb(dev, MUnit.OIMR, dev->OIMR &= 0xfb); + if (dev->new_comm_interface) + rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xf7); + else + rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb); return 0; } @@ -248,8 +232,7 @@ static int rx_sync_cmd(struct aac_dev *dev, u32 command, u32 p1, u32 *status) static void aac_rx_interrupt_adapter(struct aac_dev *dev) { - u32 ret; - rx_sync_cmd(dev, BREAKPOINT_REQUEST, 0, &ret); + rx_sync_cmd(dev, BREAKPOINT_REQUEST, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL); } /** @@ -278,7 +261,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, &ret); break; case FastIo: rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_6); @@ -299,29 +281,15 @@ 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) { - u32 status; struct aac_init *init; init = dev->init; - init->HostElapsedSeconds = cpu_to_le32(jiffies/HZ); - /* - * Tell the adapter we are back and up and running so it will scan - * its command queues and enable our interrupts - */ - dev->irq_mask = (DoorBellPrintfReady | OUTBOUNDDOORBELL_1 | OUTBOUNDDOORBELL_2 | OUTBOUNDDOORBELL_3 | OUTBOUNDDOORBELL_4); - /* - * First clear out all interrupts. Then enable the one's that we - * can handle. - */ - rx_writeb(dev, MUnit.OIMR, 0xff); - rx_writel(dev, MUnit.ODR, 0xffffffff); -// rx_writeb(dev, MUnit.OIMR, ~(u8)OUTBOUND_DOORBELL_INTERRUPT_MASK); - rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb); - + init->HostElapsedSeconds = cpu_to_le32(get_seconds()); // We can only use a 32 bit address here - rx_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (u32)(ulong)dev->init_pa, &status); + rx_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (u32)(ulong)dev->init_pa, + 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL); } /** @@ -333,7 +301,7 @@ static void aac_rx_start_adapter(struct aac_dev *dev) */ static int aac_rx_check_health(struct aac_dev *dev) { - long status = rx_readl(dev, IndexRegs.Mailbox[7]); + u32 status = rx_readl(dev, MUnit.OMRx[0]); /* * Check to see if the board failed any self tests. @@ -341,12 +309,47 @@ static int aac_rx_check_health(struct aac_dev *dev) if (status & SELF_TEST_FAILED) return -1; /* - * Check to see if the board panic'd while booting. + * Check to see if the board panic'd. */ - if (status & KERNEL_PANIC) - return -2; + if (status & KERNEL_PANIC) { + char * buffer; + struct POSTSTATUS { + __le32 Post_Command; + __le32 Post_Address; + } * post; + dma_addr_t paddr, baddr; + int ret; + + if ((status & 0xFF000000L) == 0xBC000000L) + return (status >> 16) & 0xFF; + buffer = pci_alloc_consistent(dev->pdev, 512, &baddr); + ret = -2; + if (buffer == NULL) + return ret; + post = pci_alloc_consistent(dev->pdev, + sizeof(struct POSTSTATUS), &paddr); + if (post == NULL) { + pci_free_consistent(dev->pdev, 512, buffer, baddr); + return ret; + } + memset(buffer, 0, 512); + post->Post_Command = cpu_to_le32(COMMAND_POST_RESULTS); + post->Post_Address = cpu_to_le32(baddr); + rx_writel(dev, MUnit.IMRx[0], paddr); + rx_sync_cmd(dev, COMMAND_POST_RESULTS, baddr, 0, 0, 0, 0, 0, + NULL, NULL, NULL, NULL, NULL); + pci_free_consistent(dev->pdev, sizeof(struct POSTSTATUS), + post, paddr); + if ((buffer[0] == '0') && ((buffer[1] == 'x') || (buffer[1] == 'X'))) { + ret = (buffer[2] <= '9') ? (buffer[2] - '0') : (buffer[2] - 'A' + 10); + ret <<= 4; + ret += (buffer[3] <= '9') ? (buffer[3] - '0') : (buffer[3] - 'A' + 10); + } + pci_free_consistent(dev->pdev, 512, buffer, baddr); + return ret; + } /* - * Wait for the adapter to be up and running. Wait up to 3 minutes + * Wait for the adapter to be up and running. */ if (!(status & KERNEL_UP_AND_RUNNING)) return -3; @@ -354,91 +357,193 @@ static int aac_rx_check_health(struct aac_dev *dev) * Everything is OK */ return 0; -} /* aac_rx_check_health */ +} + +/** + * aac_rx_send + * @fib: fib to issue + * + * Will send a fib, returning 0 if successful. + */ +static int aac_rx_send(struct fib * fib) +{ + u64 addr = fib->hw_fib_pa; + struct aac_dev *dev = fib->dev; + volatile void __iomem *device = dev->regs.rx; + u32 Index; + + dprintk((KERN_DEBUG "%p->aac_rx_send(%p->%llx)\n", dev, fib, addr)); + Index = rx_readl(dev, MUnit.InboundQueue); + if (Index == 0xFFFFFFFFL) + Index = rx_readl(dev, MUnit.InboundQueue); + dprintk((KERN_DEBUG "Index = 0x%x\n", Index)); + if (Index == 0xFFFFFFFFL) + return Index; + device = dev->base + Index; + dprintk((KERN_DEBUG "entry = %x %x %u\n", (u32)(addr & 0xffffffff), + (u32)(addr >> 32), (u32)le16_to_cpu(fib->hw_fib->header.Size))); + 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_init - initialize an i960 based AAC card * @dev: device to configure - * @devnum: adapter number * * Allocate and set up resources for the i960 based AAC variants. The * device_interface in the commregion will be allocated and linked * to the comm region. */ -int aac_rx_init(struct aac_dev *dev, unsigned long num) +int _aac_rx_init(struct aac_dev *dev) { unsigned long start; unsigned long status; int instance; const char * name; - dev->devnum = num; 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; + } + /* - * Map in the registers from the adapter. + * Check to see if the board panic'd while booting. */ - if((dev->regs.rx = (struct rx_registers *)ioremap((unsigned long)dev->scsi_host_ptr->base, 8192))==NULL) - { - printk(KERN_WARNING "aacraid: unable to map i960.\n" ); - return -1; - } + 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, IndexRegs.Mailbox[7]) & 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); - return -1; + goto error_iounmap; } /* - * Check to see if the board panic'd while booting. + * Check to see if the monitor panic'd while booting. */ - if (rx_readl(dev, IndexRegs.Mailbox[7]) & KERNEL_PANIC) { - printk(KERN_ERR "%s%d: adapter kernel panic'd.\n", dev->name, instance); - return -1; + 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 (!(rx_readl(dev, IndexRegs.Mailbox[7]) & 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]) >> 16; - printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %ld.\n", dev->name, instance, status); - return -1; + printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %lx.\n", + dev->name, instance, status); + goto error_iounmap; } - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + msleep(1); } - if (request_irq(dev->scsi_host_ptr->irq, aac_rx_intr, SA_SHIRQ|SA_INTERRUPT, "aacraid", (void *)dev)<0) + if (request_irq(dev->scsi_host_ptr->irq, aac_rx_intr, IRQF_SHARED|IRQF_DISABLED, "aacraid", (void *)dev)<0) { printk(KERN_ERR "%s%d: Interrupt unavailable.\n", name, instance); - return -1; + goto error_iounmap; } /* * Fill in the function dispatch table. */ dev->a_ops.adapter_interrupt = aac_rx_interrupt_adapter; - dev->a_ops.adapter_enable_int = aac_rx_enable_interrupt; 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; - if (aac_init_adapter(dev) == NULL) - return -1; /* - * Start any kernel threads needed + * First clear out all interrupts. Then enable the one's that we + * can handle. */ - dev->thread_pid = kernel_thread((int (*)(void *))aac_command_thread, dev, 0); + rx_writeb(dev, MUnit.OIMR, 0xff); + rx_writel(dev, MUnit.ODR, 0xffffffff); + rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb); + + if (aac_init_adapter(dev) == NULL) + goto error_irq; + if (dev->new_comm_interface) + rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xf7); + + return 0; + +error_irq: + rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff); + free_irq(dev->scsi_host_ptr->irq, (void *)dev); + +error_iounmap: + + return -1; +} + +int aac_rx_init(struct aac_dev *dev) +{ + int retval; + /* - * Tell the adapter that all is configured, and it can start - * accepting requests + * Fill in the function dispatch table. */ - aac_rx_start_adapter(dev); - return 0; + dev->a_ops.adapter_ioremap = aac_rx_ioremap; + + retval = _aac_rx_init(dev); + if (!retval) { + /* + * Tell the adapter that all is configured, and it can + * start accepting requests + */ + aac_rx_start_adapter(dev); + } + return retval; }