Commit 7190575f authored by Giridhar Malavali's avatar Giridhar Malavali Committed by James Bottomley
Browse files

[SCSI] qla2xxx: Abort pending commands for faster recovery during ISP reset.

parent cf2d7712
Loading
Loading
Loading
Loading
+6 −3
Original line number Diff line number Diff line
@@ -2402,13 +2402,13 @@ struct qla_hw_data {
	volatile struct {
		uint32_t	mbox_int		:1;
		uint32_t	mbox_busy		:1;

		uint32_t	disable_risc_code_load	:1;
		uint32_t	enable_64bit_addressing	:1;
		uint32_t	enable_lip_reset	:1;
		uint32_t	enable_target_reset	:1;
		uint32_t	enable_lip_full_login	:1;
		uint32_t	enable_led_scheme	:1;

		uint32_t	msi_enabled		:1;
		uint32_t	msix_enabled		:1;
		uint32_t	disable_serdes		:1;
@@ -2417,6 +2417,7 @@ struct qla_hw_data {
		uint32_t	pci_channel_io_perm_failure	:1;
		uint32_t	fce_enabled		:1;
		uint32_t	fac_supported		:1;

		uint32_t	chip_reset_done		:1;
		uint32_t	port0			:1;
		uint32_t	running_gold_fw		:1;
@@ -2424,9 +2425,11 @@ struct qla_hw_data {
		uint32_t	cpu_affinity_enabled	:1;
		uint32_t	disable_msix_handshake	:1;
		uint32_t	fcp_prio_enabled	:1;
		uint32_t	fw_hung	:1;
		uint32_t	isp82xx_fw_hung:1;

		uint32_t	quiesce_owner:1;
		uint32_t	thermal_supported:1;
		uint32_t	isp82xx_reset_hdlr_active:1;
		/* 26 bits */
	} flags;

+1 −0
Original line number Diff line number Diff line
@@ -565,6 +565,7 @@ extern int qla82xx_mbx_intr_enable(scsi_qla_host_t *);
extern int qla82xx_mbx_intr_disable(scsi_qla_host_t *);
extern void qla82xx_start_iocbs(srb_t *);
extern int qla82xx_fcoe_ctx_reset(scsi_qla_host_t *);
extern void qla82xx_chip_reset_cleanup(scsi_qla_host_t *);

/* BSG related functions */
extern int qla24xx_bsg_request(struct fc_bsg_job *);
+3 −8
Original line number Diff line number Diff line
@@ -1967,7 +1967,7 @@ qla2x00_fw_ready(scsi_qla_host_t *vha)
		} else {
			/* Mailbox cmd failed. Timeout on min_wait. */
			if (time_after_eq(jiffies, mtime) ||
			    (IS_QLA82XX(ha) && ha->flags.fw_hung))
				ha->flags.isp82xx_fw_hung)
				break;
		}

@@ -3980,13 +3980,8 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha)

	if (!ha->flags.eeh_busy) {
		/* Make sure for ISP 82XX IO DMA is complete */
		if (IS_QLA82XX(ha)) {
			if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0,
				WAIT_HOST) == QLA_SUCCESS) {
				DEBUG2(qla_printk(KERN_INFO, ha,
				"Done wait for pending commands\n"));
			}
		}
		if (IS_QLA82XX(ha))
			qla82xx_chip_reset_cleanup(vha);

		/* Requeue all commands in outstanding command list. */
		qla2x00_abort_all_cmds(vha, DID_RESET << 16);
