[SCSI] qla4xxx: Added support for ISP82XX
[pandora-kernel.git] / drivers / scsi / qla4xxx / ql4_mbx.c
index 54db6cb..0d3a652 100644 (file)
  * @mbx_cmd: data pointer for mailbox in registers.
  * @mbx_sts: data pointer for mailbox out registers.
  *
- * This routine sssue mailbox commands and waits for completion.
+ * This routine isssue mailbox commands and waits for completion.
  * If outCount is 0, this routine completes successfully WITHOUT waiting
  * for the mailbox command to complete.
  **/
-static int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
-                                  uint8_t outCount, uint32_t *mbx_cmd,
-                                  uint32_t *mbx_sts)
+int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
+                           uint8_t outCount, uint32_t *mbx_cmd,
+                           uint32_t *mbx_sts)
 {
        int status = QLA_ERROR;
        uint8_t i;
@@ -59,32 +59,66 @@ static int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
        }
 
        /* To prevent overwriting mailbox registers for a command that has
-        * not yet been serviced, check to see if a previously issued
-        * mailbox command is interrupting.
+        * not yet been serviced, check to see if an active command
+        * (AEN, IOCB, etc.) is interrupting, then service it.
         * -----------------------------------------------------------------
         */
        spin_lock_irqsave(&ha->hardware_lock, flags);
-       intr_status = readl(&ha->reg->ctrl_status);
-       if (intr_status & CSR_SCSI_PROCESSOR_INTR) {
-               /* Service existing interrupt */
-               qla4xxx_interrupt_service_routine(ha, intr_status);
-               clear_bit(AF_MBOX_COMMAND_DONE, &ha->flags);
+
+       if (is_qla8022(ha)) {
+               intr_status = readl(&ha->qla4_8xxx_reg->host_int);
+               if (intr_status & ISRX_82XX_RISC_INT) {
+                       /* Service existing interrupt */
+                       DEBUG2(printk("scsi%ld: %s: "
+                           "servicing existing interrupt\n",
+                           ha->host_no, __func__));
+                       intr_status = readl(&ha->qla4_8xxx_reg->host_status);
+                       ha->isp_ops->interrupt_service_routine(ha, intr_status);
+                       clear_bit(AF_MBOX_COMMAND_DONE, &ha->flags);
+                       if (test_bit(AF_INTERRUPTS_ON, &ha->flags) &&
+                           test_bit(AF_INTx_ENABLED, &ha->flags))
+                               qla4_8xxx_wr_32(ha,
+                                   ha->nx_legacy_intr.tgt_mask_reg,
+                                   0xfbff);
+               }
+       } else {
+               intr_status = readl(&ha->reg->ctrl_status);
+               if (intr_status & CSR_SCSI_PROCESSOR_INTR) {
+                       /* Service existing interrupt */
+                       ha->isp_ops->interrupt_service_routine(ha, intr_status);
+                       clear_bit(AF_MBOX_COMMAND_DONE, &ha->flags);
+               }
        }
 
-       /* Send the mailbox command to the firmware */
        ha->mbox_status_count = outCount;
        for (i = 0; i < outCount; i++)
                ha->mbox_status[i] = 0;
 
-       /* Load all mailbox registers, except mailbox 0. */
-       for (i = 1; i < inCount; i++)
-               writel(mbx_cmd[i], &ha->reg->mailbox[i]);
+       if (is_qla8022(ha)) {
+               /* Load all mailbox registers, except mailbox 0. */
+               DEBUG5(
+                   printk("scsi%ld: %s: Cmd ", ha->host_no, __func__);
+                   for (i = 0; i < inCount; i++)
+                       printk("mb%d=%04x ", i, mbx_cmd[i]);
+                   printk("\n"));
+
+               for (i = 1; i < inCount; i++)
+                       writel(mbx_cmd[i], &ha->qla4_8xxx_reg->mailbox_in[i]);
+               writel(mbx_cmd[0], &ha->qla4_8xxx_reg->mailbox_in[0]);
+               readl(&ha->qla4_8xxx_reg->mailbox_in[0]);
+               writel(HINT_MBX_INT_PENDING, &ha->qla4_8xxx_reg->hint);
+       } else {
+               /* Load all mailbox registers, except mailbox 0. */
+               for (i = 1; i < inCount; i++)
+                       writel(mbx_cmd[i], &ha->reg->mailbox[i]);
+
+               /* Wakeup firmware  */
+               writel(mbx_cmd[0], &ha->reg->mailbox[0]);
+               readl(&ha->reg->mailbox[0]);
+               writel(set_rmask(CSR_INTR_RISC), &ha->reg->ctrl_status);
+               readl(&ha->reg->ctrl_status);
+       }
 
-       /* Wakeup firmware  */
-       writel(mbx_cmd[0], &ha->reg->mailbox[0]);
-       readl(&ha->reg->mailbox[0]);
-       writel(set_rmask(CSR_INTR_RISC), &ha->reg->ctrl_status);
-       readl(&ha->reg->ctrl_status);
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
        /* Wait for completion */
@@ -98,26 +132,66 @@ static int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
                status = QLA_SUCCESS;
                goto mbox_exit;
        }
