forked from Minki/linux
[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:
parent
2944369144
commit
95d31262b3
@ -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 {
|
||||
|
@ -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 */
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user