]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/scsi/qla2xxx/qla_isr.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog
[linux-2.6-omap-h63xx.git] / drivers / scsi / qla2xxx / qla_isr.c
index eecae9905ece16b2af17e3d133115778b5a7fb2a..642a0c3f09c6a6a11fb9d99d884b1334d64aa651 100644 (file)
@@ -6,6 +6,7 @@
  */
 #include "qla_def.h"
 
+#include <linux/delay.h>
 #include <scsi/scsi_tcq.h>
 
 static void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t);
@@ -34,6 +35,7 @@ qla2100_intr_handler(int irq, void *dev_id)
        int             status;
        unsigned long   flags;
        unsigned long   iter;
+       uint16_t        hccr;
        uint16_t        mb[4];
 
        ha = (scsi_qla_host_t *) dev_id;
@@ -48,7 +50,23 @@ qla2100_intr_handler(int irq, void *dev_id)
 
        spin_lock_irqsave(&ha->hardware_lock, flags);
        for (iter = 50; iter--; ) {
-               if ((RD_REG_WORD(&reg->istatus) & ISR_RISC_INT) == 0)
+               hccr = RD_REG_WORD(&reg->hccr);
+               if (hccr & HCCR_RISC_PAUSE) {
+                       if (pci_channel_offline(ha->pdev))
+                               break;
+
+                       /*
+                        * Issue a "HARD" reset in order for the RISC interrupt
+                        * bit to be cleared.  Schedule a big hammmer to get
+                        * out of the RISC PAUSED state.
+                        */
+                       WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
+                       RD_REG_WORD(&reg->hccr);
+
+                       ha->isp_ops->fw_dump(ha, 1);
+                       set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+                       break;
+               } else if ((RD_REG_WORD(&reg->istatus) & ISR_RISC_INT) == 0)
                        break;
 
                if (RD_REG_WORD(&reg->semaphore) & BIT_0) {
@@ -86,7 +104,7 @@ qla2100_intr_handler(int irq, void *dev_id)
        if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
            (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
                set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
-               up(&ha->mbx_intr_sem);
+               complete(&ha->mbx_intr_comp);
        }
 
        return (IRQ_HANDLED);
@@ -127,6 +145,9 @@ qla2300_intr_handler(int irq, void *dev_id)
        for (iter = 50; iter--; ) {
                stat = RD_REG_DWORD(&reg->u.isp2300.host_status);
                if (stat & HSR_RISC_PAUSED) {
+                       if (pci_channel_offline(ha->pdev))
+                               break;
+
                        hccr = RD_REG_WORD(&reg->hccr);
                        if (hccr & (BIT_15 | BIT_13 | BIT_11 | BIT_8))
                                qla_printk(KERN_INFO, ha, "Parity error -- "
@@ -195,7 +216,7 @@ qla2300_intr_handler(int irq, void *dev_id)
        if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
            (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
                set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
-               up(&ha->mbx_intr_sem);
+               complete(&ha->mbx_intr_comp);
        }
 
        return (IRQ_HANDLED);
@@ -326,10 +347,6 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
                break;
 
        case MBA_SYSTEM_ERR:            /* System Error */
-               mb[1] = RD_MAILBOX_REG(ha, reg, 1);
-               mb[2] = RD_MAILBOX_REG(ha, reg, 2);
-               mb[3] = RD_MAILBOX_REG(ha, reg, 3);
-
                qla_printk(KERN_INFO, ha,
                    "ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh.\n",
                    mb[1], mb[2], mb[3]);
@@ -558,12 +575,15 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
                /* Check if the Vport has issued a SCR */
                if (ha->parent && test_bit(VP_SCR_NEEDED, &ha->vp_flags))
                        break;
+               /* Only handle SCNs for our Vport index. */
+               if (ha->flags.npiv_supported && ha->vp_idx != mb[3])
+                       break;
 
                DEBUG2(printk("scsi(%ld): Asynchronous RSCR UPDATE.\n",
                    ha->host_no));
                DEBUG(printk(KERN_INFO
-                   "scsi(%ld): RSCN database changed -- %04x %04x.\n",
-                   ha->host_no, mb[1], mb[2]));
+                   "scsi(%ld): RSCN database changed -- %04x %04x %04x.\n",
+                   ha->host_no, mb[1], mb[2], mb[3]));
 
                rscn_entry = (mb[1] << 16) | mb[2];
                host_pid = (ha->d_id.b.domain << 16) | (ha->d_id.b.area << 8) |
@@ -802,6 +822,35 @@ qla2x00_process_response_queue(struct scsi_qla_host *ha)
        WRT_REG_WORD(ISP_RSP_Q_OUT(ha, reg), ha->rsp_ring_index);
 }
 
+static inline void
+qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t sense_len)
+{
+       struct scsi_cmnd *cp = sp->cmd;
+
+       if (sense_len >= SCSI_SENSE_BUFFERSIZE)
+               sense_len = SCSI_SENSE_BUFFERSIZE;
+
+       CMD_ACTUAL_SNSLEN(cp) = sense_len;
+       sp->request_sense_length = sense_len;
+       sp->request_sense_ptr = cp->sense_buffer;
+       if (sp->request_sense_length > 32)
+               sense_len = 32;
+
+       memcpy(cp->sense_buffer, sense_data, sense_len);
+
+       sp->request_sense_ptr += sense_len;
+       sp->request_sense_length -= sense_len;
+       if (sp->request_sense_length != 0)
+               sp->ha->status_srb = sp;
+
+       DEBUG5(printk("%s(): Check condition Sense data, scsi(%ld:%d:%d:%d) "
+           "cmd=%p pid=%ld\n", __func__, sp->ha->host_no, cp->device->channel,
+           cp->device->id, cp->device->lun, cp, cp->serial_number));
+       if (sense_len)
+               DEBUG5(qla2x00_dump_buffer(cp->sense_buffer,
+                   CMD_ACTUAL_SNSLEN(cp)));
+}
+
 /**
  * qla2x00_status_entry() - Process a Status IOCB entry.
  * @ha: SCSI driver HA context
@@ -956,43 +1005,24 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
                if (lscsi_status != SS_CHECK_CONDITION)
                        break;
 
-               /* Copy Sense Data into sense buffer. */
-               memset(cp->sense_buffer, 0, sizeof(cp->sense_buffer));
-
+               memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
                if (!(scsi_status & SS_SENSE_LEN_VALID))
                        break;
 
-               if (sense_len >= sizeof(cp->sense_buffer))
-                       sense_len = sizeof(cp->sense_buffer);
-
-               CMD_ACTUAL_SNSLEN(cp) = sense_len;
-               sp->request_sense_length = sense_len;
-               sp->request_sense_ptr = cp->sense_buffer;
-
-               if (sp->request_sense_length > 32)
-                       sense_len = 32;
-
-               memcpy(cp->sense_buffer, sense_data, sense_len);
-
-               sp->request_sense_ptr += sense_len;
-               sp->request_sense_length -= sense_len;
-               if (sp->request_sense_length != 0)
-                       ha->status_srb = sp;
-
-               DEBUG5(printk("%s(): Check condition Sense data, "
-                   "scsi(%ld:%d:%d:%d) cmd=%p pid=%ld\n", __func__,
-                   ha->host_no, cp->device->channel, cp->device->id,
-                   cp->device->lun, cp, cp->serial_number));
-               if (sense_len)
-                       DEBUG5(qla2x00_dump_buffer(cp->sense_buffer,
-                           CMD_ACTUAL_SNSLEN(cp)));
+               qla2x00_handle_sense(sp, sense_data, sense_len);
                break;
 
        case CS_DATA_UNDERRUN:
                resid = resid_len;
                /* Use F/W calculated residual length. */
-               if (IS_FWI2_CAPABLE(ha))
+               if (IS_FWI2_CAPABLE(ha)) {
+                       if (scsi_status & SS_RESIDUAL_UNDER &&
+                           resid != fw_resid_len) {
+                               scsi_status &= ~SS_RESIDUAL_UNDER;
+                               lscsi_status = 0;
+                       }
                        resid = fw_resid_len;
+               }
 
                if (scsi_status & SS_RESIDUAL_UNDER) {
                        scsi_set_resid(cp, resid);
@@ -1034,34 +1064,11 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
                        if (lscsi_status != SS_CHECK_CONDITION)
                                break;
 
-                       /* Copy Sense Data into sense buffer */
-                       memset(cp->sense_buffer, 0, sizeof(cp->sense_buffer));
-
+                       memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
                        if (!(scsi_status & SS_SENSE_LEN_VALID))
                                break;
 
-                       if (sense_len >= sizeof(cp->sense_buffer))
-                               sense_len = sizeof(cp->sense_buffer);
-
-                       CMD_ACTUAL_SNSLEN(cp) = sense_len;
-                       sp->request_sense_length = sense_len;
-                       sp->request_sense_ptr = cp->sense_buffer;
-
-                       if (sp->request_sense_length > 32)
-                               sense_len = 32;
-
-                       memcpy(cp->sense_buffer, sense_data, sense_len);
-
-                       sp->request_sense_ptr += sense_len;
-                       sp->request_sense_length -= sense_len;
-                       if (sp->request_sense_length != 0)
-                               ha->status_srb = sp;
-
-                       DEBUG5(printk("%s(): Check condition Sense data, "
-                           "scsi(%ld:%d:%d:%d) cmd=%p pid=%ld\n",
-                           __func__, ha->host_no, cp->device->channel,
-                           cp->device->id, cp->device->lun, cp,
-                           cp->serial_number));
+                       qla2x00_handle_sense(sp, sense_data, sense_len);
 
                        /*
                         * In case of a Underrun condition, set both the lscsi
@@ -1081,10 +1088,6 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
 
                                cp->result = DID_ERROR << 16 | lscsi_status;
                        }
-
-                       if (sense_len)
-                               DEBUG5(qla2x00_dump_buffer(cp->sense_buffer,
-                                   CMD_ACTUAL_SNSLEN(cp)));
                } else {
                        /*
                         * If RISC reports underrun and target does not report
@@ -1464,6 +1467,52 @@ qla24xx_process_response_queue(struct scsi_qla_host *ha)
        WRT_REG_DWORD(&reg->rsp_q_out, ha->rsp_ring_index);
 }
 
+static void
+qla2xxx_check_risc_status(scsi_qla_host_t *ha)
+{
+       int rval;
+       uint32_t cnt;
+       struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+
+       if (!IS_QLA25XX(ha))
+               return;
+
+       rval = QLA_SUCCESS;
+       WRT_REG_DWORD(&reg->iobase_addr, 0x7C00);
+       RD_REG_DWORD(&reg->iobase_addr);
+       WRT_REG_DWORD(&reg->iobase_window, 0x0001);
+       for (cnt = 10000; (RD_REG_DWORD(&reg->iobase_window) & BIT_0) == 0 &&
+           rval == QLA_SUCCESS; cnt--) {
+               if (cnt) {
+                       WRT_REG_DWORD(&reg->iobase_window, 0x0001);
+                       udelay(10);
+               } else
+                       rval = QLA_FUNCTION_TIMEOUT;
+       }
+       if (rval == QLA_SUCCESS)
+               goto next_test;
+
+       WRT_REG_DWORD(&reg->iobase_window, 0x0003);
+       for (cnt = 100; (RD_REG_DWORD(&reg->iobase_window) & BIT_0) == 0 &&
+           rval == QLA_SUCCESS; cnt--) {
+               if (cnt) {
+                       WRT_REG_DWORD(&reg->iobase_window, 0x0003);
+                       udelay(10);
+               } else
+                       rval = QLA_FUNCTION_TIMEOUT;
+       }
+       if (rval != QLA_SUCCESS)
+               goto done;
+
+next_test:
+       if (RD_REG_DWORD(&reg->iobase_c8) & BIT_3)
+               qla_printk(KERN_INFO, ha, "Additional code -- 0x55AA.\n");
+
+done:
+       WRT_REG_DWORD(&reg->iobase_window, 0x0000);
+       RD_REG_DWORD(&reg->iobase_window);
+}
+
 /**
  * qla24xx_intr_handler() - Process interrupts for the ISP23xx and ISP63xx.
  * @irq:
@@ -1499,10 +1548,16 @@ qla24xx_intr_handler(int irq, void *dev_id)
        for (iter = 50; iter--; ) {
                stat = RD_REG_DWORD(&reg->host_status);
                if (stat & HSRX_RISC_PAUSED) {
+                       if (pci_channel_offline(ha->pdev))
+                               break;
+
                        hccr = RD_REG_DWORD(&reg->hccr);
 
                        qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, "
                            "Dumping firmware!\n", hccr);
+
+                       qla2xxx_check_risc_status(ha);
+
                        ha->isp_ops->fw_dump(ha, 1);
                        set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
                        break;
@@ -1542,7 +1597,7 @@ qla24xx_intr_handler(int irq, void *dev_id)
        if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
            (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
                set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
-               up(&ha->mbx_intr_sem);
+               complete(&ha->mbx_intr_comp);
        }
 
        return IRQ_HANDLED;
@@ -1606,7 +1661,6 @@ qla24xx_msix_rsp_q(int irq, void *dev_id)
        qla24xx_process_response_queue(ha);
 
        WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
-       RD_REG_DWORD_RELAXED(&reg->hccr);
 
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
@@ -1620,7 +1674,6 @@ qla24xx_msix_default(int irq, void *dev_id)
        struct device_reg_24xx __iomem *reg;
        int             status;
        unsigned long   flags;
-       unsigned long   iter;
        uint32_t        stat;
        uint32_t        hccr;
        uint16_t        mb[4];
@@ -1630,13 +1683,19 @@ qla24xx_msix_default(int irq, void *dev_id)
        status = 0;
 
        spin_lock_irqsave(&ha->hardware_lock, flags);
-       for (iter = 50; iter--; ) {
+       do {
                stat = RD_REG_DWORD(&reg->host_status);
                if (stat & HSRX_RISC_PAUSED) {
+                       if (pci_channel_offline(ha->pdev))
+                               break;
+
                        hccr = RD_REG_DWORD(&reg->hccr);
 
                        qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, "
                            "Dumping firmware!\n", hccr);
+
+                       qla2xxx_check_risc_status(ha);
+
                        ha->isp_ops->fw_dump(ha, 1);
                        set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
                        break;
@@ -1669,14 +1728,13 @@ qla24xx_msix_default(int irq, void *dev_id)
                        break;
                }
                WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
-               RD_REG_DWORD_RELAXED(&reg->hccr);
-       }
+       } while (0);
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
        if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
            (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
                set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
-               up(&ha->mbx_intr_sem);
+               complete(&ha->mbx_intr_comp);
        }
 
        return IRQ_HANDLED;
@@ -1771,6 +1829,18 @@ qla2x00_request_irqs(scsi_qla_host_t *ha)
                goto skip_msix;
        }
 
+       if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_HP &&
+           (ha->pdev->subsystem_device == 0x7040 ||
+               ha->pdev->subsystem_device == 0x7041 ||
+               ha->pdev->subsystem_device == 0x1705)) {
+               DEBUG2(qla_printk(KERN_WARNING, ha,
+                   "MSI-X: Unsupported ISP2432 SSVID/SSDID (0x%X, 0x%X).\n",
+                   ha->pdev->subsystem_vendor,
+                   ha->pdev->subsystem_device));
+
+               goto skip_msi;
+       }
+
        ret = qla24xx_enable_msix(ha);
        if (!ret) {
                DEBUG2(qla_printk(KERN_INFO, ha,