-       /* Wait for command to complete */
-       wait_count = jiffies + MBOX_TOV * HZ;
-       while (test_bit(AF_MBOX_COMMAND_DONE, &ha->flags) == 0) {
-               if (time_after_eq(jiffies, wait_count))
-                       break;
 
-               spin_lock_irqsave(&ha->hardware_lock, flags);
-               intr_status = readl(&ha->reg->ctrl_status);
-               if (intr_status & INTR_PENDING) {
+       /*
+        * Wait for completion: Poll or completion queue
+        */
+       if (test_bit(AF_IRQ_ATTACHED, &ha->flags) &&
+           test_bit(AF_INTERRUPTS_ON, &ha->flags) &&
+           test_bit(AF_ONLINE, &ha->flags) &&
+           !test_bit(AF_HBA_GOING_AWAY, &ha->flags)) {
+               /* Do not poll for completion. Use completion queue */
+               set_bit(AF_MBOX_COMMAND_NOPOLL, &ha->flags);
+               wait_for_completion_timeout(&ha->mbx_intr_comp, MBOX_TOV * HZ);
+               clear_bit(AF_MBOX_COMMAND_NOPOLL, &ha->flags);
+       } else {
+               /* Poll for command to complete */
+               wait_count = jiffies + MBOX_TOV * HZ;
+               while (test_bit(AF_MBOX_COMMAND_DONE, &ha->flags) == 0) {
+                       if (time_after_eq(jiffies, wait_count))
+                               break;
                        /*
                         * Service the interrupt.
                         * The ISR will save the mailbox status registers
                         * to a temporary storage location in the adapter
                         * structure.
                         */
-                       ha->mbox_status_count = outCount;
-                       qla4xxx_interrupt_service_routine(ha, intr_status);
+
+                       spin_lock_irqsave(&ha->hardware_lock, flags);
+                       if (is_qla8022(ha)) {
+                               intr_status =
+                                   readl(&ha->qla4_8xxx_reg->host_int);
+                               if (intr_status & ISRX_82XX_RISC_INT) {
+                                       ha->mbox_status_count = outCount;
+                                       intr_status =
+                                        readl(&ha->qla4_8xxx_reg->host_status);
+                                       ha->isp_ops->interrupt_service_routine(
+                                           ha, intr_status);
+                                       if (test_bit(AF_INTERRUPTS_ON,
+                                           &ha->flags) &&
+                                           test_bit(AF_INTx_ENABLED,
+                                           &ha->flags))
+                                               qla4_8xxx_wr_32(ha,
+                                               ha->nx_legacy_intr.tgt_mask_reg,
+                                               0xfbff);
+                               }
+                       } else {
+                               intr_status = readl(&ha->reg->ctrl_status);
+                               if (intr_status & INTR_PENDING) {
+                                       /*
+                                        * Service the interrupt.
+                                        * The ISR will save the mailbox status
+                                        * registers to a temporary storage
+                                        * location in the adapter structure.
+                                        */
+                                       ha->mbox_status_count = outCount;
+                                       ha->isp_ops->interrupt_service_routine(
+                                           ha, intr_status);
+                               }
+                       }
+                       spin_unlock_irqrestore(&ha->hardware_lock, flags);
+                       msleep(10);
                }
-               spin_unlock_irqrestore(&ha->hardware_lock, flags);
-               msleep(10);
        }
 
        /* Check for mailbox timeout. */
@@ -172,7 +246,7 @@ mbox_exit:
        return status;
 }
 
-uint8_t
+static uint8_t
 qla4xxx_set_ifcb(struct scsi_qla_host *ha, uint32_t *mbox_cmd,
                 uint32_t *mbox_sts, dma_addr_t init_fw_cb_dma)
 {
@@ -196,7 +270,7 @@ qla4xxx_set_ifcb(struct scsi_qla_host *ha, uint32_t *mbox_cmd,
        return QLA_SUCCESS;
 }
 
-uint8_t
+static uint8_t
 qla4xxx_get_ifcb(struct scsi_qla_host *ha, uint32_t *mbox_cmd,
                 uint32_t *mbox_sts, dma_addr_t init_fw_cb_dma)
 {
@@ -218,7 +292,7 @@ qla4xxx_get_ifcb(struct scsi_qla_host *ha, uint32_t *mbox_cmd,
        return QLA_SUCCESS;
 }
 
-void
+static void
 qla4xxx_update_local_ip(struct scsi_qla_host *ha,
                         struct addr_ctrl_blk  *init_fw_cb)
 {
@@ -256,7 +330,7 @@ qla4xxx_update_local_ip(struct scsi_qla_host *ha,
        }
 }
 
-uint8_t
+static uint8_t
 qla4xxx_update_local_ifcb(struct scsi_qla_host *ha,
                          uint32_t *mbox_cmd,
                          uint32_t *mbox_sts,
@@ -445,7 +519,7 @@ int qla4xxx_get_firmware_state(struct scsi_qla_host * ha)
        DEBUG2(printk("scsi%ld: %s firmware_state=0x%x\n",
                      ha->host_no, __func__, ha->firmware_state);)
 
-               return QLA_SUCCESS;
+       return QLA_SUCCESS;
 }
 
 /**
@@ -470,6 +544,10 @@ int qla4xxx_get_firmware_status(struct scsi_qla_host * ha)
                              mbox_sts[0]));
                return QLA_ERROR;
        }
+
+       ql4_printk(KERN_INFO, ha, "%ld firmare IOCBs available (%d).\n",
+           ha->host_no, mbox_cmd[2]);
+
        return QLA_SUCCESS;
 }
 
@@ -500,7 +578,7 @@ int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha,
 
        /* Make sure the device index is valid */
        if (fw_ddb_index >= MAX_DDB_ENTRIES) {
-               DEBUG2(printk("scsi%ld: %s: index [%d] out of range.\n",
+               DEBUG2(printk("scsi%ld: %s: ddb [%d] out of range.\n",
                              ha->host_no, __func__, fw_ddb_index));
                goto exit_get_fwddb;
        }
@@ -521,7 +599,7 @@ int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha,
                goto exit_get_fwddb;
        }
        if (fw_ddb_index != mbox_sts[1]) {
-               DEBUG2(printk("scsi%ld: %s: index mismatch [%d] != [%d].\n",
+               DEBUG2(printk("scsi%ld: %s: ddb mismatch [%d] != [%d].\n",
                              ha->host_no, __func__, fw_ddb_index,
                              mbox_sts[1]));
                goto exit_get_fwddb;
@@ -590,6 +668,7 @@ int qla4xxx_set_ddb_entry(struct scsi_qla_host * ha, uint16_t fw_ddb_index,
 {
        uint32_t mbox_cmd[MBOX_REG_COUNT];
        uint32_t mbox_sts[MBOX_REG_COUNT];
+       int status;
 
        /* Do not wait for completion. The firmware will send us an
         * ASTS_DATABASE_CHANGED (0x8014) to notify us of the login status.
@@ -603,7 +682,12 @@ int qla4xxx_set_ddb_entry(struct scsi_qla_host * ha, uint16_t fw_ddb_index,
        mbox_cmd[3] = MSDW(fw_ddb_entry_dma);
        mbox_cmd[4] = sizeof(struct dev_db_entry);
 
-       return qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]);
+       status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0],
+           &mbox_sts[0]);
+       DEBUG2(printk("scsi%ld: %s: status=%d mbx0=0x%x mbx4=0x%x\n",
+           ha->host_no, __func__, status, mbox_sts[0], mbox_sts[4]);)
+
+       return status;
 }
 
 /**
@@ -817,8 +901,8 @@ int qla4xxx_abort_task(struct scsi_qla_host *ha, struct srb *srb)
 /**
  * qla4xxx_reset_lun - issues LUN Reset
  * @ha: Pointer to host adapter structure.
- * @db_entry: Pointer to device database entry
- * @un_entry: Pointer to lun entry structure
+ * @ddb_entry: Pointer to device database entry
+ * @lun: lun number
  *
  * This routine performs a LUN RESET on the specified target/lun.
  * The caller must ensure that the ddb_entry and lun_entry pointers
@@ -832,7 +916,7 @@ int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry,
        int status = QLA_SUCCESS;
 
        DEBUG2(printk("scsi%ld:%d:%d: lun reset issued\n", ha->host_no,
-                     ddb_entry->os_target_id, lun));
+                     ddb_entry->fw_ddb_index, lun));
 
        /*
         * Send lun reset command to ISP, so that the ISP will return all
@@ -872,7 +956,7 @@ int qla4xxx_reset_target(struct scsi_qla_host *ha,
        int status = QLA_SUCCESS;
 
        DEBUG2(printk("scsi%ld:%d: target reset issued\n", ha->host_no,
-                     ddb_entry->os_target_id));
+                     ddb_entry->fw_ddb_index));
 
        /*
         * Send target reset command to ISP, so that the ISP will return all