+2 −2
Original line number Diff line number Diff line
@@ -83,7 +83,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
		return QLA_FUNCTION_TIMEOUT;
	}

	if (IS_QLA82XX(ha) && ha->flags.fw_hung) {
	if (ha->flags.isp82xx_fw_hung) {
		/* Setting Link-Down error */
		mcp->mb[0] = MBS_LINK_DOWN_ERROR;
		rval = QLA_FUNCTION_FAILED;
@@ -223,7 +223,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
		ha->flags.mbox_int = 0;
		clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);

		if (IS_QLA82XX(ha) && ha->flags.fw_hung) {
		if (ha->flags.isp82xx_fw_hung) {
			ha->flags.mbox_busy = 0;
			/* Setting Link-Down error */
			mcp->mb[0] = MBS_LINK_DOWN_ERROR;
+110 −45
Original line number Diff line number Diff line
@@ -3457,46 +3457,28 @@ qla82xx_need_reset_handler(scsi_qla_host_t *vha)
	}
}

static void
int
qla82xx_check_fw_alive(scsi_qla_host_t *vha)
{
	uint32_t fw_heartbeat_counter, halt_status;
	struct qla_hw_data *ha = vha->hw;
	uint32_t fw_heartbeat_counter;
	int status = 0;

	fw_heartbeat_counter = qla82xx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER);
	fw_heartbeat_counter = qla82xx_rd_32(vha->hw,
		QLA82XX_PEG_ALIVE_COUNTER);
	/* all 0xff, assume AER/EEH in progress, ignore */
	if (fw_heartbeat_counter == 0xffffffff)
		return;
		return status;
	if (vha->fw_heartbeat_counter == fw_heartbeat_counter) {
		vha->seconds_since_last_heartbeat++;
		/* FW not alive after 2 seconds */
		if (vha->seconds_since_last_heartbeat == 2) {
			vha->seconds_since_last_heartbeat = 0;
			halt_status = qla82xx_rd_32(ha,
				QLA82XX_PEG_HALT_STATUS1);
			if (halt_status & HALT_STATUS_UNRECOVERABLE) {
				set_bit(ISP_UNRECOVERABLE, &vha->dpc_flags);
			} else {
				qla_printk(KERN_INFO, ha,
					"scsi(%ld): %s - detect abort needed\n",
					vha->host_no, __func__);
				set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
			}
			qla2xxx_wake_dpc(vha);
			ha->flags.fw_hung = 1;
			if (ha->flags.mbox_busy) {
				ha->flags.mbox_int = 1;
				DEBUG2(qla_printk(KERN_ERR, ha,
					"Due to fw hung, doing premature "
					"completion of mbx command\n"));
				if (test_bit(MBX_INTR_WAIT,
					&ha->mbx_cmd_flags))
					complete(&ha->mbx_intr_comp);
			}
			status = 1;
		}
	} else
		vha->seconds_since_last_heartbeat = 0;
	vha->fw_heartbeat_counter = fw_heartbeat_counter;
	return status;
}

/*
@@ -3598,30 +3580,18 @@ exit:

void qla82xx_watchdog(scsi_qla_host_t *vha)
{
	uint32_t dev_state;
	uint32_t dev_state, halt_status;
	struct qla_hw_data *ha = vha->hw;

	dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);

	/* don't poll if reset is going on */
	if (!(test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) ||
		test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) ||
		test_bit(ISP_ABORT_RETRY, &vha->dpc_flags))) {
		if (dev_state == QLA82XX_DEV_NEED_RESET) {
	if (!ha->flags.isp82xx_reset_hdlr_active) {
		dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
		if (dev_state == QLA82XX_DEV_NEED_RESET &&
		    !test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags)) {
			qla_printk(KERN_WARNING, ha,
			    "%s(): Adapter reset needed!\n", __func__);
			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
			qla2xxx_wake_dpc(vha);
			ha->flags.fw_hung = 1;
			if (ha->flags.mbox_busy) {
				ha->flags.mbox_int = 1;
				DEBUG2(qla_printk(KERN_ERR, ha,
					"Need reset, doing premature "
					"completion of mbx command\n"));
				if (test_bit(MBX_INTR_WAIT,
					&ha->mbx_cmd_flags))
					complete(&ha->mbx_intr_comp);
			}
		} else if (dev_state == QLA82XX_DEV_NEED_QUIESCENT &&
			!test_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags)) {
			DEBUG(qla_printk(KERN_INFO, ha,
@@ -3631,6 +3601,31 @@ void qla82xx_watchdog(scsi_qla_host_t *vha)
			qla2xxx_wake_dpc(vha);
		} else {
			qla82xx_check_fw_alive(vha);
			if (qla82xx_check_fw_alive(vha)) {
				halt_status = qla82xx_rd_32(ha,
				    QLA82XX_PEG_HALT_STATUS1);
				if (halt_status & HALT_STATUS_UNRECOVERABLE) {
					set_bit(ISP_UNRECOVERABLE,
					    &vha->dpc_flags);
				} else {
					qla_printk(KERN_INFO, ha,
					    "scsi(%ld): %s - detect abort needed\n",
					    vha->host_no, __func__);
					set_bit(ISP_ABORT_NEEDED,
					    &vha->dpc_flags);
				}
				qla2xxx_wake_dpc(vha);
				ha->flags.isp82xx_fw_hung = 1;
				if (ha->flags.mbox_busy) {
					ha->flags.mbox_int = 1;
					DEBUG2(qla_printk(KERN_ERR, ha,
					    "Due to fw hung, doing premature "
					    "completion of mbx command\n"));
					if (test_bit(MBX_INTR_WAIT,
					    &ha->mbx_cmd_flags))
						complete(&ha->mbx_intr_comp);
				}
			}
		}
	}
}
@@ -3665,6 +3660,7 @@ qla82xx_abort_isp(scsi_qla_host_t *vha)
			"Exiting.\n", __func__, vha->host_no);
		return QLA_SUCCESS;
	}
	ha->flags.isp82xx_reset_hdlr_active = 1;

	qla82xx_idc_lock(ha);
	dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
