[SCSI] qla2xxx: Add acquiring of risc semaphore before doing ISP reset.
authorJoe Carnuccio <joe.carnuccio@qlogic.com>
Wed, 21 Nov 2012 07:40:37 +0000 (02:40 -0500)
committerJames Bottomley <JBottomley@Parallels.com>
Fri, 30 Nov 2012 15:11:16 +0000 (15:11 +0000)
Try to acquire the semaphore; if semaphore is hung then acquire it by force.
The ISP reset clears the semaphore, thereby implicitly releasing it.

Signed-off-by: Joe Carnuccio <joe.carnuccio@qlogic.com>
Signed-off-by: Saurav Kashyap <saurav.kashyap@qlogic.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
drivers/scsi/qla2xxx/qla_fw.h
drivers/scsi/qla2xxx/qla_init.c

index 59524aa0ab324cf538fa1928d43ecdb843c5c28a..be6d61a89edcb812fa57db086fe26e58e6af10ed 100644 (file)
@@ -1092,6 +1092,27 @@ struct device_reg_24xx {
        uint32_t unused_6[2];           /* Gap. */
        uint32_t iobase_sdata;
 };
+/* RISC-RISC semaphore register PCI offet */
+#define RISC_REGISTER_BASE_OFFSET      0x7010
+#define RISC_REGISTER_WINDOW_OFFET     0x6
+
+/* RISC-RISC semaphore/flag register (risc address 0x7016) */
+
+#define RISC_SEMAPHORE         0x1UL
+#define RISC_SEMAPHORE_WE      (RISC_SEMAPHORE << 16)
+#define RISC_SEMAPHORE_CLR     (RISC_SEMAPHORE_WE | 0x0UL)
+#define RISC_SEMAPHORE_SET     (RISC_SEMAPHORE_WE | RISC_SEMAPHORE)
+
+#define RISC_SEMAPHORE_FORCE           0x8000UL
+#define RISC_SEMAPHORE_FORCE_WE                (RISC_SEMAPHORE_FORCE << 16)
+#define RISC_SEMAPHORE_FORCE_CLR       (RISC_SEMAPHORE_FORCE_WE | 0x0UL)
+#define RISC_SEMAPHORE_FORCE_SET       \
+               (RISC_SEMAPHORE_FORCE_WE | RISC_SEMAPHORE_FORCE)
+
+/* RISC semaphore timeouts (ms) */
+#define TIMEOUT_SEMAPHORE              2500
+#define TIMEOUT_SEMAPHORE_FORCE                2000
+#define TIMEOUT_TOTAL_ELAPSED          4500
 
 /* Trace Control *************************************************************/
 
index b7e42a80e165e9afc869afbdf9b9f48c453ca7a7..7464a4731ef617c973d9fd04707f33ed83087c53 100644 (file)
@@ -1095,6 +1095,83 @@ qla24xx_reset_risc(scsi_qla_host_t *vha)
                ha->isp_ops->enable_intrs(ha);
 }
 
+static void
+qla25xx_read_risc_sema_reg(scsi_qla_host_t *vha, uint32_t *data)
+{
+       struct device_reg_24xx __iomem *reg = &vha->hw->iobase->isp24;
+
+       WRT_REG_DWORD(&reg->iobase_addr, RISC_REGISTER_BASE_OFFSET);
+       *data = RD_REG_DWORD(&reg->iobase_window + RISC_REGISTER_WINDOW_OFFET);
+
+}
+
+static void
+qla25xx_write_risc_sema_reg(scsi_qla_host_t *vha, uint32_t data)
+{
+       struct device_reg_24xx __iomem *reg = &vha->hw->iobase->isp24;
+
+       WRT_REG_DWORD(&reg->iobase_addr, RISC_REGISTER_BASE_OFFSET);
+       WRT_REG_DWORD(&reg->iobase_window + RISC_REGISTER_WINDOW_OFFET, data);
+}
+
+static void
+qla25xx_manipulate_risc_semaphore(scsi_qla_host_t *vha)
+{
+       struct qla_hw_data *ha = vha->hw;
+       uint32_t wd32 = 0;
+       uint delta_msec = 100;
+       uint elapsed_msec = 0;
+       uint timeout_msec;
+       ulong n;
+
+       if (!IS_QLA25XX(ha) && !IS_QLA2031(ha))
+               return;
+
+attempt:
+       timeout_msec = TIMEOUT_SEMAPHORE;
+       n = timeout_msec / delta_msec;
+       while (n--) {
+               qla25xx_write_risc_sema_reg(vha, RISC_SEMAPHORE_SET);
+               qla25xx_read_risc_sema_reg(vha, &wd32);
+               if (wd32 & RISC_SEMAPHORE)
+                       break;
+               msleep(delta_msec);
+               elapsed_msec += delta_msec;
+               if (elapsed_msec > TIMEOUT_TOTAL_ELAPSED)
+                       goto force;
+       }
+
+       if (!(wd32 & RISC_SEMAPHORE))
+               goto force;
+
+       if (!(wd32 & RISC_SEMAPHORE_FORCE))
+               goto acquired;
+
+       qla25xx_write_risc_sema_reg(vha, RISC_SEMAPHORE_CLR);
+       timeout_msec = TIMEOUT_SEMAPHORE_FORCE;
+       n = timeout_msec / delta_msec;
+       while (n--) {
+               qla25xx_read_risc_sema_reg(vha, &wd32);
+               if (!(wd32 & RISC_SEMAPHORE_FORCE))
+                       break;
+               msleep(delta_msec);
+               elapsed_msec += delta_msec;
+               if (elapsed_msec > TIMEOUT_TOTAL_ELAPSED)
+                       goto force;
+       }
+
+       if (wd32 & RISC_SEMAPHORE_FORCE)
+               qla25xx_write_risc_sema_reg(vha, RISC_SEMAPHORE_FORCE_CLR);
+
+       goto attempt;
+
+force:
+       qla25xx_write_risc_sema_reg(vha, RISC_SEMAPHORE_FORCE_SET);
+
+acquired:
+       return;
+}
+
 /**
  * qla24xx_reset_chip() - Reset ISP24xx chip.
  * @ha: HA context
@@ -1113,6 +1190,8 @@ qla24xx_reset_chip(scsi_qla_host_t *vha)
 
        ha->isp_ops->disable_intrs(ha);
 
+       qla25xx_manipulate_risc_semaphore(vha);
+
        /* Perform RISC reset. */
        qla24xx_reset_risc(vha);
 }