forked from mirrors/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
					
				
					 4 changed files with 114 additions and 0 deletions
				
			
		| 
						 | 
				
			
			@ -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 a new issue