[SCSI] qla4xxx: Added support for adapter and firmware reset

Signed-off-by: Vikas Chaudhary <vikas.chaudhary@qlogic.com>
Reviewed-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
This commit is contained in:
Vikas Chaudhary 2011-08-12 02:51:29 -07:00 committed by James Bottomley
parent 2944369144
commit 95d31262b3
4 changed files with 114 additions and 0 deletions

View File

@ -172,6 +172,7 @@
#define RELOGIN_TOV 18
#define ISNS_DEREG_TOV 5
#define HBA_ONLINE_TOV 30
#define DISABLE_ACB_TOV 30
#define MAX_RESET_HA_RETRIES 2
@ -616,6 +617,7 @@ struct scsi_qla_host {
uint16_t phy_port_cnt;
uint16_t iscsi_pci_func_cnt;
uint8_t model_name[16];
struct completion disable_acb_comp;
};
struct ql4_task_data {

View File

@ -605,6 +605,9 @@ struct init_fw_ctrl_blk {
/* struct addr_ctrl_blk sec;*/
};
#define PRIMARI_ACB 0
#define SECONDARY_ACB 1
struct addr_ctrl_blk_def {
uint8_t reserved1[1]; /* 00 */
uint8_t control; /* 01 */

View File

@ -619,6 +619,8 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
else if ((mbox_sts[3] == ACB_STATE_ACQUIRING) &&
(mbox_sts[2] == ACB_STATE_VALID))
set_bit(DPC_RESET_HA, &ha->dpc_flags);
else if ((mbox_sts[3] == ACB_STATE_UNCONFIGURED))
complete(&ha->disable_acb_comp);
break;
case MBOX_ASTS_MAC_ADDRESS_CHANGED:

View File

@ -121,6 +121,7 @@ static int qla4xxx_slave_alloc(struct scsi_device *device);
static int qla4xxx_slave_configure(struct scsi_device *device);
static void qla4xxx_slave_destroy(struct scsi_device *sdev);
static mode_t ql4_attr_is_visible(int param_type, int param);
static int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type);
static struct qla4_8xxx_legacy_intr_set legacy_intr[] =
QLA82XX_LEGACY_INTR_CONFIG;
@ -148,6 +149,7 @@ static struct scsi_host_template qla4xxx_driver_template = {
.max_sectors = 0xFFFF,
.shost_attrs = qla4xxx_host_attrs,
.host_reset = qla4xxx_host_reset,
.vendor_id = SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_QLOGIC,
};
@ -3133,6 +3135,7 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
mutex_init(&ha->mbox_sem);
init_completion(&ha->mbx_intr_comp);
init_completion(&ha->disable_acb_comp);
spin_lock_init(&ha->hardware_lock);
@ -3761,6 +3764,110 @@ static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd)
return return_status;
}
static int qla4xxx_context_reset(struct scsi_qla_host *ha)
{
uint32_t mbox_cmd[MBOX_REG_COUNT];
uint32_t mbox_sts[MBOX_REG_COUNT];
struct addr_ctrl_blk_def *acb = NULL;
uint32_t acb_len = sizeof(struct addr_ctrl_blk_def);
int rval = QLA_SUCCESS;
dma_addr_t acb_dma;
acb = dma_alloc_coherent(&ha->pdev->dev,
sizeof(struct addr_ctrl_blk_def),
&acb_dma, GFP_KERNEL);
if (!acb) {
ql4_printk(KERN_ERR, ha, "%s: Unable to alloc acb\n",
__func__);
rval = -ENOMEM;
goto exit_port_reset;
}
memset(acb, 0, acb_len);
rval = qla4xxx_get_acb(ha, acb_dma, PRIMARI_ACB, acb_len);
if (rval != QLA_SUCCESS) {
rval = -EIO;
goto exit_free_acb;
}
rval = qla4xxx_disable_acb(ha);
if (rval != QLA_SUCCESS) {
rval = -EIO;
goto exit_free_acb;
}
wait_for_completion_timeout(&ha->disable_acb_comp,
DISABLE_ACB_TOV * HZ);
rval = qla4xxx_set_acb(ha, &mbox_cmd[0], &mbox_sts[0], acb_dma);
if (rval != QLA_SUCCESS) {
rval = -EIO;
goto exit_free_acb;
}
exit_free_acb:
dma_free_coherent(&ha->pdev->dev, sizeof(struct addr_ctrl_blk_def),
acb, acb_dma);
exit_port_reset:
DEBUG2(ql4_printk(KERN_INFO, ha, "%s %s\n", __func__,
rval == QLA_SUCCESS ? "SUCCEEDED" : "FAILED"));
return rval;
}
static int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type)
{
struct scsi_qla_host *ha = to_qla_host(shost);
int rval = QLA_SUCCESS;
if (ql4xdontresethba) {
DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Don't Reset HBA\n",
__func__));
rval = -EPERM;
goto exit_host_reset;
}
rval = qla4xxx_wait_for_hba_online(ha);
if (rval != QLA_SUCCESS) {
DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Unable to reset host "
"adapter\n", __func__));
rval = -EIO;
goto exit_host_reset;
}
if (test_bit(DPC_RESET_HA, &ha->dpc_flags))
goto recover_adapter;
switch (reset_type) {
case SCSI_ADAPTER_RESET:
set_bit(DPC_RESET_HA, &ha->dpc_flags);
break;
case SCSI_FIRMWARE_RESET:
if (!test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
if (is_qla8022(ha))
/* set firmware context reset */
set_bit(DPC_RESET_HA_FW_CONTEXT,
&ha->dpc_flags);
else {
rval = qla4xxx_context_reset(ha);
goto exit_host_reset;
}
}
break;
}
recover_adapter:
rval = qla4xxx_recover_adapter(ha);
if (rval != QLA_SUCCESS) {
DEBUG2(ql4_printk(KERN_INFO, ha, "%s: recover adapter fail\n",
__func__));
rval = -EIO;
}
exit_host_reset:
return rval;
}
/* PCI AER driver recovers from all correctable errors w/o
* driver intervention. For uncorrectable errors PCI AER
* driver calls the following device driver's callbacks