@@ -3685,7 +3681,8 @@ qla82xx_abort_isp(scsi_qla_host_t *vha)
	qla82xx_idc_unlock(ha);

	if (rval == QLA_SUCCESS) {
		ha->flags.fw_hung = 0;
		ha->flags.isp82xx_fw_hung = 0;
		ha->flags.isp82xx_reset_hdlr_active = 0;
		qla82xx_restart_isp(vha);
	}

@@ -3793,3 +3790,71 @@ int qla2x00_wait_for_fcoe_ctx_reset(scsi_qla_host_t *vha)

	return status;
}

void
qla82xx_chip_reset_cleanup(scsi_qla_host_t *vha)
{
	int i;
	unsigned long flags;
	struct qla_hw_data *ha = vha->hw;

	/* Check if 82XX firmware is alive or not
	 * We may have arrived here from NEED_RESET
	 * detection only
	 */
	if (!ha->flags.isp82xx_fw_hung) {
		for (i = 0; i < 2; i++) {
			msleep(1000);
			if (qla82xx_check_fw_alive(vha)) {
				ha->flags.isp82xx_fw_hung = 1;
				if (ha->flags.mbox_busy) {
					ha->flags.mbox_int = 1;
					complete(&ha->mbx_intr_comp);
				}
				break;
			}
		}
	}

	/* Abort all commands gracefully if fw NOT hung */
	if (!ha->flags.isp82xx_fw_hung) {
		int cnt, que;
		srb_t *sp;
		struct req_que *req;

		spin_lock_irqsave(&ha->hardware_lock, flags);
		for (que = 0; que < ha->max_req_queues; que++) {
			req = ha->req_q_map[que];
			if (!req)
				continue;
			for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
				sp = req->outstanding_cmds[cnt];
				if (sp) {
					if (!sp->ctx ||
					    (sp->flags & SRB_FCP_CMND_DMA_VALID)) {
						spin_unlock_irqrestore(
						    &ha->hardware_lock, flags);
						if (ha->isp_ops->abort_command(sp)) {
							qla_printk(KERN_INFO, ha,
							    "scsi(%ld): mbx abort command failed in %s\n",
							    vha->host_no, __func__);
						} else {
							qla_printk(KERN_INFO, ha,
							    "scsi(%ld): mbx abort command success in %s\n",
							    vha->host_no, __func__);
						}
						spin_lock_irqsave(&ha->hardware_lock, flags);
					}
				}
			}
		}
		spin_unlock_irqrestore(&ha->hardware_lock, flags);

		/* Wait for pending cmds (physical and virtual) to complete */
		if (!qla2x00_eh_wait_for_pending_commands(vha, 0, 0,
		    WAIT_HOST) == QLA_SUCCESS) {
			DEBUG2(qla_printk(KERN_INFO, ha,
			    "Done wait for pending commands\n"));
		}
	}
}
Loading