162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * QLogic Fibre Channel HBA Driver
462306a36Sopenharmony_ci * Copyright (c)  2003-2014 QLogic Corporation
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci#include "qla_def.h"
762306a36Sopenharmony_ci#include <linux/delay.h>
862306a36Sopenharmony_ci#include <linux/ktime.h>
962306a36Sopenharmony_ci#include <linux/pci.h>
1062306a36Sopenharmony_ci#include <linux/ratelimit.h>
1162306a36Sopenharmony_ci#include <linux/vmalloc.h>
1262306a36Sopenharmony_ci#include <scsi/scsi_tcq.h>
1362306a36Sopenharmony_ci#include <linux/utsname.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci/* QLAFX00 specific Mailbox implementation functions */
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci/*
1962306a36Sopenharmony_ci * qlafx00_mailbox_command
2062306a36Sopenharmony_ci *	Issue mailbox command and waits for completion.
2162306a36Sopenharmony_ci *
2262306a36Sopenharmony_ci * Input:
2362306a36Sopenharmony_ci *	ha = adapter block pointer.
2462306a36Sopenharmony_ci *	mcp = driver internal mbx struct pointer.
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci * Output:
2762306a36Sopenharmony_ci *	mb[MAX_MAILBOX_REGISTER_COUNT] = returned mailbox data.
2862306a36Sopenharmony_ci *
2962306a36Sopenharmony_ci * Returns:
3062306a36Sopenharmony_ci *	0 : QLA_SUCCESS = cmd performed success
3162306a36Sopenharmony_ci *	1 : QLA_FUNCTION_FAILED   (error encountered)
3262306a36Sopenharmony_ci *	6 : QLA_FUNCTION_TIMEOUT (timeout condition encountered)
3362306a36Sopenharmony_ci *
3462306a36Sopenharmony_ci * Context:
3562306a36Sopenharmony_ci *	Kernel context.
3662306a36Sopenharmony_ci */
3762306a36Sopenharmony_cistatic int
3862306a36Sopenharmony_ciqlafx00_mailbox_command(scsi_qla_host_t *vha, struct mbx_cmd_32 *mcp)
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci{
4162306a36Sopenharmony_ci	int		rval;
4262306a36Sopenharmony_ci	unsigned long    flags = 0;
4362306a36Sopenharmony_ci	device_reg_t *reg;
4462306a36Sopenharmony_ci	uint8_t		abort_active;
4562306a36Sopenharmony_ci	uint8_t		io_lock_on;
4662306a36Sopenharmony_ci	uint16_t	command = 0;
4762306a36Sopenharmony_ci	uint32_t	*iptr;
4862306a36Sopenharmony_ci	__le32 __iomem *optr;
4962306a36Sopenharmony_ci	uint32_t	cnt;
5062306a36Sopenharmony_ci	uint32_t	mboxes;
5162306a36Sopenharmony_ci	unsigned long	wait_time;
5262306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
5362306a36Sopenharmony_ci	scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	if (ha->pdev->error_state == pci_channel_io_perm_failure) {
5662306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x115c,
5762306a36Sopenharmony_ci		    "PCI channel failed permanently, exiting.\n");
5862306a36Sopenharmony_ci		return QLA_FUNCTION_TIMEOUT;
5962306a36Sopenharmony_ci	}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	if (vha->device_flags & DFLG_DEV_FAILED) {
6262306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x115f,
6362306a36Sopenharmony_ci		    "Device in failed state, exiting.\n");
6462306a36Sopenharmony_ci		return QLA_FUNCTION_TIMEOUT;
6562306a36Sopenharmony_ci	}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	reg = ha->iobase;
6862306a36Sopenharmony_ci	io_lock_on = base_vha->flags.init_done;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	rval = QLA_SUCCESS;
7162306a36Sopenharmony_ci	abort_active = test_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	if (ha->flags.pci_channel_io_perm_failure) {
7462306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x1175,
7562306a36Sopenharmony_ci		    "Perm failure on EEH timeout MBX, exiting.\n");
7662306a36Sopenharmony_ci		return QLA_FUNCTION_TIMEOUT;
7762306a36Sopenharmony_ci	}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	if (ha->flags.isp82xx_fw_hung) {
8062306a36Sopenharmony_ci		/* Setting Link-Down error */
8162306a36Sopenharmony_ci		mcp->mb[0] = MBS_LINK_DOWN_ERROR;
8262306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x1176,
8362306a36Sopenharmony_ci		    "FW hung = %d.\n", ha->flags.isp82xx_fw_hung);
8462306a36Sopenharmony_ci		rval = QLA_FUNCTION_FAILED;
8562306a36Sopenharmony_ci		goto premature_exit;
8662306a36Sopenharmony_ci	}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	/*
8962306a36Sopenharmony_ci	 * Wait for active mailbox commands to finish by waiting at most tov
9062306a36Sopenharmony_ci	 * seconds. This is to serialize actual issuing of mailbox cmds during
9162306a36Sopenharmony_ci	 * non ISP abort time.
9262306a36Sopenharmony_ci	 */
9362306a36Sopenharmony_ci	if (!wait_for_completion_timeout(&ha->mbx_cmd_comp, mcp->tov * HZ)) {
9462306a36Sopenharmony_ci		/* Timeout occurred. Return error. */
9562306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x1177,
9662306a36Sopenharmony_ci		    "Cmd access timeout, cmd=0x%x, Exiting.\n",
9762306a36Sopenharmony_ci		    mcp->mb[0]);
9862306a36Sopenharmony_ci		return QLA_FUNCTION_TIMEOUT;
9962306a36Sopenharmony_ci	}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	ha->flags.mbox_busy = 1;
10262306a36Sopenharmony_ci	/* Save mailbox command for debug */
10362306a36Sopenharmony_ci	ha->mcp32 = mcp;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	ql_dbg(ql_dbg_mbx, vha, 0x1178,
10662306a36Sopenharmony_ci	    "Prepare to issue mbox cmd=0x%x.\n", mcp->mb[0]);
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	/* Load mailbox registers. */
11162306a36Sopenharmony_ci	optr = &reg->ispfx00.mailbox0;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	iptr = mcp->mb;
11462306a36Sopenharmony_ci	command = mcp->mb[0];
11562306a36Sopenharmony_ci	mboxes = mcp->out_mb;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	for (cnt = 0; cnt < ha->mbx_count; cnt++) {
11862306a36Sopenharmony_ci		if (mboxes & BIT_0)
11962306a36Sopenharmony_ci			wrt_reg_dword(optr, *iptr);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci		mboxes >>= 1;
12262306a36Sopenharmony_ci		optr++;
12362306a36Sopenharmony_ci		iptr++;
12462306a36Sopenharmony_ci	}
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	/* Issue set host interrupt command to send cmd out. */
12762306a36Sopenharmony_ci	ha->flags.mbox_int = 0;
12862306a36Sopenharmony_ci	clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1172,
13162306a36Sopenharmony_ci	    (uint8_t *)mcp->mb, 16);
13262306a36Sopenharmony_ci	ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1173,
13362306a36Sopenharmony_ci	    ((uint8_t *)mcp->mb + 0x10), 16);
13462306a36Sopenharmony_ci	ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1174,
13562306a36Sopenharmony_ci	    ((uint8_t *)mcp->mb + 0x20), 8);
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	/* Unlock mbx registers and wait for interrupt */
13862306a36Sopenharmony_ci	ql_dbg(ql_dbg_mbx, vha, 0x1179,
13962306a36Sopenharmony_ci	    "Going to unlock irq & waiting for interrupts. "
14062306a36Sopenharmony_ci	    "jiffies=%lx.\n", jiffies);
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	/* Wait for mbx cmd completion until timeout */
14362306a36Sopenharmony_ci	if ((!abort_active && io_lock_on) || IS_NOPOLLING_TYPE(ha)) {
14462306a36Sopenharmony_ci		set_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags);
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci		QLAFX00_SET_HST_INTR(ha, ha->mbx_intr_code);
14762306a36Sopenharmony_ci		spin_unlock_irqrestore(&ha->hardware_lock, flags);
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci		WARN_ON_ONCE(wait_for_completion_timeout(&ha->mbx_intr_comp,
15062306a36Sopenharmony_ci							 mcp->tov * HZ) != 0);
15162306a36Sopenharmony_ci	} else {
15262306a36Sopenharmony_ci		ql_dbg(ql_dbg_mbx, vha, 0x112c,
15362306a36Sopenharmony_ci		    "Cmd=%x Polling Mode.\n", command);
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci		QLAFX00_SET_HST_INTR(ha, ha->mbx_intr_code);
15662306a36Sopenharmony_ci		spin_unlock_irqrestore(&ha->hardware_lock, flags);
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci		wait_time = jiffies + mcp->tov * HZ; /* wait at most tov secs */
15962306a36Sopenharmony_ci		while (!ha->flags.mbox_int) {
16062306a36Sopenharmony_ci			if (time_after(jiffies, wait_time))
16162306a36Sopenharmony_ci				break;
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci			/* Check for pending interrupts. */
16462306a36Sopenharmony_ci			qla2x00_poll(ha->rsp_q_map[0]);
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci			if (!ha->flags.mbox_int &&
16762306a36Sopenharmony_ci			    !(IS_QLA2200(ha) &&
16862306a36Sopenharmony_ci			    command == MBC_LOAD_RISC_RAM_EXTENDED))
16962306a36Sopenharmony_ci				usleep_range(10000, 11000);
17062306a36Sopenharmony_ci		} /* while */
17162306a36Sopenharmony_ci		ql_dbg(ql_dbg_mbx, vha, 0x112d,
17262306a36Sopenharmony_ci		    "Waited %d sec.\n",
17362306a36Sopenharmony_ci		    (uint)((jiffies - (wait_time - (mcp->tov * HZ)))/HZ));
17462306a36Sopenharmony_ci	}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	/* Check whether we timed out */
17762306a36Sopenharmony_ci	if (ha->flags.mbox_int) {
17862306a36Sopenharmony_ci		uint32_t *iptr2;
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci		ql_dbg(ql_dbg_mbx, vha, 0x112e,
18162306a36Sopenharmony_ci		    "Cmd=%x completed.\n", command);
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci		/* Got interrupt. Clear the flag. */
18462306a36Sopenharmony_ci		ha->flags.mbox_int = 0;
18562306a36Sopenharmony_ci		clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci		if (ha->mailbox_out32[0] != MBS_COMMAND_COMPLETE)
18862306a36Sopenharmony_ci			rval = QLA_FUNCTION_FAILED;
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci		/* Load return mailbox registers. */
19162306a36Sopenharmony_ci		iptr2 = mcp->mb;
19262306a36Sopenharmony_ci		iptr = (uint32_t *)&ha->mailbox_out32[0];
19362306a36Sopenharmony_ci		mboxes = mcp->in_mb;
19462306a36Sopenharmony_ci		for (cnt = 0; cnt < ha->mbx_count; cnt++) {
19562306a36Sopenharmony_ci			if (mboxes & BIT_0)
19662306a36Sopenharmony_ci				*iptr2 = *iptr;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci			mboxes >>= 1;
19962306a36Sopenharmony_ci			iptr2++;
20062306a36Sopenharmony_ci			iptr++;
20162306a36Sopenharmony_ci		}
20262306a36Sopenharmony_ci	} else {
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci		rval = QLA_FUNCTION_TIMEOUT;
20562306a36Sopenharmony_ci	}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	ha->flags.mbox_busy = 0;
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	/* Clean up */
21062306a36Sopenharmony_ci	ha->mcp32 = NULL;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	if ((abort_active || !io_lock_on) && !IS_NOPOLLING_TYPE(ha)) {
21362306a36Sopenharmony_ci		ql_dbg(ql_dbg_mbx, vha, 0x113a,
21462306a36Sopenharmony_ci		    "checking for additional resp interrupt.\n");
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci		/* polling mode for non isp_abort commands. */
21762306a36Sopenharmony_ci		qla2x00_poll(ha->rsp_q_map[0]);
21862306a36Sopenharmony_ci	}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	if (rval == QLA_FUNCTION_TIMEOUT &&
22162306a36Sopenharmony_ci	    mcp->mb[0] != MBC_GEN_SYSTEM_ERROR) {
22262306a36Sopenharmony_ci		if (!io_lock_on || (mcp->flags & IOCTL_CMD) ||
22362306a36Sopenharmony_ci		    ha->flags.eeh_busy) {
22462306a36Sopenharmony_ci			/* not in dpc. schedule it for dpc to take over. */
22562306a36Sopenharmony_ci			ql_dbg(ql_dbg_mbx, vha, 0x115d,
22662306a36Sopenharmony_ci			    "Timeout, schedule isp_abort_needed.\n");
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci			if (!test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) &&
22962306a36Sopenharmony_ci			    !test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) &&
23062306a36Sopenharmony_ci			    !test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci				ql_log(ql_log_info, base_vha, 0x115e,
23362306a36Sopenharmony_ci				    "Mailbox cmd timeout occurred, cmd=0x%x, "
23462306a36Sopenharmony_ci				    "mb[0]=0x%x, eeh_busy=0x%x. Scheduling ISP "
23562306a36Sopenharmony_ci				    "abort.\n", command, mcp->mb[0],
23662306a36Sopenharmony_ci				    ha->flags.eeh_busy);
23762306a36Sopenharmony_ci				set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
23862306a36Sopenharmony_ci				qla2xxx_wake_dpc(vha);
23962306a36Sopenharmony_ci			}
24062306a36Sopenharmony_ci		} else if (!abort_active) {
24162306a36Sopenharmony_ci			/* call abort directly since we are in the DPC thread */
24262306a36Sopenharmony_ci			ql_dbg(ql_dbg_mbx, vha, 0x1160,
24362306a36Sopenharmony_ci			    "Timeout, calling abort_isp.\n");
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci			if (!test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) &&
24662306a36Sopenharmony_ci			    !test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) &&
24762306a36Sopenharmony_ci			    !test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci				ql_log(ql_log_info, base_vha, 0x1161,
25062306a36Sopenharmony_ci				    "Mailbox cmd timeout occurred, cmd=0x%x, "
25162306a36Sopenharmony_ci				    "mb[0]=0x%x. Scheduling ISP abort ",
25262306a36Sopenharmony_ci				    command, mcp->mb[0]);
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci				set_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags);
25562306a36Sopenharmony_ci				clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
25662306a36Sopenharmony_ci				if (ha->isp_ops->abort_isp(vha)) {
25762306a36Sopenharmony_ci					/* Failed. retry later. */
25862306a36Sopenharmony_ci					set_bit(ISP_ABORT_NEEDED,
25962306a36Sopenharmony_ci					    &vha->dpc_flags);
26062306a36Sopenharmony_ci				}
26162306a36Sopenharmony_ci				clear_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags);
26262306a36Sopenharmony_ci				ql_dbg(ql_dbg_mbx, vha, 0x1162,
26362306a36Sopenharmony_ci				    "Finished abort_isp.\n");
26462306a36Sopenharmony_ci			}
26562306a36Sopenharmony_ci		}
26662306a36Sopenharmony_ci	}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_cipremature_exit:
26962306a36Sopenharmony_ci	/* Allow next mbx cmd to come in. */
27062306a36Sopenharmony_ci	complete(&ha->mbx_cmd_comp);
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	if (rval) {
27362306a36Sopenharmony_ci		ql_log(ql_log_warn, base_vha, 0x1163,
27462306a36Sopenharmony_ci		       "**** Failed=%x mbx[0]=%x, mb[1]=%x, mb[2]=%x, mb[3]=%x, cmd=%x ****.\n",
27562306a36Sopenharmony_ci		       rval, mcp->mb[0], mcp->mb[1], mcp->mb[2], mcp->mb[3],
27662306a36Sopenharmony_ci		       command);
27762306a36Sopenharmony_ci	} else {
27862306a36Sopenharmony_ci		ql_dbg(ql_dbg_mbx, base_vha, 0x1164, "Done %s.\n", __func__);
27962306a36Sopenharmony_ci	}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	return rval;
28262306a36Sopenharmony_ci}
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci/*
28562306a36Sopenharmony_ci * qlafx00_driver_shutdown
28662306a36Sopenharmony_ci *	Indicate a driver shutdown to firmware.
28762306a36Sopenharmony_ci *
28862306a36Sopenharmony_ci * Input:
28962306a36Sopenharmony_ci *	ha = adapter block pointer.
29062306a36Sopenharmony_ci *
29162306a36Sopenharmony_ci * Returns:
29262306a36Sopenharmony_ci *	local function return status code.
29362306a36Sopenharmony_ci *
29462306a36Sopenharmony_ci * Context:
29562306a36Sopenharmony_ci *	Kernel context.
29662306a36Sopenharmony_ci */
29762306a36Sopenharmony_ciint
29862306a36Sopenharmony_ciqlafx00_driver_shutdown(scsi_qla_host_t *vha, int tmo)
29962306a36Sopenharmony_ci{
30062306a36Sopenharmony_ci	int rval;
30162306a36Sopenharmony_ci	struct mbx_cmd_32 mc;
30262306a36Sopenharmony_ci	struct mbx_cmd_32 *mcp = &mc;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1166,
30562306a36Sopenharmony_ci	    "Entered %s.\n", __func__);
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	mcp->mb[0] = MBC_MR_DRV_SHUTDOWN;
30862306a36Sopenharmony_ci	mcp->out_mb = MBX_0;
30962306a36Sopenharmony_ci	mcp->in_mb = MBX_0;
31062306a36Sopenharmony_ci	if (tmo)
31162306a36Sopenharmony_ci		mcp->tov = tmo;
31262306a36Sopenharmony_ci	else
31362306a36Sopenharmony_ci		mcp->tov = MBX_TOV_SECONDS;
31462306a36Sopenharmony_ci	mcp->flags = 0;
31562306a36Sopenharmony_ci	rval = qlafx00_mailbox_command(vha, mcp);
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	if (rval != QLA_SUCCESS) {
31862306a36Sopenharmony_ci		ql_dbg(ql_dbg_mbx, vha, 0x1167,
31962306a36Sopenharmony_ci		    "Failed=%x.\n", rval);
32062306a36Sopenharmony_ci	} else {
32162306a36Sopenharmony_ci		ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1168,
32262306a36Sopenharmony_ci		    "Done %s.\n", __func__);
32362306a36Sopenharmony_ci	}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	return rval;
32662306a36Sopenharmony_ci}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci/*
32962306a36Sopenharmony_ci * qlafx00_get_firmware_state
33062306a36Sopenharmony_ci *	Get adapter firmware state.
33162306a36Sopenharmony_ci *
33262306a36Sopenharmony_ci * Input:
33362306a36Sopenharmony_ci *	ha = adapter block pointer.
33462306a36Sopenharmony_ci *	TARGET_QUEUE_LOCK must be released.
33562306a36Sopenharmony_ci *	ADAPTER_STATE_LOCK must be released.
33662306a36Sopenharmony_ci *
33762306a36Sopenharmony_ci * Returns:
33862306a36Sopenharmony_ci *	qla7xxx local function return status code.
33962306a36Sopenharmony_ci *
34062306a36Sopenharmony_ci * Context:
34162306a36Sopenharmony_ci *	Kernel context.
34262306a36Sopenharmony_ci */
34362306a36Sopenharmony_cistatic int
34462306a36Sopenharmony_ciqlafx00_get_firmware_state(scsi_qla_host_t *vha, uint32_t *states)
34562306a36Sopenharmony_ci{
34662306a36Sopenharmony_ci	int rval;
34762306a36Sopenharmony_ci	struct mbx_cmd_32 mc;
34862306a36Sopenharmony_ci	struct mbx_cmd_32 *mcp = &mc;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1169,
35162306a36Sopenharmony_ci	    "Entered %s.\n", __func__);
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	mcp->mb[0] = MBC_GET_FIRMWARE_STATE;
35462306a36Sopenharmony_ci	mcp->out_mb = MBX_0;
35562306a36Sopenharmony_ci	mcp->in_mb = MBX_1|MBX_0;
35662306a36Sopenharmony_ci	mcp->tov = MBX_TOV_SECONDS;
35762306a36Sopenharmony_ci	mcp->flags = 0;
35862306a36Sopenharmony_ci	rval = qlafx00_mailbox_command(vha, mcp);
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	/* Return firmware states. */
36162306a36Sopenharmony_ci	states[0] = mcp->mb[1];
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	if (rval != QLA_SUCCESS) {
36462306a36Sopenharmony_ci		ql_dbg(ql_dbg_mbx, vha, 0x116a,
36562306a36Sopenharmony_ci		    "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
36662306a36Sopenharmony_ci	} else {
36762306a36Sopenharmony_ci		ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x116b,
36862306a36Sopenharmony_ci		    "Done %s.\n", __func__);
36962306a36Sopenharmony_ci	}
37062306a36Sopenharmony_ci	return rval;
37162306a36Sopenharmony_ci}
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci/*
37462306a36Sopenharmony_ci * qlafx00_init_firmware
37562306a36Sopenharmony_ci *	Initialize adapter firmware.
37662306a36Sopenharmony_ci *
37762306a36Sopenharmony_ci * Input:
37862306a36Sopenharmony_ci *	ha = adapter block pointer.
37962306a36Sopenharmony_ci *	dptr = Initialization control block pointer.
38062306a36Sopenharmony_ci *	size = size of initialization control block.
38162306a36Sopenharmony_ci *	TARGET_QUEUE_LOCK must be released.
38262306a36Sopenharmony_ci *	ADAPTER_STATE_LOCK must be released.
38362306a36Sopenharmony_ci *
38462306a36Sopenharmony_ci * Returns:
38562306a36Sopenharmony_ci *	qlafx00 local function return status code.
38662306a36Sopenharmony_ci *
38762306a36Sopenharmony_ci * Context:
38862306a36Sopenharmony_ci *	Kernel context.
38962306a36Sopenharmony_ci */
39062306a36Sopenharmony_ciint
39162306a36Sopenharmony_ciqlafx00_init_firmware(scsi_qla_host_t *vha, uint16_t size)
39262306a36Sopenharmony_ci{
39362306a36Sopenharmony_ci	int rval;
39462306a36Sopenharmony_ci	struct mbx_cmd_32 mc;
39562306a36Sopenharmony_ci	struct mbx_cmd_32 *mcp = &mc;
39662306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x116c,
39962306a36Sopenharmony_ci	    "Entered %s.\n", __func__);
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	mcp->mb[0] = MBC_INITIALIZE_FIRMWARE;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	mcp->mb[1] = 0;
40462306a36Sopenharmony_ci	mcp->mb[2] = MSD(ha->init_cb_dma);
40562306a36Sopenharmony_ci	mcp->mb[3] = LSD(ha->init_cb_dma);
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0;
40862306a36Sopenharmony_ci	mcp->in_mb = MBX_0;
40962306a36Sopenharmony_ci	mcp->buf_size = size;
41062306a36Sopenharmony_ci	mcp->flags = MBX_DMA_OUT;
41162306a36Sopenharmony_ci	mcp->tov = MBX_TOV_SECONDS;
41262306a36Sopenharmony_ci	rval = qlafx00_mailbox_command(vha, mcp);
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	if (rval != QLA_SUCCESS) {
41562306a36Sopenharmony_ci		ql_dbg(ql_dbg_mbx, vha, 0x116d,
41662306a36Sopenharmony_ci		    "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
41762306a36Sopenharmony_ci	} else {
41862306a36Sopenharmony_ci		ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x116e,
41962306a36Sopenharmony_ci		    "Done %s.\n", __func__);
42062306a36Sopenharmony_ci	}
42162306a36Sopenharmony_ci	return rval;
42262306a36Sopenharmony_ci}
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci/*
42562306a36Sopenharmony_ci * qlafx00_mbx_reg_test
42662306a36Sopenharmony_ci */
42762306a36Sopenharmony_cistatic int
42862306a36Sopenharmony_ciqlafx00_mbx_reg_test(scsi_qla_host_t *vha)
42962306a36Sopenharmony_ci{
43062306a36Sopenharmony_ci	int rval;
43162306a36Sopenharmony_ci	struct mbx_cmd_32 mc;
43262306a36Sopenharmony_ci	struct mbx_cmd_32 *mcp = &mc;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x116f,
43562306a36Sopenharmony_ci	    "Entered %s.\n", __func__);
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	mcp->mb[0] = MBC_MAILBOX_REGISTER_TEST;
43962306a36Sopenharmony_ci	mcp->mb[1] = 0xAAAA;
44062306a36Sopenharmony_ci	mcp->mb[2] = 0x5555;
44162306a36Sopenharmony_ci	mcp->mb[3] = 0xAA55;
44262306a36Sopenharmony_ci	mcp->mb[4] = 0x55AA;
44362306a36Sopenharmony_ci	mcp->mb[5] = 0xA5A5;
44462306a36Sopenharmony_ci	mcp->mb[6] = 0x5A5A;
44562306a36Sopenharmony_ci	mcp->mb[7] = 0x2525;
44662306a36Sopenharmony_ci	mcp->mb[8] = 0xBBBB;
44762306a36Sopenharmony_ci	mcp->mb[9] = 0x6666;
44862306a36Sopenharmony_ci	mcp->mb[10] = 0xBB66;
44962306a36Sopenharmony_ci	mcp->mb[11] = 0x66BB;
45062306a36Sopenharmony_ci	mcp->mb[12] = 0xB6B6;
45162306a36Sopenharmony_ci	mcp->mb[13] = 0x6B6B;
45262306a36Sopenharmony_ci	mcp->mb[14] = 0x3636;
45362306a36Sopenharmony_ci	mcp->mb[15] = 0xCCCC;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	mcp->out_mb = MBX_15|MBX_14|MBX_13|MBX_12|MBX_11|MBX_10|MBX_9|MBX_8|
45762306a36Sopenharmony_ci			MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
45862306a36Sopenharmony_ci	mcp->in_mb = MBX_15|MBX_14|MBX_13|MBX_12|MBX_11|MBX_10|MBX_9|MBX_8|
45962306a36Sopenharmony_ci			MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
46062306a36Sopenharmony_ci	mcp->buf_size = 0;
46162306a36Sopenharmony_ci	mcp->flags = MBX_DMA_OUT;
46262306a36Sopenharmony_ci	mcp->tov = MBX_TOV_SECONDS;
46362306a36Sopenharmony_ci	rval = qlafx00_mailbox_command(vha, mcp);
46462306a36Sopenharmony_ci	if (rval == QLA_SUCCESS) {
46562306a36Sopenharmony_ci		if (mcp->mb[17] != 0xAAAA || mcp->mb[18] != 0x5555 ||
46662306a36Sopenharmony_ci		    mcp->mb[19] != 0xAA55 || mcp->mb[20] != 0x55AA)
46762306a36Sopenharmony_ci			rval = QLA_FUNCTION_FAILED;
46862306a36Sopenharmony_ci		if (mcp->mb[21] != 0xA5A5 || mcp->mb[22] != 0x5A5A ||
46962306a36Sopenharmony_ci		    mcp->mb[23] != 0x2525 || mcp->mb[24] != 0xBBBB)
47062306a36Sopenharmony_ci			rval = QLA_FUNCTION_FAILED;
47162306a36Sopenharmony_ci		if (mcp->mb[25] != 0x6666 || mcp->mb[26] != 0xBB66 ||
47262306a36Sopenharmony_ci		    mcp->mb[27] != 0x66BB || mcp->mb[28] != 0xB6B6)
47362306a36Sopenharmony_ci			rval = QLA_FUNCTION_FAILED;
47462306a36Sopenharmony_ci		if (mcp->mb[29] != 0x6B6B || mcp->mb[30] != 0x3636 ||
47562306a36Sopenharmony_ci		    mcp->mb[31] != 0xCCCC)
47662306a36Sopenharmony_ci			rval = QLA_FUNCTION_FAILED;
47762306a36Sopenharmony_ci	}
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	if (rval != QLA_SUCCESS) {
48062306a36Sopenharmony_ci		ql_dbg(ql_dbg_mbx, vha, 0x1170,
48162306a36Sopenharmony_ci		    "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
48262306a36Sopenharmony_ci	} else {
48362306a36Sopenharmony_ci		ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1171,
48462306a36Sopenharmony_ci		    "Done %s.\n", __func__);
48562306a36Sopenharmony_ci	}
48662306a36Sopenharmony_ci	return rval;
48762306a36Sopenharmony_ci}
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci/**
49062306a36Sopenharmony_ci * qlafx00_pci_config() - Setup ISPFx00 PCI configuration registers.
49162306a36Sopenharmony_ci * @vha: HA context
49262306a36Sopenharmony_ci *
49362306a36Sopenharmony_ci * Returns 0 on success.
49462306a36Sopenharmony_ci */
49562306a36Sopenharmony_ciint
49662306a36Sopenharmony_ciqlafx00_pci_config(scsi_qla_host_t *vha)
49762306a36Sopenharmony_ci{
49862306a36Sopenharmony_ci	uint16_t w;
49962306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	pci_set_master(ha->pdev);
50262306a36Sopenharmony_ci	pci_try_set_mwi(ha->pdev);
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
50562306a36Sopenharmony_ci	w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
50662306a36Sopenharmony_ci	w &= ~PCI_COMMAND_INTX_DISABLE;
50762306a36Sopenharmony_ci	pci_write_config_word(ha->pdev, PCI_COMMAND, w);
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	/* PCIe -- adjust Maximum Read Request Size (2048). */
51062306a36Sopenharmony_ci	if (pci_is_pcie(ha->pdev))
51162306a36Sopenharmony_ci		pcie_set_readrq(ha->pdev, 2048);
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	ha->chip_revision = ha->pdev->revision;
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	return QLA_SUCCESS;
51662306a36Sopenharmony_ci}
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci/**
51962306a36Sopenharmony_ci * qlafx00_soc_cpu_reset() - Perform warm reset of iSA(CPUs being reset on SOC).
52062306a36Sopenharmony_ci * @vha: HA context
52162306a36Sopenharmony_ci *
52262306a36Sopenharmony_ci */
52362306a36Sopenharmony_cistatic inline void
52462306a36Sopenharmony_ciqlafx00_soc_cpu_reset(scsi_qla_host_t *vha)
52562306a36Sopenharmony_ci{
52662306a36Sopenharmony_ci	unsigned long flags = 0;
52762306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
52862306a36Sopenharmony_ci	int i, core;
52962306a36Sopenharmony_ci	uint32_t cnt;
53062306a36Sopenharmony_ci	uint32_t reg_val;
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	QLAFX00_SET_HBA_SOC_REG(ha, 0x80004, 0);
53562306a36Sopenharmony_ci	QLAFX00_SET_HBA_SOC_REG(ha, 0x82004, 0);
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	/* stop the XOR DMA engines */
53862306a36Sopenharmony_ci	QLAFX00_SET_HBA_SOC_REG(ha, 0x60920, 0x02);
53962306a36Sopenharmony_ci	QLAFX00_SET_HBA_SOC_REG(ha, 0x60924, 0x02);
54062306a36Sopenharmony_ci	QLAFX00_SET_HBA_SOC_REG(ha, 0xf0920, 0x02);
54162306a36Sopenharmony_ci	QLAFX00_SET_HBA_SOC_REG(ha, 0xf0924, 0x02);
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	/* stop the IDMA engines */
54462306a36Sopenharmony_ci	reg_val = QLAFX00_GET_HBA_SOC_REG(ha, 0x60840);
54562306a36Sopenharmony_ci	reg_val &= ~(1<<12);
54662306a36Sopenharmony_ci	QLAFX00_SET_HBA_SOC_REG(ha, 0x60840, reg_val);
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	reg_val = QLAFX00_GET_HBA_SOC_REG(ha, 0x60844);
54962306a36Sopenharmony_ci	reg_val &= ~(1<<12);
55062306a36Sopenharmony_ci	QLAFX00_SET_HBA_SOC_REG(ha, 0x60844, reg_val);
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	reg_val = QLAFX00_GET_HBA_SOC_REG(ha, 0x60848);
55362306a36Sopenharmony_ci	reg_val &= ~(1<<12);
55462306a36Sopenharmony_ci	QLAFX00_SET_HBA_SOC_REG(ha, 0x60848, reg_val);
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	reg_val = QLAFX00_GET_HBA_SOC_REG(ha, 0x6084C);
55762306a36Sopenharmony_ci	reg_val &= ~(1<<12);
55862306a36Sopenharmony_ci	QLAFX00_SET_HBA_SOC_REG(ha, 0x6084C, reg_val);
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	for (i = 0; i < 100000; i++) {
56162306a36Sopenharmony_ci		if ((QLAFX00_GET_HBA_SOC_REG(ha, 0xd0000) & 0x10000000) == 0 &&
56262306a36Sopenharmony_ci		    (QLAFX00_GET_HBA_SOC_REG(ha, 0x10600) & 0x1) == 0)
56362306a36Sopenharmony_ci			break;
56462306a36Sopenharmony_ci		udelay(100);
56562306a36Sopenharmony_ci	}
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	/* Set all 4 cores in reset */
56862306a36Sopenharmony_ci	for (i = 0; i < 4; i++) {
56962306a36Sopenharmony_ci		QLAFX00_SET_HBA_SOC_REG(ha,
57062306a36Sopenharmony_ci		    (SOC_SW_RST_CONTROL_REG_CORE0 + 8*i), (0xF01));
57162306a36Sopenharmony_ci		QLAFX00_SET_HBA_SOC_REG(ha,
57262306a36Sopenharmony_ci		    (SOC_SW_RST_CONTROL_REG_CORE0 + 4 + 8*i), (0x01010101));
57362306a36Sopenharmony_ci	}
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	/* Reset all units in Fabric */
57662306a36Sopenharmony_ci	QLAFX00_SET_HBA_SOC_REG(ha, SOC_FABRIC_RST_CONTROL_REG, (0x011f0101));
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	/* */
57962306a36Sopenharmony_ci	QLAFX00_SET_HBA_SOC_REG(ha, 0x10610, 1);
58062306a36Sopenharmony_ci	QLAFX00_SET_HBA_SOC_REG(ha, 0x10600, 0);
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	/* Set all 4 core Memory Power Down Registers */
58362306a36Sopenharmony_ci	for (i = 0; i < 5; i++) {
58462306a36Sopenharmony_ci		QLAFX00_SET_HBA_SOC_REG(ha,
58562306a36Sopenharmony_ci		    (SOC_PWR_MANAGEMENT_PWR_DOWN_REG + 4*i), (0x0));
58662306a36Sopenharmony_ci	}
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	/* Reset all interrupt control registers */
58962306a36Sopenharmony_ci	for (i = 0; i < 115; i++) {
59062306a36Sopenharmony_ci		QLAFX00_SET_HBA_SOC_REG(ha,
59162306a36Sopenharmony_ci		    (SOC_INTERRUPT_SOURCE_I_CONTROL_REG + 4*i), (0x0));
59262306a36Sopenharmony_ci	}
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	/* Reset Timers control registers. per core */
59562306a36Sopenharmony_ci	for (core = 0; core < 4; core++)
59662306a36Sopenharmony_ci		for (i = 0; i < 8; i++)
59762306a36Sopenharmony_ci			QLAFX00_SET_HBA_SOC_REG(ha,
59862306a36Sopenharmony_ci			    (SOC_CORE_TIMER_REG + 0x100*core + 4*i), (0x0));
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	/* Reset per core IRQ ack register */
60162306a36Sopenharmony_ci	for (core = 0; core < 4; core++)
60262306a36Sopenharmony_ci		QLAFX00_SET_HBA_SOC_REG(ha,
60362306a36Sopenharmony_ci		    (SOC_IRQ_ACK_REG + 0x100*core), (0x3FF));
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	/* Set Fabric control and config to defaults */
60662306a36Sopenharmony_ci	QLAFX00_SET_HBA_SOC_REG(ha, SOC_FABRIC_CONTROL_REG, (0x2));
60762306a36Sopenharmony_ci	QLAFX00_SET_HBA_SOC_REG(ha, SOC_FABRIC_CONFIG_REG, (0x3));
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	/* Kick in Fabric units */
61062306a36Sopenharmony_ci	QLAFX00_SET_HBA_SOC_REG(ha, SOC_FABRIC_RST_CONTROL_REG, (0x0));
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	/* Kick in Core0 to start boot process */
61362306a36Sopenharmony_ci	QLAFX00_SET_HBA_SOC_REG(ha, SOC_SW_RST_CONTROL_REG_CORE0, (0xF00));
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	/* Wait 10secs for soft-reset to complete. */
61862306a36Sopenharmony_ci	for (cnt = 10; cnt; cnt--) {
61962306a36Sopenharmony_ci		msleep(1000);
62062306a36Sopenharmony_ci		barrier();
62162306a36Sopenharmony_ci	}
62262306a36Sopenharmony_ci}
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci/**
62562306a36Sopenharmony_ci * qlafx00_soft_reset() - Soft Reset ISPFx00.
62662306a36Sopenharmony_ci * @vha: HA context
62762306a36Sopenharmony_ci *
62862306a36Sopenharmony_ci * Returns 0 on success.
62962306a36Sopenharmony_ci */
63062306a36Sopenharmony_ciint
63162306a36Sopenharmony_ciqlafx00_soft_reset(scsi_qla_host_t *vha)
63262306a36Sopenharmony_ci{
63362306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
63462306a36Sopenharmony_ci	int rval = QLA_FUNCTION_FAILED;
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci	if (unlikely(pci_channel_offline(ha->pdev) &&
63762306a36Sopenharmony_ci	    ha->flags.pci_channel_io_perm_failure))
63862306a36Sopenharmony_ci		return rval;
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	ha->isp_ops->disable_intrs(ha);
64162306a36Sopenharmony_ci	qlafx00_soc_cpu_reset(vha);
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	return QLA_SUCCESS;
64462306a36Sopenharmony_ci}
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci/**
64762306a36Sopenharmony_ci * qlafx00_chip_diag() - Test ISPFx00 for proper operation.
64862306a36Sopenharmony_ci * @vha: HA context
64962306a36Sopenharmony_ci *
65062306a36Sopenharmony_ci * Returns 0 on success.
65162306a36Sopenharmony_ci */
65262306a36Sopenharmony_ciint
65362306a36Sopenharmony_ciqlafx00_chip_diag(scsi_qla_host_t *vha)
65462306a36Sopenharmony_ci{
65562306a36Sopenharmony_ci	int rval = 0;
65662306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
65762306a36Sopenharmony_ci	struct req_que *req = ha->req_q_map[0];
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	ha->fw_transfer_size = REQUEST_ENTRY_SIZE * req->length;
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	rval = qlafx00_mbx_reg_test(vha);
66262306a36Sopenharmony_ci	if (rval) {
66362306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x1165,
66462306a36Sopenharmony_ci		    "Failed mailbox send register test\n");
66562306a36Sopenharmony_ci	} else {
66662306a36Sopenharmony_ci		/* Flag a successful rval */
66762306a36Sopenharmony_ci		rval = QLA_SUCCESS;
66862306a36Sopenharmony_ci	}
66962306a36Sopenharmony_ci	return rval;
67062306a36Sopenharmony_ci}
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_civoid
67362306a36Sopenharmony_ciqlafx00_config_rings(struct scsi_qla_host *vha)
67462306a36Sopenharmony_ci{
67562306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
67662306a36Sopenharmony_ci	struct device_reg_fx00 __iomem *reg = &ha->iobase->ispfx00;
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	wrt_reg_dword(&reg->req_q_in, 0);
67962306a36Sopenharmony_ci	wrt_reg_dword(&reg->req_q_out, 0);
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	wrt_reg_dword(&reg->rsp_q_in, 0);
68262306a36Sopenharmony_ci	wrt_reg_dword(&reg->rsp_q_out, 0);
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	/* PCI posting */
68562306a36Sopenharmony_ci	rd_reg_dword(&reg->rsp_q_out);
68662306a36Sopenharmony_ci}
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_cichar *
68962306a36Sopenharmony_ciqlafx00_pci_info_str(struct scsi_qla_host *vha, char *str, size_t str_len)
69062306a36Sopenharmony_ci{
69162306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci	if (pci_is_pcie(ha->pdev))
69462306a36Sopenharmony_ci		strscpy(str, "PCIe iSA", str_len);
69562306a36Sopenharmony_ci	return str;
69662306a36Sopenharmony_ci}
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_cichar *
69962306a36Sopenharmony_ciqlafx00_fw_version_str(struct scsi_qla_host *vha, char *str, size_t size)
70062306a36Sopenharmony_ci{
70162306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	snprintf(str, size, "%s", ha->mr.fw_version);
70462306a36Sopenharmony_ci	return str;
70562306a36Sopenharmony_ci}
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_civoid
70862306a36Sopenharmony_ciqlafx00_enable_intrs(struct qla_hw_data *ha)
70962306a36Sopenharmony_ci{
71062306a36Sopenharmony_ci	unsigned long flags = 0;
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
71362306a36Sopenharmony_ci	ha->interrupts_on = 1;
71462306a36Sopenharmony_ci	QLAFX00_ENABLE_ICNTRL_REG(ha);
71562306a36Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
71662306a36Sopenharmony_ci}
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_civoid
71962306a36Sopenharmony_ciqlafx00_disable_intrs(struct qla_hw_data *ha)
72062306a36Sopenharmony_ci{
72162306a36Sopenharmony_ci	unsigned long flags = 0;
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
72462306a36Sopenharmony_ci	ha->interrupts_on = 0;
72562306a36Sopenharmony_ci	QLAFX00_DISABLE_ICNTRL_REG(ha);
72662306a36Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
72762306a36Sopenharmony_ci}
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ciint
73062306a36Sopenharmony_ciqlafx00_abort_target(fc_port_t *fcport, uint64_t l, int tag)
73162306a36Sopenharmony_ci{
73262306a36Sopenharmony_ci	return qla2x00_async_tm_cmd(fcport, TCF_TARGET_RESET, l, tag);
73362306a36Sopenharmony_ci}
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ciint
73662306a36Sopenharmony_ciqlafx00_lun_reset(fc_port_t *fcport, uint64_t l, int tag)
73762306a36Sopenharmony_ci{
73862306a36Sopenharmony_ci	return qla2x00_async_tm_cmd(fcport, TCF_LUN_RESET, l, tag);
73962306a36Sopenharmony_ci}
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ciint
74262306a36Sopenharmony_ciqlafx00_iospace_config(struct qla_hw_data *ha)
74362306a36Sopenharmony_ci{
74462306a36Sopenharmony_ci	if (pci_request_selected_regions(ha->pdev, ha->bars,
74562306a36Sopenharmony_ci	    QLA2XXX_DRIVER_NAME)) {
74662306a36Sopenharmony_ci		ql_log_pci(ql_log_fatal, ha->pdev, 0x014e,
74762306a36Sopenharmony_ci		    "Failed to reserve PIO/MMIO regions (%s), aborting.\n",
74862306a36Sopenharmony_ci		    pci_name(ha->pdev));
74962306a36Sopenharmony_ci		goto iospace_error_exit;
75062306a36Sopenharmony_ci	}
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	/* Use MMIO operations for all accesses. */
75362306a36Sopenharmony_ci	if (!(pci_resource_flags(ha->pdev, 0) & IORESOURCE_MEM)) {
75462306a36Sopenharmony_ci		ql_log_pci(ql_log_warn, ha->pdev, 0x014f,
75562306a36Sopenharmony_ci		    "Invalid pci I/O region size (%s).\n",
75662306a36Sopenharmony_ci		    pci_name(ha->pdev));
75762306a36Sopenharmony_ci		goto iospace_error_exit;
75862306a36Sopenharmony_ci	}
75962306a36Sopenharmony_ci	if (pci_resource_len(ha->pdev, 0) < BAR0_LEN_FX00) {
76062306a36Sopenharmony_ci		ql_log_pci(ql_log_warn, ha->pdev, 0x0127,
76162306a36Sopenharmony_ci		    "Invalid PCI mem BAR0 region size (%s), aborting\n",
76262306a36Sopenharmony_ci			pci_name(ha->pdev));
76362306a36Sopenharmony_ci		goto iospace_error_exit;
76462306a36Sopenharmony_ci	}
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci	ha->cregbase =
76762306a36Sopenharmony_ci	    ioremap(pci_resource_start(ha->pdev, 0), BAR0_LEN_FX00);
76862306a36Sopenharmony_ci	if (!ha->cregbase) {
76962306a36Sopenharmony_ci		ql_log_pci(ql_log_fatal, ha->pdev, 0x0128,
77062306a36Sopenharmony_ci		    "cannot remap MMIO (%s), aborting\n", pci_name(ha->pdev));
77162306a36Sopenharmony_ci		goto iospace_error_exit;
77262306a36Sopenharmony_ci	}
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	if (!(pci_resource_flags(ha->pdev, 2) & IORESOURCE_MEM)) {
77562306a36Sopenharmony_ci		ql_log_pci(ql_log_warn, ha->pdev, 0x0129,
77662306a36Sopenharmony_ci		    "region #2 not an MMIO resource (%s), aborting\n",
77762306a36Sopenharmony_ci		    pci_name(ha->pdev));
77862306a36Sopenharmony_ci		goto iospace_error_exit;
77962306a36Sopenharmony_ci	}
78062306a36Sopenharmony_ci	if (pci_resource_len(ha->pdev, 2) < BAR2_LEN_FX00) {
78162306a36Sopenharmony_ci		ql_log_pci(ql_log_warn, ha->pdev, 0x012a,
78262306a36Sopenharmony_ci		    "Invalid PCI mem BAR2 region size (%s), aborting\n",
78362306a36Sopenharmony_ci			pci_name(ha->pdev));
78462306a36Sopenharmony_ci		goto iospace_error_exit;
78562306a36Sopenharmony_ci	}
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	ha->iobase =
78862306a36Sopenharmony_ci	    ioremap(pci_resource_start(ha->pdev, 2), BAR2_LEN_FX00);
78962306a36Sopenharmony_ci	if (!ha->iobase) {
79062306a36Sopenharmony_ci		ql_log_pci(ql_log_fatal, ha->pdev, 0x012b,
79162306a36Sopenharmony_ci		    "cannot remap MMIO (%s), aborting\n", pci_name(ha->pdev));
79262306a36Sopenharmony_ci		goto iospace_error_exit;
79362306a36Sopenharmony_ci	}
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	/* Determine queue resources */
79662306a36Sopenharmony_ci	ha->max_req_queues = ha->max_rsp_queues = 1;
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	ql_log_pci(ql_log_info, ha->pdev, 0x012c,
79962306a36Sopenharmony_ci	    "Bars 0x%x, iobase0 0x%p, iobase2 0x%p\n",
80062306a36Sopenharmony_ci	    ha->bars, ha->cregbase, ha->iobase);
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	return 0;
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ciiospace_error_exit:
80562306a36Sopenharmony_ci	return -ENOMEM;
80662306a36Sopenharmony_ci}
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_cistatic void
80962306a36Sopenharmony_ciqlafx00_save_queue_ptrs(struct scsi_qla_host *vha)
81062306a36Sopenharmony_ci{
81162306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
81262306a36Sopenharmony_ci	struct req_que *req = ha->req_q_map[0];
81362306a36Sopenharmony_ci	struct rsp_que *rsp = ha->rsp_q_map[0];
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci	req->length_fx00 = req->length;
81662306a36Sopenharmony_ci	req->ring_fx00 = req->ring;
81762306a36Sopenharmony_ci	req->dma_fx00 = req->dma;
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	rsp->length_fx00 = rsp->length;
82062306a36Sopenharmony_ci	rsp->ring_fx00 = rsp->ring;
82162306a36Sopenharmony_ci	rsp->dma_fx00 = rsp->dma;
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	ql_dbg(ql_dbg_init, vha, 0x012d,
82462306a36Sopenharmony_ci	    "req: %p, ring_fx00: %p, length_fx00: 0x%x,"
82562306a36Sopenharmony_ci	    "req->dma_fx00: 0x%llx\n", req, req->ring_fx00,
82662306a36Sopenharmony_ci	    req->length_fx00, (u64)req->dma_fx00);
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	ql_dbg(ql_dbg_init, vha, 0x012e,
82962306a36Sopenharmony_ci	    "rsp: %p, ring_fx00: %p, length_fx00: 0x%x,"
83062306a36Sopenharmony_ci	    "rsp->dma_fx00: 0x%llx\n", rsp, rsp->ring_fx00,
83162306a36Sopenharmony_ci	    rsp->length_fx00, (u64)rsp->dma_fx00);
83262306a36Sopenharmony_ci}
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_cistatic int
83562306a36Sopenharmony_ciqlafx00_config_queues(struct scsi_qla_host *vha)
83662306a36Sopenharmony_ci{
83762306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
83862306a36Sopenharmony_ci	struct req_que *req = ha->req_q_map[0];
83962306a36Sopenharmony_ci	struct rsp_que *rsp = ha->rsp_q_map[0];
84062306a36Sopenharmony_ci	dma_addr_t bar2_hdl = pci_resource_start(ha->pdev, 2);
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	req->length = ha->req_que_len;
84362306a36Sopenharmony_ci	req->ring = (void __force *)ha->iobase + ha->req_que_off;
84462306a36Sopenharmony_ci	req->dma = bar2_hdl + ha->req_que_off;
84562306a36Sopenharmony_ci	if ((!req->ring) || (req->length == 0)) {
84662306a36Sopenharmony_ci		ql_log_pci(ql_log_info, ha->pdev, 0x012f,
84762306a36Sopenharmony_ci		    "Unable to allocate memory for req_ring\n");
84862306a36Sopenharmony_ci		return QLA_FUNCTION_FAILED;
84962306a36Sopenharmony_ci	}
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	ql_dbg(ql_dbg_init, vha, 0x0130,
85262306a36Sopenharmony_ci	    "req: %p req_ring pointer %p req len 0x%x "
85362306a36Sopenharmony_ci	    "req off 0x%x\n, req->dma: 0x%llx",
85462306a36Sopenharmony_ci	    req, req->ring, req->length,
85562306a36Sopenharmony_ci	    ha->req_que_off, (u64)req->dma);
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	rsp->length = ha->rsp_que_len;
85862306a36Sopenharmony_ci	rsp->ring = (void __force *)ha->iobase + ha->rsp_que_off;
85962306a36Sopenharmony_ci	rsp->dma = bar2_hdl + ha->rsp_que_off;
86062306a36Sopenharmony_ci	if ((!rsp->ring) || (rsp->length == 0)) {
86162306a36Sopenharmony_ci		ql_log_pci(ql_log_info, ha->pdev, 0x0131,
86262306a36Sopenharmony_ci		    "Unable to allocate memory for rsp_ring\n");
86362306a36Sopenharmony_ci		return QLA_FUNCTION_FAILED;
86462306a36Sopenharmony_ci	}
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci	ql_dbg(ql_dbg_init, vha, 0x0132,
86762306a36Sopenharmony_ci	    "rsp: %p rsp_ring pointer %p rsp len 0x%x "
86862306a36Sopenharmony_ci	    "rsp off 0x%x, rsp->dma: 0x%llx\n",
86962306a36Sopenharmony_ci	    rsp, rsp->ring, rsp->length,
87062306a36Sopenharmony_ci	    ha->rsp_que_off, (u64)rsp->dma);
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	return QLA_SUCCESS;
87362306a36Sopenharmony_ci}
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_cistatic int
87662306a36Sopenharmony_ciqlafx00_init_fw_ready(scsi_qla_host_t *vha)
87762306a36Sopenharmony_ci{
87862306a36Sopenharmony_ci	int rval = 0;
87962306a36Sopenharmony_ci	unsigned long wtime;
88062306a36Sopenharmony_ci	uint16_t wait_time;	/* Wait time */
88162306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
88262306a36Sopenharmony_ci	struct device_reg_fx00 __iomem *reg = &ha->iobase->ispfx00;
88362306a36Sopenharmony_ci	uint32_t aenmbx, aenmbx7 = 0;
88462306a36Sopenharmony_ci	uint32_t pseudo_aen;
88562306a36Sopenharmony_ci	uint32_t state[5];
88662306a36Sopenharmony_ci	bool done = false;
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	/* 30 seconds wait - Adjust if required */
88962306a36Sopenharmony_ci	wait_time = 30;
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci	pseudo_aen = rd_reg_dword(&reg->pseudoaen);
89262306a36Sopenharmony_ci	if (pseudo_aen == 1) {
89362306a36Sopenharmony_ci		aenmbx7 = rd_reg_dword(&reg->initval7);
89462306a36Sopenharmony_ci		ha->mbx_intr_code = MSW(aenmbx7);
89562306a36Sopenharmony_ci		ha->rqstq_intr_code = LSW(aenmbx7);
89662306a36Sopenharmony_ci		rval = qlafx00_driver_shutdown(vha, 10);
89762306a36Sopenharmony_ci		if (rval != QLA_SUCCESS)
89862306a36Sopenharmony_ci			qlafx00_soft_reset(vha);
89962306a36Sopenharmony_ci	}
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	/* wait time before firmware ready */
90262306a36Sopenharmony_ci	wtime = jiffies + (wait_time * HZ);
90362306a36Sopenharmony_ci	do {
90462306a36Sopenharmony_ci		aenmbx = rd_reg_dword(&reg->aenmailbox0);
90562306a36Sopenharmony_ci		barrier();
90662306a36Sopenharmony_ci		ql_dbg(ql_dbg_mbx, vha, 0x0133,
90762306a36Sopenharmony_ci		    "aenmbx: 0x%x\n", aenmbx);
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci		switch (aenmbx) {
91062306a36Sopenharmony_ci		case MBA_FW_NOT_STARTED:
91162306a36Sopenharmony_ci		case MBA_FW_STARTING:
91262306a36Sopenharmony_ci			break;
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci		case MBA_SYSTEM_ERR:
91562306a36Sopenharmony_ci		case MBA_REQ_TRANSFER_ERR:
91662306a36Sopenharmony_ci		case MBA_RSP_TRANSFER_ERR:
91762306a36Sopenharmony_ci		case MBA_FW_INIT_FAILURE:
91862306a36Sopenharmony_ci			qlafx00_soft_reset(vha);
91962306a36Sopenharmony_ci			break;
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci		case MBA_FW_RESTART_CMPLT:
92262306a36Sopenharmony_ci			/* Set the mbx and rqstq intr code */
92362306a36Sopenharmony_ci			aenmbx7 = rd_reg_dword(&reg->aenmailbox7);
92462306a36Sopenharmony_ci			ha->mbx_intr_code = MSW(aenmbx7);
92562306a36Sopenharmony_ci			ha->rqstq_intr_code = LSW(aenmbx7);
92662306a36Sopenharmony_ci			ha->req_que_off = rd_reg_dword(&reg->aenmailbox1);
92762306a36Sopenharmony_ci			ha->rsp_que_off = rd_reg_dword(&reg->aenmailbox3);
92862306a36Sopenharmony_ci			ha->req_que_len = rd_reg_dword(&reg->aenmailbox5);
92962306a36Sopenharmony_ci			ha->rsp_que_len = rd_reg_dword(&reg->aenmailbox6);
93062306a36Sopenharmony_ci			wrt_reg_dword(&reg->aenmailbox0, 0);
93162306a36Sopenharmony_ci			rd_reg_dword_relaxed(&reg->aenmailbox0);
93262306a36Sopenharmony_ci			ql_dbg(ql_dbg_init, vha, 0x0134,
93362306a36Sopenharmony_ci			    "f/w returned mbx_intr_code: 0x%x, "
93462306a36Sopenharmony_ci			    "rqstq_intr_code: 0x%x\n",
93562306a36Sopenharmony_ci			    ha->mbx_intr_code, ha->rqstq_intr_code);
93662306a36Sopenharmony_ci			QLAFX00_CLR_INTR_REG(ha, QLAFX00_HST_INT_STS_BITS);
93762306a36Sopenharmony_ci			rval = QLA_SUCCESS;
93862306a36Sopenharmony_ci			done = true;
93962306a36Sopenharmony_ci			break;
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci		default:
94262306a36Sopenharmony_ci			if ((aenmbx & 0xFF00) == MBA_FW_INIT_INPROGRESS)
94362306a36Sopenharmony_ci				break;
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci			/* If fw is apparently not ready. In order to continue,
94662306a36Sopenharmony_ci			 * we might need to issue Mbox cmd, but the problem is
94762306a36Sopenharmony_ci			 * that the DoorBell vector values that come with the
94862306a36Sopenharmony_ci			 * 8060 AEN are most likely gone by now (and thus no
94962306a36Sopenharmony_ci			 * bell would be rung on the fw side when mbox cmd is
95062306a36Sopenharmony_ci			 * issued). We have to therefore grab the 8060 AEN
95162306a36Sopenharmony_ci			 * shadow regs (filled in by FW when the last 8060
95262306a36Sopenharmony_ci			 * AEN was being posted).
95362306a36Sopenharmony_ci			 * Do the following to determine what is needed in
95462306a36Sopenharmony_ci			 * order to get the FW ready:
95562306a36Sopenharmony_ci			 * 1. reload the 8060 AEN values from the shadow regs
95662306a36Sopenharmony_ci			 * 2. clear int status to get rid of possible pending
95762306a36Sopenharmony_ci			 *    interrupts
95862306a36Sopenharmony_ci			 * 3. issue Get FW State Mbox cmd to determine fw state
95962306a36Sopenharmony_ci			 * Set the mbx and rqstq intr code from Shadow Regs
96062306a36Sopenharmony_ci			 */
96162306a36Sopenharmony_ci			aenmbx7 = rd_reg_dword(&reg->initval7);
96262306a36Sopenharmony_ci			ha->mbx_intr_code = MSW(aenmbx7);
96362306a36Sopenharmony_ci			ha->rqstq_intr_code = LSW(aenmbx7);
96462306a36Sopenharmony_ci			ha->req_que_off = rd_reg_dword(&reg->initval1);
96562306a36Sopenharmony_ci			ha->rsp_que_off = rd_reg_dword(&reg->initval3);
96662306a36Sopenharmony_ci			ha->req_que_len = rd_reg_dword(&reg->initval5);
96762306a36Sopenharmony_ci			ha->rsp_que_len = rd_reg_dword(&reg->initval6);
96862306a36Sopenharmony_ci			ql_dbg(ql_dbg_init, vha, 0x0135,
96962306a36Sopenharmony_ci			    "f/w returned mbx_intr_code: 0x%x, "
97062306a36Sopenharmony_ci			    "rqstq_intr_code: 0x%x\n",
97162306a36Sopenharmony_ci			    ha->mbx_intr_code, ha->rqstq_intr_code);
97262306a36Sopenharmony_ci			QLAFX00_CLR_INTR_REG(ha, QLAFX00_HST_INT_STS_BITS);
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci			/* Get the FW state */
97562306a36Sopenharmony_ci			rval = qlafx00_get_firmware_state(vha, state);
97662306a36Sopenharmony_ci			if (rval != QLA_SUCCESS) {
97762306a36Sopenharmony_ci				/* Retry if timer has not expired */
97862306a36Sopenharmony_ci				break;
97962306a36Sopenharmony_ci			}
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci			if (state[0] == FSTATE_FX00_CONFIG_WAIT) {
98262306a36Sopenharmony_ci				/* Firmware is waiting to be
98362306a36Sopenharmony_ci				 * initialized by driver
98462306a36Sopenharmony_ci				 */
98562306a36Sopenharmony_ci				rval = QLA_SUCCESS;
98662306a36Sopenharmony_ci				done = true;
98762306a36Sopenharmony_ci				break;
98862306a36Sopenharmony_ci			}
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci			/* Issue driver shutdown and wait until f/w recovers.
99162306a36Sopenharmony_ci			 * Driver should continue to poll until 8060 AEN is
99262306a36Sopenharmony_ci			 * received indicating firmware recovery.
99362306a36Sopenharmony_ci			 */
99462306a36Sopenharmony_ci			ql_dbg(ql_dbg_init, vha, 0x0136,
99562306a36Sopenharmony_ci			    "Sending Driver shutdown fw_state 0x%x\n",
99662306a36Sopenharmony_ci			    state[0]);
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci			rval = qlafx00_driver_shutdown(vha, 10);
99962306a36Sopenharmony_ci			if (rval != QLA_SUCCESS) {
100062306a36Sopenharmony_ci				rval = QLA_FUNCTION_FAILED;
100162306a36Sopenharmony_ci				break;
100262306a36Sopenharmony_ci			}
100362306a36Sopenharmony_ci			msleep(500);
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci			wtime = jiffies + (wait_time * HZ);
100662306a36Sopenharmony_ci			break;
100762306a36Sopenharmony_ci		}
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci		if (!done) {
101062306a36Sopenharmony_ci			if (time_after_eq(jiffies, wtime)) {
101162306a36Sopenharmony_ci				ql_dbg(ql_dbg_init, vha, 0x0137,
101262306a36Sopenharmony_ci				    "Init f/w failed: aen[7]: 0x%x\n",
101362306a36Sopenharmony_ci				    rd_reg_dword(&reg->aenmailbox7));
101462306a36Sopenharmony_ci				rval = QLA_FUNCTION_FAILED;
101562306a36Sopenharmony_ci				done = true;
101662306a36Sopenharmony_ci				break;
101762306a36Sopenharmony_ci			}
101862306a36Sopenharmony_ci			/* Delay for a while */
101962306a36Sopenharmony_ci			msleep(500);
102062306a36Sopenharmony_ci		}
102162306a36Sopenharmony_ci	} while (!done);
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci	if (rval)
102462306a36Sopenharmony_ci		ql_dbg(ql_dbg_init, vha, 0x0138,
102562306a36Sopenharmony_ci		    "%s **** FAILED ****.\n", __func__);
102662306a36Sopenharmony_ci	else
102762306a36Sopenharmony_ci		ql_dbg(ql_dbg_init, vha, 0x0139,
102862306a36Sopenharmony_ci		    "%s **** SUCCESS ****.\n", __func__);
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci	return rval;
103162306a36Sopenharmony_ci}
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci/*
103462306a36Sopenharmony_ci * qlafx00_fw_ready() - Waits for firmware ready.
103562306a36Sopenharmony_ci * @ha: HA context
103662306a36Sopenharmony_ci *
103762306a36Sopenharmony_ci * Returns 0 on success.
103862306a36Sopenharmony_ci */
103962306a36Sopenharmony_ciint
104062306a36Sopenharmony_ciqlafx00_fw_ready(scsi_qla_host_t *vha)
104162306a36Sopenharmony_ci{
104262306a36Sopenharmony_ci	int		rval;
104362306a36Sopenharmony_ci	unsigned long	wtime;
104462306a36Sopenharmony_ci	uint16_t	wait_time;	/* Wait time if loop is coming ready */
104562306a36Sopenharmony_ci	uint32_t	state[5];
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_ci	rval = QLA_SUCCESS;
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ci	wait_time = 10;
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	/* wait time before firmware ready */
105262306a36Sopenharmony_ci	wtime = jiffies + (wait_time * HZ);
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci	/* Wait for ISP to finish init */
105562306a36Sopenharmony_ci	if (!vha->flags.init_done)
105662306a36Sopenharmony_ci		ql_dbg(ql_dbg_init, vha, 0x013a,
105762306a36Sopenharmony_ci		    "Waiting for init to complete...\n");
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	do {
106062306a36Sopenharmony_ci		rval = qlafx00_get_firmware_state(vha, state);
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci		if (rval == QLA_SUCCESS) {
106362306a36Sopenharmony_ci			if (state[0] == FSTATE_FX00_INITIALIZED) {
106462306a36Sopenharmony_ci				ql_dbg(ql_dbg_init, vha, 0x013b,
106562306a36Sopenharmony_ci				    "fw_state=%x\n", state[0]);
106662306a36Sopenharmony_ci				rval = QLA_SUCCESS;
106762306a36Sopenharmony_ci					break;
106862306a36Sopenharmony_ci			}
106962306a36Sopenharmony_ci		}
107062306a36Sopenharmony_ci		rval = QLA_FUNCTION_FAILED;
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci		if (time_after_eq(jiffies, wtime))
107362306a36Sopenharmony_ci			break;
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci		/* Delay for a while */
107662306a36Sopenharmony_ci		msleep(500);
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci		ql_dbg(ql_dbg_init, vha, 0x013c,
107962306a36Sopenharmony_ci		    "fw_state=%x curr time=%lx.\n", state[0], jiffies);
108062306a36Sopenharmony_ci	} while (1);
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	if (rval)
108462306a36Sopenharmony_ci		ql_dbg(ql_dbg_init, vha, 0x013d,
108562306a36Sopenharmony_ci		    "Firmware ready **** FAILED ****.\n");
108662306a36Sopenharmony_ci	else
108762306a36Sopenharmony_ci		ql_dbg(ql_dbg_init, vha, 0x013e,
108862306a36Sopenharmony_ci		    "Firmware ready **** SUCCESS ****.\n");
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci	return rval;
109162306a36Sopenharmony_ci}
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_cistatic int
109462306a36Sopenharmony_ciqlafx00_find_all_targets(scsi_qla_host_t *vha,
109562306a36Sopenharmony_ci	struct list_head *new_fcports)
109662306a36Sopenharmony_ci{
109762306a36Sopenharmony_ci	int		rval;
109862306a36Sopenharmony_ci	uint16_t	tgt_id;
109962306a36Sopenharmony_ci	fc_port_t	*fcport, *new_fcport;
110062306a36Sopenharmony_ci	int		found;
110162306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci	rval = QLA_SUCCESS;
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	if (!test_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags))
110662306a36Sopenharmony_ci		return QLA_FUNCTION_FAILED;
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ci	if ((atomic_read(&vha->loop_down_timer) ||
110962306a36Sopenharmony_ci	     STATE_TRANSITION(vha))) {
111062306a36Sopenharmony_ci		atomic_set(&vha->loop_down_timer, 0);
111162306a36Sopenharmony_ci		set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
111262306a36Sopenharmony_ci		return QLA_FUNCTION_FAILED;
111362306a36Sopenharmony_ci	}
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci	ql_dbg(ql_dbg_disc + ql_dbg_init, vha, 0x2088,
111662306a36Sopenharmony_ci	    "Listing Target bit map...\n");
111762306a36Sopenharmony_ci	ql_dump_buffer(ql_dbg_disc + ql_dbg_init, vha, 0x2089,
111862306a36Sopenharmony_ci	    ha->gid_list, 32);
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci	/* Allocate temporary rmtport for any new rmtports discovered. */
112162306a36Sopenharmony_ci	new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
112262306a36Sopenharmony_ci	if (new_fcport == NULL)
112362306a36Sopenharmony_ci		return QLA_MEMORY_ALLOC_FAILED;
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_ci	for_each_set_bit(tgt_id, (void *)ha->gid_list,
112662306a36Sopenharmony_ci	    QLAFX00_TGT_NODE_LIST_SIZE) {
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci		/* Send get target node info */
112962306a36Sopenharmony_ci		new_fcport->tgt_id = tgt_id;
113062306a36Sopenharmony_ci		rval = qlafx00_fx_disc(vha, new_fcport,
113162306a36Sopenharmony_ci		    FXDISC_GET_TGT_NODE_INFO);
113262306a36Sopenharmony_ci		if (rval != QLA_SUCCESS) {
113362306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x208a,
113462306a36Sopenharmony_ci			    "Target info scan failed -- assuming zero-entry "
113562306a36Sopenharmony_ci			    "result...\n");
113662306a36Sopenharmony_ci			continue;
113762306a36Sopenharmony_ci		}
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci		/* Locate matching device in database. */
114062306a36Sopenharmony_ci		found = 0;
114162306a36Sopenharmony_ci		list_for_each_entry(fcport, &vha->vp_fcports, list) {
114262306a36Sopenharmony_ci			if (memcmp(new_fcport->port_name,
114362306a36Sopenharmony_ci			    fcport->port_name, WWN_SIZE))
114462306a36Sopenharmony_ci				continue;
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci			found++;
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_ci			/*
114962306a36Sopenharmony_ci			 * If tgt_id is same and state FCS_ONLINE, nothing
115062306a36Sopenharmony_ci			 * changed.
115162306a36Sopenharmony_ci			 */
115262306a36Sopenharmony_ci			if (fcport->tgt_id == new_fcport->tgt_id &&
115362306a36Sopenharmony_ci			    atomic_read(&fcport->state) == FCS_ONLINE)
115462306a36Sopenharmony_ci				break;
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci			/*
115762306a36Sopenharmony_ci			 * Tgt ID changed or device was marked to be updated.
115862306a36Sopenharmony_ci			 */
115962306a36Sopenharmony_ci			ql_dbg(ql_dbg_disc + ql_dbg_init, vha, 0x208b,
116062306a36Sopenharmony_ci			    "TGT-ID Change(%s): Present tgt id: "
116162306a36Sopenharmony_ci			    "0x%x state: 0x%x "
116262306a36Sopenharmony_ci			    "wwnn = %llx wwpn = %llx.\n",
116362306a36Sopenharmony_ci			    __func__, fcport->tgt_id,
116462306a36Sopenharmony_ci			    atomic_read(&fcport->state),
116562306a36Sopenharmony_ci			    (unsigned long long)wwn_to_u64(fcport->node_name),
116662306a36Sopenharmony_ci			    (unsigned long long)wwn_to_u64(fcport->port_name));
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci			ql_log(ql_log_info, vha, 0x208c,
116962306a36Sopenharmony_ci			    "TGT-ID Announce(%s): Discovered tgt "
117062306a36Sopenharmony_ci			    "id 0x%x wwnn = %llx "
117162306a36Sopenharmony_ci			    "wwpn = %llx.\n", __func__, new_fcport->tgt_id,
117262306a36Sopenharmony_ci			    (unsigned long long)
117362306a36Sopenharmony_ci			    wwn_to_u64(new_fcport->node_name),
117462306a36Sopenharmony_ci			    (unsigned long long)
117562306a36Sopenharmony_ci			    wwn_to_u64(new_fcport->port_name));
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci			if (atomic_read(&fcport->state) != FCS_ONLINE) {
117862306a36Sopenharmony_ci				fcport->old_tgt_id = fcport->tgt_id;
117962306a36Sopenharmony_ci				fcport->tgt_id = new_fcport->tgt_id;
118062306a36Sopenharmony_ci				ql_log(ql_log_info, vha, 0x208d,
118162306a36Sopenharmony_ci				   "TGT-ID: New fcport Added: %p\n", fcport);
118262306a36Sopenharmony_ci				qla2x00_update_fcport(vha, fcport);
118362306a36Sopenharmony_ci			} else {
118462306a36Sopenharmony_ci				ql_log(ql_log_info, vha, 0x208e,
118562306a36Sopenharmony_ci				    " Existing TGT-ID %x did not get "
118662306a36Sopenharmony_ci				    " offline event from firmware.\n",
118762306a36Sopenharmony_ci				    fcport->old_tgt_id);
118862306a36Sopenharmony_ci				qla2x00_mark_device_lost(vha, fcport, 0);
118962306a36Sopenharmony_ci				set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
119062306a36Sopenharmony_ci				qla2x00_free_fcport(new_fcport);
119162306a36Sopenharmony_ci				return rval;
119262306a36Sopenharmony_ci			}
119362306a36Sopenharmony_ci			break;
119462306a36Sopenharmony_ci		}
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ci		if (found)
119762306a36Sopenharmony_ci			continue;
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_ci		/* If device was not in our fcports list, then add it. */
120062306a36Sopenharmony_ci		list_add_tail(&new_fcport->list, new_fcports);
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci		/* Allocate a new replacement fcport. */
120362306a36Sopenharmony_ci		new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
120462306a36Sopenharmony_ci		if (new_fcport == NULL)
120562306a36Sopenharmony_ci			return QLA_MEMORY_ALLOC_FAILED;
120662306a36Sopenharmony_ci	}
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_ci	qla2x00_free_fcport(new_fcport);
120962306a36Sopenharmony_ci	return rval;
121062306a36Sopenharmony_ci}
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci/*
121362306a36Sopenharmony_ci * qlafx00_configure_all_targets
121462306a36Sopenharmony_ci *      Setup target devices with node ID's.
121562306a36Sopenharmony_ci *
121662306a36Sopenharmony_ci * Input:
121762306a36Sopenharmony_ci *      ha = adapter block pointer.
121862306a36Sopenharmony_ci *
121962306a36Sopenharmony_ci * Returns:
122062306a36Sopenharmony_ci *      0 = success.
122162306a36Sopenharmony_ci *      BIT_0 = error
122262306a36Sopenharmony_ci */
122362306a36Sopenharmony_cistatic int
122462306a36Sopenharmony_ciqlafx00_configure_all_targets(scsi_qla_host_t *vha)
122562306a36Sopenharmony_ci{
122662306a36Sopenharmony_ci	int rval;
122762306a36Sopenharmony_ci	fc_port_t *fcport, *rmptemp;
122862306a36Sopenharmony_ci	LIST_HEAD(new_fcports);
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_ci	rval = qlafx00_fx_disc(vha, &vha->hw->mr.fcport,
123162306a36Sopenharmony_ci	    FXDISC_GET_TGT_NODE_LIST);
123262306a36Sopenharmony_ci	if (rval != QLA_SUCCESS) {
123362306a36Sopenharmony_ci		set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
123462306a36Sopenharmony_ci		return rval;
123562306a36Sopenharmony_ci	}
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci	rval = qlafx00_find_all_targets(vha, &new_fcports);
123862306a36Sopenharmony_ci	if (rval != QLA_SUCCESS) {
123962306a36Sopenharmony_ci		set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
124062306a36Sopenharmony_ci		return rval;
124162306a36Sopenharmony_ci	}
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_ci	/*
124462306a36Sopenharmony_ci	 * Delete all previous devices marked lost.
124562306a36Sopenharmony_ci	 */
124662306a36Sopenharmony_ci	list_for_each_entry(fcport, &vha->vp_fcports, list) {
124762306a36Sopenharmony_ci		if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags))
124862306a36Sopenharmony_ci			break;
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci		if (atomic_read(&fcport->state) == FCS_DEVICE_LOST) {
125162306a36Sopenharmony_ci			if (fcport->port_type != FCT_INITIATOR)
125262306a36Sopenharmony_ci				qla2x00_mark_device_lost(vha, fcport, 0);
125362306a36Sopenharmony_ci		}
125462306a36Sopenharmony_ci	}
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci	/*
125762306a36Sopenharmony_ci	 * Add the new devices to our devices list.
125862306a36Sopenharmony_ci	 */
125962306a36Sopenharmony_ci	list_for_each_entry_safe(fcport, rmptemp, &new_fcports, list) {
126062306a36Sopenharmony_ci		if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags))
126162306a36Sopenharmony_ci			break;
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci		qla2x00_update_fcport(vha, fcport);
126462306a36Sopenharmony_ci		list_move_tail(&fcport->list, &vha->vp_fcports);
126562306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0x208f,
126662306a36Sopenharmony_ci		    "Attach new target id 0x%x wwnn = %llx "
126762306a36Sopenharmony_ci		    "wwpn = %llx.\n",
126862306a36Sopenharmony_ci		    fcport->tgt_id,
126962306a36Sopenharmony_ci		    (unsigned long long)wwn_to_u64(fcport->node_name),
127062306a36Sopenharmony_ci		    (unsigned long long)wwn_to_u64(fcport->port_name));
127162306a36Sopenharmony_ci	}
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_ci	/* Free all new device structures not processed. */
127462306a36Sopenharmony_ci	list_for_each_entry_safe(fcport, rmptemp, &new_fcports, list) {
127562306a36Sopenharmony_ci		list_del(&fcport->list);
127662306a36Sopenharmony_ci		qla2x00_free_fcport(fcport);
127762306a36Sopenharmony_ci	}
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_ci	return rval;
128062306a36Sopenharmony_ci}
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_ci/*
128362306a36Sopenharmony_ci * qlafx00_configure_devices
128462306a36Sopenharmony_ci *      Updates Fibre Channel Device Database with what is actually on loop.
128562306a36Sopenharmony_ci *
128662306a36Sopenharmony_ci * Input:
128762306a36Sopenharmony_ci *      ha                = adapter block pointer.
128862306a36Sopenharmony_ci *
128962306a36Sopenharmony_ci * Returns:
129062306a36Sopenharmony_ci *      0 = success.
129162306a36Sopenharmony_ci *      1 = error.
129262306a36Sopenharmony_ci *      2 = database was full and device was not configured.
129362306a36Sopenharmony_ci */
129462306a36Sopenharmony_ciint
129562306a36Sopenharmony_ciqlafx00_configure_devices(scsi_qla_host_t *vha)
129662306a36Sopenharmony_ci{
129762306a36Sopenharmony_ci	int  rval;
129862306a36Sopenharmony_ci	unsigned long flags;
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_ci	rval = QLA_SUCCESS;
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci	flags = vha->dpc_flags;
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ci	ql_dbg(ql_dbg_disc, vha, 0x2090,
130562306a36Sopenharmony_ci	    "Configure devices -- dpc flags =0x%lx\n", flags);
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ci	rval = qlafx00_configure_all_targets(vha);
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_ci	if (rval == QLA_SUCCESS) {
131062306a36Sopenharmony_ci		if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) {
131162306a36Sopenharmony_ci			rval = QLA_FUNCTION_FAILED;
131262306a36Sopenharmony_ci		} else {
131362306a36Sopenharmony_ci			atomic_set(&vha->loop_state, LOOP_READY);
131462306a36Sopenharmony_ci			ql_log(ql_log_info, vha, 0x2091,
131562306a36Sopenharmony_ci			    "Device Ready\n");
131662306a36Sopenharmony_ci		}
131762306a36Sopenharmony_ci	}
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci	if (rval) {
132062306a36Sopenharmony_ci		ql_dbg(ql_dbg_disc, vha, 0x2092,
132162306a36Sopenharmony_ci		    "%s *** FAILED ***.\n", __func__);
132262306a36Sopenharmony_ci	} else {
132362306a36Sopenharmony_ci		ql_dbg(ql_dbg_disc, vha, 0x2093,
132462306a36Sopenharmony_ci		    "%s: exiting normally.\n", __func__);
132562306a36Sopenharmony_ci	}
132662306a36Sopenharmony_ci	return rval;
132762306a36Sopenharmony_ci}
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_cistatic void
133062306a36Sopenharmony_ciqlafx00_abort_isp_cleanup(scsi_qla_host_t *vha, bool critemp)
133162306a36Sopenharmony_ci{
133262306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
133362306a36Sopenharmony_ci	fc_port_t *fcport;
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_ci	vha->flags.online = 0;
133662306a36Sopenharmony_ci	ha->mr.fw_hbt_en = 0;
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci	if (!critemp) {
133962306a36Sopenharmony_ci		ha->flags.chip_reset_done = 0;
134062306a36Sopenharmony_ci		clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
134162306a36Sopenharmony_ci		vha->qla_stats.total_isp_aborts++;
134262306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0x013f,
134362306a36Sopenharmony_ci		    "Performing ISP error recovery - ha = %p.\n", ha);
134462306a36Sopenharmony_ci		ha->isp_ops->reset_chip(vha);
134562306a36Sopenharmony_ci	}
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci	if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
134862306a36Sopenharmony_ci		atomic_set(&vha->loop_state, LOOP_DOWN);
134962306a36Sopenharmony_ci		atomic_set(&vha->loop_down_timer,
135062306a36Sopenharmony_ci		    QLAFX00_LOOP_DOWN_TIME);
135162306a36Sopenharmony_ci	} else {
135262306a36Sopenharmony_ci		if (!atomic_read(&vha->loop_down_timer))
135362306a36Sopenharmony_ci			atomic_set(&vha->loop_down_timer,
135462306a36Sopenharmony_ci			    QLAFX00_LOOP_DOWN_TIME);
135562306a36Sopenharmony_ci	}
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci	/* Clear all async request states across all VPs. */
135862306a36Sopenharmony_ci	list_for_each_entry(fcport, &vha->vp_fcports, list) {
135962306a36Sopenharmony_ci		fcport->flags = 0;
136062306a36Sopenharmony_ci		if (atomic_read(&fcport->state) == FCS_ONLINE)
136162306a36Sopenharmony_ci			qla2x00_set_fcport_state(fcport, FCS_DEVICE_LOST);
136262306a36Sopenharmony_ci	}
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci	if (!ha->flags.eeh_busy) {
136562306a36Sopenharmony_ci		if (critemp) {
136662306a36Sopenharmony_ci			qla2x00_abort_all_cmds(vha, DID_NO_CONNECT << 16);
136762306a36Sopenharmony_ci		} else {
136862306a36Sopenharmony_ci			/* Requeue all commands in outstanding command list. */
136962306a36Sopenharmony_ci			qla2x00_abort_all_cmds(vha, DID_RESET << 16);
137062306a36Sopenharmony_ci		}
137162306a36Sopenharmony_ci	}
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci	qla2x00_free_irqs(vha);
137462306a36Sopenharmony_ci	if (critemp)
137562306a36Sopenharmony_ci		set_bit(FX00_CRITEMP_RECOVERY, &vha->dpc_flags);
137662306a36Sopenharmony_ci	else
137762306a36Sopenharmony_ci		set_bit(FX00_RESET_RECOVERY, &vha->dpc_flags);
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci	/* Clear the Interrupts */
138062306a36Sopenharmony_ci	QLAFX00_CLR_INTR_REG(ha, QLAFX00_HST_INT_STS_BITS);
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_ci	ql_log(ql_log_info, vha, 0x0140,
138362306a36Sopenharmony_ci	    "%s Done done - ha=%p.\n", __func__, ha);
138462306a36Sopenharmony_ci}
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_ci/**
138762306a36Sopenharmony_ci * qlafx00_init_response_q_entries() - Initializes response queue entries.
138862306a36Sopenharmony_ci * @rsp: response queue
138962306a36Sopenharmony_ci *
139062306a36Sopenharmony_ci * Beginning of request ring has initialization control block already built
139162306a36Sopenharmony_ci * by nvram config routine.
139262306a36Sopenharmony_ci *
139362306a36Sopenharmony_ci * Returns 0 on success.
139462306a36Sopenharmony_ci */
139562306a36Sopenharmony_civoid
139662306a36Sopenharmony_ciqlafx00_init_response_q_entries(struct rsp_que *rsp)
139762306a36Sopenharmony_ci{
139862306a36Sopenharmony_ci	uint16_t cnt;
139962306a36Sopenharmony_ci	response_t *pkt;
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_ci	rsp->ring_ptr = rsp->ring;
140262306a36Sopenharmony_ci	rsp->ring_index    = 0;
140362306a36Sopenharmony_ci	rsp->status_srb = NULL;
140462306a36Sopenharmony_ci	pkt = rsp->ring_ptr;
140562306a36Sopenharmony_ci	for (cnt = 0; cnt < rsp->length; cnt++) {
140662306a36Sopenharmony_ci		pkt->signature = RESPONSE_PROCESSED;
140762306a36Sopenharmony_ci		wrt_reg_dword((void __force __iomem *)&pkt->signature,
140862306a36Sopenharmony_ci		    RESPONSE_PROCESSED);
140962306a36Sopenharmony_ci		pkt++;
141062306a36Sopenharmony_ci	}
141162306a36Sopenharmony_ci}
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ciint
141462306a36Sopenharmony_ciqlafx00_rescan_isp(scsi_qla_host_t *vha)
141562306a36Sopenharmony_ci{
141662306a36Sopenharmony_ci	uint32_t status = QLA_FUNCTION_FAILED;
141762306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
141862306a36Sopenharmony_ci	struct device_reg_fx00 __iomem *reg = &ha->iobase->ispfx00;
141962306a36Sopenharmony_ci	uint32_t aenmbx7;
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_ci	qla2x00_request_irqs(ha, ha->rsp_q_map[0]);
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci	aenmbx7 = rd_reg_dword(&reg->aenmailbox7);
142462306a36Sopenharmony_ci	ha->mbx_intr_code = MSW(aenmbx7);
142562306a36Sopenharmony_ci	ha->rqstq_intr_code = LSW(aenmbx7);
142662306a36Sopenharmony_ci	ha->req_que_off = rd_reg_dword(&reg->aenmailbox1);
142762306a36Sopenharmony_ci	ha->rsp_que_off = rd_reg_dword(&reg->aenmailbox3);
142862306a36Sopenharmony_ci	ha->req_que_len = rd_reg_dword(&reg->aenmailbox5);
142962306a36Sopenharmony_ci	ha->rsp_que_len = rd_reg_dword(&reg->aenmailbox6);
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_ci	ql_dbg(ql_dbg_disc, vha, 0x2094,
143262306a36Sopenharmony_ci	    "fw returned mbx_intr_code: 0x%x, rqstq_intr_code: 0x%x "
143362306a36Sopenharmony_ci	    " Req que offset 0x%x Rsp que offset 0x%x\n",
143462306a36Sopenharmony_ci	    ha->mbx_intr_code, ha->rqstq_intr_code,
143562306a36Sopenharmony_ci	    ha->req_que_off, ha->rsp_que_len);
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_ci	/* Clear the Interrupts */
143862306a36Sopenharmony_ci	QLAFX00_CLR_INTR_REG(ha, QLAFX00_HST_INT_STS_BITS);
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci	status = qla2x00_init_rings(vha);
144162306a36Sopenharmony_ci	if (!status) {
144262306a36Sopenharmony_ci		vha->flags.online = 1;
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci		/* if no cable then assume it's good */
144562306a36Sopenharmony_ci		if ((vha->device_flags & DFLG_NO_CABLE))
144662306a36Sopenharmony_ci			status = 0;
144762306a36Sopenharmony_ci		/* Register system information */
144862306a36Sopenharmony_ci		if (qlafx00_fx_disc(vha,
144962306a36Sopenharmony_ci		    &vha->hw->mr.fcport, FXDISC_REG_HOST_INFO))
145062306a36Sopenharmony_ci			ql_dbg(ql_dbg_disc, vha, 0x2095,
145162306a36Sopenharmony_ci			    "failed to register host info\n");
145262306a36Sopenharmony_ci	}
145362306a36Sopenharmony_ci	scsi_unblock_requests(vha->host);
145462306a36Sopenharmony_ci	return status;
145562306a36Sopenharmony_ci}
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_civoid
145862306a36Sopenharmony_ciqlafx00_timer_routine(scsi_qla_host_t *vha)
145962306a36Sopenharmony_ci{
146062306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
146162306a36Sopenharmony_ci	uint32_t fw_heart_beat;
146262306a36Sopenharmony_ci	uint32_t aenmbx0;
146362306a36Sopenharmony_ci	struct device_reg_fx00 __iomem *reg = &ha->iobase->ispfx00;
146462306a36Sopenharmony_ci	uint32_t tempc;
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_ci	/* Check firmware health */
146762306a36Sopenharmony_ci	if (ha->mr.fw_hbt_cnt)
146862306a36Sopenharmony_ci		ha->mr.fw_hbt_cnt--;
146962306a36Sopenharmony_ci	else {
147062306a36Sopenharmony_ci		if ((!ha->flags.mr_reset_hdlr_active) &&
147162306a36Sopenharmony_ci		    (!test_bit(UNLOADING, &vha->dpc_flags)) &&
147262306a36Sopenharmony_ci		    (!test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) &&
147362306a36Sopenharmony_ci		    (ha->mr.fw_hbt_en)) {
147462306a36Sopenharmony_ci			fw_heart_beat = rd_reg_dword(&reg->fwheartbeat);
147562306a36Sopenharmony_ci			if (fw_heart_beat != ha->mr.old_fw_hbt_cnt) {
147662306a36Sopenharmony_ci				ha->mr.old_fw_hbt_cnt = fw_heart_beat;
147762306a36Sopenharmony_ci				ha->mr.fw_hbt_miss_cnt = 0;
147862306a36Sopenharmony_ci			} else {
147962306a36Sopenharmony_ci				ha->mr.fw_hbt_miss_cnt++;
148062306a36Sopenharmony_ci				if (ha->mr.fw_hbt_miss_cnt ==
148162306a36Sopenharmony_ci				    QLAFX00_HEARTBEAT_MISS_CNT) {
148262306a36Sopenharmony_ci					set_bit(ISP_ABORT_NEEDED,
148362306a36Sopenharmony_ci					    &vha->dpc_flags);
148462306a36Sopenharmony_ci					qla2xxx_wake_dpc(vha);
148562306a36Sopenharmony_ci					ha->mr.fw_hbt_miss_cnt = 0;
148662306a36Sopenharmony_ci				}
148762306a36Sopenharmony_ci			}
148862306a36Sopenharmony_ci		}
148962306a36Sopenharmony_ci		ha->mr.fw_hbt_cnt = QLAFX00_HEARTBEAT_INTERVAL;
149062306a36Sopenharmony_ci	}
149162306a36Sopenharmony_ci
149262306a36Sopenharmony_ci	if (test_bit(FX00_RESET_RECOVERY, &vha->dpc_flags)) {
149362306a36Sopenharmony_ci		/* Reset recovery to be performed in timer routine */
149462306a36Sopenharmony_ci		aenmbx0 = rd_reg_dword(&reg->aenmailbox0);
149562306a36Sopenharmony_ci		if (ha->mr.fw_reset_timer_exp) {
149662306a36Sopenharmony_ci			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
149762306a36Sopenharmony_ci			qla2xxx_wake_dpc(vha);
149862306a36Sopenharmony_ci			ha->mr.fw_reset_timer_exp = 0;
149962306a36Sopenharmony_ci		} else if (aenmbx0 == MBA_FW_RESTART_CMPLT) {
150062306a36Sopenharmony_ci			/* Wake up DPC to rescan the targets */
150162306a36Sopenharmony_ci			set_bit(FX00_TARGET_SCAN, &vha->dpc_flags);
150262306a36Sopenharmony_ci			clear_bit(FX00_RESET_RECOVERY, &vha->dpc_flags);
150362306a36Sopenharmony_ci			qla2xxx_wake_dpc(vha);
150462306a36Sopenharmony_ci			ha->mr.fw_reset_timer_tick = QLAFX00_RESET_INTERVAL;
150562306a36Sopenharmony_ci		} else if ((aenmbx0 == MBA_FW_STARTING) &&
150662306a36Sopenharmony_ci		    (!ha->mr.fw_hbt_en)) {
150762306a36Sopenharmony_ci			ha->mr.fw_hbt_en = 1;
150862306a36Sopenharmony_ci		} else if (!ha->mr.fw_reset_timer_tick) {
150962306a36Sopenharmony_ci			if (aenmbx0 == ha->mr.old_aenmbx0_state)
151062306a36Sopenharmony_ci				ha->mr.fw_reset_timer_exp = 1;
151162306a36Sopenharmony_ci			ha->mr.fw_reset_timer_tick = QLAFX00_RESET_INTERVAL;
151262306a36Sopenharmony_ci		} else if (aenmbx0 == 0xFFFFFFFF) {
151362306a36Sopenharmony_ci			uint32_t data0, data1;
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_ci			data0 = QLAFX00_RD_REG(ha,
151662306a36Sopenharmony_ci			    QLAFX00_BAR1_BASE_ADDR_REG);
151762306a36Sopenharmony_ci			data1 = QLAFX00_RD_REG(ha,
151862306a36Sopenharmony_ci			    QLAFX00_PEX0_WIN0_BASE_ADDR_REG);
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_ci			data0 &= 0xffff0000;
152162306a36Sopenharmony_ci			data1 &= 0x0000ffff;
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_ci			QLAFX00_WR_REG(ha,
152462306a36Sopenharmony_ci			    QLAFX00_PEX0_WIN0_BASE_ADDR_REG,
152562306a36Sopenharmony_ci			    (data0 | data1));
152662306a36Sopenharmony_ci		} else if ((aenmbx0 & 0xFF00) == MBA_FW_POLL_STATE) {
152762306a36Sopenharmony_ci			ha->mr.fw_reset_timer_tick =
152862306a36Sopenharmony_ci			    QLAFX00_MAX_RESET_INTERVAL;
152962306a36Sopenharmony_ci		} else if (aenmbx0 == MBA_FW_RESET_FCT) {
153062306a36Sopenharmony_ci			ha->mr.fw_reset_timer_tick =
153162306a36Sopenharmony_ci			    QLAFX00_MAX_RESET_INTERVAL;
153262306a36Sopenharmony_ci		}
153362306a36Sopenharmony_ci		if (ha->mr.old_aenmbx0_state != aenmbx0) {
153462306a36Sopenharmony_ci			ha->mr.old_aenmbx0_state = aenmbx0;
153562306a36Sopenharmony_ci			ha->mr.fw_reset_timer_tick = QLAFX00_RESET_INTERVAL;
153662306a36Sopenharmony_ci		}
153762306a36Sopenharmony_ci		ha->mr.fw_reset_timer_tick--;
153862306a36Sopenharmony_ci	}
153962306a36Sopenharmony_ci	if (test_bit(FX00_CRITEMP_RECOVERY, &vha->dpc_flags)) {
154062306a36Sopenharmony_ci		/*
154162306a36Sopenharmony_ci		 * Critical temperature recovery to be
154262306a36Sopenharmony_ci		 * performed in timer routine
154362306a36Sopenharmony_ci		 */
154462306a36Sopenharmony_ci		if (ha->mr.fw_critemp_timer_tick == 0) {
154562306a36Sopenharmony_ci			tempc = QLAFX00_GET_TEMPERATURE(ha);
154662306a36Sopenharmony_ci			ql_dbg(ql_dbg_timer, vha, 0x6012,
154762306a36Sopenharmony_ci			    "ISPFx00(%s): Critical temp timer, "
154862306a36Sopenharmony_ci			    "current SOC temperature: %d\n",
154962306a36Sopenharmony_ci			    __func__, tempc);
155062306a36Sopenharmony_ci			if (tempc < ha->mr.critical_temperature) {
155162306a36Sopenharmony_ci				set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
155262306a36Sopenharmony_ci				clear_bit(FX00_CRITEMP_RECOVERY,
155362306a36Sopenharmony_ci				    &vha->dpc_flags);
155462306a36Sopenharmony_ci				qla2xxx_wake_dpc(vha);
155562306a36Sopenharmony_ci			}
155662306a36Sopenharmony_ci			ha->mr.fw_critemp_timer_tick =
155762306a36Sopenharmony_ci			    QLAFX00_CRITEMP_INTERVAL;
155862306a36Sopenharmony_ci		} else {
155962306a36Sopenharmony_ci			ha->mr.fw_critemp_timer_tick--;
156062306a36Sopenharmony_ci		}
156162306a36Sopenharmony_ci	}
156262306a36Sopenharmony_ci	if (ha->mr.host_info_resend) {
156362306a36Sopenharmony_ci		/*
156462306a36Sopenharmony_ci		 * Incomplete host info might be sent to firmware
156562306a36Sopenharmony_ci		 * durinng system boot - info should be resend
156662306a36Sopenharmony_ci		 */
156762306a36Sopenharmony_ci		if (ha->mr.hinfo_resend_timer_tick == 0) {
156862306a36Sopenharmony_ci			ha->mr.host_info_resend = false;
156962306a36Sopenharmony_ci			set_bit(FX00_HOST_INFO_RESEND, &vha->dpc_flags);
157062306a36Sopenharmony_ci			ha->mr.hinfo_resend_timer_tick =
157162306a36Sopenharmony_ci			    QLAFX00_HINFO_RESEND_INTERVAL;
157262306a36Sopenharmony_ci			qla2xxx_wake_dpc(vha);
157362306a36Sopenharmony_ci		} else {
157462306a36Sopenharmony_ci			ha->mr.hinfo_resend_timer_tick--;
157562306a36Sopenharmony_ci		}
157662306a36Sopenharmony_ci	}
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_ci}
157962306a36Sopenharmony_ci
158062306a36Sopenharmony_ci/*
158162306a36Sopenharmony_ci *  qlfx00a_reset_initialize
158262306a36Sopenharmony_ci *      Re-initialize after a iSA device reset.
158362306a36Sopenharmony_ci *
158462306a36Sopenharmony_ci * Input:
158562306a36Sopenharmony_ci *      ha  = adapter block pointer.
158662306a36Sopenharmony_ci *
158762306a36Sopenharmony_ci * Returns:
158862306a36Sopenharmony_ci *      0 = success
158962306a36Sopenharmony_ci */
159062306a36Sopenharmony_ciint
159162306a36Sopenharmony_ciqlafx00_reset_initialize(scsi_qla_host_t *vha)
159262306a36Sopenharmony_ci{
159362306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
159462306a36Sopenharmony_ci
159562306a36Sopenharmony_ci	if (vha->device_flags & DFLG_DEV_FAILED) {
159662306a36Sopenharmony_ci		ql_dbg(ql_dbg_init, vha, 0x0142,
159762306a36Sopenharmony_ci		    "Device in failed state\n");
159862306a36Sopenharmony_ci		return QLA_SUCCESS;
159962306a36Sopenharmony_ci	}
160062306a36Sopenharmony_ci
160162306a36Sopenharmony_ci	ha->flags.mr_reset_hdlr_active = 1;
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_ci	if (vha->flags.online) {
160462306a36Sopenharmony_ci		scsi_block_requests(vha->host);
160562306a36Sopenharmony_ci		qlafx00_abort_isp_cleanup(vha, false);
160662306a36Sopenharmony_ci	}
160762306a36Sopenharmony_ci
160862306a36Sopenharmony_ci	ql_log(ql_log_info, vha, 0x0143,
160962306a36Sopenharmony_ci	    "(%s): succeeded.\n", __func__);
161062306a36Sopenharmony_ci	ha->flags.mr_reset_hdlr_active = 0;
161162306a36Sopenharmony_ci	return QLA_SUCCESS;
161262306a36Sopenharmony_ci}
161362306a36Sopenharmony_ci
161462306a36Sopenharmony_ci/*
161562306a36Sopenharmony_ci *  qlafx00_abort_isp
161662306a36Sopenharmony_ci *      Resets ISP and aborts all outstanding commands.
161762306a36Sopenharmony_ci *
161862306a36Sopenharmony_ci * Input:
161962306a36Sopenharmony_ci *      ha  = adapter block pointer.
162062306a36Sopenharmony_ci *
162162306a36Sopenharmony_ci * Returns:
162262306a36Sopenharmony_ci *      0 = success
162362306a36Sopenharmony_ci */
162462306a36Sopenharmony_ciint
162562306a36Sopenharmony_ciqlafx00_abort_isp(scsi_qla_host_t *vha)
162662306a36Sopenharmony_ci{
162762306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
162862306a36Sopenharmony_ci
162962306a36Sopenharmony_ci	if (vha->flags.online) {
163062306a36Sopenharmony_ci		if (unlikely(pci_channel_offline(ha->pdev) &&
163162306a36Sopenharmony_ci		    ha->flags.pci_channel_io_perm_failure)) {
163262306a36Sopenharmony_ci			clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags);
163362306a36Sopenharmony_ci			return QLA_SUCCESS;
163462306a36Sopenharmony_ci		}
163562306a36Sopenharmony_ci
163662306a36Sopenharmony_ci		scsi_block_requests(vha->host);
163762306a36Sopenharmony_ci		qlafx00_abort_isp_cleanup(vha, false);
163862306a36Sopenharmony_ci	} else {
163962306a36Sopenharmony_ci		scsi_block_requests(vha->host);
164062306a36Sopenharmony_ci		clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
164162306a36Sopenharmony_ci		vha->qla_stats.total_isp_aborts++;
164262306a36Sopenharmony_ci		ha->isp_ops->reset_chip(vha);
164362306a36Sopenharmony_ci		set_bit(FX00_RESET_RECOVERY, &vha->dpc_flags);
164462306a36Sopenharmony_ci		/* Clear the Interrupts */
164562306a36Sopenharmony_ci		QLAFX00_CLR_INTR_REG(ha, QLAFX00_HST_INT_STS_BITS);
164662306a36Sopenharmony_ci	}
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_ci	ql_log(ql_log_info, vha, 0x0145,
164962306a36Sopenharmony_ci	    "(%s): succeeded.\n", __func__);
165062306a36Sopenharmony_ci
165162306a36Sopenharmony_ci	return QLA_SUCCESS;
165262306a36Sopenharmony_ci}
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_cistatic inline fc_port_t*
165562306a36Sopenharmony_ciqlafx00_get_fcport(struct scsi_qla_host *vha, int tgt_id)
165662306a36Sopenharmony_ci{
165762306a36Sopenharmony_ci	fc_port_t	*fcport;
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_ci	/* Check for matching device in remote port list. */
166062306a36Sopenharmony_ci	list_for_each_entry(fcport, &vha->vp_fcports, list) {
166162306a36Sopenharmony_ci		if (fcport->tgt_id == tgt_id) {
166262306a36Sopenharmony_ci			ql_dbg(ql_dbg_async, vha, 0x5072,
166362306a36Sopenharmony_ci			    "Matching fcport(%p) found with TGT-ID: 0x%x "
166462306a36Sopenharmony_ci			    "and Remote TGT_ID: 0x%x\n",
166562306a36Sopenharmony_ci			    fcport, fcport->tgt_id, tgt_id);
166662306a36Sopenharmony_ci			return fcport;
166762306a36Sopenharmony_ci		}
166862306a36Sopenharmony_ci	}
166962306a36Sopenharmony_ci	return NULL;
167062306a36Sopenharmony_ci}
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_cistatic void
167362306a36Sopenharmony_ciqlafx00_tgt_detach(struct scsi_qla_host *vha, int tgt_id)
167462306a36Sopenharmony_ci{
167562306a36Sopenharmony_ci	fc_port_t	*fcport;
167662306a36Sopenharmony_ci
167762306a36Sopenharmony_ci	ql_log(ql_log_info, vha, 0x5073,
167862306a36Sopenharmony_ci	    "Detach TGT-ID: 0x%x\n", tgt_id);
167962306a36Sopenharmony_ci
168062306a36Sopenharmony_ci	fcport = qlafx00_get_fcport(vha, tgt_id);
168162306a36Sopenharmony_ci	if (!fcport)
168262306a36Sopenharmony_ci		return;
168362306a36Sopenharmony_ci
168462306a36Sopenharmony_ci	qla2x00_mark_device_lost(vha, fcport, 0);
168562306a36Sopenharmony_ci
168662306a36Sopenharmony_ci	return;
168762306a36Sopenharmony_ci}
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_civoid
169062306a36Sopenharmony_ciqlafx00_process_aen(struct scsi_qla_host *vha, struct qla_work_evt *evt)
169162306a36Sopenharmony_ci{
169262306a36Sopenharmony_ci	uint32_t aen_code, aen_data;
169362306a36Sopenharmony_ci
169462306a36Sopenharmony_ci	aen_code = FCH_EVT_VENDOR_UNIQUE;
169562306a36Sopenharmony_ci	aen_data = evt->u.aenfx.evtcode;
169662306a36Sopenharmony_ci
169762306a36Sopenharmony_ci	switch (evt->u.aenfx.evtcode) {
169862306a36Sopenharmony_ci	case QLAFX00_MBA_PORT_UPDATE:		/* Port database update */
169962306a36Sopenharmony_ci		if (evt->u.aenfx.mbx[1] == 0) {
170062306a36Sopenharmony_ci			if (evt->u.aenfx.mbx[2] == 1) {
170162306a36Sopenharmony_ci				if (!vha->flags.fw_tgt_reported)
170262306a36Sopenharmony_ci					vha->flags.fw_tgt_reported = 1;
170362306a36Sopenharmony_ci				atomic_set(&vha->loop_down_timer, 0);
170462306a36Sopenharmony_ci				atomic_set(&vha->loop_state, LOOP_UP);
170562306a36Sopenharmony_ci				set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
170662306a36Sopenharmony_ci				qla2xxx_wake_dpc(vha);
170762306a36Sopenharmony_ci			} else if (evt->u.aenfx.mbx[2] == 2) {
170862306a36Sopenharmony_ci				qlafx00_tgt_detach(vha, evt->u.aenfx.mbx[3]);
170962306a36Sopenharmony_ci			}
171062306a36Sopenharmony_ci		} else if (evt->u.aenfx.mbx[1] == 0xffff) {
171162306a36Sopenharmony_ci			if (evt->u.aenfx.mbx[2] == 1) {
171262306a36Sopenharmony_ci				if (!vha->flags.fw_tgt_reported)
171362306a36Sopenharmony_ci					vha->flags.fw_tgt_reported = 1;
171462306a36Sopenharmony_ci				set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
171562306a36Sopenharmony_ci			} else if (evt->u.aenfx.mbx[2] == 2) {
171662306a36Sopenharmony_ci				vha->device_flags |= DFLG_NO_CABLE;
171762306a36Sopenharmony_ci				qla2x00_mark_all_devices_lost(vha);
171862306a36Sopenharmony_ci			}
171962306a36Sopenharmony_ci		}
172062306a36Sopenharmony_ci		break;
172162306a36Sopenharmony_ci	case QLAFX00_MBA_LINK_UP:
172262306a36Sopenharmony_ci		aen_code = FCH_EVT_LINKUP;
172362306a36Sopenharmony_ci		aen_data = 0;
172462306a36Sopenharmony_ci		break;
172562306a36Sopenharmony_ci	case QLAFX00_MBA_LINK_DOWN:
172662306a36Sopenharmony_ci		aen_code = FCH_EVT_LINKDOWN;
172762306a36Sopenharmony_ci		aen_data = 0;
172862306a36Sopenharmony_ci		break;
172962306a36Sopenharmony_ci	case QLAFX00_MBA_TEMP_CRIT:	/* Critical temperature event */
173062306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0x5082,
173162306a36Sopenharmony_ci		    "Process critical temperature event "
173262306a36Sopenharmony_ci		    "aenmb[0]: %x\n",
173362306a36Sopenharmony_ci		    evt->u.aenfx.evtcode);
173462306a36Sopenharmony_ci		scsi_block_requests(vha->host);
173562306a36Sopenharmony_ci		qlafx00_abort_isp_cleanup(vha, true);
173662306a36Sopenharmony_ci		scsi_unblock_requests(vha->host);
173762306a36Sopenharmony_ci		break;
173862306a36Sopenharmony_ci	}
173962306a36Sopenharmony_ci
174062306a36Sopenharmony_ci	fc_host_post_event(vha->host, fc_get_event_number(),
174162306a36Sopenharmony_ci	    aen_code, aen_data);
174262306a36Sopenharmony_ci}
174362306a36Sopenharmony_ci
174462306a36Sopenharmony_cistatic void
174562306a36Sopenharmony_ciqlafx00_update_host_attr(scsi_qla_host_t *vha, struct port_info_data *pinfo)
174662306a36Sopenharmony_ci{
174762306a36Sopenharmony_ci	u64 port_name = 0, node_name = 0;
174862306a36Sopenharmony_ci
174962306a36Sopenharmony_ci	port_name = (unsigned long long)wwn_to_u64(pinfo->port_name);
175062306a36Sopenharmony_ci	node_name = (unsigned long long)wwn_to_u64(pinfo->node_name);
175162306a36Sopenharmony_ci
175262306a36Sopenharmony_ci	fc_host_node_name(vha->host) = node_name;
175362306a36Sopenharmony_ci	fc_host_port_name(vha->host) = port_name;
175462306a36Sopenharmony_ci	if (!pinfo->port_type)
175562306a36Sopenharmony_ci		vha->hw->current_topology = ISP_CFG_F;
175662306a36Sopenharmony_ci	if (pinfo->link_status == QLAFX00_LINK_STATUS_UP)
175762306a36Sopenharmony_ci		atomic_set(&vha->loop_state, LOOP_READY);
175862306a36Sopenharmony_ci	else if (pinfo->link_status == QLAFX00_LINK_STATUS_DOWN)
175962306a36Sopenharmony_ci		atomic_set(&vha->loop_state, LOOP_DOWN);
176062306a36Sopenharmony_ci	vha->hw->link_data_rate = (uint16_t)pinfo->link_config;
176162306a36Sopenharmony_ci}
176262306a36Sopenharmony_ci
176362306a36Sopenharmony_cistatic void
176462306a36Sopenharmony_ciqla2x00_fxdisc_iocb_timeout(void *data)
176562306a36Sopenharmony_ci{
176662306a36Sopenharmony_ci	srb_t *sp = data;
176762306a36Sopenharmony_ci	struct srb_iocb *lio = &sp->u.iocb_cmd;
176862306a36Sopenharmony_ci
176962306a36Sopenharmony_ci	complete(&lio->u.fxiocb.fxiocb_comp);
177062306a36Sopenharmony_ci}
177162306a36Sopenharmony_ci
177262306a36Sopenharmony_cistatic void qla2x00_fxdisc_sp_done(srb_t *sp, int res)
177362306a36Sopenharmony_ci{
177462306a36Sopenharmony_ci	struct srb_iocb *lio = &sp->u.iocb_cmd;
177562306a36Sopenharmony_ci
177662306a36Sopenharmony_ci	complete(&lio->u.fxiocb.fxiocb_comp);
177762306a36Sopenharmony_ci}
177862306a36Sopenharmony_ci
177962306a36Sopenharmony_ciint
178062306a36Sopenharmony_ciqlafx00_fx_disc(scsi_qla_host_t *vha, fc_port_t *fcport, uint16_t fx_type)
178162306a36Sopenharmony_ci{
178262306a36Sopenharmony_ci	srb_t *sp;
178362306a36Sopenharmony_ci	struct srb_iocb *fdisc;
178462306a36Sopenharmony_ci	int rval = QLA_FUNCTION_FAILED;
178562306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
178662306a36Sopenharmony_ci	struct host_system_info *phost_info;
178762306a36Sopenharmony_ci	struct register_host_info *preg_hsi;
178862306a36Sopenharmony_ci	struct new_utsname *p_sysid = NULL;
178962306a36Sopenharmony_ci
179062306a36Sopenharmony_ci	/* ref: INIT */
179162306a36Sopenharmony_ci	sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
179262306a36Sopenharmony_ci	if (!sp)
179362306a36Sopenharmony_ci		goto done;
179462306a36Sopenharmony_ci
179562306a36Sopenharmony_ci	sp->type = SRB_FXIOCB_DCMD;
179662306a36Sopenharmony_ci	sp->name = "fxdisc";
179762306a36Sopenharmony_ci	qla2x00_init_async_sp(sp, FXDISC_TIMEOUT,
179862306a36Sopenharmony_ci			      qla2x00_fxdisc_sp_done);
179962306a36Sopenharmony_ci	sp->u.iocb_cmd.timeout = qla2x00_fxdisc_iocb_timeout;
180062306a36Sopenharmony_ci
180162306a36Sopenharmony_ci	fdisc = &sp->u.iocb_cmd;
180262306a36Sopenharmony_ci	switch (fx_type) {
180362306a36Sopenharmony_ci	case FXDISC_GET_CONFIG_INFO:
180462306a36Sopenharmony_ci	fdisc->u.fxiocb.flags =
180562306a36Sopenharmony_ci		    SRB_FXDISC_RESP_DMA_VALID;
180662306a36Sopenharmony_ci		fdisc->u.fxiocb.rsp_len = sizeof(struct config_info_data);
180762306a36Sopenharmony_ci		break;
180862306a36Sopenharmony_ci	case FXDISC_GET_PORT_INFO:
180962306a36Sopenharmony_ci		fdisc->u.fxiocb.flags =
181062306a36Sopenharmony_ci		    SRB_FXDISC_RESP_DMA_VALID | SRB_FXDISC_REQ_DWRD_VALID;
181162306a36Sopenharmony_ci		fdisc->u.fxiocb.rsp_len = QLAFX00_PORT_DATA_INFO;
181262306a36Sopenharmony_ci		fdisc->u.fxiocb.req_data = cpu_to_le32(fcport->port_id);
181362306a36Sopenharmony_ci		break;
181462306a36Sopenharmony_ci	case FXDISC_GET_TGT_NODE_INFO:
181562306a36Sopenharmony_ci		fdisc->u.fxiocb.flags =
181662306a36Sopenharmony_ci		    SRB_FXDISC_RESP_DMA_VALID | SRB_FXDISC_REQ_DWRD_VALID;
181762306a36Sopenharmony_ci		fdisc->u.fxiocb.rsp_len = QLAFX00_TGT_NODE_INFO;
181862306a36Sopenharmony_ci		fdisc->u.fxiocb.req_data = cpu_to_le32(fcport->tgt_id);
181962306a36Sopenharmony_ci		break;
182062306a36Sopenharmony_ci	case FXDISC_GET_TGT_NODE_LIST:
182162306a36Sopenharmony_ci		fdisc->u.fxiocb.flags =
182262306a36Sopenharmony_ci		    SRB_FXDISC_RESP_DMA_VALID | SRB_FXDISC_REQ_DWRD_VALID;
182362306a36Sopenharmony_ci		fdisc->u.fxiocb.rsp_len = QLAFX00_TGT_NODE_LIST_SIZE;
182462306a36Sopenharmony_ci		break;
182562306a36Sopenharmony_ci	case FXDISC_REG_HOST_INFO:
182662306a36Sopenharmony_ci		fdisc->u.fxiocb.flags = SRB_FXDISC_REQ_DMA_VALID;
182762306a36Sopenharmony_ci		fdisc->u.fxiocb.req_len = sizeof(struct register_host_info);
182862306a36Sopenharmony_ci		p_sysid = utsname();
182962306a36Sopenharmony_ci		if (!p_sysid) {
183062306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x303c,
183162306a36Sopenharmony_ci			    "Not able to get the system information\n");
183262306a36Sopenharmony_ci			goto done_free_sp;
183362306a36Sopenharmony_ci		}
183462306a36Sopenharmony_ci		break;
183562306a36Sopenharmony_ci	case FXDISC_ABORT_IOCTL:
183662306a36Sopenharmony_ci	default:
183762306a36Sopenharmony_ci		break;
183862306a36Sopenharmony_ci	}
183962306a36Sopenharmony_ci
184062306a36Sopenharmony_ci	if (fdisc->u.fxiocb.flags & SRB_FXDISC_REQ_DMA_VALID) {
184162306a36Sopenharmony_ci		fdisc->u.fxiocb.req_addr = dma_alloc_coherent(&ha->pdev->dev,
184262306a36Sopenharmony_ci		    fdisc->u.fxiocb.req_len,
184362306a36Sopenharmony_ci		    &fdisc->u.fxiocb.req_dma_handle, GFP_KERNEL);
184462306a36Sopenharmony_ci		if (!fdisc->u.fxiocb.req_addr)
184562306a36Sopenharmony_ci			goto done_free_sp;
184662306a36Sopenharmony_ci
184762306a36Sopenharmony_ci		if (fx_type == FXDISC_REG_HOST_INFO) {
184862306a36Sopenharmony_ci			preg_hsi = (struct register_host_info *)
184962306a36Sopenharmony_ci				fdisc->u.fxiocb.req_addr;
185062306a36Sopenharmony_ci			phost_info = &preg_hsi->hsi;
185162306a36Sopenharmony_ci			memset(preg_hsi, 0, sizeof(struct register_host_info));
185262306a36Sopenharmony_ci			phost_info->os_type = OS_TYPE_LINUX;
185362306a36Sopenharmony_ci			strscpy(phost_info->sysname, p_sysid->sysname,
185462306a36Sopenharmony_ci				sizeof(phost_info->sysname));
185562306a36Sopenharmony_ci			strscpy(phost_info->nodename, p_sysid->nodename,
185662306a36Sopenharmony_ci				sizeof(phost_info->nodename));
185762306a36Sopenharmony_ci			if (!strcmp(phost_info->nodename, "(none)"))
185862306a36Sopenharmony_ci				ha->mr.host_info_resend = true;
185962306a36Sopenharmony_ci			strscpy(phost_info->release, p_sysid->release,
186062306a36Sopenharmony_ci				sizeof(phost_info->release));
186162306a36Sopenharmony_ci			strscpy(phost_info->version, p_sysid->version,
186262306a36Sopenharmony_ci				sizeof(phost_info->version));
186362306a36Sopenharmony_ci			strscpy(phost_info->machine, p_sysid->machine,
186462306a36Sopenharmony_ci				sizeof(phost_info->machine));
186562306a36Sopenharmony_ci			strscpy(phost_info->domainname, p_sysid->domainname,
186662306a36Sopenharmony_ci				sizeof(phost_info->domainname));
186762306a36Sopenharmony_ci			strscpy(phost_info->hostdriver, QLA2XXX_VERSION,
186862306a36Sopenharmony_ci				sizeof(phost_info->hostdriver));
186962306a36Sopenharmony_ci			preg_hsi->utc = (uint64_t)ktime_get_real_seconds();
187062306a36Sopenharmony_ci			ql_dbg(ql_dbg_init, vha, 0x0149,
187162306a36Sopenharmony_ci			    "ISP%04X: Host registration with firmware\n",
187262306a36Sopenharmony_ci			    ha->pdev->device);
187362306a36Sopenharmony_ci			ql_dbg(ql_dbg_init, vha, 0x014a,
187462306a36Sopenharmony_ci			    "os_type = '%d', sysname = '%s', nodname = '%s'\n",
187562306a36Sopenharmony_ci			    phost_info->os_type,
187662306a36Sopenharmony_ci			    phost_info->sysname,
187762306a36Sopenharmony_ci			    phost_info->nodename);
187862306a36Sopenharmony_ci			ql_dbg(ql_dbg_init, vha, 0x014b,
187962306a36Sopenharmony_ci			    "release = '%s', version = '%s'\n",
188062306a36Sopenharmony_ci			    phost_info->release,
188162306a36Sopenharmony_ci			    phost_info->version);
188262306a36Sopenharmony_ci			ql_dbg(ql_dbg_init, vha, 0x014c,
188362306a36Sopenharmony_ci			    "machine = '%s' "
188462306a36Sopenharmony_ci			    "domainname = '%s', hostdriver = '%s'\n",
188562306a36Sopenharmony_ci			    phost_info->machine,
188662306a36Sopenharmony_ci			    phost_info->domainname,
188762306a36Sopenharmony_ci			    phost_info->hostdriver);
188862306a36Sopenharmony_ci			ql_dump_buffer(ql_dbg_init + ql_dbg_disc, vha, 0x014d,
188962306a36Sopenharmony_ci			    phost_info, sizeof(*phost_info));
189062306a36Sopenharmony_ci		}
189162306a36Sopenharmony_ci	}
189262306a36Sopenharmony_ci
189362306a36Sopenharmony_ci	if (fdisc->u.fxiocb.flags & SRB_FXDISC_RESP_DMA_VALID) {
189462306a36Sopenharmony_ci		fdisc->u.fxiocb.rsp_addr = dma_alloc_coherent(&ha->pdev->dev,
189562306a36Sopenharmony_ci		    fdisc->u.fxiocb.rsp_len,
189662306a36Sopenharmony_ci		    &fdisc->u.fxiocb.rsp_dma_handle, GFP_KERNEL);
189762306a36Sopenharmony_ci		if (!fdisc->u.fxiocb.rsp_addr)
189862306a36Sopenharmony_ci			goto done_unmap_req;
189962306a36Sopenharmony_ci	}
190062306a36Sopenharmony_ci
190162306a36Sopenharmony_ci	fdisc->u.fxiocb.req_func_type = cpu_to_le16(fx_type);
190262306a36Sopenharmony_ci
190362306a36Sopenharmony_ci	rval = qla2x00_start_sp(sp);
190462306a36Sopenharmony_ci	if (rval != QLA_SUCCESS)
190562306a36Sopenharmony_ci		goto done_unmap_dma;
190662306a36Sopenharmony_ci
190762306a36Sopenharmony_ci	wait_for_completion(&fdisc->u.fxiocb.fxiocb_comp);
190862306a36Sopenharmony_ci
190962306a36Sopenharmony_ci	if (fx_type == FXDISC_GET_CONFIG_INFO) {
191062306a36Sopenharmony_ci		struct config_info_data *pinfo =
191162306a36Sopenharmony_ci		    (struct config_info_data *) fdisc->u.fxiocb.rsp_addr;
191262306a36Sopenharmony_ci		strscpy(vha->hw->model_number, pinfo->model_num,
191362306a36Sopenharmony_ci			ARRAY_SIZE(vha->hw->model_number));
191462306a36Sopenharmony_ci		strscpy(vha->hw->model_desc, pinfo->model_description,
191562306a36Sopenharmony_ci			ARRAY_SIZE(vha->hw->model_desc));
191662306a36Sopenharmony_ci		memcpy(&vha->hw->mr.symbolic_name, pinfo->symbolic_name,
191762306a36Sopenharmony_ci		    sizeof(vha->hw->mr.symbolic_name));
191862306a36Sopenharmony_ci		memcpy(&vha->hw->mr.serial_num, pinfo->serial_num,
191962306a36Sopenharmony_ci		    sizeof(vha->hw->mr.serial_num));
192062306a36Sopenharmony_ci		memcpy(&vha->hw->mr.hw_version, pinfo->hw_version,
192162306a36Sopenharmony_ci		    sizeof(vha->hw->mr.hw_version));
192262306a36Sopenharmony_ci		memcpy(&vha->hw->mr.fw_version, pinfo->fw_version,
192362306a36Sopenharmony_ci		    sizeof(vha->hw->mr.fw_version));
192462306a36Sopenharmony_ci		strim(vha->hw->mr.fw_version);
192562306a36Sopenharmony_ci		memcpy(&vha->hw->mr.uboot_version, pinfo->uboot_version,
192662306a36Sopenharmony_ci		    sizeof(vha->hw->mr.uboot_version));
192762306a36Sopenharmony_ci		memcpy(&vha->hw->mr.fru_serial_num, pinfo->fru_serial_num,
192862306a36Sopenharmony_ci		    sizeof(vha->hw->mr.fru_serial_num));
192962306a36Sopenharmony_ci		vha->hw->mr.critical_temperature =
193062306a36Sopenharmony_ci		    (pinfo->nominal_temp_value) ?
193162306a36Sopenharmony_ci		    pinfo->nominal_temp_value : QLAFX00_CRITEMP_THRSHLD;
193262306a36Sopenharmony_ci		ha->mr.extended_io_enabled = (pinfo->enabled_capabilities &
193362306a36Sopenharmony_ci		    QLAFX00_EXTENDED_IO_EN_MASK) != 0;
193462306a36Sopenharmony_ci	} else if (fx_type == FXDISC_GET_PORT_INFO) {
193562306a36Sopenharmony_ci		struct port_info_data *pinfo =
193662306a36Sopenharmony_ci		    (struct port_info_data *) fdisc->u.fxiocb.rsp_addr;
193762306a36Sopenharmony_ci		memcpy(vha->node_name, pinfo->node_name, WWN_SIZE);
193862306a36Sopenharmony_ci		memcpy(vha->port_name, pinfo->port_name, WWN_SIZE);
193962306a36Sopenharmony_ci		vha->d_id.b.domain = pinfo->port_id[0];
194062306a36Sopenharmony_ci		vha->d_id.b.area = pinfo->port_id[1];
194162306a36Sopenharmony_ci		vha->d_id.b.al_pa = pinfo->port_id[2];
194262306a36Sopenharmony_ci		qlafx00_update_host_attr(vha, pinfo);
194362306a36Sopenharmony_ci		ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0141,
194462306a36Sopenharmony_ci		    pinfo, 16);
194562306a36Sopenharmony_ci	} else if (fx_type == FXDISC_GET_TGT_NODE_INFO) {
194662306a36Sopenharmony_ci		struct qlafx00_tgt_node_info *pinfo =
194762306a36Sopenharmony_ci		    (struct qlafx00_tgt_node_info *) fdisc->u.fxiocb.rsp_addr;
194862306a36Sopenharmony_ci		memcpy(fcport->node_name, pinfo->tgt_node_wwnn, WWN_SIZE);
194962306a36Sopenharmony_ci		memcpy(fcport->port_name, pinfo->tgt_node_wwpn, WWN_SIZE);
195062306a36Sopenharmony_ci		fcport->port_type = FCT_TARGET;
195162306a36Sopenharmony_ci		ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0144,
195262306a36Sopenharmony_ci		    pinfo, 16);
195362306a36Sopenharmony_ci	} else if (fx_type == FXDISC_GET_TGT_NODE_LIST) {
195462306a36Sopenharmony_ci		struct qlafx00_tgt_node_info *pinfo =
195562306a36Sopenharmony_ci		    (struct qlafx00_tgt_node_info *) fdisc->u.fxiocb.rsp_addr;
195662306a36Sopenharmony_ci		ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0146,
195762306a36Sopenharmony_ci		    pinfo, 16);
195862306a36Sopenharmony_ci		memcpy(vha->hw->gid_list, pinfo, QLAFX00_TGT_NODE_LIST_SIZE);
195962306a36Sopenharmony_ci	} else if (fx_type == FXDISC_ABORT_IOCTL)
196062306a36Sopenharmony_ci		fdisc->u.fxiocb.result =
196162306a36Sopenharmony_ci		    (fdisc->u.fxiocb.result ==
196262306a36Sopenharmony_ci			cpu_to_le32(QLAFX00_IOCTL_ICOB_ABORT_SUCCESS)) ?
196362306a36Sopenharmony_ci		    cpu_to_le32(QLA_SUCCESS) : cpu_to_le32(QLA_FUNCTION_FAILED);
196462306a36Sopenharmony_ci
196562306a36Sopenharmony_ci	rval = le32_to_cpu(fdisc->u.fxiocb.result);
196662306a36Sopenharmony_ci
196762306a36Sopenharmony_cidone_unmap_dma:
196862306a36Sopenharmony_ci	if (fdisc->u.fxiocb.rsp_addr)
196962306a36Sopenharmony_ci		dma_free_coherent(&ha->pdev->dev, fdisc->u.fxiocb.rsp_len,
197062306a36Sopenharmony_ci		    fdisc->u.fxiocb.rsp_addr, fdisc->u.fxiocb.rsp_dma_handle);
197162306a36Sopenharmony_ci
197262306a36Sopenharmony_cidone_unmap_req:
197362306a36Sopenharmony_ci	if (fdisc->u.fxiocb.req_addr)
197462306a36Sopenharmony_ci		dma_free_coherent(&ha->pdev->dev, fdisc->u.fxiocb.req_len,
197562306a36Sopenharmony_ci		    fdisc->u.fxiocb.req_addr, fdisc->u.fxiocb.req_dma_handle);
197662306a36Sopenharmony_cidone_free_sp:
197762306a36Sopenharmony_ci	/* ref: INIT */
197862306a36Sopenharmony_ci	kref_put(&sp->cmd_kref, qla2x00_sp_release);
197962306a36Sopenharmony_cidone:
198062306a36Sopenharmony_ci	return rval;
198162306a36Sopenharmony_ci}
198262306a36Sopenharmony_ci
198362306a36Sopenharmony_ci/*
198462306a36Sopenharmony_ci * qlafx00_initialize_adapter
198562306a36Sopenharmony_ci *      Initialize board.
198662306a36Sopenharmony_ci *
198762306a36Sopenharmony_ci * Input:
198862306a36Sopenharmony_ci *      ha = adapter block pointer.
198962306a36Sopenharmony_ci *
199062306a36Sopenharmony_ci * Returns:
199162306a36Sopenharmony_ci *      0 = success
199262306a36Sopenharmony_ci */
199362306a36Sopenharmony_ciint
199462306a36Sopenharmony_ciqlafx00_initialize_adapter(scsi_qla_host_t *vha)
199562306a36Sopenharmony_ci{
199662306a36Sopenharmony_ci	int	rval;
199762306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
199862306a36Sopenharmony_ci	uint32_t tempc;
199962306a36Sopenharmony_ci
200062306a36Sopenharmony_ci	/* Clear adapter flags. */
200162306a36Sopenharmony_ci	vha->flags.online = 0;
200262306a36Sopenharmony_ci	ha->flags.chip_reset_done = 0;
200362306a36Sopenharmony_ci	vha->flags.reset_active = 0;
200462306a36Sopenharmony_ci	ha->flags.pci_channel_io_perm_failure = 0;
200562306a36Sopenharmony_ci	ha->flags.eeh_busy = 0;
200662306a36Sopenharmony_ci	atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
200762306a36Sopenharmony_ci	atomic_set(&vha->loop_state, LOOP_DOWN);
200862306a36Sopenharmony_ci	vha->device_flags = DFLG_NO_CABLE;
200962306a36Sopenharmony_ci	vha->dpc_flags = 0;
201062306a36Sopenharmony_ci	vha->flags.management_server_logged_in = 0;
201162306a36Sopenharmony_ci	ha->isp_abort_cnt = 0;
201262306a36Sopenharmony_ci	ha->beacon_blink_led = 0;
201362306a36Sopenharmony_ci
201462306a36Sopenharmony_ci	set_bit(0, ha->req_qid_map);
201562306a36Sopenharmony_ci	set_bit(0, ha->rsp_qid_map);
201662306a36Sopenharmony_ci
201762306a36Sopenharmony_ci	ql_dbg(ql_dbg_init, vha, 0x0147,
201862306a36Sopenharmony_ci	    "Configuring PCI space...\n");
201962306a36Sopenharmony_ci
202062306a36Sopenharmony_ci	rval = ha->isp_ops->pci_config(vha);
202162306a36Sopenharmony_ci	if (rval) {
202262306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x0148,
202362306a36Sopenharmony_ci		    "Unable to configure PCI space.\n");
202462306a36Sopenharmony_ci		return rval;
202562306a36Sopenharmony_ci	}
202662306a36Sopenharmony_ci
202762306a36Sopenharmony_ci	rval = qlafx00_init_fw_ready(vha);
202862306a36Sopenharmony_ci	if (rval != QLA_SUCCESS)
202962306a36Sopenharmony_ci		return rval;
203062306a36Sopenharmony_ci
203162306a36Sopenharmony_ci	qlafx00_save_queue_ptrs(vha);
203262306a36Sopenharmony_ci
203362306a36Sopenharmony_ci	rval = qlafx00_config_queues(vha);
203462306a36Sopenharmony_ci	if (rval != QLA_SUCCESS)
203562306a36Sopenharmony_ci		return rval;
203662306a36Sopenharmony_ci
203762306a36Sopenharmony_ci	/*
203862306a36Sopenharmony_ci	 * Allocate the array of outstanding commands
203962306a36Sopenharmony_ci	 * now that we know the firmware resources.
204062306a36Sopenharmony_ci	 */
204162306a36Sopenharmony_ci	rval = qla2x00_alloc_outstanding_cmds(ha, vha->req);
204262306a36Sopenharmony_ci	if (rval != QLA_SUCCESS)
204362306a36Sopenharmony_ci		return rval;
204462306a36Sopenharmony_ci
204562306a36Sopenharmony_ci	rval = qla2x00_init_rings(vha);
204662306a36Sopenharmony_ci	ha->flags.chip_reset_done = 1;
204762306a36Sopenharmony_ci
204862306a36Sopenharmony_ci	tempc = QLAFX00_GET_TEMPERATURE(ha);
204962306a36Sopenharmony_ci	ql_dbg(ql_dbg_init, vha, 0x0152,
205062306a36Sopenharmony_ci	    "ISPFx00(%s): Critical temp timer, current SOC temperature: 0x%x\n",
205162306a36Sopenharmony_ci	    __func__, tempc);
205262306a36Sopenharmony_ci
205362306a36Sopenharmony_ci	return rval;
205462306a36Sopenharmony_ci}
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_ciuint32_t
205762306a36Sopenharmony_ciqlafx00_fw_state_show(struct device *dev, struct device_attribute *attr,
205862306a36Sopenharmony_ci		      char *buf)
205962306a36Sopenharmony_ci{
206062306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
206162306a36Sopenharmony_ci	int rval = QLA_FUNCTION_FAILED;
206262306a36Sopenharmony_ci	uint32_t state[1];
206362306a36Sopenharmony_ci
206462306a36Sopenharmony_ci	if (qla2x00_reset_active(vha))
206562306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x70ce,
206662306a36Sopenharmony_ci		    "ISP reset active.\n");
206762306a36Sopenharmony_ci	else if (!vha->hw->flags.eeh_busy) {
206862306a36Sopenharmony_ci		rval = qlafx00_get_firmware_state(vha, state);
206962306a36Sopenharmony_ci	}
207062306a36Sopenharmony_ci	if (rval != QLA_SUCCESS)
207162306a36Sopenharmony_ci		memset(state, -1, sizeof(state));
207262306a36Sopenharmony_ci
207362306a36Sopenharmony_ci	return state[0];
207462306a36Sopenharmony_ci}
207562306a36Sopenharmony_ci
207662306a36Sopenharmony_civoid
207762306a36Sopenharmony_ciqlafx00_get_host_speed(struct Scsi_Host *shost)
207862306a36Sopenharmony_ci{
207962306a36Sopenharmony_ci	struct qla_hw_data *ha = ((struct scsi_qla_host *)
208062306a36Sopenharmony_ci					(shost_priv(shost)))->hw;
208162306a36Sopenharmony_ci	u32 speed = FC_PORTSPEED_UNKNOWN;
208262306a36Sopenharmony_ci
208362306a36Sopenharmony_ci	switch (ha->link_data_rate) {
208462306a36Sopenharmony_ci	case QLAFX00_PORT_SPEED_2G:
208562306a36Sopenharmony_ci		speed = FC_PORTSPEED_2GBIT;
208662306a36Sopenharmony_ci		break;
208762306a36Sopenharmony_ci	case QLAFX00_PORT_SPEED_4G:
208862306a36Sopenharmony_ci		speed = FC_PORTSPEED_4GBIT;
208962306a36Sopenharmony_ci		break;
209062306a36Sopenharmony_ci	case QLAFX00_PORT_SPEED_8G:
209162306a36Sopenharmony_ci		speed = FC_PORTSPEED_8GBIT;
209262306a36Sopenharmony_ci		break;
209362306a36Sopenharmony_ci	case QLAFX00_PORT_SPEED_10G:
209462306a36Sopenharmony_ci		speed = FC_PORTSPEED_10GBIT;
209562306a36Sopenharmony_ci		break;
209662306a36Sopenharmony_ci	}
209762306a36Sopenharmony_ci	fc_host_speed(shost) = speed;
209862306a36Sopenharmony_ci}
209962306a36Sopenharmony_ci
210062306a36Sopenharmony_ci/** QLAFX00 specific ISR implementation functions */
210162306a36Sopenharmony_ci
210262306a36Sopenharmony_cistatic inline void
210362306a36Sopenharmony_ciqlafx00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t par_sense_len,
210462306a36Sopenharmony_ci		     uint32_t sense_len, struct rsp_que *rsp, int res)
210562306a36Sopenharmony_ci{
210662306a36Sopenharmony_ci	struct scsi_qla_host *vha = sp->vha;
210762306a36Sopenharmony_ci	struct scsi_cmnd *cp = GET_CMD_SP(sp);
210862306a36Sopenharmony_ci	uint32_t track_sense_len;
210962306a36Sopenharmony_ci
211062306a36Sopenharmony_ci	SET_FW_SENSE_LEN(sp, sense_len);
211162306a36Sopenharmony_ci
211262306a36Sopenharmony_ci	if (sense_len >= SCSI_SENSE_BUFFERSIZE)
211362306a36Sopenharmony_ci		sense_len = SCSI_SENSE_BUFFERSIZE;
211462306a36Sopenharmony_ci
211562306a36Sopenharmony_ci	SET_CMD_SENSE_LEN(sp, sense_len);
211662306a36Sopenharmony_ci	SET_CMD_SENSE_PTR(sp, cp->sense_buffer);
211762306a36Sopenharmony_ci	track_sense_len = sense_len;
211862306a36Sopenharmony_ci
211962306a36Sopenharmony_ci	if (sense_len > par_sense_len)
212062306a36Sopenharmony_ci		sense_len = par_sense_len;
212162306a36Sopenharmony_ci
212262306a36Sopenharmony_ci	memcpy(cp->sense_buffer, sense_data, sense_len);
212362306a36Sopenharmony_ci
212462306a36Sopenharmony_ci	SET_FW_SENSE_LEN(sp, GET_FW_SENSE_LEN(sp) - sense_len);
212562306a36Sopenharmony_ci
212662306a36Sopenharmony_ci	SET_CMD_SENSE_PTR(sp, cp->sense_buffer + sense_len);
212762306a36Sopenharmony_ci	track_sense_len -= sense_len;
212862306a36Sopenharmony_ci	SET_CMD_SENSE_LEN(sp, track_sense_len);
212962306a36Sopenharmony_ci
213062306a36Sopenharmony_ci	ql_dbg(ql_dbg_io, vha, 0x304d,
213162306a36Sopenharmony_ci	    "sense_len=0x%x par_sense_len=0x%x track_sense_len=0x%x.\n",
213262306a36Sopenharmony_ci	    sense_len, par_sense_len, track_sense_len);
213362306a36Sopenharmony_ci	if (GET_FW_SENSE_LEN(sp) > 0) {
213462306a36Sopenharmony_ci		rsp->status_srb = sp;
213562306a36Sopenharmony_ci		cp->result = res;
213662306a36Sopenharmony_ci	}
213762306a36Sopenharmony_ci
213862306a36Sopenharmony_ci	if (sense_len) {
213962306a36Sopenharmony_ci		ql_dbg(ql_dbg_io + ql_dbg_buffer, vha, 0x3039,
214062306a36Sopenharmony_ci		    "Check condition Sense data, nexus%ld:%d:%llu cmd=%p.\n",
214162306a36Sopenharmony_ci		    sp->vha->host_no, cp->device->id, cp->device->lun,
214262306a36Sopenharmony_ci		    cp);
214362306a36Sopenharmony_ci		ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x3049,
214462306a36Sopenharmony_ci		    cp->sense_buffer, sense_len);
214562306a36Sopenharmony_ci	}
214662306a36Sopenharmony_ci}
214762306a36Sopenharmony_ci
214862306a36Sopenharmony_cistatic void
214962306a36Sopenharmony_ciqlafx00_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
215062306a36Sopenharmony_ci		      struct tsk_mgmt_entry_fx00 *pkt, srb_t *sp,
215162306a36Sopenharmony_ci		      __le16 sstatus, __le16 cpstatus)
215262306a36Sopenharmony_ci{
215362306a36Sopenharmony_ci	struct srb_iocb *tmf;
215462306a36Sopenharmony_ci
215562306a36Sopenharmony_ci	tmf = &sp->u.iocb_cmd;
215662306a36Sopenharmony_ci	if (cpstatus != cpu_to_le16((uint16_t)CS_COMPLETE) ||
215762306a36Sopenharmony_ci	    (sstatus & cpu_to_le16((uint16_t)SS_RESPONSE_INFO_LEN_VALID)))
215862306a36Sopenharmony_ci		cpstatus = cpu_to_le16((uint16_t)CS_INCOMPLETE);
215962306a36Sopenharmony_ci	tmf->u.tmf.comp_status = cpstatus;
216062306a36Sopenharmony_ci	sp->done(sp, 0);
216162306a36Sopenharmony_ci}
216262306a36Sopenharmony_ci
216362306a36Sopenharmony_cistatic void
216462306a36Sopenharmony_ciqlafx00_abort_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
216562306a36Sopenharmony_ci			 struct abort_iocb_entry_fx00 *pkt)
216662306a36Sopenharmony_ci{
216762306a36Sopenharmony_ci	const char func[] = "ABT_IOCB";
216862306a36Sopenharmony_ci	srb_t *sp;
216962306a36Sopenharmony_ci	struct srb_iocb *abt;
217062306a36Sopenharmony_ci
217162306a36Sopenharmony_ci	sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
217262306a36Sopenharmony_ci	if (!sp)
217362306a36Sopenharmony_ci		return;
217462306a36Sopenharmony_ci
217562306a36Sopenharmony_ci	abt = &sp->u.iocb_cmd;
217662306a36Sopenharmony_ci	abt->u.abt.comp_status = pkt->tgt_id_sts;
217762306a36Sopenharmony_ci	sp->done(sp, 0);
217862306a36Sopenharmony_ci}
217962306a36Sopenharmony_ci
218062306a36Sopenharmony_cistatic void
218162306a36Sopenharmony_ciqlafx00_ioctl_iosb_entry(scsi_qla_host_t *vha, struct req_que *req,
218262306a36Sopenharmony_ci			 struct ioctl_iocb_entry_fx00 *pkt)
218362306a36Sopenharmony_ci{
218462306a36Sopenharmony_ci	const char func[] = "IOSB_IOCB";
218562306a36Sopenharmony_ci	srb_t *sp;
218662306a36Sopenharmony_ci	struct bsg_job *bsg_job;
218762306a36Sopenharmony_ci	struct fc_bsg_reply *bsg_reply;
218862306a36Sopenharmony_ci	struct srb_iocb *iocb_job;
218962306a36Sopenharmony_ci	int res = 0;
219062306a36Sopenharmony_ci	struct qla_mt_iocb_rsp_fx00 fstatus;
219162306a36Sopenharmony_ci	uint8_t	*fw_sts_ptr;
219262306a36Sopenharmony_ci
219362306a36Sopenharmony_ci	sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
219462306a36Sopenharmony_ci	if (!sp)
219562306a36Sopenharmony_ci		return;
219662306a36Sopenharmony_ci
219762306a36Sopenharmony_ci	if (sp->type == SRB_FXIOCB_DCMD) {
219862306a36Sopenharmony_ci		iocb_job = &sp->u.iocb_cmd;
219962306a36Sopenharmony_ci		iocb_job->u.fxiocb.seq_number = pkt->seq_no;
220062306a36Sopenharmony_ci		iocb_job->u.fxiocb.fw_flags = pkt->fw_iotcl_flags;
220162306a36Sopenharmony_ci		iocb_job->u.fxiocb.result = pkt->status;
220262306a36Sopenharmony_ci		if (iocb_job->u.fxiocb.flags & SRB_FXDISC_RSP_DWRD_VALID)
220362306a36Sopenharmony_ci			iocb_job->u.fxiocb.req_data =
220462306a36Sopenharmony_ci			    pkt->dataword_r;
220562306a36Sopenharmony_ci	} else {
220662306a36Sopenharmony_ci		bsg_job = sp->u.bsg_job;
220762306a36Sopenharmony_ci		bsg_reply = bsg_job->reply;
220862306a36Sopenharmony_ci
220962306a36Sopenharmony_ci		memset(&fstatus, 0, sizeof(struct qla_mt_iocb_rsp_fx00));
221062306a36Sopenharmony_ci
221162306a36Sopenharmony_ci		fstatus.reserved_1 = pkt->reserved_0;
221262306a36Sopenharmony_ci		fstatus.func_type = pkt->comp_func_num;
221362306a36Sopenharmony_ci		fstatus.ioctl_flags = pkt->fw_iotcl_flags;
221462306a36Sopenharmony_ci		fstatus.ioctl_data = pkt->dataword_r;
221562306a36Sopenharmony_ci		fstatus.adapid = pkt->adapid;
221662306a36Sopenharmony_ci		fstatus.reserved_2 = pkt->dataword_r_extra;
221762306a36Sopenharmony_ci		fstatus.res_count = pkt->residuallen;
221862306a36Sopenharmony_ci		fstatus.status = pkt->status;
221962306a36Sopenharmony_ci		fstatus.seq_number = pkt->seq_no;
222062306a36Sopenharmony_ci		memcpy(fstatus.reserved_3,
222162306a36Sopenharmony_ci		    pkt->reserved_2, 20 * sizeof(uint8_t));
222262306a36Sopenharmony_ci
222362306a36Sopenharmony_ci		fw_sts_ptr = bsg_job->reply + sizeof(struct fc_bsg_reply);
222462306a36Sopenharmony_ci
222562306a36Sopenharmony_ci		memcpy(fw_sts_ptr, &fstatus, sizeof(fstatus));
222662306a36Sopenharmony_ci		bsg_job->reply_len = sizeof(struct fc_bsg_reply) +
222762306a36Sopenharmony_ci			sizeof(struct qla_mt_iocb_rsp_fx00) + sizeof(uint8_t);
222862306a36Sopenharmony_ci
222962306a36Sopenharmony_ci		ql_dump_buffer(ql_dbg_user + ql_dbg_verbose,
223062306a36Sopenharmony_ci		    sp->vha, 0x5080, pkt, sizeof(*pkt));
223162306a36Sopenharmony_ci
223262306a36Sopenharmony_ci		ql_dump_buffer(ql_dbg_user + ql_dbg_verbose,
223362306a36Sopenharmony_ci		    sp->vha, 0x5074,
223462306a36Sopenharmony_ci		    fw_sts_ptr, sizeof(fstatus));
223562306a36Sopenharmony_ci
223662306a36Sopenharmony_ci		res = bsg_reply->result = DID_OK << 16;
223762306a36Sopenharmony_ci		bsg_reply->reply_payload_rcv_len =
223862306a36Sopenharmony_ci		    bsg_job->reply_payload.payload_len;
223962306a36Sopenharmony_ci	}
224062306a36Sopenharmony_ci	sp->done(sp, res);
224162306a36Sopenharmony_ci}
224262306a36Sopenharmony_ci
224362306a36Sopenharmony_ci/**
224462306a36Sopenharmony_ci * qlafx00_status_entry() - Process a Status IOCB entry.
224562306a36Sopenharmony_ci * @vha: SCSI driver HA context
224662306a36Sopenharmony_ci * @rsp: response queue
224762306a36Sopenharmony_ci * @pkt: Entry pointer
224862306a36Sopenharmony_ci */
224962306a36Sopenharmony_cistatic void
225062306a36Sopenharmony_ciqlafx00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
225162306a36Sopenharmony_ci{
225262306a36Sopenharmony_ci	srb_t		*sp;
225362306a36Sopenharmony_ci	fc_port_t	*fcport;
225462306a36Sopenharmony_ci	struct scsi_cmnd *cp;
225562306a36Sopenharmony_ci	struct sts_entry_fx00 *sts;
225662306a36Sopenharmony_ci	__le16		comp_status;
225762306a36Sopenharmony_ci	__le16		scsi_status;
225862306a36Sopenharmony_ci	__le16		lscsi_status;
225962306a36Sopenharmony_ci	int32_t		resid;
226062306a36Sopenharmony_ci	uint32_t	sense_len, par_sense_len, rsp_info_len, resid_len,
226162306a36Sopenharmony_ci	    fw_resid_len;
226262306a36Sopenharmony_ci	uint8_t		*rsp_info = NULL, *sense_data = NULL;
226362306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
226462306a36Sopenharmony_ci	uint32_t hindex, handle;
226562306a36Sopenharmony_ci	uint16_t que;
226662306a36Sopenharmony_ci	struct req_que *req;
226762306a36Sopenharmony_ci	int logit = 1;
226862306a36Sopenharmony_ci	int res = 0;
226962306a36Sopenharmony_ci
227062306a36Sopenharmony_ci	sts = (struct sts_entry_fx00 *) pkt;
227162306a36Sopenharmony_ci
227262306a36Sopenharmony_ci	comp_status = sts->comp_status;
227362306a36Sopenharmony_ci	scsi_status = sts->scsi_status & cpu_to_le16((uint16_t)SS_MASK);
227462306a36Sopenharmony_ci	hindex = sts->handle;
227562306a36Sopenharmony_ci	handle = LSW(hindex);
227662306a36Sopenharmony_ci
227762306a36Sopenharmony_ci	que = MSW(hindex);
227862306a36Sopenharmony_ci	req = ha->req_q_map[que];
227962306a36Sopenharmony_ci
228062306a36Sopenharmony_ci	/* Validate handle. */
228162306a36Sopenharmony_ci	if (handle < req->num_outstanding_cmds)
228262306a36Sopenharmony_ci		sp = req->outstanding_cmds[handle];
228362306a36Sopenharmony_ci	else
228462306a36Sopenharmony_ci		sp = NULL;
228562306a36Sopenharmony_ci
228662306a36Sopenharmony_ci	if (sp == NULL) {
228762306a36Sopenharmony_ci		ql_dbg(ql_dbg_io, vha, 0x3034,
228862306a36Sopenharmony_ci		    "Invalid status handle (0x%x).\n", handle);
228962306a36Sopenharmony_ci
229062306a36Sopenharmony_ci		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
229162306a36Sopenharmony_ci		qla2xxx_wake_dpc(vha);
229262306a36Sopenharmony_ci		return;
229362306a36Sopenharmony_ci	}
229462306a36Sopenharmony_ci
229562306a36Sopenharmony_ci	if (sp->type == SRB_TM_CMD) {
229662306a36Sopenharmony_ci		req->outstanding_cmds[handle] = NULL;
229762306a36Sopenharmony_ci		qlafx00_tm_iocb_entry(vha, req, pkt, sp,
229862306a36Sopenharmony_ci		    scsi_status, comp_status);
229962306a36Sopenharmony_ci		return;
230062306a36Sopenharmony_ci	}
230162306a36Sopenharmony_ci
230262306a36Sopenharmony_ci	/* Fast path completion. */
230362306a36Sopenharmony_ci	if (comp_status == CS_COMPLETE && scsi_status == 0) {
230462306a36Sopenharmony_ci		qla2x00_process_completed_request(vha, req, handle);
230562306a36Sopenharmony_ci		return;
230662306a36Sopenharmony_ci	}
230762306a36Sopenharmony_ci
230862306a36Sopenharmony_ci	req->outstanding_cmds[handle] = NULL;
230962306a36Sopenharmony_ci	cp = GET_CMD_SP(sp);
231062306a36Sopenharmony_ci	if (cp == NULL) {
231162306a36Sopenharmony_ci		ql_dbg(ql_dbg_io, vha, 0x3048,
231262306a36Sopenharmony_ci		    "Command already returned (0x%x/%p).\n",
231362306a36Sopenharmony_ci		    handle, sp);
231462306a36Sopenharmony_ci
231562306a36Sopenharmony_ci		return;
231662306a36Sopenharmony_ci	}
231762306a36Sopenharmony_ci
231862306a36Sopenharmony_ci	lscsi_status = scsi_status & cpu_to_le16((uint16_t)STATUS_MASK);
231962306a36Sopenharmony_ci
232062306a36Sopenharmony_ci	fcport = sp->fcport;
232162306a36Sopenharmony_ci
232262306a36Sopenharmony_ci	sense_len = par_sense_len = rsp_info_len = resid_len =
232362306a36Sopenharmony_ci		fw_resid_len = 0;
232462306a36Sopenharmony_ci	if (scsi_status & cpu_to_le16((uint16_t)SS_SENSE_LEN_VALID))
232562306a36Sopenharmony_ci		sense_len = sts->sense_len;
232662306a36Sopenharmony_ci	if (scsi_status & cpu_to_le16(((uint16_t)SS_RESIDUAL_UNDER
232762306a36Sopenharmony_ci	    | (uint16_t)SS_RESIDUAL_OVER)))
232862306a36Sopenharmony_ci		resid_len = le32_to_cpu(sts->residual_len);
232962306a36Sopenharmony_ci	if (comp_status == cpu_to_le16((uint16_t)CS_DATA_UNDERRUN))
233062306a36Sopenharmony_ci		fw_resid_len = le32_to_cpu(sts->residual_len);
233162306a36Sopenharmony_ci	rsp_info = sense_data = sts->data;
233262306a36Sopenharmony_ci	par_sense_len = sizeof(sts->data);
233362306a36Sopenharmony_ci
233462306a36Sopenharmony_ci	/* Check for overrun. */
233562306a36Sopenharmony_ci	if (comp_status == CS_COMPLETE &&
233662306a36Sopenharmony_ci	    scsi_status & cpu_to_le16((uint16_t)SS_RESIDUAL_OVER))
233762306a36Sopenharmony_ci		comp_status = cpu_to_le16((uint16_t)CS_DATA_OVERRUN);
233862306a36Sopenharmony_ci
233962306a36Sopenharmony_ci	/*
234062306a36Sopenharmony_ci	 * Based on Host and scsi status generate status code for Linux
234162306a36Sopenharmony_ci	 */
234262306a36Sopenharmony_ci	switch (le16_to_cpu(comp_status)) {
234362306a36Sopenharmony_ci	case CS_COMPLETE:
234462306a36Sopenharmony_ci	case CS_QUEUE_FULL:
234562306a36Sopenharmony_ci		if (scsi_status == 0) {
234662306a36Sopenharmony_ci			res = DID_OK << 16;
234762306a36Sopenharmony_ci			break;
234862306a36Sopenharmony_ci		}
234962306a36Sopenharmony_ci		if (scsi_status & cpu_to_le16(((uint16_t)SS_RESIDUAL_UNDER
235062306a36Sopenharmony_ci		    | (uint16_t)SS_RESIDUAL_OVER))) {
235162306a36Sopenharmony_ci			resid = resid_len;
235262306a36Sopenharmony_ci			scsi_set_resid(cp, resid);
235362306a36Sopenharmony_ci
235462306a36Sopenharmony_ci			if (!lscsi_status &&
235562306a36Sopenharmony_ci			    ((unsigned)(scsi_bufflen(cp) - resid) <
235662306a36Sopenharmony_ci			     cp->underflow)) {
235762306a36Sopenharmony_ci				ql_dbg(ql_dbg_io, fcport->vha, 0x3050,
235862306a36Sopenharmony_ci				    "Mid-layer underflow "
235962306a36Sopenharmony_ci				    "detected (0x%x of 0x%x bytes).\n",
236062306a36Sopenharmony_ci				    resid, scsi_bufflen(cp));
236162306a36Sopenharmony_ci
236262306a36Sopenharmony_ci				res = DID_ERROR << 16;
236362306a36Sopenharmony_ci				break;
236462306a36Sopenharmony_ci			}
236562306a36Sopenharmony_ci		}
236662306a36Sopenharmony_ci		res = DID_OK << 16 | le16_to_cpu(lscsi_status);
236762306a36Sopenharmony_ci
236862306a36Sopenharmony_ci		if (lscsi_status ==
236962306a36Sopenharmony_ci		    cpu_to_le16((uint16_t)SAM_STAT_TASK_SET_FULL)) {
237062306a36Sopenharmony_ci			ql_dbg(ql_dbg_io, fcport->vha, 0x3051,
237162306a36Sopenharmony_ci			    "QUEUE FULL detected.\n");
237262306a36Sopenharmony_ci			break;
237362306a36Sopenharmony_ci		}
237462306a36Sopenharmony_ci		logit = 0;
237562306a36Sopenharmony_ci		if (lscsi_status != cpu_to_le16((uint16_t)SS_CHECK_CONDITION))
237662306a36Sopenharmony_ci			break;
237762306a36Sopenharmony_ci
237862306a36Sopenharmony_ci		memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
237962306a36Sopenharmony_ci		if (!(scsi_status & cpu_to_le16((uint16_t)SS_SENSE_LEN_VALID)))
238062306a36Sopenharmony_ci			break;
238162306a36Sopenharmony_ci
238262306a36Sopenharmony_ci		qlafx00_handle_sense(sp, sense_data, par_sense_len, sense_len,
238362306a36Sopenharmony_ci		    rsp, res);
238462306a36Sopenharmony_ci		break;
238562306a36Sopenharmony_ci
238662306a36Sopenharmony_ci	case CS_DATA_UNDERRUN:
238762306a36Sopenharmony_ci		/* Use F/W calculated residual length. */
238862306a36Sopenharmony_ci		if (IS_FWI2_CAPABLE(ha) || IS_QLAFX00(ha))
238962306a36Sopenharmony_ci			resid = fw_resid_len;
239062306a36Sopenharmony_ci		else
239162306a36Sopenharmony_ci			resid = resid_len;
239262306a36Sopenharmony_ci		scsi_set_resid(cp, resid);
239362306a36Sopenharmony_ci		if (scsi_status & cpu_to_le16((uint16_t)SS_RESIDUAL_UNDER)) {
239462306a36Sopenharmony_ci			if ((IS_FWI2_CAPABLE(ha) || IS_QLAFX00(ha))
239562306a36Sopenharmony_ci			    && fw_resid_len != resid_len) {
239662306a36Sopenharmony_ci				ql_dbg(ql_dbg_io, fcport->vha, 0x3052,
239762306a36Sopenharmony_ci				    "Dropped frame(s) detected "
239862306a36Sopenharmony_ci				    "(0x%x of 0x%x bytes).\n",
239962306a36Sopenharmony_ci				    resid, scsi_bufflen(cp));
240062306a36Sopenharmony_ci
240162306a36Sopenharmony_ci				res = DID_ERROR << 16 |
240262306a36Sopenharmony_ci				    le16_to_cpu(lscsi_status);
240362306a36Sopenharmony_ci				goto check_scsi_status;
240462306a36Sopenharmony_ci			}
240562306a36Sopenharmony_ci
240662306a36Sopenharmony_ci			if (!lscsi_status &&
240762306a36Sopenharmony_ci			    ((unsigned)(scsi_bufflen(cp) - resid) <
240862306a36Sopenharmony_ci			    cp->underflow)) {
240962306a36Sopenharmony_ci				ql_dbg(ql_dbg_io, fcport->vha, 0x3053,
241062306a36Sopenharmony_ci				    "Mid-layer underflow "
241162306a36Sopenharmony_ci				    "detected (0x%x of 0x%x bytes, "
241262306a36Sopenharmony_ci				    "cp->underflow: 0x%x).\n",
241362306a36Sopenharmony_ci				    resid, scsi_bufflen(cp), cp->underflow);
241462306a36Sopenharmony_ci
241562306a36Sopenharmony_ci				res = DID_ERROR << 16;
241662306a36Sopenharmony_ci				break;
241762306a36Sopenharmony_ci			}
241862306a36Sopenharmony_ci		} else if (lscsi_status !=
241962306a36Sopenharmony_ci		    cpu_to_le16((uint16_t)SAM_STAT_TASK_SET_FULL) &&
242062306a36Sopenharmony_ci		    lscsi_status != cpu_to_le16((uint16_t)SAM_STAT_BUSY)) {
242162306a36Sopenharmony_ci			/*
242262306a36Sopenharmony_ci			 * scsi status of task set and busy are considered
242362306a36Sopenharmony_ci			 * to be task not completed.
242462306a36Sopenharmony_ci			 */
242562306a36Sopenharmony_ci
242662306a36Sopenharmony_ci			ql_dbg(ql_dbg_io, fcport->vha, 0x3054,
242762306a36Sopenharmony_ci			    "Dropped frame(s) detected (0x%x "
242862306a36Sopenharmony_ci			    "of 0x%x bytes).\n", resid,
242962306a36Sopenharmony_ci			    scsi_bufflen(cp));
243062306a36Sopenharmony_ci
243162306a36Sopenharmony_ci			res = DID_ERROR << 16 | le16_to_cpu(lscsi_status);
243262306a36Sopenharmony_ci			goto check_scsi_status;
243362306a36Sopenharmony_ci		} else {
243462306a36Sopenharmony_ci			ql_dbg(ql_dbg_io, fcport->vha, 0x3055,
243562306a36Sopenharmony_ci			    "scsi_status: 0x%x, lscsi_status: 0x%x\n",
243662306a36Sopenharmony_ci			    scsi_status, lscsi_status);
243762306a36Sopenharmony_ci		}
243862306a36Sopenharmony_ci
243962306a36Sopenharmony_ci		res = DID_OK << 16 | le16_to_cpu(lscsi_status);
244062306a36Sopenharmony_ci		logit = 0;
244162306a36Sopenharmony_ci
244262306a36Sopenharmony_cicheck_scsi_status:
244362306a36Sopenharmony_ci		/*
244462306a36Sopenharmony_ci		 * Check to see if SCSI Status is non zero. If so report SCSI
244562306a36Sopenharmony_ci		 * Status.
244662306a36Sopenharmony_ci		 */
244762306a36Sopenharmony_ci		if (lscsi_status != 0) {
244862306a36Sopenharmony_ci			if (lscsi_status ==
244962306a36Sopenharmony_ci			    cpu_to_le16((uint16_t)SAM_STAT_TASK_SET_FULL)) {
245062306a36Sopenharmony_ci				ql_dbg(ql_dbg_io, fcport->vha, 0x3056,
245162306a36Sopenharmony_ci				    "QUEUE FULL detected.\n");
245262306a36Sopenharmony_ci				logit = 1;
245362306a36Sopenharmony_ci				break;
245462306a36Sopenharmony_ci			}
245562306a36Sopenharmony_ci			if (lscsi_status !=
245662306a36Sopenharmony_ci			    cpu_to_le16((uint16_t)SS_CHECK_CONDITION))
245762306a36Sopenharmony_ci				break;
245862306a36Sopenharmony_ci
245962306a36Sopenharmony_ci			memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
246062306a36Sopenharmony_ci			if (!(scsi_status &
246162306a36Sopenharmony_ci			    cpu_to_le16((uint16_t)SS_SENSE_LEN_VALID)))
246262306a36Sopenharmony_ci				break;
246362306a36Sopenharmony_ci
246462306a36Sopenharmony_ci			qlafx00_handle_sense(sp, sense_data, par_sense_len,
246562306a36Sopenharmony_ci			    sense_len, rsp, res);
246662306a36Sopenharmony_ci		}
246762306a36Sopenharmony_ci		break;
246862306a36Sopenharmony_ci
246962306a36Sopenharmony_ci	case CS_PORT_LOGGED_OUT:
247062306a36Sopenharmony_ci	case CS_PORT_CONFIG_CHG:
247162306a36Sopenharmony_ci	case CS_PORT_BUSY:
247262306a36Sopenharmony_ci	case CS_INCOMPLETE:
247362306a36Sopenharmony_ci	case CS_PORT_UNAVAILABLE:
247462306a36Sopenharmony_ci	case CS_TIMEOUT:
247562306a36Sopenharmony_ci	case CS_RESET:
247662306a36Sopenharmony_ci
247762306a36Sopenharmony_ci		/*
247862306a36Sopenharmony_ci		 * We are going to have the fc class block the rport
247962306a36Sopenharmony_ci		 * while we try to recover so instruct the mid layer
248062306a36Sopenharmony_ci		 * to requeue until the class decides how to handle this.
248162306a36Sopenharmony_ci		 */
248262306a36Sopenharmony_ci		res = DID_TRANSPORT_DISRUPTED << 16;
248362306a36Sopenharmony_ci
248462306a36Sopenharmony_ci		ql_dbg(ql_dbg_io, fcport->vha, 0x3057,
248562306a36Sopenharmony_ci		    "Port down status: port-state=0x%x.\n",
248662306a36Sopenharmony_ci		    atomic_read(&fcport->state));
248762306a36Sopenharmony_ci
248862306a36Sopenharmony_ci		if (atomic_read(&fcport->state) == FCS_ONLINE)
248962306a36Sopenharmony_ci			qla2x00_mark_device_lost(fcport->vha, fcport, 1);
249062306a36Sopenharmony_ci		break;
249162306a36Sopenharmony_ci
249262306a36Sopenharmony_ci	case CS_ABORTED:
249362306a36Sopenharmony_ci		res = DID_RESET << 16;
249462306a36Sopenharmony_ci		break;
249562306a36Sopenharmony_ci
249662306a36Sopenharmony_ci	default:
249762306a36Sopenharmony_ci		res = DID_ERROR << 16;
249862306a36Sopenharmony_ci		break;
249962306a36Sopenharmony_ci	}
250062306a36Sopenharmony_ci
250162306a36Sopenharmony_ci	if (logit)
250262306a36Sopenharmony_ci		ql_dbg(ql_dbg_io, fcport->vha, 0x3058,
250362306a36Sopenharmony_ci		    "FCP command status: 0x%x-0x%x (0x%x) nexus=%ld:%d:%llu "
250462306a36Sopenharmony_ci		    "tgt_id: 0x%x lscsi_status: 0x%x cdb=%10phN len=0x%x "
250562306a36Sopenharmony_ci		    "rsp_info=%p resid=0x%x fw_resid=0x%x sense_len=0x%x, "
250662306a36Sopenharmony_ci		    "par_sense_len=0x%x, rsp_info_len=0x%x\n",
250762306a36Sopenharmony_ci		    comp_status, scsi_status, res, vha->host_no,
250862306a36Sopenharmony_ci		    cp->device->id, cp->device->lun, fcport->tgt_id,
250962306a36Sopenharmony_ci		    lscsi_status, cp->cmnd, scsi_bufflen(cp),
251062306a36Sopenharmony_ci		    rsp_info, resid_len, fw_resid_len, sense_len,
251162306a36Sopenharmony_ci		    par_sense_len, rsp_info_len);
251262306a36Sopenharmony_ci
251362306a36Sopenharmony_ci	if (rsp->status_srb == NULL)
251462306a36Sopenharmony_ci		sp->done(sp, res);
251562306a36Sopenharmony_ci	else
251662306a36Sopenharmony_ci		WARN_ON_ONCE(true);
251762306a36Sopenharmony_ci}
251862306a36Sopenharmony_ci
251962306a36Sopenharmony_ci/**
252062306a36Sopenharmony_ci * qlafx00_status_cont_entry() - Process a Status Continuations entry.
252162306a36Sopenharmony_ci * @rsp: response queue
252262306a36Sopenharmony_ci * @pkt: Entry pointer
252362306a36Sopenharmony_ci *
252462306a36Sopenharmony_ci * Extended sense data.
252562306a36Sopenharmony_ci */
252662306a36Sopenharmony_cistatic void
252762306a36Sopenharmony_ciqlafx00_status_cont_entry(struct rsp_que *rsp, sts_cont_entry_t *pkt)
252862306a36Sopenharmony_ci{
252962306a36Sopenharmony_ci	uint8_t	sense_sz = 0;
253062306a36Sopenharmony_ci	struct qla_hw_data *ha = rsp->hw;
253162306a36Sopenharmony_ci	struct scsi_qla_host *vha = pci_get_drvdata(ha->pdev);
253262306a36Sopenharmony_ci	srb_t *sp = rsp->status_srb;
253362306a36Sopenharmony_ci	struct scsi_cmnd *cp;
253462306a36Sopenharmony_ci	uint32_t sense_len;
253562306a36Sopenharmony_ci	uint8_t *sense_ptr;
253662306a36Sopenharmony_ci
253762306a36Sopenharmony_ci	if (!sp) {
253862306a36Sopenharmony_ci		ql_dbg(ql_dbg_io, vha, 0x3037,
253962306a36Sopenharmony_ci		    "no SP, sp = %p\n", sp);
254062306a36Sopenharmony_ci		return;
254162306a36Sopenharmony_ci	}
254262306a36Sopenharmony_ci
254362306a36Sopenharmony_ci	if (!GET_FW_SENSE_LEN(sp)) {
254462306a36Sopenharmony_ci		ql_dbg(ql_dbg_io, vha, 0x304b,
254562306a36Sopenharmony_ci		    "no fw sense data, sp = %p\n", sp);
254662306a36Sopenharmony_ci		return;
254762306a36Sopenharmony_ci	}
254862306a36Sopenharmony_ci	cp = GET_CMD_SP(sp);
254962306a36Sopenharmony_ci	if (cp == NULL) {
255062306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x303b,
255162306a36Sopenharmony_ci		    "cmd is NULL: already returned to OS (sp=%p).\n", sp);
255262306a36Sopenharmony_ci
255362306a36Sopenharmony_ci		rsp->status_srb = NULL;
255462306a36Sopenharmony_ci		return;
255562306a36Sopenharmony_ci	}
255662306a36Sopenharmony_ci
255762306a36Sopenharmony_ci	if (!GET_CMD_SENSE_LEN(sp)) {
255862306a36Sopenharmony_ci		ql_dbg(ql_dbg_io, vha, 0x304c,
255962306a36Sopenharmony_ci		    "no sense data, sp = %p\n", sp);
256062306a36Sopenharmony_ci	} else {
256162306a36Sopenharmony_ci		sense_len = GET_CMD_SENSE_LEN(sp);
256262306a36Sopenharmony_ci		sense_ptr = GET_CMD_SENSE_PTR(sp);
256362306a36Sopenharmony_ci		ql_dbg(ql_dbg_io, vha, 0x304f,
256462306a36Sopenharmony_ci		    "sp=%p sense_len=0x%x sense_ptr=%p.\n",
256562306a36Sopenharmony_ci		    sp, sense_len, sense_ptr);
256662306a36Sopenharmony_ci
256762306a36Sopenharmony_ci		if (sense_len > sizeof(pkt->data))
256862306a36Sopenharmony_ci			sense_sz = sizeof(pkt->data);
256962306a36Sopenharmony_ci		else
257062306a36Sopenharmony_ci			sense_sz = sense_len;
257162306a36Sopenharmony_ci
257262306a36Sopenharmony_ci		/* Move sense data. */
257362306a36Sopenharmony_ci		ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x304e,
257462306a36Sopenharmony_ci		    pkt, sizeof(*pkt));
257562306a36Sopenharmony_ci		memcpy(sense_ptr, pkt->data, sense_sz);
257662306a36Sopenharmony_ci		ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x304a,
257762306a36Sopenharmony_ci		    sense_ptr, sense_sz);
257862306a36Sopenharmony_ci
257962306a36Sopenharmony_ci		sense_len -= sense_sz;
258062306a36Sopenharmony_ci		sense_ptr += sense_sz;
258162306a36Sopenharmony_ci
258262306a36Sopenharmony_ci		SET_CMD_SENSE_PTR(sp, sense_ptr);
258362306a36Sopenharmony_ci		SET_CMD_SENSE_LEN(sp, sense_len);
258462306a36Sopenharmony_ci	}
258562306a36Sopenharmony_ci	sense_len = GET_FW_SENSE_LEN(sp);
258662306a36Sopenharmony_ci	sense_len = (sense_len > sizeof(pkt->data)) ?
258762306a36Sopenharmony_ci	    (sense_len - sizeof(pkt->data)) : 0;
258862306a36Sopenharmony_ci	SET_FW_SENSE_LEN(sp, sense_len);
258962306a36Sopenharmony_ci
259062306a36Sopenharmony_ci	/* Place command on done queue. */
259162306a36Sopenharmony_ci	if (sense_len == 0) {
259262306a36Sopenharmony_ci		rsp->status_srb = NULL;
259362306a36Sopenharmony_ci		sp->done(sp, cp->result);
259462306a36Sopenharmony_ci	} else {
259562306a36Sopenharmony_ci		WARN_ON_ONCE(true);
259662306a36Sopenharmony_ci	}
259762306a36Sopenharmony_ci}
259862306a36Sopenharmony_ci
259962306a36Sopenharmony_ci/**
260062306a36Sopenharmony_ci * qlafx00_multistatus_entry() - Process Multi response queue entries.
260162306a36Sopenharmony_ci * @vha: SCSI driver HA context
260262306a36Sopenharmony_ci * @rsp: response queue
260362306a36Sopenharmony_ci * @pkt: received packet
260462306a36Sopenharmony_ci */
260562306a36Sopenharmony_cistatic void
260662306a36Sopenharmony_ciqlafx00_multistatus_entry(struct scsi_qla_host *vha,
260762306a36Sopenharmony_ci	struct rsp_que *rsp, void *pkt)
260862306a36Sopenharmony_ci{
260962306a36Sopenharmony_ci	srb_t		*sp;
261062306a36Sopenharmony_ci	struct multi_sts_entry_fx00 *stsmfx;
261162306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
261262306a36Sopenharmony_ci	uint32_t handle, hindex, handle_count, i;
261362306a36Sopenharmony_ci	uint16_t que;
261462306a36Sopenharmony_ci	struct req_que *req;
261562306a36Sopenharmony_ci	__le32 *handle_ptr;
261662306a36Sopenharmony_ci
261762306a36Sopenharmony_ci	stsmfx = (struct multi_sts_entry_fx00 *) pkt;
261862306a36Sopenharmony_ci
261962306a36Sopenharmony_ci	handle_count = stsmfx->handle_count;
262062306a36Sopenharmony_ci
262162306a36Sopenharmony_ci	if (handle_count > MAX_HANDLE_COUNT) {
262262306a36Sopenharmony_ci		ql_dbg(ql_dbg_io, vha, 0x3035,
262362306a36Sopenharmony_ci		    "Invalid handle count (0x%x).\n", handle_count);
262462306a36Sopenharmony_ci		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
262562306a36Sopenharmony_ci		qla2xxx_wake_dpc(vha);
262662306a36Sopenharmony_ci		return;
262762306a36Sopenharmony_ci	}
262862306a36Sopenharmony_ci
262962306a36Sopenharmony_ci	handle_ptr =  &stsmfx->handles[0];
263062306a36Sopenharmony_ci
263162306a36Sopenharmony_ci	for (i = 0; i < handle_count; i++) {
263262306a36Sopenharmony_ci		hindex = le32_to_cpu(*handle_ptr);
263362306a36Sopenharmony_ci		handle = LSW(hindex);
263462306a36Sopenharmony_ci		que = MSW(hindex);
263562306a36Sopenharmony_ci		req = ha->req_q_map[que];
263662306a36Sopenharmony_ci
263762306a36Sopenharmony_ci		/* Validate handle. */
263862306a36Sopenharmony_ci		if (handle < req->num_outstanding_cmds)
263962306a36Sopenharmony_ci			sp = req->outstanding_cmds[handle];
264062306a36Sopenharmony_ci		else
264162306a36Sopenharmony_ci			sp = NULL;
264262306a36Sopenharmony_ci
264362306a36Sopenharmony_ci		if (sp == NULL) {
264462306a36Sopenharmony_ci			ql_dbg(ql_dbg_io, vha, 0x3044,
264562306a36Sopenharmony_ci			    "Invalid status handle (0x%x).\n", handle);
264662306a36Sopenharmony_ci			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
264762306a36Sopenharmony_ci			qla2xxx_wake_dpc(vha);
264862306a36Sopenharmony_ci			return;
264962306a36Sopenharmony_ci		}
265062306a36Sopenharmony_ci		qla2x00_process_completed_request(vha, req, handle);
265162306a36Sopenharmony_ci		handle_ptr++;
265262306a36Sopenharmony_ci	}
265362306a36Sopenharmony_ci}
265462306a36Sopenharmony_ci
265562306a36Sopenharmony_ci/**
265662306a36Sopenharmony_ci * qlafx00_error_entry() - Process an error entry.
265762306a36Sopenharmony_ci * @vha: SCSI driver HA context
265862306a36Sopenharmony_ci * @rsp: response queue
265962306a36Sopenharmony_ci * @pkt: Entry pointer
266062306a36Sopenharmony_ci */
266162306a36Sopenharmony_cistatic void
266262306a36Sopenharmony_ciqlafx00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp,
266362306a36Sopenharmony_ci		    struct sts_entry_fx00 *pkt)
266462306a36Sopenharmony_ci{
266562306a36Sopenharmony_ci	srb_t *sp;
266662306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
266762306a36Sopenharmony_ci	const char func[] = "ERROR-IOCB";
266862306a36Sopenharmony_ci	uint16_t que = 0;
266962306a36Sopenharmony_ci	struct req_que *req = NULL;
267062306a36Sopenharmony_ci	int res = DID_ERROR << 16;
267162306a36Sopenharmony_ci
267262306a36Sopenharmony_ci	req = ha->req_q_map[que];
267362306a36Sopenharmony_ci
267462306a36Sopenharmony_ci	sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
267562306a36Sopenharmony_ci	if (sp) {
267662306a36Sopenharmony_ci		sp->done(sp, res);
267762306a36Sopenharmony_ci		return;
267862306a36Sopenharmony_ci	}
267962306a36Sopenharmony_ci
268062306a36Sopenharmony_ci	set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
268162306a36Sopenharmony_ci	qla2xxx_wake_dpc(vha);
268262306a36Sopenharmony_ci}
268362306a36Sopenharmony_ci
268462306a36Sopenharmony_ci/**
268562306a36Sopenharmony_ci * qlafx00_process_response_queue() - Process response queue entries.
268662306a36Sopenharmony_ci * @vha: SCSI driver HA context
268762306a36Sopenharmony_ci * @rsp: response queue
268862306a36Sopenharmony_ci */
268962306a36Sopenharmony_cistatic void
269062306a36Sopenharmony_ciqlafx00_process_response_queue(struct scsi_qla_host *vha,
269162306a36Sopenharmony_ci	struct rsp_que *rsp)
269262306a36Sopenharmony_ci{
269362306a36Sopenharmony_ci	struct sts_entry_fx00 *pkt;
269462306a36Sopenharmony_ci	response_t *lptr;
269562306a36Sopenharmony_ci	uint16_t lreq_q_in = 0;
269662306a36Sopenharmony_ci	uint16_t lreq_q_out = 0;
269762306a36Sopenharmony_ci
269862306a36Sopenharmony_ci	lreq_q_in = rd_reg_dword(rsp->rsp_q_in);
269962306a36Sopenharmony_ci	lreq_q_out = rsp->ring_index;
270062306a36Sopenharmony_ci
270162306a36Sopenharmony_ci	while (lreq_q_in != lreq_q_out) {
270262306a36Sopenharmony_ci		lptr = rsp->ring_ptr;
270362306a36Sopenharmony_ci		memcpy_fromio(rsp->rsp_pkt, (void __iomem *)lptr,
270462306a36Sopenharmony_ci		    sizeof(rsp->rsp_pkt));
270562306a36Sopenharmony_ci		pkt = (struct sts_entry_fx00 *)rsp->rsp_pkt;
270662306a36Sopenharmony_ci
270762306a36Sopenharmony_ci		rsp->ring_index++;
270862306a36Sopenharmony_ci		lreq_q_out++;
270962306a36Sopenharmony_ci		if (rsp->ring_index == rsp->length) {
271062306a36Sopenharmony_ci			lreq_q_out = 0;
271162306a36Sopenharmony_ci			rsp->ring_index = 0;
271262306a36Sopenharmony_ci			rsp->ring_ptr = rsp->ring;
271362306a36Sopenharmony_ci		} else {
271462306a36Sopenharmony_ci			rsp->ring_ptr++;
271562306a36Sopenharmony_ci		}
271662306a36Sopenharmony_ci
271762306a36Sopenharmony_ci		if (pkt->entry_status != 0 &&
271862306a36Sopenharmony_ci		    pkt->entry_type != IOCTL_IOSB_TYPE_FX00) {
271962306a36Sopenharmony_ci			ql_dbg(ql_dbg_async, vha, 0x507f,
272062306a36Sopenharmony_ci			       "type of error status in response: 0x%x\n",
272162306a36Sopenharmony_ci			       pkt->entry_status);
272262306a36Sopenharmony_ci			qlafx00_error_entry(vha, rsp,
272362306a36Sopenharmony_ci					    (struct sts_entry_fx00 *)pkt);
272462306a36Sopenharmony_ci			continue;
272562306a36Sopenharmony_ci		}
272662306a36Sopenharmony_ci
272762306a36Sopenharmony_ci		switch (pkt->entry_type) {
272862306a36Sopenharmony_ci		case STATUS_TYPE_FX00:
272962306a36Sopenharmony_ci			qlafx00_status_entry(vha, rsp, pkt);
273062306a36Sopenharmony_ci			break;
273162306a36Sopenharmony_ci
273262306a36Sopenharmony_ci		case STATUS_CONT_TYPE_FX00:
273362306a36Sopenharmony_ci			qlafx00_status_cont_entry(rsp, (sts_cont_entry_t *)pkt);
273462306a36Sopenharmony_ci			break;
273562306a36Sopenharmony_ci
273662306a36Sopenharmony_ci		case MULTI_STATUS_TYPE_FX00:
273762306a36Sopenharmony_ci			qlafx00_multistatus_entry(vha, rsp, pkt);
273862306a36Sopenharmony_ci			break;
273962306a36Sopenharmony_ci
274062306a36Sopenharmony_ci		case ABORT_IOCB_TYPE_FX00:
274162306a36Sopenharmony_ci			qlafx00_abort_iocb_entry(vha, rsp->req,
274262306a36Sopenharmony_ci			   (struct abort_iocb_entry_fx00 *)pkt);
274362306a36Sopenharmony_ci			break;
274462306a36Sopenharmony_ci
274562306a36Sopenharmony_ci		case IOCTL_IOSB_TYPE_FX00:
274662306a36Sopenharmony_ci			qlafx00_ioctl_iosb_entry(vha, rsp->req,
274762306a36Sopenharmony_ci			    (struct ioctl_iocb_entry_fx00 *)pkt);
274862306a36Sopenharmony_ci			break;
274962306a36Sopenharmony_ci		default:
275062306a36Sopenharmony_ci			/* Type Not Supported. */
275162306a36Sopenharmony_ci			ql_dbg(ql_dbg_async, vha, 0x5081,
275262306a36Sopenharmony_ci			    "Received unknown response pkt type %x "
275362306a36Sopenharmony_ci			    "entry status=%x.\n",
275462306a36Sopenharmony_ci			    pkt->entry_type, pkt->entry_status);
275562306a36Sopenharmony_ci			break;
275662306a36Sopenharmony_ci		}
275762306a36Sopenharmony_ci	}
275862306a36Sopenharmony_ci
275962306a36Sopenharmony_ci	/* Adjust ring index */
276062306a36Sopenharmony_ci	wrt_reg_dword(rsp->rsp_q_out, rsp->ring_index);
276162306a36Sopenharmony_ci}
276262306a36Sopenharmony_ci
276362306a36Sopenharmony_ci/**
276462306a36Sopenharmony_ci * qlafx00_async_event() - Process aynchronous events.
276562306a36Sopenharmony_ci * @vha: SCSI driver HA context
276662306a36Sopenharmony_ci */
276762306a36Sopenharmony_cistatic void
276862306a36Sopenharmony_ciqlafx00_async_event(scsi_qla_host_t *vha)
276962306a36Sopenharmony_ci{
277062306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
277162306a36Sopenharmony_ci	struct device_reg_fx00 __iomem *reg;
277262306a36Sopenharmony_ci	int data_size = 1;
277362306a36Sopenharmony_ci
277462306a36Sopenharmony_ci	reg = &ha->iobase->ispfx00;
277562306a36Sopenharmony_ci	/* Setup to process RIO completion. */
277662306a36Sopenharmony_ci	switch (ha->aenmb[0]) {
277762306a36Sopenharmony_ci	case QLAFX00_MBA_SYSTEM_ERR:		/* System Error */
277862306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x5079,
277962306a36Sopenharmony_ci		    "ISP System Error - mbx1=%x\n", ha->aenmb[0]);
278062306a36Sopenharmony_ci		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
278162306a36Sopenharmony_ci		break;
278262306a36Sopenharmony_ci
278362306a36Sopenharmony_ci	case QLAFX00_MBA_SHUTDOWN_RQSTD:	/* Shutdown requested */
278462306a36Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5076,
278562306a36Sopenharmony_ci		    "Asynchronous FW shutdown requested.\n");
278662306a36Sopenharmony_ci		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
278762306a36Sopenharmony_ci		qla2xxx_wake_dpc(vha);
278862306a36Sopenharmony_ci		break;
278962306a36Sopenharmony_ci
279062306a36Sopenharmony_ci	case QLAFX00_MBA_PORT_UPDATE:		/* Port database update */
279162306a36Sopenharmony_ci		ha->aenmb[1] = rd_reg_dword(&reg->aenmailbox1);
279262306a36Sopenharmony_ci		ha->aenmb[2] = rd_reg_dword(&reg->aenmailbox2);
279362306a36Sopenharmony_ci		ha->aenmb[3] = rd_reg_dword(&reg->aenmailbox3);
279462306a36Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5077,
279562306a36Sopenharmony_ci		    "Asynchronous port Update received "
279662306a36Sopenharmony_ci		    "aenmb[0]: %x, aenmb[1]: %x, aenmb[2]: %x, aenmb[3]: %x\n",
279762306a36Sopenharmony_ci		    ha->aenmb[0], ha->aenmb[1], ha->aenmb[2], ha->aenmb[3]);
279862306a36Sopenharmony_ci		data_size = 4;
279962306a36Sopenharmony_ci		break;
280062306a36Sopenharmony_ci
280162306a36Sopenharmony_ci	case QLAFX00_MBA_TEMP_OVER:	/* Over temperature event */
280262306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0x5085,
280362306a36Sopenharmony_ci		    "Asynchronous over temperature event received "
280462306a36Sopenharmony_ci		    "aenmb[0]: %x\n",
280562306a36Sopenharmony_ci		    ha->aenmb[0]);
280662306a36Sopenharmony_ci		break;
280762306a36Sopenharmony_ci
280862306a36Sopenharmony_ci	case QLAFX00_MBA_TEMP_NORM:	/* Normal temperature event */
280962306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0x5086,
281062306a36Sopenharmony_ci		    "Asynchronous normal temperature event received "
281162306a36Sopenharmony_ci		    "aenmb[0]: %x\n",
281262306a36Sopenharmony_ci		    ha->aenmb[0]);
281362306a36Sopenharmony_ci		break;
281462306a36Sopenharmony_ci
281562306a36Sopenharmony_ci	case QLAFX00_MBA_TEMP_CRIT:	/* Critical temperature event */
281662306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0x5083,
281762306a36Sopenharmony_ci		    "Asynchronous critical temperature event received "
281862306a36Sopenharmony_ci		    "aenmb[0]: %x\n",
281962306a36Sopenharmony_ci		ha->aenmb[0]);
282062306a36Sopenharmony_ci		break;
282162306a36Sopenharmony_ci
282262306a36Sopenharmony_ci	default:
282362306a36Sopenharmony_ci		ha->aenmb[1] = rd_reg_dword(&reg->aenmailbox1);
282462306a36Sopenharmony_ci		ha->aenmb[2] = rd_reg_dword(&reg->aenmailbox2);
282562306a36Sopenharmony_ci		ha->aenmb[3] = rd_reg_dword(&reg->aenmailbox3);
282662306a36Sopenharmony_ci		ha->aenmb[4] = rd_reg_dword(&reg->aenmailbox4);
282762306a36Sopenharmony_ci		ha->aenmb[5] = rd_reg_dword(&reg->aenmailbox5);
282862306a36Sopenharmony_ci		ha->aenmb[6] = rd_reg_dword(&reg->aenmailbox6);
282962306a36Sopenharmony_ci		ha->aenmb[7] = rd_reg_dword(&reg->aenmailbox7);
283062306a36Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5078,
283162306a36Sopenharmony_ci		    "AEN:%04x %04x %04x %04x :%04x %04x %04x %04x\n",
283262306a36Sopenharmony_ci		    ha->aenmb[0], ha->aenmb[1], ha->aenmb[2], ha->aenmb[3],
283362306a36Sopenharmony_ci		    ha->aenmb[4], ha->aenmb[5], ha->aenmb[6], ha->aenmb[7]);
283462306a36Sopenharmony_ci		break;
283562306a36Sopenharmony_ci	}
283662306a36Sopenharmony_ci	qlafx00_post_aenfx_work(vha, ha->aenmb[0],
283762306a36Sopenharmony_ci	    (uint32_t *)ha->aenmb, data_size);
283862306a36Sopenharmony_ci}
283962306a36Sopenharmony_ci
284062306a36Sopenharmony_ci/**
284162306a36Sopenharmony_ci * qlafx00_mbx_completion() - Process mailbox command completions.
284262306a36Sopenharmony_ci * @vha: SCSI driver HA context
284362306a36Sopenharmony_ci * @mb0: value to be written into mailbox register 0
284462306a36Sopenharmony_ci */
284562306a36Sopenharmony_cistatic void
284662306a36Sopenharmony_ciqlafx00_mbx_completion(scsi_qla_host_t *vha, uint32_t mb0)
284762306a36Sopenharmony_ci{
284862306a36Sopenharmony_ci	uint16_t	cnt;
284962306a36Sopenharmony_ci	__le32 __iomem *wptr;
285062306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
285162306a36Sopenharmony_ci	struct device_reg_fx00 __iomem *reg = &ha->iobase->ispfx00;
285262306a36Sopenharmony_ci
285362306a36Sopenharmony_ci	if (!ha->mcp32)
285462306a36Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x507e, "MBX pointer ERROR.\n");
285562306a36Sopenharmony_ci
285662306a36Sopenharmony_ci	/* Load return mailbox registers. */
285762306a36Sopenharmony_ci	ha->flags.mbox_int = 1;
285862306a36Sopenharmony_ci	ha->mailbox_out32[0] = mb0;
285962306a36Sopenharmony_ci	wptr = &reg->mailbox17;
286062306a36Sopenharmony_ci
286162306a36Sopenharmony_ci	for (cnt = 1; cnt < ha->mbx_count; cnt++) {
286262306a36Sopenharmony_ci		ha->mailbox_out32[cnt] = rd_reg_dword(wptr);
286362306a36Sopenharmony_ci		wptr++;
286462306a36Sopenharmony_ci	}
286562306a36Sopenharmony_ci}
286662306a36Sopenharmony_ci
286762306a36Sopenharmony_ci/**
286862306a36Sopenharmony_ci * qlafx00_intr_handler() - Process interrupts for the ISPFX00.
286962306a36Sopenharmony_ci * @irq: interrupt number
287062306a36Sopenharmony_ci * @dev_id: SCSI driver HA context
287162306a36Sopenharmony_ci *
287262306a36Sopenharmony_ci * Called by system whenever the host adapter generates an interrupt.
287362306a36Sopenharmony_ci *
287462306a36Sopenharmony_ci * Returns handled flag.
287562306a36Sopenharmony_ci */
287662306a36Sopenharmony_ciirqreturn_t
287762306a36Sopenharmony_ciqlafx00_intr_handler(int irq, void *dev_id)
287862306a36Sopenharmony_ci{
287962306a36Sopenharmony_ci	scsi_qla_host_t	*vha;
288062306a36Sopenharmony_ci	struct qla_hw_data *ha;
288162306a36Sopenharmony_ci	struct device_reg_fx00 __iomem *reg;
288262306a36Sopenharmony_ci	int		status;
288362306a36Sopenharmony_ci	unsigned long	iter;
288462306a36Sopenharmony_ci	uint32_t	stat;
288562306a36Sopenharmony_ci	uint32_t	mb[8];
288662306a36Sopenharmony_ci	struct rsp_que *rsp;
288762306a36Sopenharmony_ci	unsigned long	flags;
288862306a36Sopenharmony_ci	uint32_t clr_intr = 0;
288962306a36Sopenharmony_ci	uint32_t intr_stat = 0;
289062306a36Sopenharmony_ci
289162306a36Sopenharmony_ci	rsp = (struct rsp_que *) dev_id;
289262306a36Sopenharmony_ci	if (!rsp) {
289362306a36Sopenharmony_ci		ql_log(ql_log_info, NULL, 0x507d,
289462306a36Sopenharmony_ci		    "%s: NULL response queue pointer.\n", __func__);
289562306a36Sopenharmony_ci		return IRQ_NONE;
289662306a36Sopenharmony_ci	}
289762306a36Sopenharmony_ci
289862306a36Sopenharmony_ci	ha = rsp->hw;
289962306a36Sopenharmony_ci	reg = &ha->iobase->ispfx00;
290062306a36Sopenharmony_ci	status = 0;
290162306a36Sopenharmony_ci
290262306a36Sopenharmony_ci	if (unlikely(pci_channel_offline(ha->pdev)))
290362306a36Sopenharmony_ci		return IRQ_HANDLED;
290462306a36Sopenharmony_ci
290562306a36Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
290662306a36Sopenharmony_ci	vha = pci_get_drvdata(ha->pdev);
290762306a36Sopenharmony_ci	for (iter = 50; iter--; clr_intr = 0) {
290862306a36Sopenharmony_ci		stat = QLAFX00_RD_INTR_REG(ha);
290962306a36Sopenharmony_ci		if (qla2x00_check_reg32_for_disconnect(vha, stat))
291062306a36Sopenharmony_ci			break;
291162306a36Sopenharmony_ci		intr_stat = stat & QLAFX00_HST_INT_STS_BITS;
291262306a36Sopenharmony_ci		if (!intr_stat)
291362306a36Sopenharmony_ci			break;
291462306a36Sopenharmony_ci
291562306a36Sopenharmony_ci		if (stat & QLAFX00_INTR_MB_CMPLT) {
291662306a36Sopenharmony_ci			mb[0] = rd_reg_dword(&reg->mailbox16);
291762306a36Sopenharmony_ci			qlafx00_mbx_completion(vha, mb[0]);
291862306a36Sopenharmony_ci			status |= MBX_INTERRUPT;
291962306a36Sopenharmony_ci			clr_intr |= QLAFX00_INTR_MB_CMPLT;
292062306a36Sopenharmony_ci		}
292162306a36Sopenharmony_ci		if (intr_stat & QLAFX00_INTR_ASYNC_CMPLT) {
292262306a36Sopenharmony_ci			ha->aenmb[0] = rd_reg_dword(&reg->aenmailbox0);
292362306a36Sopenharmony_ci			qlafx00_async_event(vha);
292462306a36Sopenharmony_ci			clr_intr |= QLAFX00_INTR_ASYNC_CMPLT;
292562306a36Sopenharmony_ci		}
292662306a36Sopenharmony_ci		if (intr_stat & QLAFX00_INTR_RSP_CMPLT) {
292762306a36Sopenharmony_ci			qlafx00_process_response_queue(vha, rsp);
292862306a36Sopenharmony_ci			clr_intr |= QLAFX00_INTR_RSP_CMPLT;
292962306a36Sopenharmony_ci		}
293062306a36Sopenharmony_ci
293162306a36Sopenharmony_ci		QLAFX00_CLR_INTR_REG(ha, clr_intr);
293262306a36Sopenharmony_ci		QLAFX00_RD_INTR_REG(ha);
293362306a36Sopenharmony_ci	}
293462306a36Sopenharmony_ci
293562306a36Sopenharmony_ci	qla2x00_handle_mbx_completion(ha, status);
293662306a36Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
293762306a36Sopenharmony_ci
293862306a36Sopenharmony_ci	return IRQ_HANDLED;
293962306a36Sopenharmony_ci}
294062306a36Sopenharmony_ci
294162306a36Sopenharmony_ci/** QLAFX00 specific IOCB implementation functions */
294262306a36Sopenharmony_ci
294362306a36Sopenharmony_cistatic inline cont_a64_entry_t *
294462306a36Sopenharmony_ciqlafx00_prep_cont_type1_iocb(struct req_que *req,
294562306a36Sopenharmony_ci			     cont_a64_entry_t *lcont_pkt)
294662306a36Sopenharmony_ci{
294762306a36Sopenharmony_ci	cont_a64_entry_t *cont_pkt;
294862306a36Sopenharmony_ci
294962306a36Sopenharmony_ci	/* Adjust ring index. */
295062306a36Sopenharmony_ci	req->ring_index++;
295162306a36Sopenharmony_ci	if (req->ring_index == req->length) {
295262306a36Sopenharmony_ci		req->ring_index = 0;
295362306a36Sopenharmony_ci		req->ring_ptr = req->ring;
295462306a36Sopenharmony_ci	} else {
295562306a36Sopenharmony_ci		req->ring_ptr++;
295662306a36Sopenharmony_ci	}
295762306a36Sopenharmony_ci
295862306a36Sopenharmony_ci	cont_pkt = (cont_a64_entry_t *)req->ring_ptr;
295962306a36Sopenharmony_ci
296062306a36Sopenharmony_ci	/* Load packet defaults. */
296162306a36Sopenharmony_ci	lcont_pkt->entry_type = CONTINUE_A64_TYPE_FX00;
296262306a36Sopenharmony_ci
296362306a36Sopenharmony_ci	return cont_pkt;
296462306a36Sopenharmony_ci}
296562306a36Sopenharmony_ci
296662306a36Sopenharmony_cistatic inline void
296762306a36Sopenharmony_ciqlafx00_build_scsi_iocbs(srb_t *sp, struct cmd_type_7_fx00 *cmd_pkt,
296862306a36Sopenharmony_ci			 uint16_t tot_dsds, struct cmd_type_7_fx00 *lcmd_pkt)
296962306a36Sopenharmony_ci{
297062306a36Sopenharmony_ci	uint16_t	avail_dsds;
297162306a36Sopenharmony_ci	struct dsd64	*cur_dsd;
297262306a36Sopenharmony_ci	scsi_qla_host_t	*vha;
297362306a36Sopenharmony_ci	struct scsi_cmnd *cmd;
297462306a36Sopenharmony_ci	struct scatterlist *sg;
297562306a36Sopenharmony_ci	int i, cont;
297662306a36Sopenharmony_ci	struct req_que *req;
297762306a36Sopenharmony_ci	cont_a64_entry_t lcont_pkt;
297862306a36Sopenharmony_ci	cont_a64_entry_t *cont_pkt;
297962306a36Sopenharmony_ci
298062306a36Sopenharmony_ci	vha = sp->vha;
298162306a36Sopenharmony_ci	req = vha->req;
298262306a36Sopenharmony_ci
298362306a36Sopenharmony_ci	cmd = GET_CMD_SP(sp);
298462306a36Sopenharmony_ci	cont = 0;
298562306a36Sopenharmony_ci	cont_pkt = NULL;
298662306a36Sopenharmony_ci
298762306a36Sopenharmony_ci	/* Update entry type to indicate Command Type 3 IOCB */
298862306a36Sopenharmony_ci	lcmd_pkt->entry_type = FX00_COMMAND_TYPE_7;
298962306a36Sopenharmony_ci
299062306a36Sopenharmony_ci	/* No data transfer */
299162306a36Sopenharmony_ci	if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) {
299262306a36Sopenharmony_ci		lcmd_pkt->byte_count = cpu_to_le32(0);
299362306a36Sopenharmony_ci		return;
299462306a36Sopenharmony_ci	}
299562306a36Sopenharmony_ci
299662306a36Sopenharmony_ci	/* Set transfer direction */
299762306a36Sopenharmony_ci	if (cmd->sc_data_direction == DMA_TO_DEVICE) {
299862306a36Sopenharmony_ci		lcmd_pkt->cntrl_flags = TMF_WRITE_DATA;
299962306a36Sopenharmony_ci		vha->qla_stats.output_bytes += scsi_bufflen(cmd);
300062306a36Sopenharmony_ci	} else if (cmd->sc_data_direction == DMA_FROM_DEVICE) {
300162306a36Sopenharmony_ci		lcmd_pkt->cntrl_flags = TMF_READ_DATA;
300262306a36Sopenharmony_ci		vha->qla_stats.input_bytes += scsi_bufflen(cmd);
300362306a36Sopenharmony_ci	}
300462306a36Sopenharmony_ci
300562306a36Sopenharmony_ci	/* One DSD is available in the Command Type 3 IOCB */
300662306a36Sopenharmony_ci	avail_dsds = 1;
300762306a36Sopenharmony_ci	cur_dsd = &lcmd_pkt->dsd;
300862306a36Sopenharmony_ci
300962306a36Sopenharmony_ci	/* Load data segments */
301062306a36Sopenharmony_ci	scsi_for_each_sg(cmd, sg, tot_dsds, i) {
301162306a36Sopenharmony_ci		/* Allocate additional continuation packets? */
301262306a36Sopenharmony_ci		if (avail_dsds == 0) {
301362306a36Sopenharmony_ci			/*
301462306a36Sopenharmony_ci			 * Five DSDs are available in the Continuation
301562306a36Sopenharmony_ci			 * Type 1 IOCB.
301662306a36Sopenharmony_ci			 */
301762306a36Sopenharmony_ci			memset(&lcont_pkt, 0, REQUEST_ENTRY_SIZE);
301862306a36Sopenharmony_ci			cont_pkt =
301962306a36Sopenharmony_ci			    qlafx00_prep_cont_type1_iocb(req, &lcont_pkt);
302062306a36Sopenharmony_ci			cur_dsd = lcont_pkt.dsd;
302162306a36Sopenharmony_ci			avail_dsds = 5;
302262306a36Sopenharmony_ci			cont = 1;
302362306a36Sopenharmony_ci		}
302462306a36Sopenharmony_ci
302562306a36Sopenharmony_ci		append_dsd64(&cur_dsd, sg);
302662306a36Sopenharmony_ci		avail_dsds--;
302762306a36Sopenharmony_ci		if (avail_dsds == 0 && cont == 1) {
302862306a36Sopenharmony_ci			cont = 0;
302962306a36Sopenharmony_ci			memcpy_toio((void __iomem *)cont_pkt, &lcont_pkt,
303062306a36Sopenharmony_ci			    sizeof(lcont_pkt));
303162306a36Sopenharmony_ci		}
303262306a36Sopenharmony_ci
303362306a36Sopenharmony_ci	}
303462306a36Sopenharmony_ci	if (avail_dsds != 0 && cont == 1) {
303562306a36Sopenharmony_ci		memcpy_toio((void __iomem *)cont_pkt, &lcont_pkt,
303662306a36Sopenharmony_ci		    sizeof(lcont_pkt));
303762306a36Sopenharmony_ci	}
303862306a36Sopenharmony_ci}
303962306a36Sopenharmony_ci
304062306a36Sopenharmony_ci/**
304162306a36Sopenharmony_ci * qlafx00_start_scsi() - Send a SCSI command to the ISP
304262306a36Sopenharmony_ci * @sp: command to send to the ISP
304362306a36Sopenharmony_ci *
304462306a36Sopenharmony_ci * Returns non-zero if a failure occurred, else zero.
304562306a36Sopenharmony_ci */
304662306a36Sopenharmony_ciint
304762306a36Sopenharmony_ciqlafx00_start_scsi(srb_t *sp)
304862306a36Sopenharmony_ci{
304962306a36Sopenharmony_ci	int		nseg;
305062306a36Sopenharmony_ci	unsigned long   flags;
305162306a36Sopenharmony_ci	uint32_t	handle;
305262306a36Sopenharmony_ci	uint16_t	cnt;
305362306a36Sopenharmony_ci	uint16_t	req_cnt;
305462306a36Sopenharmony_ci	uint16_t	tot_dsds;
305562306a36Sopenharmony_ci	struct req_que *req = NULL;
305662306a36Sopenharmony_ci	struct rsp_que *rsp = NULL;
305762306a36Sopenharmony_ci	struct scsi_cmnd *cmd = GET_CMD_SP(sp);
305862306a36Sopenharmony_ci	struct scsi_qla_host *vha = sp->vha;
305962306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
306062306a36Sopenharmony_ci	struct cmd_type_7_fx00 *cmd_pkt;
306162306a36Sopenharmony_ci	struct cmd_type_7_fx00 lcmd_pkt;
306262306a36Sopenharmony_ci	struct scsi_lun llun;
306362306a36Sopenharmony_ci
306462306a36Sopenharmony_ci	/* Setup device pointers. */
306562306a36Sopenharmony_ci	rsp = ha->rsp_q_map[0];
306662306a36Sopenharmony_ci	req = vha->req;
306762306a36Sopenharmony_ci
306862306a36Sopenharmony_ci	/* So we know we haven't pci_map'ed anything yet */
306962306a36Sopenharmony_ci	tot_dsds = 0;
307062306a36Sopenharmony_ci
307162306a36Sopenharmony_ci	/* Acquire ring specific lock */
307262306a36Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
307362306a36Sopenharmony_ci
307462306a36Sopenharmony_ci	handle = qla2xxx_get_next_handle(req);
307562306a36Sopenharmony_ci	if (handle == 0)
307662306a36Sopenharmony_ci		goto queuing_error;
307762306a36Sopenharmony_ci
307862306a36Sopenharmony_ci	/* Map the sg table so we have an accurate count of sg entries needed */
307962306a36Sopenharmony_ci	if (scsi_sg_count(cmd)) {
308062306a36Sopenharmony_ci		nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd),
308162306a36Sopenharmony_ci		    scsi_sg_count(cmd), cmd->sc_data_direction);
308262306a36Sopenharmony_ci		if (unlikely(!nseg))
308362306a36Sopenharmony_ci			goto queuing_error;
308462306a36Sopenharmony_ci	} else
308562306a36Sopenharmony_ci		nseg = 0;
308662306a36Sopenharmony_ci
308762306a36Sopenharmony_ci	tot_dsds = nseg;
308862306a36Sopenharmony_ci	req_cnt = qla24xx_calc_iocbs(vha, tot_dsds);
308962306a36Sopenharmony_ci	if (req->cnt < (req_cnt + 2)) {
309062306a36Sopenharmony_ci		cnt = rd_reg_dword_relaxed(req->req_q_out);
309162306a36Sopenharmony_ci
309262306a36Sopenharmony_ci		if (req->ring_index < cnt)
309362306a36Sopenharmony_ci			req->cnt = cnt - req->ring_index;
309462306a36Sopenharmony_ci		else
309562306a36Sopenharmony_ci			req->cnt = req->length -
309662306a36Sopenharmony_ci				(req->ring_index - cnt);
309762306a36Sopenharmony_ci		if (req->cnt < (req_cnt + 2))
309862306a36Sopenharmony_ci			goto queuing_error;
309962306a36Sopenharmony_ci	}
310062306a36Sopenharmony_ci
310162306a36Sopenharmony_ci	/* Build command packet. */
310262306a36Sopenharmony_ci	req->current_outstanding_cmd = handle;
310362306a36Sopenharmony_ci	req->outstanding_cmds[handle] = sp;
310462306a36Sopenharmony_ci	sp->handle = handle;
310562306a36Sopenharmony_ci	cmd->host_scribble = (unsigned char *)(unsigned long)handle;
310662306a36Sopenharmony_ci	req->cnt -= req_cnt;
310762306a36Sopenharmony_ci
310862306a36Sopenharmony_ci	cmd_pkt = (struct cmd_type_7_fx00 *)req->ring_ptr;
310962306a36Sopenharmony_ci
311062306a36Sopenharmony_ci	memset(&lcmd_pkt, 0, REQUEST_ENTRY_SIZE);
311162306a36Sopenharmony_ci
311262306a36Sopenharmony_ci	lcmd_pkt.handle = make_handle(req->id, sp->handle);
311362306a36Sopenharmony_ci	lcmd_pkt.reserved_0 = 0;
311462306a36Sopenharmony_ci	lcmd_pkt.port_path_ctrl = 0;
311562306a36Sopenharmony_ci	lcmd_pkt.reserved_1 = 0;
311662306a36Sopenharmony_ci	lcmd_pkt.dseg_count = cpu_to_le16(tot_dsds);
311762306a36Sopenharmony_ci	lcmd_pkt.tgt_idx = cpu_to_le16(sp->fcport->tgt_id);
311862306a36Sopenharmony_ci
311962306a36Sopenharmony_ci	int_to_scsilun(cmd->device->lun, &llun);
312062306a36Sopenharmony_ci	host_to_adap((uint8_t *)&llun, (uint8_t *)&lcmd_pkt.lun,
312162306a36Sopenharmony_ci	    sizeof(lcmd_pkt.lun));
312262306a36Sopenharmony_ci
312362306a36Sopenharmony_ci	/* Load SCSI command packet. */
312462306a36Sopenharmony_ci	host_to_adap(cmd->cmnd, lcmd_pkt.fcp_cdb, sizeof(lcmd_pkt.fcp_cdb));
312562306a36Sopenharmony_ci	lcmd_pkt.byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd));
312662306a36Sopenharmony_ci
312762306a36Sopenharmony_ci	/* Build IOCB segments */
312862306a36Sopenharmony_ci	qlafx00_build_scsi_iocbs(sp, cmd_pkt, tot_dsds, &lcmd_pkt);
312962306a36Sopenharmony_ci
313062306a36Sopenharmony_ci	/* Set total data segment count. */
313162306a36Sopenharmony_ci	lcmd_pkt.entry_count = (uint8_t)req_cnt;
313262306a36Sopenharmony_ci
313362306a36Sopenharmony_ci	/* Specify response queue number where completion should happen */
313462306a36Sopenharmony_ci	lcmd_pkt.entry_status = (uint8_t) rsp->id;
313562306a36Sopenharmony_ci
313662306a36Sopenharmony_ci	ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x302e,
313762306a36Sopenharmony_ci	    cmd->cmnd, cmd->cmd_len);
313862306a36Sopenharmony_ci	ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x3032,
313962306a36Sopenharmony_ci	    &lcmd_pkt, sizeof(lcmd_pkt));
314062306a36Sopenharmony_ci
314162306a36Sopenharmony_ci	memcpy_toio((void __iomem *)cmd_pkt, &lcmd_pkt, REQUEST_ENTRY_SIZE);
314262306a36Sopenharmony_ci	wmb();
314362306a36Sopenharmony_ci
314462306a36Sopenharmony_ci	/* Adjust ring index. */
314562306a36Sopenharmony_ci	req->ring_index++;
314662306a36Sopenharmony_ci	if (req->ring_index == req->length) {
314762306a36Sopenharmony_ci		req->ring_index = 0;
314862306a36Sopenharmony_ci		req->ring_ptr = req->ring;
314962306a36Sopenharmony_ci	} else
315062306a36Sopenharmony_ci		req->ring_ptr++;
315162306a36Sopenharmony_ci
315262306a36Sopenharmony_ci	sp->flags |= SRB_DMA_VALID;
315362306a36Sopenharmony_ci
315462306a36Sopenharmony_ci	/* Set chip new ring index. */
315562306a36Sopenharmony_ci	wrt_reg_dword(req->req_q_in, req->ring_index);
315662306a36Sopenharmony_ci	QLAFX00_SET_HST_INTR(ha, ha->rqstq_intr_code);
315762306a36Sopenharmony_ci
315862306a36Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
315962306a36Sopenharmony_ci	return QLA_SUCCESS;
316062306a36Sopenharmony_ci
316162306a36Sopenharmony_ciqueuing_error:
316262306a36Sopenharmony_ci	if (tot_dsds)
316362306a36Sopenharmony_ci		scsi_dma_unmap(cmd);
316462306a36Sopenharmony_ci
316562306a36Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
316662306a36Sopenharmony_ci
316762306a36Sopenharmony_ci	return QLA_FUNCTION_FAILED;
316862306a36Sopenharmony_ci}
316962306a36Sopenharmony_ci
317062306a36Sopenharmony_civoid
317162306a36Sopenharmony_ciqlafx00_tm_iocb(srb_t *sp, struct tsk_mgmt_entry_fx00 *ptm_iocb)
317262306a36Sopenharmony_ci{
317362306a36Sopenharmony_ci	struct srb_iocb *fxio = &sp->u.iocb_cmd;
317462306a36Sopenharmony_ci	scsi_qla_host_t *vha = sp->vha;
317562306a36Sopenharmony_ci	struct req_que *req = vha->req;
317662306a36Sopenharmony_ci	struct tsk_mgmt_entry_fx00 tm_iocb;
317762306a36Sopenharmony_ci	struct scsi_lun llun;
317862306a36Sopenharmony_ci
317962306a36Sopenharmony_ci	memset(&tm_iocb, 0, sizeof(struct tsk_mgmt_entry_fx00));
318062306a36Sopenharmony_ci	tm_iocb.entry_type = TSK_MGMT_IOCB_TYPE_FX00;
318162306a36Sopenharmony_ci	tm_iocb.entry_count = 1;
318262306a36Sopenharmony_ci	tm_iocb.handle = make_handle(req->id, sp->handle);
318362306a36Sopenharmony_ci	tm_iocb.reserved_0 = 0;
318462306a36Sopenharmony_ci	tm_iocb.tgt_id = cpu_to_le16(sp->fcport->tgt_id);
318562306a36Sopenharmony_ci	tm_iocb.control_flags = cpu_to_le32(fxio->u.tmf.flags);
318662306a36Sopenharmony_ci	if (tm_iocb.control_flags == cpu_to_le32((uint32_t)TCF_LUN_RESET)) {
318762306a36Sopenharmony_ci		int_to_scsilun(fxio->u.tmf.lun, &llun);
318862306a36Sopenharmony_ci		host_to_adap((uint8_t *)&llun, (uint8_t *)&tm_iocb.lun,
318962306a36Sopenharmony_ci		    sizeof(struct scsi_lun));
319062306a36Sopenharmony_ci	}
319162306a36Sopenharmony_ci
319262306a36Sopenharmony_ci	memcpy(ptm_iocb, &tm_iocb,
319362306a36Sopenharmony_ci	    sizeof(struct tsk_mgmt_entry_fx00));
319462306a36Sopenharmony_ci	wmb();
319562306a36Sopenharmony_ci}
319662306a36Sopenharmony_ci
319762306a36Sopenharmony_civoid
319862306a36Sopenharmony_ciqlafx00_abort_iocb(srb_t *sp, struct abort_iocb_entry_fx00 *pabt_iocb)
319962306a36Sopenharmony_ci{
320062306a36Sopenharmony_ci	struct srb_iocb *fxio = &sp->u.iocb_cmd;
320162306a36Sopenharmony_ci	scsi_qla_host_t *vha = sp->vha;
320262306a36Sopenharmony_ci	struct req_que *req = vha->req;
320362306a36Sopenharmony_ci	struct abort_iocb_entry_fx00 abt_iocb;
320462306a36Sopenharmony_ci
320562306a36Sopenharmony_ci	memset(&abt_iocb, 0, sizeof(struct abort_iocb_entry_fx00));
320662306a36Sopenharmony_ci	abt_iocb.entry_type = ABORT_IOCB_TYPE_FX00;
320762306a36Sopenharmony_ci	abt_iocb.entry_count = 1;
320862306a36Sopenharmony_ci	abt_iocb.handle = make_handle(req->id, sp->handle);
320962306a36Sopenharmony_ci	abt_iocb.abort_handle = make_handle(req->id, fxio->u.abt.cmd_hndl);
321062306a36Sopenharmony_ci	abt_iocb.tgt_id_sts = cpu_to_le16(sp->fcport->tgt_id);
321162306a36Sopenharmony_ci	abt_iocb.req_que_no = cpu_to_le16(req->id);
321262306a36Sopenharmony_ci
321362306a36Sopenharmony_ci	memcpy(pabt_iocb, &abt_iocb,
321462306a36Sopenharmony_ci	    sizeof(struct abort_iocb_entry_fx00));
321562306a36Sopenharmony_ci	wmb();
321662306a36Sopenharmony_ci}
321762306a36Sopenharmony_ci
321862306a36Sopenharmony_civoid
321962306a36Sopenharmony_ciqlafx00_fxdisc_iocb(srb_t *sp, struct fxdisc_entry_fx00 *pfxiocb)
322062306a36Sopenharmony_ci{
322162306a36Sopenharmony_ci	struct srb_iocb *fxio = &sp->u.iocb_cmd;
322262306a36Sopenharmony_ci	struct qla_mt_iocb_rqst_fx00 *piocb_rqst;
322362306a36Sopenharmony_ci	struct bsg_job *bsg_job;
322462306a36Sopenharmony_ci	struct fc_bsg_request *bsg_request;
322562306a36Sopenharmony_ci	struct fxdisc_entry_fx00 fx_iocb;
322662306a36Sopenharmony_ci	uint8_t entry_cnt = 1;
322762306a36Sopenharmony_ci
322862306a36Sopenharmony_ci	memset(&fx_iocb, 0, sizeof(struct fxdisc_entry_fx00));
322962306a36Sopenharmony_ci	fx_iocb.entry_type = FX00_IOCB_TYPE;
323062306a36Sopenharmony_ci	fx_iocb.handle = sp->handle;
323162306a36Sopenharmony_ci	fx_iocb.entry_count = entry_cnt;
323262306a36Sopenharmony_ci
323362306a36Sopenharmony_ci	if (sp->type == SRB_FXIOCB_DCMD) {
323462306a36Sopenharmony_ci		fx_iocb.func_num =
323562306a36Sopenharmony_ci		    sp->u.iocb_cmd.u.fxiocb.req_func_type;
323662306a36Sopenharmony_ci		fx_iocb.adapid = fxio->u.fxiocb.adapter_id;
323762306a36Sopenharmony_ci		fx_iocb.adapid_hi = fxio->u.fxiocb.adapter_id_hi;
323862306a36Sopenharmony_ci		fx_iocb.reserved_0 = fxio->u.fxiocb.reserved_0;
323962306a36Sopenharmony_ci		fx_iocb.reserved_1 = fxio->u.fxiocb.reserved_1;
324062306a36Sopenharmony_ci		fx_iocb.dataword_extra = fxio->u.fxiocb.req_data_extra;
324162306a36Sopenharmony_ci
324262306a36Sopenharmony_ci		if (fxio->u.fxiocb.flags & SRB_FXDISC_REQ_DMA_VALID) {
324362306a36Sopenharmony_ci			fx_iocb.req_dsdcnt = cpu_to_le16(1);
324462306a36Sopenharmony_ci			fx_iocb.req_xfrcnt =
324562306a36Sopenharmony_ci			    cpu_to_le16(fxio->u.fxiocb.req_len);
324662306a36Sopenharmony_ci			put_unaligned_le64(fxio->u.fxiocb.req_dma_handle,
324762306a36Sopenharmony_ci					   &fx_iocb.dseg_rq[0].address);
324862306a36Sopenharmony_ci			fx_iocb.dseg_rq[0].length =
324962306a36Sopenharmony_ci			    cpu_to_le32(fxio->u.fxiocb.req_len);
325062306a36Sopenharmony_ci		}
325162306a36Sopenharmony_ci
325262306a36Sopenharmony_ci		if (fxio->u.fxiocb.flags & SRB_FXDISC_RESP_DMA_VALID) {
325362306a36Sopenharmony_ci			fx_iocb.rsp_dsdcnt = cpu_to_le16(1);
325462306a36Sopenharmony_ci			fx_iocb.rsp_xfrcnt =
325562306a36Sopenharmony_ci			    cpu_to_le16(fxio->u.fxiocb.rsp_len);
325662306a36Sopenharmony_ci			put_unaligned_le64(fxio->u.fxiocb.rsp_dma_handle,
325762306a36Sopenharmony_ci					   &fx_iocb.dseg_rsp[0].address);
325862306a36Sopenharmony_ci			fx_iocb.dseg_rsp[0].length =
325962306a36Sopenharmony_ci			    cpu_to_le32(fxio->u.fxiocb.rsp_len);
326062306a36Sopenharmony_ci		}
326162306a36Sopenharmony_ci
326262306a36Sopenharmony_ci		if (fxio->u.fxiocb.flags & SRB_FXDISC_REQ_DWRD_VALID) {
326362306a36Sopenharmony_ci			fx_iocb.dataword = fxio->u.fxiocb.req_data;
326462306a36Sopenharmony_ci		}
326562306a36Sopenharmony_ci		fx_iocb.flags = fxio->u.fxiocb.flags;
326662306a36Sopenharmony_ci	} else {
326762306a36Sopenharmony_ci		struct scatterlist *sg;
326862306a36Sopenharmony_ci
326962306a36Sopenharmony_ci		bsg_job = sp->u.bsg_job;
327062306a36Sopenharmony_ci		bsg_request = bsg_job->request;
327162306a36Sopenharmony_ci		piocb_rqst = (struct qla_mt_iocb_rqst_fx00 *)
327262306a36Sopenharmony_ci			&bsg_request->rqst_data.h_vendor.vendor_cmd[1];
327362306a36Sopenharmony_ci
327462306a36Sopenharmony_ci		fx_iocb.func_num = piocb_rqst->func_type;
327562306a36Sopenharmony_ci		fx_iocb.adapid = piocb_rqst->adapid;
327662306a36Sopenharmony_ci		fx_iocb.adapid_hi = piocb_rqst->adapid_hi;
327762306a36Sopenharmony_ci		fx_iocb.reserved_0 = piocb_rqst->reserved_0;
327862306a36Sopenharmony_ci		fx_iocb.reserved_1 = piocb_rqst->reserved_1;
327962306a36Sopenharmony_ci		fx_iocb.dataword_extra = piocb_rqst->dataword_extra;
328062306a36Sopenharmony_ci		fx_iocb.dataword = piocb_rqst->dataword;
328162306a36Sopenharmony_ci		fx_iocb.req_xfrcnt = piocb_rqst->req_len;
328262306a36Sopenharmony_ci		fx_iocb.rsp_xfrcnt = piocb_rqst->rsp_len;
328362306a36Sopenharmony_ci
328462306a36Sopenharmony_ci		if (piocb_rqst->flags & SRB_FXDISC_REQ_DMA_VALID) {
328562306a36Sopenharmony_ci			int avail_dsds, tot_dsds;
328662306a36Sopenharmony_ci			cont_a64_entry_t lcont_pkt;
328762306a36Sopenharmony_ci			cont_a64_entry_t *cont_pkt = NULL;
328862306a36Sopenharmony_ci			struct dsd64 *cur_dsd;
328962306a36Sopenharmony_ci			int index = 0, cont = 0;
329062306a36Sopenharmony_ci
329162306a36Sopenharmony_ci			fx_iocb.req_dsdcnt =
329262306a36Sopenharmony_ci			    cpu_to_le16(bsg_job->request_payload.sg_cnt);
329362306a36Sopenharmony_ci			tot_dsds =
329462306a36Sopenharmony_ci			    bsg_job->request_payload.sg_cnt;
329562306a36Sopenharmony_ci			cur_dsd = &fx_iocb.dseg_rq[0];
329662306a36Sopenharmony_ci			avail_dsds = 1;
329762306a36Sopenharmony_ci			for_each_sg(bsg_job->request_payload.sg_list, sg,
329862306a36Sopenharmony_ci			    tot_dsds, index) {
329962306a36Sopenharmony_ci				/* Allocate additional continuation packets? */
330062306a36Sopenharmony_ci				if (avail_dsds == 0) {
330162306a36Sopenharmony_ci					/*
330262306a36Sopenharmony_ci					 * Five DSDs are available in the Cont.
330362306a36Sopenharmony_ci					 * Type 1 IOCB.
330462306a36Sopenharmony_ci					 */
330562306a36Sopenharmony_ci					memset(&lcont_pkt, 0,
330662306a36Sopenharmony_ci					    REQUEST_ENTRY_SIZE);
330762306a36Sopenharmony_ci					cont_pkt =
330862306a36Sopenharmony_ci					    qlafx00_prep_cont_type1_iocb(
330962306a36Sopenharmony_ci						sp->vha->req, &lcont_pkt);
331062306a36Sopenharmony_ci					cur_dsd = lcont_pkt.dsd;
331162306a36Sopenharmony_ci					avail_dsds = 5;
331262306a36Sopenharmony_ci					cont = 1;
331362306a36Sopenharmony_ci					entry_cnt++;
331462306a36Sopenharmony_ci				}
331562306a36Sopenharmony_ci
331662306a36Sopenharmony_ci				append_dsd64(&cur_dsd, sg);
331762306a36Sopenharmony_ci				avail_dsds--;
331862306a36Sopenharmony_ci
331962306a36Sopenharmony_ci				if (avail_dsds == 0 && cont == 1) {
332062306a36Sopenharmony_ci					cont = 0;
332162306a36Sopenharmony_ci					memcpy_toio(
332262306a36Sopenharmony_ci					    (void __iomem *)cont_pkt,
332362306a36Sopenharmony_ci					    &lcont_pkt, REQUEST_ENTRY_SIZE);
332462306a36Sopenharmony_ci					ql_dump_buffer(
332562306a36Sopenharmony_ci					    ql_dbg_user + ql_dbg_verbose,
332662306a36Sopenharmony_ci					    sp->vha, 0x3042,
332762306a36Sopenharmony_ci					    (uint8_t *)&lcont_pkt,
332862306a36Sopenharmony_ci					     REQUEST_ENTRY_SIZE);
332962306a36Sopenharmony_ci				}
333062306a36Sopenharmony_ci			}
333162306a36Sopenharmony_ci			if (avail_dsds != 0 && cont == 1) {
333262306a36Sopenharmony_ci				memcpy_toio((void __iomem *)cont_pkt,
333362306a36Sopenharmony_ci				    &lcont_pkt, REQUEST_ENTRY_SIZE);
333462306a36Sopenharmony_ci				ql_dump_buffer(ql_dbg_user + ql_dbg_verbose,
333562306a36Sopenharmony_ci				    sp->vha, 0x3043,
333662306a36Sopenharmony_ci				    (uint8_t *)&lcont_pkt, REQUEST_ENTRY_SIZE);
333762306a36Sopenharmony_ci			}
333862306a36Sopenharmony_ci		}
333962306a36Sopenharmony_ci
334062306a36Sopenharmony_ci		if (piocb_rqst->flags & SRB_FXDISC_RESP_DMA_VALID) {
334162306a36Sopenharmony_ci			int avail_dsds, tot_dsds;
334262306a36Sopenharmony_ci			cont_a64_entry_t lcont_pkt;
334362306a36Sopenharmony_ci			cont_a64_entry_t *cont_pkt = NULL;
334462306a36Sopenharmony_ci			struct dsd64 *cur_dsd;
334562306a36Sopenharmony_ci			int index = 0, cont = 0;
334662306a36Sopenharmony_ci
334762306a36Sopenharmony_ci			fx_iocb.rsp_dsdcnt =
334862306a36Sopenharmony_ci			   cpu_to_le16(bsg_job->reply_payload.sg_cnt);
334962306a36Sopenharmony_ci			tot_dsds = bsg_job->reply_payload.sg_cnt;
335062306a36Sopenharmony_ci			cur_dsd = &fx_iocb.dseg_rsp[0];
335162306a36Sopenharmony_ci			avail_dsds = 1;
335262306a36Sopenharmony_ci
335362306a36Sopenharmony_ci			for_each_sg(bsg_job->reply_payload.sg_list, sg,
335462306a36Sopenharmony_ci			    tot_dsds, index) {
335562306a36Sopenharmony_ci				/* Allocate additional continuation packets? */
335662306a36Sopenharmony_ci				if (avail_dsds == 0) {
335762306a36Sopenharmony_ci					/*
335862306a36Sopenharmony_ci					* Five DSDs are available in the Cont.
335962306a36Sopenharmony_ci					* Type 1 IOCB.
336062306a36Sopenharmony_ci					*/
336162306a36Sopenharmony_ci					memset(&lcont_pkt, 0,
336262306a36Sopenharmony_ci					    REQUEST_ENTRY_SIZE);
336362306a36Sopenharmony_ci					cont_pkt =
336462306a36Sopenharmony_ci					    qlafx00_prep_cont_type1_iocb(
336562306a36Sopenharmony_ci						sp->vha->req, &lcont_pkt);
336662306a36Sopenharmony_ci					cur_dsd = lcont_pkt.dsd;
336762306a36Sopenharmony_ci					avail_dsds = 5;
336862306a36Sopenharmony_ci					cont = 1;
336962306a36Sopenharmony_ci					entry_cnt++;
337062306a36Sopenharmony_ci				}
337162306a36Sopenharmony_ci
337262306a36Sopenharmony_ci				append_dsd64(&cur_dsd, sg);
337362306a36Sopenharmony_ci				avail_dsds--;
337462306a36Sopenharmony_ci
337562306a36Sopenharmony_ci				if (avail_dsds == 0 && cont == 1) {
337662306a36Sopenharmony_ci					cont = 0;
337762306a36Sopenharmony_ci					memcpy_toio((void __iomem *)cont_pkt,
337862306a36Sopenharmony_ci					    &lcont_pkt,
337962306a36Sopenharmony_ci					    REQUEST_ENTRY_SIZE);
338062306a36Sopenharmony_ci					ql_dump_buffer(
338162306a36Sopenharmony_ci					    ql_dbg_user + ql_dbg_verbose,
338262306a36Sopenharmony_ci					    sp->vha, 0x3045,
338362306a36Sopenharmony_ci					    (uint8_t *)&lcont_pkt,
338462306a36Sopenharmony_ci					    REQUEST_ENTRY_SIZE);
338562306a36Sopenharmony_ci				}
338662306a36Sopenharmony_ci			}
338762306a36Sopenharmony_ci			if (avail_dsds != 0 && cont == 1) {
338862306a36Sopenharmony_ci				memcpy_toio((void __iomem *)cont_pkt,
338962306a36Sopenharmony_ci				    &lcont_pkt, REQUEST_ENTRY_SIZE);
339062306a36Sopenharmony_ci				ql_dump_buffer(ql_dbg_user + ql_dbg_verbose,
339162306a36Sopenharmony_ci				    sp->vha, 0x3046,
339262306a36Sopenharmony_ci				    (uint8_t *)&lcont_pkt, REQUEST_ENTRY_SIZE);
339362306a36Sopenharmony_ci			}
339462306a36Sopenharmony_ci		}
339562306a36Sopenharmony_ci
339662306a36Sopenharmony_ci		if (piocb_rqst->flags & SRB_FXDISC_REQ_DWRD_VALID)
339762306a36Sopenharmony_ci			fx_iocb.dataword = piocb_rqst->dataword;
339862306a36Sopenharmony_ci		fx_iocb.flags = piocb_rqst->flags;
339962306a36Sopenharmony_ci		fx_iocb.entry_count = entry_cnt;
340062306a36Sopenharmony_ci	}
340162306a36Sopenharmony_ci
340262306a36Sopenharmony_ci	ql_dump_buffer(ql_dbg_user + ql_dbg_verbose,
340362306a36Sopenharmony_ci	    sp->vha, 0x3047, &fx_iocb, sizeof(fx_iocb));
340462306a36Sopenharmony_ci
340562306a36Sopenharmony_ci	memcpy_toio((void __iomem *)pfxiocb, &fx_iocb, sizeof(fx_iocb));
340662306a36Sopenharmony_ci	wmb();
340762306a36Sopenharmony_ci}
3408